@hasna/skills 0.10.61 → 0.10.63
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 +41 -0
- package/bin/index.js +2029 -1688
- package/bin/mcp.js +705 -553
- package/bin/migrate.js +8 -3
- package/bin/server.js +8 -3
- package/bin/worker.js +8 -3
- package/dist/cli/commands/runtime-copyfile.d.ts +1 -0
- package/dist/index.js +1118 -873
- package/dist/lib/agent-discovery.d.ts +3 -0
- package/dist/lib/agent-install-selection.d.ts +1 -0
- package/dist/lib/agent-integration.d.ts +19 -0
- package/dist/lib/retained-review-artifacts.d.ts +35 -0
- package/dist/runtime-prerequisites.d.ts +9 -0
- package/dist/runtime-prerequisites.js +3098 -0
- package/dist/sdk/index.js +1260 -1015
- package/docs/runtime-activation.md +23 -0
- package/package.json +8 -3
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.63",
|
|
27
27
|
description: "Skills library for AI coding agents",
|
|
28
28
|
type: "module",
|
|
29
29
|
bin: {
|
|
@@ -64,6 +64,7 @@ var init_package = __esm(() => {
|
|
|
64
64
|
"migrations/",
|
|
65
65
|
"docs/skill-standard.md",
|
|
66
66
|
"docs/plugin-admission.md",
|
|
67
|
+
"docs/runtime-activation.md",
|
|
67
68
|
"schemas/",
|
|
68
69
|
"LICENSE",
|
|
69
70
|
"README.md",
|
|
@@ -74,8 +75,8 @@ var init_package = __esm(() => {
|
|
|
74
75
|
types: "./dist/index.d.ts",
|
|
75
76
|
scripts: {
|
|
76
77
|
clean: "rm -rf bin/ dist/",
|
|
77
|
-
build: "bun run clean && bun build --external @hasna/contracts/kernel-lock ./src/cli/index.tsx --outdir ./bin --target bun && bun build --external @modelcontextprotocol/sdk ./src/mcp/index.ts --outfile ./bin/mcp.js --target bun && bun build --external @hasna/contracts/kernel-lock ./src/server/index.ts --outfile ./bin/server.js --target bun && bun build --external @hasna/contracts/kernel-lock ./src/server/worker.ts --outfile ./bin/worker.js --target bun && bun build --external @hasna/contracts/kernel-lock ./src/server/migrate.ts --outfile ./bin/migrate.js --target bun && bun build --external @hasna/contracts/kernel-lock ./src/server/maintenance.ts --outfile ./bin/maintenance.js --target bun && bun build ./src/index.ts ./src/storage.ts ./src/sdk/index.ts ./src/admin-contract.ts --outdir ./dist --target bun && tsc --emitDeclarationOnly --declaration --outDir dist && bun scripts/stage-kernel-lock-assets.ts",
|
|
78
|
-
"build:js": "rm -rf dist && bun build ./src/index.ts ./src/storage.ts ./src/sdk/index.ts ./src/admin-contract.ts --outdir ./dist --target bun && tsc --emitDeclarationOnly --declaration --outDir dist && bun scripts/stage-kernel-lock-assets.ts",
|
|
78
|
+
build: "bun run clean && bun build --external @hasna/contracts/kernel-lock ./src/cli/index.tsx --outdir ./bin --target bun && bun build --external @modelcontextprotocol/sdk ./src/mcp/index.ts --outfile ./bin/mcp.js --target bun && bun build --external @hasna/contracts/kernel-lock ./src/server/index.ts --outfile ./bin/server.js --target bun && bun build --external @hasna/contracts/kernel-lock ./src/server/worker.ts --outfile ./bin/worker.js --target bun && bun build --external @hasna/contracts/kernel-lock ./src/server/migrate.ts --outfile ./bin/migrate.js --target bun && bun build --external @hasna/contracts/kernel-lock ./src/server/maintenance.ts --outfile ./bin/maintenance.js --target bun && bun build ./src/index.ts ./src/storage.ts ./src/sdk/index.ts ./src/admin-contract.ts ./src/runtime-prerequisites.ts --outdir ./dist --target bun && tsc --emitDeclarationOnly --declaration --outDir dist && bun scripts/stage-kernel-lock-assets.ts",
|
|
79
|
+
"build:js": "rm -rf dist && bun build ./src/index.ts ./src/storage.ts ./src/sdk/index.ts ./src/admin-contract.ts ./src/runtime-prerequisites.ts --outdir ./dist --target bun && tsc --emitDeclarationOnly --declaration --outDir dist && bun scripts/stage-kernel-lock-assets.ts",
|
|
79
80
|
test: "bun test --timeout 30000",
|
|
80
81
|
dev: "bun run ./src/cli/index.tsx",
|
|
81
82
|
"dev:watch": "bun --watch run ./src/cli/index.tsx",
|
|
@@ -152,6 +153,10 @@ var init_package = __esm(() => {
|
|
|
152
153
|
homepage: "https://github.com/hasna/skills/tree/main/apps/skills",
|
|
153
154
|
bugs: {
|
|
154
155
|
url: "https://github.com/hasna/skills/issues"
|
|
156
|
+
},
|
|
157
|
+
skillsRuntimePrerequisites: {
|
|
158
|
+
version: 1,
|
|
159
|
+
entry: "dist/runtime-prerequisites.js"
|
|
155
160
|
}
|
|
156
161
|
};
|
|
157
162
|
});
|
|
@@ -23114,6 +23119,15 @@ function assertAgentPolicyCollections(policy) {
|
|
|
23114
23119
|
}
|
|
23115
23120
|
} else
|
|
23116
23121
|
requireBound(source.managedPlugins === undefined);
|
|
23122
|
+
if (source.reviewArtifact !== undefined) {
|
|
23123
|
+
const artifact = source.reviewArtifact;
|
|
23124
|
+
requireBound(agent === "codex" && value.method === "reviewed" && source.hashMode === "bytes" && object2(artifact) && Object.keys(artifact).length === 6 && Object.keys(artifact).every((key) => ["version", "kind", "storeRoot", "originalPath", "sha256", "catalogSha256"].includes(key)) && artifact.version === 1 && artifact.kind === "codex-native-catalog" && artifact.sha256 === source.sha256 && /^[a-f0-9]{64}$/.test(artifact.catalogSha256));
|
|
23125
|
+
for (const path of [artifact.storeRoot, artifact.originalPath]) {
|
|
23126
|
+
text(path);
|
|
23127
|
+
requireBound(isAbsolute5(path) && resolve4(path) === path);
|
|
23128
|
+
}
|
|
23129
|
+
requireBound(source.path === join10(artifact.storeRoot, "agent-discovery", "artifacts", artifact.sha256, "catalog.json"));
|
|
23130
|
+
}
|
|
23117
23131
|
if (source.format !== undefined)
|
|
23118
23132
|
requireBound(["json", "toml", "yaml"].includes(source.format));
|
|
23119
23133
|
if (source.fields !== undefined)
|
|
@@ -32717,11 +32731,55 @@ var init_codex_hook_rpc = __esm(() => {
|
|
|
32717
32731
|
});
|
|
32718
32732
|
|
|
32719
32733
|
// src/lib/codex-native-skill-catalog.ts
|
|
32734
|
+
import { isAbsolute as isAbsolute10, normalize as normalize2 } from "path";
|
|
32720
32735
|
function codexPluginSourceIsConfigControlled(plugin) {
|
|
32721
32736
|
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"];
|
|
32722
32737
|
return Boolean(plugin.sourceType && ["local", "git", "npm"].includes(plugin.sourceType) && plugin.sourceSha256 && /^[a-f0-9]{64}$/.test(plugin.sourceSha256) && !plugin.remotePluginId && !remoteRealms.includes(plugin.id.slice(plugin.id.lastIndexOf("@") + 1)));
|
|
32723
32738
|
}
|
|
32724
|
-
|
|
32739
|
+
function refuse() {
|
|
32740
|
+
throw new Error("CODEX_NATIVE_SKILL_CATALOG_INVALID");
|
|
32741
|
+
}
|
|
32742
|
+
function projectCodexNativeSkillCatalog(response, cwd) {
|
|
32743
|
+
if (!absolutePath2(cwd) || !object5(response) || !Array.isArray(response.data) || response.data.length !== 1)
|
|
32744
|
+
refuse();
|
|
32745
|
+
const entry = response.data[0];
|
|
32746
|
+
if (!object5(entry) || entry.cwd !== cwd || !Array.isArray(entry.errors) || entry.errors.length !== 0 || !Array.isArray(entry.skills) || entry.skills.length > MAX_SKILLS)
|
|
32747
|
+
refuse();
|
|
32748
|
+
const paths = new Set;
|
|
32749
|
+
return entry.skills.map((value) => {
|
|
32750
|
+
if (!object5(value) || !scalar(value.name, MAX_NAME_BYTES) || !absolutePath2(value.path) || typeof value.enabled !== "boolean" || value.pluginId !== undefined && value.pluginId !== null && !scalar(value.pluginId, MAX_NAME_BYTES))
|
|
32751
|
+
refuse();
|
|
32752
|
+
if (paths.has(value.path))
|
|
32753
|
+
refuse();
|
|
32754
|
+
paths.add(value.path);
|
|
32755
|
+
return { name: value.name, path: value.path, enabled: value.enabled, pluginId: value.pluginId ?? null };
|
|
32756
|
+
});
|
|
32757
|
+
}
|
|
32758
|
+
function projectCodexInstalledPluginEntries(value) {
|
|
32759
|
+
if (!Array.isArray(value) || value.length > MAX_SKILLS)
|
|
32760
|
+
refuse();
|
|
32761
|
+
const ids = new Set;
|
|
32762
|
+
return value.map((item) => {
|
|
32763
|
+
if (!object5(item) || !scalar(item.id, MAX_PLUGIN_ID_BYTES) || !scalar(item.name, MAX_NAME_BYTES) || typeof item.installed !== "boolean" || typeof item.enabled !== "boolean" || item.localVersion !== null && !scalar(item.localVersion, MAX_NAME_BYTES) || item.remotePluginId !== undefined && item.remotePluginId !== null && !remotePluginIdentifier(item.remotePluginId) || item.sourceType !== undefined && !["remote", "local", "git", "npm"].includes(item.sourceType) || (["local", "git", "npm"].includes(item.sourceType) ? typeof item.sourceSha256 !== "string" || !/^[a-f0-9]{64}$/.test(item.sourceSha256) : item.sourceSha256 !== undefined) || (item.sourceType === "local" ? !absolutePath2(item.sourcePath) || normalize2(item.sourcePath) !== item.sourcePath || item.sourceSha256 !== hashNativeJsonControls(JSON.stringify({ type: "local", path: item.sourcePath })) : item.sourcePath !== undefined))
|
|
32764
|
+
refuse();
|
|
32765
|
+
const at = item.id.lastIndexOf("@");
|
|
32766
|
+
if (at < 1 || item.id.slice(0, at) !== item.name || at === item.id.length - 1 || ids.has(item.id))
|
|
32767
|
+
refuse();
|
|
32768
|
+
ids.add(item.id);
|
|
32769
|
+
return {
|
|
32770
|
+
id: item.id,
|
|
32771
|
+
name: item.name,
|
|
32772
|
+
installed: item.installed,
|
|
32773
|
+
enabled: item.enabled,
|
|
32774
|
+
localVersion: item.localVersion ?? null,
|
|
32775
|
+
...item.sourceType === undefined ? {} : { sourceType: item.sourceType },
|
|
32776
|
+
...item.sourceSha256 === undefined ? {} : { sourceSha256: item.sourceSha256 },
|
|
32777
|
+
...item.sourcePath === undefined ? {} : { sourcePath: item.sourcePath },
|
|
32778
|
+
...item.remotePluginId == null ? {} : { remotePluginId: item.remotePluginId }
|
|
32779
|
+
};
|
|
32780
|
+
});
|
|
32781
|
+
}
|
|
32782
|
+
var MAX_SKILLS = 4096, MAX_NAME_BYTES = 1024, MAX_PATH_BYTES = 16384, MAX_PLUGIN_ID_BYTES = 1024, object5 = (value) => value !== null && typeof value === "object" && !Array.isArray(value), scalar = (value, max) => typeof value === "string" && value.length > 0 && value.trim() === value && Buffer.byteLength(value, "utf8") <= max && !/[\u0000-\u001f\u007f]/u.test(value), remotePluginIdentifier = (value) => typeof value === "string" && /^[A-Za-z0-9_~-]{1,1024}$/.test(value), absolutePath2 = (value) => scalar(value, MAX_PATH_BYTES) && isAbsolute10(value);
|
|
32725
32783
|
var init_codex_native_skill_catalog = __esm(() => {
|
|
32726
32784
|
init_codex_hook_rpc();
|
|
32727
32785
|
init_codex_native_compatibility();
|
|
@@ -32731,7 +32789,7 @@ var init_codex_native_skill_catalog = __esm(() => {
|
|
|
32731
32789
|
// src/lib/codex-plugin-skill-controls.ts
|
|
32732
32790
|
import { basename as basename6, dirname as dirname12, join as join18, relative as relative5, resolve as resolve11, sep as sep6 } from "path";
|
|
32733
32791
|
import { lstatSync as lstatSync12, readdirSync as readdirSync6, readlinkSync as readlinkSync3, realpathSync as realpathSync4 } from "fs";
|
|
32734
|
-
function
|
|
32792
|
+
function refuse2() {
|
|
32735
32793
|
throw new Error("CODEX_NATIVE_SKILL_IDENTITY_UNSUPPORTED: review native plugin names and hook controls");
|
|
32736
32794
|
}
|
|
32737
32795
|
function remoteInstallationMatches(parent, remotePluginId, read) {
|
|
@@ -32756,17 +32814,17 @@ function appControls(path, read) {
|
|
|
32756
32814
|
sha2562 = hashNativeJsonControls(text2);
|
|
32757
32815
|
value = JSON.parse(text2);
|
|
32758
32816
|
} catch {
|
|
32759
|
-
|
|
32817
|
+
refuse2();
|
|
32760
32818
|
}
|
|
32761
|
-
const
|
|
32762
|
-
if (!
|
|
32763
|
-
|
|
32819
|
+
const object6 = (v) => Boolean(v && typeof v === "object" && !Array.isArray(v));
|
|
32820
|
+
if (!object6(value) || Object.keys(value).length !== 1 || !object6(value.apps))
|
|
32821
|
+
refuse2();
|
|
32764
32822
|
const apps = Object.entries(value.apps);
|
|
32765
32823
|
if (!apps.length || apps.length > 256)
|
|
32766
|
-
|
|
32824
|
+
refuse2();
|
|
32767
32825
|
for (const [name, entry] of apps) {
|
|
32768
|
-
if (!identifier2(name) || !
|
|
32769
|
-
|
|
32826
|
+
if (!identifier2(name) || !object6(entry) || !Object.keys(entry).every((key) => ["id", "category", "required"].includes(key)) || typeof entry.id !== "string" || !/^[A-Za-z0-9_-]{1,256}$/.test(entry.id) || entry.category !== undefined && (typeof entry.category !== "string" || !entry.category.trim() || entry.category.length > 256 || /[\x00-\x1f\x7f]/.test(entry.category)) || entry.required !== undefined && typeof entry.required !== "boolean")
|
|
32827
|
+
refuse2();
|
|
32770
32828
|
}
|
|
32771
32829
|
return sha2562;
|
|
32772
32830
|
}
|
|
@@ -32777,26 +32835,26 @@ function mcpControls(path, read) {
|
|
|
32777
32835
|
sha2562 = hashNativeJsonControls(text2);
|
|
32778
32836
|
value = JSON.parse(text2);
|
|
32779
32837
|
} catch {
|
|
32780
|
-
|
|
32838
|
+
refuse2();
|
|
32781
32839
|
}
|
|
32782
|
-
const
|
|
32783
|
-
if (!
|
|
32784
|
-
|
|
32840
|
+
const object6 = (v) => Boolean(v && typeof v === "object" && !Array.isArray(v));
|
|
32841
|
+
if (!object6(value) || Object.keys(value).length !== 1 || !object6(value.mcpServers))
|
|
32842
|
+
refuse2();
|
|
32785
32843
|
const servers = Object.entries(value.mcpServers);
|
|
32786
32844
|
if (!servers.length || servers.length > 256)
|
|
32787
|
-
|
|
32845
|
+
refuse2();
|
|
32788
32846
|
for (const [name, server] of servers)
|
|
32789
32847
|
if (!isCodexLocalStdioMcpServer(name, server))
|
|
32790
|
-
|
|
32848
|
+
refuse2();
|
|
32791
32849
|
return sha2562;
|
|
32792
32850
|
}
|
|
32793
32851
|
function isBundledCleanupHooks(root, namespace, value) {
|
|
32794
|
-
const
|
|
32852
|
+
const object6 = (v) => Boolean(v && typeof v === "object" && !Array.isArray(v));
|
|
32795
32853
|
const exactKeys = (v, keys) => Object.keys(v).length === keys.length && keys.every((key) => Object.hasOwn(v, key));
|
|
32796
32854
|
if (basename6(dirname12(root)) !== namespace || basename6(dirname12(dirname12(root))) !== "openai-bundled")
|
|
32797
32855
|
return false;
|
|
32798
32856
|
const server = namespace === "unified-computer-use" ? "cua_repl" : ["browser", "chrome", "chrome-dev", "chrome-internal", "computer-use"].includes(namespace) ? "node_repl" : undefined;
|
|
32799
|
-
if (!server || !
|
|
32857
|
+
if (!server || !object6(value) || !exactKeys(value, ["hooks"]) || !object6(value.hooks))
|
|
32800
32858
|
return false;
|
|
32801
32859
|
const events = Object.entries(value.hooks);
|
|
32802
32860
|
if (!events.length || events.length > 3)
|
|
@@ -32805,10 +32863,10 @@ function isBundledCleanupHooks(root, namespace, value) {
|
|
|
32805
32863
|
if (!["Interrupt", "SubagentStop", "Stop"].includes(event) || !Array.isArray(groups) || groups.length !== 1)
|
|
32806
32864
|
return false;
|
|
32807
32865
|
const group = groups[0];
|
|
32808
|
-
if (!
|
|
32866
|
+
if (!object6(group) || !exactKeys(group, ["hooks"]) || !Array.isArray(group.hooks) || group.hooks.length !== 1)
|
|
32809
32867
|
return false;
|
|
32810
32868
|
const handler = group.hooks[0];
|
|
32811
|
-
if (!
|
|
32869
|
+
if (!object6(handler) || !exactKeys(handler, ["type", "server", "tool", "input"]) || handler.type !== "mcp_tool" || handler.server !== server || handler.tool !== "turn_ended" || !object6(handler.input) || !exactKeys(handler.input, ["hook_event_name", "session_id", "turn_id"]) || handler.input.hook_event_name !== "${hook_event_name}" || handler.input.turn_id !== "${turn_id}" || handler.input.session_id !== (event === "SubagentStop" ? "${agent_id}" : "${session_id}"))
|
|
32812
32870
|
return false;
|
|
32813
32871
|
}
|
|
32814
32872
|
return true;
|
|
@@ -32816,35 +32874,35 @@ function isBundledCleanupHooks(root, namespace, value) {
|
|
|
32816
32874
|
function rootControls(root, read) {
|
|
32817
32875
|
const manifestPath = join18(root, ".codex-plugin/plugin.json"), manifestFile = lstatSync12(manifestPath, { throwIfNoEntry: false });
|
|
32818
32876
|
if (!lstatSync12(join18(root, ".codex-plugin"), { throwIfNoEntry: false })?.isDirectory() || !manifestFile?.isFile() || manifestFile.size > 1024 * 1024)
|
|
32819
|
-
|
|
32877
|
+
refuse2();
|
|
32820
32878
|
let manifest, manifestSha256;
|
|
32821
32879
|
try {
|
|
32822
32880
|
const text2 = read(manifestPath);
|
|
32823
32881
|
manifestSha256 = hashNativeJsonControls(text2, "version");
|
|
32824
32882
|
manifest = JSON.parse(text2);
|
|
32825
32883
|
} catch {
|
|
32826
|
-
|
|
32884
|
+
refuse2();
|
|
32827
32885
|
}
|
|
32828
32886
|
if (!manifest || typeof manifest !== "object" || Array.isArray(manifest) || !identifier2(manifest.name))
|
|
32829
|
-
|
|
32887
|
+
refuse2();
|
|
32830
32888
|
const cacheVersion = basename6(root), declaredVersion = manifest.version === undefined ? "" : typeof manifest.version === "string" ? manifest.version.trim() : null;
|
|
32831
32889
|
if (declaredVersion === null || (declaredVersion ? declaredVersion !== cacheVersion : cacheVersion !== CODEX_DEFAULT_AGENT_PLUGIN_VERSION))
|
|
32832
|
-
|
|
32890
|
+
refuse2();
|
|
32833
32891
|
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" || lstatSync12(join18(root, "hooks"), { throwIfNoEntry: false }))
|
|
32834
|
-
|
|
32892
|
+
refuse2();
|
|
32835
32893
|
const mcp = join18(root, ".mcp.json"), mcpPresent = lstatSync12(mcp, { throwIfNoEntry: false });
|
|
32836
32894
|
if (manifest.hooks !== undefined && (manifest.mcpServers !== undefined || mcpPresent))
|
|
32837
|
-
|
|
32895
|
+
refuse2();
|
|
32838
32896
|
if (mcpPresent && (!mcpPresent.isFile() || mcpPresent.isSymbolicLink() || mcpPresent.size > 1024 * 1024 || realpathSync4(mcp) !== mcp))
|
|
32839
|
-
|
|
32897
|
+
refuse2();
|
|
32840
32898
|
if (Boolean(mcpPresent) !== (manifest.mcpServers !== undefined))
|
|
32841
|
-
|
|
32899
|
+
refuse2();
|
|
32842
32900
|
const mcpSha256 = mcpPresent ? mcpControls(mcp, read) : undefined;
|
|
32843
32901
|
const app = join18(root, ".app.json"), present = lstatSync12(app, { throwIfNoEntry: false });
|
|
32844
32902
|
if (present && (!present.isFile() || present.isSymbolicLink() || present.size > 1024 * 1024))
|
|
32845
|
-
|
|
32903
|
+
refuse2();
|
|
32846
32904
|
if (manifest.apps !== undefined && !present)
|
|
32847
|
-
|
|
32905
|
+
refuse2();
|
|
32848
32906
|
const appSha256 = present ? appControls(app, read) : undefined;
|
|
32849
32907
|
return { namespace: manifest.name, manifestSha256, ...appSha256 ? { appSha256 } : {}, ...mcpSha256 ? { mcpSha256 } : {} };
|
|
32850
32908
|
}
|
|
@@ -32960,10 +33018,10 @@ function sourceInputUnchanged(input2, cache, read) {
|
|
|
32960
33018
|
}
|
|
32961
33019
|
function reviewedCodexPluginSourceRoots(cache, inputs, read) {
|
|
32962
33020
|
if (!Array.isArray(inputs) || inputs.length > 4096 || new Set(inputs.map((input2) => input2.pluginId)).size !== inputs.length || new Set(inputs.map((input2) => input2.sourceRoot)).size !== inputs.length || inputs.some((input2) => !sourceInputUnchanged(input2, cache, read)))
|
|
32963
|
-
|
|
33021
|
+
refuse2();
|
|
32964
33022
|
const roots = inputs.map((input2) => input2.sourceRoot);
|
|
32965
33023
|
if (roots.some((root) => roots.some((other) => root !== other && root.startsWith(other + sep6))))
|
|
32966
|
-
|
|
33024
|
+
refuse2();
|
|
32967
33025
|
return roots;
|
|
32968
33026
|
}
|
|
32969
33027
|
var identifier2 = (v) => typeof v === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(v), CODEX_DEFAULT_AGENT_PLUGIN_VERSION = "1.0.0";
|
|
@@ -33218,7 +33276,7 @@ function canonical6(value, depth = 0, budget2 = { remaining: 65536 }) {
|
|
|
33218
33276
|
need5(isRecord3(value));
|
|
33219
33277
|
return ["object", Object.entries(value).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, child2]) => [key, canonical6(child2, depth + 1, budget2)])];
|
|
33220
33278
|
}
|
|
33221
|
-
function
|
|
33279
|
+
function normalize3(config2, version2 = 2) {
|
|
33222
33280
|
if (isRecord3(config2.hooks)) {
|
|
33223
33281
|
delete config2.hooks.state;
|
|
33224
33282
|
if (!Object.keys(config2.hooks).length)
|
|
@@ -33389,7 +33447,7 @@ function settingsDigest2(text2, version2 = 2) {
|
|
|
33389
33447
|
need5(isRecord3(config2));
|
|
33390
33448
|
const mcp = version2 >= 3 ? projectRegularCodexMcp(config2, text2) : { config: config2, numericSource: text2 };
|
|
33391
33449
|
const projected = version2 === 4 ? projectModelAvailabilityNux(mcp.config, mcp.numericSource) : mcp;
|
|
33392
|
-
|
|
33450
|
+
normalize3(projected.config, version2);
|
|
33393
33451
|
return sha2(`hasna.skills.codex-settings.v${version2}\x00${JSON.stringify([canonical6(projected.config), numericTokens2(projected.numericSource)])}`);
|
|
33394
33452
|
}
|
|
33395
33453
|
function hashCodexSettingsReplacementV2(text2, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
@@ -33540,15 +33598,15 @@ var init_agent_codex = () => {};
|
|
|
33540
33598
|
// src/lib/agent-sumi.ts
|
|
33541
33599
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
33542
33600
|
import { accessSync, constants as constants8, existsSync as existsSync8, lstatSync as lstatSync14, realpathSync as realpathSync5, statSync as statSync7 } from "fs";
|
|
33543
|
-
import { delimiter, isAbsolute as
|
|
33601
|
+
import { delimiter, isAbsolute as isAbsolute11, join as join20, resolve as resolve12 } from "path";
|
|
33544
33602
|
function recordWithKeys(value, keys) {
|
|
33545
33603
|
return value !== null && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
|
|
33546
33604
|
}
|
|
33547
|
-
function
|
|
33548
|
-
return typeof value === "string" && value.length > 0 && value.length <= 32768 && !/[\x00-\x1f\x7f]/.test(value) &&
|
|
33605
|
+
function absolutePath3(value) {
|
|
33606
|
+
return typeof value === "string" && value.length > 0 && value.length <= 32768 && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute11(value) && resolve12(value) === value;
|
|
33549
33607
|
}
|
|
33550
33608
|
function absoluteInput(value) {
|
|
33551
|
-
return value.length > 0 && value.length <= 32768 && !/[\x00-\x1f\x7f]/.test(value) &&
|
|
33609
|
+
return value.length > 0 && value.length <= 32768 && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute11(value);
|
|
33552
33610
|
}
|
|
33553
33611
|
function resolveSumiPathsCommand(pathValue) {
|
|
33554
33612
|
if (!pathValue)
|
|
@@ -33573,18 +33631,18 @@ function validPathPlan(value, home, cwd) {
|
|
|
33573
33631
|
if (!recordWithKeys(value.roots, SUMI_PATH_KEYS) || !recordWithKeys(value.legacyRoots, SUMI_PATH_KEYS))
|
|
33574
33632
|
return false;
|
|
33575
33633
|
for (const key of SUMI_PATH_KEYS) {
|
|
33576
|
-
if (!
|
|
33634
|
+
if (!absolutePath3(value.roots[key]))
|
|
33577
33635
|
return false;
|
|
33578
|
-
if (value.legacyRoots[key] !== null && !
|
|
33636
|
+
if (value.legacyRoots[key] !== null && !absolutePath3(value.legacyRoots[key]))
|
|
33579
33637
|
return false;
|
|
33580
33638
|
}
|
|
33581
33639
|
if (!recordWithKeys(value.configFiles, ["canonical", "legacy"]) || !recordWithKeys(value.skillRoots, ["canonical", "legacy"]))
|
|
33582
33640
|
return false;
|
|
33583
|
-
if (!
|
|
33641
|
+
if (!absolutePath3(value.configFiles.canonical) || !absolutePath3(value.skillRoots.canonical))
|
|
33584
33642
|
return false;
|
|
33585
|
-
if (value.configFiles.legacy !== null && !
|
|
33643
|
+
if (value.configFiles.legacy !== null && !absolutePath3(value.configFiles.legacy))
|
|
33586
33644
|
return false;
|
|
33587
|
-
if (value.skillRoots.legacy !== null && !
|
|
33645
|
+
if (value.skillRoots.legacy !== null && !absolutePath3(value.skillRoots.legacy))
|
|
33588
33646
|
return false;
|
|
33589
33647
|
const configRoot = value.roots.config;
|
|
33590
33648
|
const legacyConfigRoot = value.legacyRoots.config;
|
|
@@ -33604,7 +33662,7 @@ function sumiPathPlan(home, cwd = process.cwd(), env = process.env) {
|
|
|
33604
33662
|
throw new SumiPathResolverError("SUMI_PATH_INPUT_REFUSED");
|
|
33605
33663
|
const runtimePath = process.env.PATH ?? "";
|
|
33606
33664
|
const executable = resolveSumiPathsCommand(runtimePath);
|
|
33607
|
-
if (!executable || !
|
|
33665
|
+
if (!executable || !isAbsolute11(executable))
|
|
33608
33666
|
throw new SumiPathResolverError("SUMI_PATH_RESOLVER_UNAVAILABLE");
|
|
33609
33667
|
const childEnv = { PATH: runtimePath };
|
|
33610
33668
|
for (const key of SUMI_PATH_SELECTORS)
|
|
@@ -33680,7 +33738,7 @@ var init_agent_sumi = __esm(() => {
|
|
|
33680
33738
|
// src/lib/codex-hook-trust-files.ts
|
|
33681
33739
|
import { closeSync as closeSync11, constants as constants9, fstatSync as fstatSync11, fsyncSync as fsyncSync2, lstatSync as lstatSync15, openSync as openSync11, readlinkSync as readlinkSync4, readSync as readSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
33682
33740
|
import { createHash as createHash15 } from "crypto";
|
|
33683
|
-
import { dirname as dirname13, isAbsolute as
|
|
33741
|
+
import { dirname as dirname13, isAbsolute as isAbsolute12, resolve as resolve13 } from "path";
|
|
33684
33742
|
function need6(value, code) {
|
|
33685
33743
|
if (!value)
|
|
33686
33744
|
throw new Error(`CODEX_HOOK_TRUST_${code}`);
|
|
@@ -33780,6 +33838,96 @@ var init_runtime_launcher = __esm(() => {
|
|
|
33780
33838
|
PINNED_LAUNCHER_MAX_BYTES = 16 * 1024;
|
|
33781
33839
|
});
|
|
33782
33840
|
|
|
33841
|
+
// src/lib/retained-review-artifacts.ts
|
|
33842
|
+
import { createHash as createHash16 } from "crypto";
|
|
33843
|
+
import { constants as constants10, closeSync as closeSync12, fstatSync as fstatSync12, fsyncSync as fsyncSync3, lstatSync as lstatSync16, mkdirSync as mkdirSync5, openSync as openSync12, readSync as readSync7, writeSync as writeSync2 } from "fs";
|
|
33844
|
+
import { dirname as dirname14, isAbsolute as isAbsolute13, join as join21, resolve as resolve14, sep as sep7 } from "path";
|
|
33845
|
+
function keys(value, names) {
|
|
33846
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === names.length && names.every((name) => Object.hasOwn(value, name)));
|
|
33847
|
+
}
|
|
33848
|
+
function safe3(path) {
|
|
33849
|
+
need7(typeof path === "string" && path.length <= AGENT_POLICY_LIMITS.pathCharacters && isAbsolute13(path) && resolve14(path) === path && !/[\x00-\x1f\x7f]/.test(path));
|
|
33850
|
+
for (let cursor = path;; cursor = dirname14(cursor)) {
|
|
33851
|
+
const stat = lstatSync16(cursor, { throwIfNoEntry: false });
|
|
33852
|
+
need7(!stat?.isSymbolicLink());
|
|
33853
|
+
if (cursor !== path && stat)
|
|
33854
|
+
need7(stat.isDirectory());
|
|
33855
|
+
if (dirname14(cursor) === cursor)
|
|
33856
|
+
break;
|
|
33857
|
+
}
|
|
33858
|
+
}
|
|
33859
|
+
function readExact(path) {
|
|
33860
|
+
safe3(path);
|
|
33861
|
+
const before = lstatSync16(path, { throwIfNoEntry: false });
|
|
33862
|
+
need7(before?.isFile() && before.nlink === 1 && before.size <= AGENT_POLICY_LIMITS.discoveryRawSourceBytes && (before.mode & 63) === 0 && (process.getuid === undefined || before.uid === process.getuid()));
|
|
33863
|
+
const fd = openSync12(path, constants10.O_RDONLY | constants10.O_NOFOLLOW | constants10.O_NONBLOCK);
|
|
33864
|
+
try {
|
|
33865
|
+
const opened = fstatSync12(fd);
|
|
33866
|
+
need7(opened.dev === before.dev && opened.ino === before.ino && opened.size === before.size && opened.mode === before.mode && opened.uid === before.uid && opened.nlink === 1);
|
|
33867
|
+
const bytes = Buffer.alloc(opened.size);
|
|
33868
|
+
let offset = 0;
|
|
33869
|
+
while (offset < bytes.length) {
|
|
33870
|
+
const count = readSync7(fd, bytes, offset, bytes.length - offset, null);
|
|
33871
|
+
need7(count > 0);
|
|
33872
|
+
offset += count;
|
|
33873
|
+
}
|
|
33874
|
+
need7(readSync7(fd, Buffer.alloc(1), 0, 1, null) === 0);
|
|
33875
|
+
const after = fstatSync12(fd), current = lstatSync16(path, { throwIfNoEntry: false });
|
|
33876
|
+
safe3(path);
|
|
33877
|
+
need7(current && opened.dev === current.dev && opened.ino === current.ino && opened.mode === current.mode && opened.uid === current.uid && opened.size === current.size && opened.mtimeMs === current.mtimeMs && opened.ctimeMs === current.ctimeMs && current.nlink === 1 && opened.mode === after.mode && opened.uid === after.uid && after.nlink === 1 && opened.size === after.size && opened.mtimeMs === after.mtimeMs && opened.ctimeMs === after.ctimeMs);
|
|
33878
|
+
const text2 = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
|
|
33879
|
+
need7(Buffer.from(text2).equals(bytes));
|
|
33880
|
+
return text2;
|
|
33881
|
+
} finally {
|
|
33882
|
+
closeSync12(fd);
|
|
33883
|
+
}
|
|
33884
|
+
}
|
|
33885
|
+
function catalogDigest(text2) {
|
|
33886
|
+
let catalog;
|
|
33887
|
+
try {
|
|
33888
|
+
catalog = JSON.parse(text2);
|
|
33889
|
+
} catch {
|
|
33890
|
+
return refuse3();
|
|
33891
|
+
}
|
|
33892
|
+
need7(catalog && typeof catalog === "object" && !Array.isArray(catalog) && Object.keys(catalog).every((key) => ["version", "cwd", "skills", "plugins"].includes(key)) && typeof catalog.version === "string" && supportsCodexNativeCapability(catalog.version, "installed-plugin-review"));
|
|
33893
|
+
const skills = projectCodexNativeSkillCatalog({ data: [{ cwd: catalog.cwd, errors: [], skills: catalog.skills }] }, catalog.cwd);
|
|
33894
|
+
const plugins = catalog.plugins === undefined ? undefined : projectCodexInstalledPluginEntries(catalog.plugins);
|
|
33895
|
+
return sha3(JSON.stringify({ version: catalog.version, cwd: catalog.cwd, skills, ...plugins === undefined ? {} : { plugins } }));
|
|
33896
|
+
}
|
|
33897
|
+
function retainedArtifactPath(metadata) {
|
|
33898
|
+
return join21(metadata.storeRoot, "agent-discovery", "artifacts", metadata.sha256, "catalog.json");
|
|
33899
|
+
}
|
|
33900
|
+
function validRetainedArtifact(value) {
|
|
33901
|
+
return keys(value, ["version", "kind", "storeRoot", "originalPath", "sha256", "catalogSha256"]) && value.version === 1 && value.kind === "codex-native-catalog" && hex3(value.sha256) && hex3(value.catalogSha256) && [value.storeRoot, value.originalPath].every((path) => typeof path === "string" && isAbsolute13(path) && resolve14(path) === path && path.length <= AGENT_POLICY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(path));
|
|
33902
|
+
}
|
|
33903
|
+
function privateStore(storeRoot) {
|
|
33904
|
+
safe3(storeRoot);
|
|
33905
|
+
const stat = lstatSync16(storeRoot, { throwIfNoEntry: false });
|
|
33906
|
+
need7(!stat || stat.isDirectory() && (stat.mode & 18) === 0 && (process.getuid === undefined || stat.uid === process.getuid()));
|
|
33907
|
+
}
|
|
33908
|
+
function verifyRetainedReviewArtifact(source, storeRoot) {
|
|
33909
|
+
const artifact = source.reviewArtifact;
|
|
33910
|
+
need7(validRetainedArtifact(artifact) && source.hashMode === "bytes" && source.sha256 === artifact.sha256 && source.format === undefined && source.fields === undefined && source.managedPlugins === undefined && source.path === retainedArtifactPath(artifact) && (storeRoot === undefined || artifact.storeRoot === resolve14(storeRoot)));
|
|
33911
|
+
privateStore(artifact.storeRoot);
|
|
33912
|
+
const text2 = readExact(source.path);
|
|
33913
|
+
need7(sha3(text2) === artifact.sha256 && catalogDigest(text2) === artifact.catalogSha256);
|
|
33914
|
+
for (let parent = dirname14(source.path);parent !== artifact.storeRoot; parent = dirname14(parent)) {
|
|
33915
|
+
const stat = lstatSync16(parent);
|
|
33916
|
+
need7(stat.isDirectory() && (stat.mode & 63) === 0 && (process.getuid === undefined || stat.uid === process.getuid()));
|
|
33917
|
+
}
|
|
33918
|
+
}
|
|
33919
|
+
var sha3 = (bytes) => createHash16("sha256").update(bytes).digest("hex"), hex3 = (value) => typeof value === "string" && /^[a-f0-9]{64}$/.test(value), refuse3 = () => {
|
|
33920
|
+
throw new Error("REVIEW_ARTIFACT_INVALID");
|
|
33921
|
+
}, need7 = (condition) => {
|
|
33922
|
+
if (!condition)
|
|
33923
|
+
refuse3();
|
|
33924
|
+
};
|
|
33925
|
+
var init_retained_review_artifacts = __esm(() => {
|
|
33926
|
+
init_agent_policy_limits();
|
|
33927
|
+
init_codex_native_skill_catalog();
|
|
33928
|
+
init_codex_native_compatibility();
|
|
33929
|
+
});
|
|
33930
|
+
|
|
33783
33931
|
// src/lib/agent-integration.ts
|
|
33784
33932
|
var init_agent_integration = __esm(() => {
|
|
33785
33933
|
init_sumi_settings_witness();
|
|
@@ -33801,6 +33949,7 @@ var init_agent_integration = __esm(() => {
|
|
|
33801
33949
|
init_claude_settings_witness();
|
|
33802
33950
|
init_codex_hook_trust_files();
|
|
33803
33951
|
init_runtime_launcher();
|
|
33952
|
+
init_retained_review_artifacts();
|
|
33804
33953
|
});
|
|
33805
33954
|
|
|
33806
33955
|
// src/lib/home-migration.ts
|
|
@@ -33837,13 +33986,13 @@ var init_skill_aliases = __esm(() => {
|
|
|
33837
33986
|
});
|
|
33838
33987
|
|
|
33839
33988
|
// src/lib/project-state.ts
|
|
33840
|
-
import { existsSync as existsSync9, mkdirSync as
|
|
33841
|
-
import { join as
|
|
33989
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync13, writeFileSync as writeFileSync5 } from "fs";
|
|
33990
|
+
import { join as join22 } from "path";
|
|
33842
33991
|
function getProjectStateDir(targetDir = process.cwd()) {
|
|
33843
|
-
return
|
|
33992
|
+
return join22(targetDir, SKILLS_PROJECT_DIR);
|
|
33844
33993
|
}
|
|
33845
33994
|
function getProjectConfigPath(targetDir = process.cwd()) {
|
|
33846
|
-
return
|
|
33995
|
+
return join22(getProjectStateDir(targetDir), PROJECT_CONFIG_FILE);
|
|
33847
33996
|
}
|
|
33848
33997
|
function loadProjectConfig(targetDir = process.cwd()) {
|
|
33849
33998
|
const path = getProjectConfigPath(targetDir);
|
|
@@ -33871,7 +34020,7 @@ function ensureProjectConfig(targetDir = process.cwd()) {
|
|
|
33871
34020
|
}
|
|
33872
34021
|
function saveProjectConfig(config2, targetDir = process.cwd()) {
|
|
33873
34022
|
const dir = getProjectStateDir(targetDir);
|
|
33874
|
-
|
|
34023
|
+
mkdirSync6(dir, { recursive: true });
|
|
33875
34024
|
const normalized = normalizeProjectConfig({ ...config2, updatedAt: new Date().toISOString() });
|
|
33876
34025
|
writeFileSync5(getProjectConfigPath(targetDir), JSON.stringify(normalized, null, 2) + `
|
|
33877
34026
|
`);
|
|
@@ -33959,7 +34108,7 @@ var init_project_state = __esm(() => {
|
|
|
33959
34108
|
|
|
33960
34109
|
// src/lib/installer.ts
|
|
33961
34110
|
import { existsSync as existsSync10, readFileSync as readFileSync14, rmSync } from "fs";
|
|
33962
|
-
import { join as
|
|
34111
|
+
import { join as join23 } from "path";
|
|
33963
34112
|
import { homedir as homedir2 } from "os";
|
|
33964
34113
|
function getSkillPath(name) {
|
|
33965
34114
|
const skillName = normalizeSkillName(getCanonicalSkillName(name));
|
|
@@ -33969,7 +34118,7 @@ function getSkillPath(name) {
|
|
|
33969
34118
|
const extensionPath = findExtensionSkillPath(skillName);
|
|
33970
34119
|
if (extensionPath)
|
|
33971
34120
|
return extensionPath;
|
|
33972
|
-
return
|
|
34121
|
+
return join23(getPortableSkillsRoot(), skillName);
|
|
33973
34122
|
}
|
|
33974
34123
|
function getCanonicalSkillName(name) {
|
|
33975
34124
|
return getSkill(name)?.name ?? resolveSkillAlias(normalizeSkillSlug(name));
|
|
@@ -34023,11 +34172,11 @@ function getAgentSkillsDir(agent, scope = "global", projectDir) {
|
|
|
34023
34172
|
const base = projectDir || process.cwd();
|
|
34024
34173
|
switch (agent) {
|
|
34025
34174
|
case "pi":
|
|
34026
|
-
return scope === "project" ?
|
|
34175
|
+
return scope === "project" ? join23(base, ".pi", "skills") : join23(homedir2(), ".pi", "agent", "skills");
|
|
34027
34176
|
case "opencode":
|
|
34028
|
-
return scope === "project" ?
|
|
34177
|
+
return scope === "project" ? join23(base, ".opencode", "skills") : join23(homedir2(), ".config", "opencode", "skills");
|
|
34029
34178
|
default:
|
|
34030
|
-
return scope === "project" ?
|
|
34179
|
+
return scope === "project" ? join23(base, `.${agent}`, "skills") : join23(homedir2(), `.${agent}`, "skills");
|
|
34031
34180
|
}
|
|
34032
34181
|
}
|
|
34033
34182
|
function warnMissingDependencies(name, targetDir) {
|
|
@@ -34042,7 +34191,7 @@ function warnMissingDependencies(name, targetDir) {
|
|
|
34042
34191
|
}
|
|
34043
34192
|
}
|
|
34044
34193
|
function readBundledSkillVersion(name) {
|
|
34045
|
-
const pkgPath =
|
|
34194
|
+
const pkgPath = join23(getSkillPath(name), "package.json");
|
|
34046
34195
|
if (!existsSync10(pkgPath))
|
|
34047
34196
|
return "unknown";
|
|
34048
34197
|
try {
|
|
@@ -34112,11 +34261,11 @@ var init_skill_doc_file = __esm(() => {
|
|
|
34112
34261
|
|
|
34113
34262
|
// src/lib/skillinfo.ts
|
|
34114
34263
|
import { existsSync as existsSync11, readFileSync as readFileSync15 } from "fs";
|
|
34115
|
-
import { join as
|
|
34264
|
+
import { join as join24 } from "path";
|
|
34116
34265
|
function isInstructionSkillDir(skillPath, meta3) {
|
|
34117
34266
|
if (meta3?.kind === "instruction")
|
|
34118
34267
|
return true;
|
|
34119
|
-
const skillMdPath =
|
|
34268
|
+
const skillMdPath = join24(skillPath, "SKILL.md");
|
|
34120
34269
|
if (!existsSync11(skillMdPath))
|
|
34121
34270
|
return false;
|
|
34122
34271
|
try {
|
|
@@ -34130,9 +34279,9 @@ function getSkillDocs(name) {
|
|
|
34130
34279
|
if (!existsSync11(skillPath))
|
|
34131
34280
|
return null;
|
|
34132
34281
|
return {
|
|
34133
|
-
skillMd: readIfExists(
|
|
34134
|
-
readme: readIfExists(
|
|
34135
|
-
claudeMd: readIfExists(
|
|
34282
|
+
skillMd: readIfExists(join24(skillPath, "SKILL.md")),
|
|
34283
|
+
readme: readIfExists(join24(skillPath, "README.md")),
|
|
34284
|
+
claudeMd: readIfExists(join24(skillPath, "CLAUDE.md"))
|
|
34136
34285
|
};
|
|
34137
34286
|
}
|
|
34138
34287
|
function getSkillBestDoc(name, file2) {
|
|
@@ -34148,14 +34297,14 @@ function getSkillRequirements(name) {
|
|
|
34148
34297
|
return null;
|
|
34149
34298
|
const texts = [];
|
|
34150
34299
|
for (const file2 of ["SKILL.md", "README.md", "CLAUDE.md", ".env.example", ".env.local.example"]) {
|
|
34151
|
-
const content = readIfExists(
|
|
34300
|
+
const content = readIfExists(join24(skillPath, file2));
|
|
34152
34301
|
if (content)
|
|
34153
34302
|
texts.push(content);
|
|
34154
34303
|
}
|
|
34155
34304
|
const meta3 = getSkill(name);
|
|
34156
34305
|
let dependencies = {};
|
|
34157
34306
|
try {
|
|
34158
|
-
dependencies = JSON.parse(readFileSync15(
|
|
34307
|
+
dependencies = JSON.parse(readFileSync15(join24(skillPath, "package.json"), "utf8")).dependencies || {};
|
|
34159
34308
|
} catch {}
|
|
34160
34309
|
return getSkillRequirementsFromContent(name, texts, dependencies, meta3);
|
|
34161
34310
|
}
|
|
@@ -34217,7 +34366,7 @@ async function runSkill(name, args, options = {}) {
|
|
|
34217
34366
|
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'.`
|
|
34218
34367
|
};
|
|
34219
34368
|
}
|
|
34220
|
-
const pkgPath =
|
|
34369
|
+
const pkgPath = join24(skillPath, "package.json");
|
|
34221
34370
|
if (!existsSync11(pkgPath)) {
|
|
34222
34371
|
return { exitCode: 1, error: `No package.json in skill '${name}'` };
|
|
34223
34372
|
}
|
|
@@ -34237,12 +34386,12 @@ async function runSkill(name, args, options = {}) {
|
|
|
34237
34386
|
} catch {
|
|
34238
34387
|
return { exitCode: 1, error: `Failed to parse package.json for skill '${name}'` };
|
|
34239
34388
|
}
|
|
34240
|
-
const entryPath =
|
|
34389
|
+
const entryPath = join24(skillPath, entryPoint2);
|
|
34241
34390
|
if (!existsSync11(entryPath)) {
|
|
34242
34391
|
return { exitCode: 1, error: `Entry point '${entryPoint2}' not found in skill '${name}'` };
|
|
34243
34392
|
}
|
|
34244
34393
|
const env = { ...process.env, ...options.env };
|
|
34245
|
-
if (!existsSync11(
|
|
34394
|
+
if (!existsSync11(join24(skillPath, "node_modules")) || hasDependencyPreparationMarker(skillPath)) {
|
|
34246
34395
|
const failure = await prepareSkillDependencies(skillPath, env, options.preparationTimeoutMs);
|
|
34247
34396
|
if (failure)
|
|
34248
34397
|
return failure;
|
|
@@ -34268,7 +34417,7 @@ async function runSkill(name, args, options = {}) {
|
|
|
34268
34417
|
function detectProjectSkills(cwd = process.cwd()) {
|
|
34269
34418
|
let pkg;
|
|
34270
34419
|
try {
|
|
34271
|
-
pkg = JSON.parse(readFileSync15(
|
|
34420
|
+
pkg = JSON.parse(readFileSync15(join24(cwd, "package.json"), "utf8"));
|
|
34272
34421
|
} catch {
|
|
34273
34422
|
return { detected: [], recommended: [] };
|
|
34274
34423
|
}
|
|
@@ -34473,7 +34622,7 @@ var init_selection_resolver = __esm(() => {
|
|
|
34473
34622
|
});
|
|
34474
34623
|
|
|
34475
34624
|
// src/lib/plugin-projection.ts
|
|
34476
|
-
import { createHash as
|
|
34625
|
+
import { createHash as createHash17 } from "crypto";
|
|
34477
34626
|
function pluginRefusal(message) {
|
|
34478
34627
|
throw new SkillSelectionError("PLUGIN_ADMISSION_REFUSED", message);
|
|
34479
34628
|
}
|
|
@@ -34484,8 +34633,8 @@ function pluginNeed(value, message) {
|
|
|
34484
34633
|
function pluginObject(value) {
|
|
34485
34634
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
34486
34635
|
}
|
|
34487
|
-
function pluginKeys(value,
|
|
34488
|
-
pluginNeed(pluginObject(value) && Object.keys(value).every((key) =>
|
|
34636
|
+
function pluginKeys(value, keys2) {
|
|
34637
|
+
pluginNeed(pluginObject(value) && Object.keys(value).every((key) => keys2.includes(key)), "Unsupported plugin contract fields");
|
|
34489
34638
|
}
|
|
34490
34639
|
function pluginText(value, limit = 4096) {
|
|
34491
34640
|
pluginNeed(typeof value === "string" && value.length > 0 && value.length <= limit && !/[\x00-\x1f\x7f]/.test(value), "Invalid plugin contract text");
|
|
@@ -34551,18 +34700,18 @@ function pluginFileWitnesses(entries) {
|
|
|
34551
34700
|
return { path: item.path, mode: item.mode, size: item.bytes.byteLength, sha256: pluginHash(item.bytes) };
|
|
34552
34701
|
});
|
|
34553
34702
|
}
|
|
34554
|
-
var PLUGIN_PROJECTION_LIMITS, pluginHash = (bytes) =>
|
|
34703
|
+
var PLUGIN_PROJECTION_LIMITS, pluginHash = (bytes) => createHash17("sha256").update(bytes).digest("hex");
|
|
34555
34704
|
var init_plugin_projection = __esm(() => {
|
|
34556
34705
|
init_selection_cache();
|
|
34557
34706
|
PLUGIN_PROJECTION_LIMITS = Object.freeze({ files: 1024, bytes: 64 * 1024 * 1024, fileBytes: 16 * 1024 * 1024, metadataBytes: 512 * 1024, registrations: 64, history: 128 });
|
|
34558
34707
|
});
|
|
34559
34708
|
|
|
34560
34709
|
// src/lib/plugin-projection-store.ts
|
|
34561
|
-
import { constants as
|
|
34562
|
-
import { dirname as
|
|
34710
|
+
import { constants as constants11, closeSync as closeSync13, fchmodSync, fstatSync as fstatSync13, fsyncSync as fsyncSync4, linkSync as linkSync2, lstatSync as lstatSync17, mkdirSync as mkdirSync7, openSync as openSync13, opendirSync as opendirSync2, readSync as readSync8, renameSync as renameSync2, rmdirSync as rmdirSync2, rmSync as rmSync2, unlinkSync as unlinkSync3, writeSync as writeSync3 } from "fs";
|
|
34711
|
+
import { dirname as dirname15, isAbsolute as isAbsolute14, join as join25, parse as parse10, resolve as resolve15 } from "path";
|
|
34563
34712
|
function stat(path) {
|
|
34564
34713
|
try {
|
|
34565
|
-
return
|
|
34714
|
+
return lstatSync17(path, { bigint: true });
|
|
34566
34715
|
} catch (error61) {
|
|
34567
34716
|
if (missing(error61))
|
|
34568
34717
|
return null;
|
|
@@ -34570,7 +34719,7 @@ function stat(path) {
|
|
|
34570
34719
|
}
|
|
34571
34720
|
}
|
|
34572
34721
|
function canonical7(path) {
|
|
34573
|
-
pluginNeed(typeof path === "string" && path.length <= 8192 &&
|
|
34722
|
+
pluginNeed(typeof path === "string" && path.length <= 8192 && isAbsolute14(path) && resolve15(path) === path && !/[\x00-\x1f\x7f]/.test(path), "Plugin storage paths must be canonical absolute paths");
|
|
34574
34723
|
}
|
|
34575
34724
|
function owner(stats, system = false) {
|
|
34576
34725
|
const current = uid();
|
|
@@ -34581,15 +34730,15 @@ function same3(left, right, identityOnly = false) {
|
|
|
34581
34730
|
}
|
|
34582
34731
|
function ancestors(path, create = false) {
|
|
34583
34732
|
canonical7(path);
|
|
34584
|
-
const result = [], parent =
|
|
34733
|
+
const result = [], parent = dirname15(path), filesystemRoot = parse10(parent).root;
|
|
34585
34734
|
let current = filesystemRoot;
|
|
34586
34735
|
for (const segment of ["", ...parent.slice(filesystemRoot.length).split("/").filter(Boolean)]) {
|
|
34587
34736
|
if (segment)
|
|
34588
|
-
current =
|
|
34737
|
+
current = join25(current, segment);
|
|
34589
34738
|
let currentStat = stat(current);
|
|
34590
34739
|
if (!currentStat && create) {
|
|
34591
34740
|
try {
|
|
34592
|
-
|
|
34741
|
+
mkdirSync7(current, { mode: 448 });
|
|
34593
34742
|
} catch (error61) {
|
|
34594
34743
|
if (!(error61 && typeof error61 === "object" && ("code" in error61) && error61.code === "EEXIST"))
|
|
34595
34744
|
pluginRefusal("Cannot create private plugin storage directory");
|
|
@@ -34631,19 +34780,19 @@ function readBytes(path, maximum, kind) {
|
|
|
34631
34780
|
fileShape(before, maximum, kind);
|
|
34632
34781
|
let fd;
|
|
34633
34782
|
try {
|
|
34634
|
-
fd =
|
|
34635
|
-
const opened =
|
|
34783
|
+
fd = openSync13(path, READ_FLAGS);
|
|
34784
|
+
const opened = fstatSync13(fd, { bigint: true });
|
|
34636
34785
|
same3(before, opened);
|
|
34637
34786
|
fileShape(opened, maximum, kind);
|
|
34638
34787
|
const bytes = new Uint8Array(Number(opened.size));
|
|
34639
34788
|
let offset = 0;
|
|
34640
34789
|
while (offset < bytes.byteLength) {
|
|
34641
|
-
const count =
|
|
34790
|
+
const count = readSync8(fd, bytes, offset, bytes.byteLength - offset, null);
|
|
34642
34791
|
pluginNeed(count > 0, "Plugin file changed while being read");
|
|
34643
34792
|
offset += count;
|
|
34644
34793
|
}
|
|
34645
|
-
pluginNeed(
|
|
34646
|
-
same3(opened,
|
|
34794
|
+
pluginNeed(readSync8(fd, new Uint8Array(1), 0, 1, null) === 0, "Plugin file grew while being read");
|
|
34795
|
+
same3(opened, fstatSync13(fd, { bigint: true }));
|
|
34647
34796
|
same3(opened, stat(path));
|
|
34648
34797
|
verifyAncestors(chain);
|
|
34649
34798
|
return bytes;
|
|
@@ -34653,7 +34802,7 @@ function readBytes(path, maximum, kind) {
|
|
|
34653
34802
|
return pluginRefusal("Cannot safely read plugin file");
|
|
34654
34803
|
} finally {
|
|
34655
34804
|
if (fd !== undefined)
|
|
34656
|
-
|
|
34805
|
+
closeSync13(fd);
|
|
34657
34806
|
}
|
|
34658
34807
|
}
|
|
34659
34808
|
function exactPaths(entries) {
|
|
@@ -34693,7 +34842,7 @@ function snapshotPluginTree(root, options = {}) {
|
|
|
34693
34842
|
pluginNeed(++visited <= PLUGIN_PROJECTION_LIMITS.files * 50, "Plugin tree membership exceeds its limit");
|
|
34694
34843
|
const path = relative6 ? `${relative6}/${name}` : name;
|
|
34695
34844
|
pluginNeed(new TextEncoder().encode(path).byteLength <= 100 && !/[\\:\x00-\x1f\x7f]/u.test(path), "Plugin entry path exceeds its limit or is unsafe");
|
|
34696
|
-
const absolute =
|
|
34845
|
+
const absolute = join25(directory, name), entryStat = stat(absolute);
|
|
34697
34846
|
pluginNeed(entryStat, "Plugin tree member disappeared");
|
|
34698
34847
|
if (relative6 === "" && name === ".orphaned_at" && (options.nativeRuntime === "claude-2.1.274" || options.nativeRuntime === "claude-2.1.276")) {
|
|
34699
34848
|
const bytes2 = readBytes(absolute, 32, "native-pin");
|
|
@@ -34710,7 +34859,7 @@ function snapshotPluginTree(root, options = {}) {
|
|
|
34710
34859
|
directories.push({ path: absolute, stat: entryStat, names: pins });
|
|
34711
34860
|
for (const pin of pins) {
|
|
34712
34861
|
pluginNeed(/^[1-9][0-9]{0,9}$/.test(pin) && Number(pin) <= 2147483647, "Unrecognized native plugin pin name");
|
|
34713
|
-
const pinPath =
|
|
34862
|
+
const pinPath = join25(absolute, pin), pinStat = stat(pinPath);
|
|
34714
34863
|
pluginNeed(pinStat, "Native plugin pin disappeared");
|
|
34715
34864
|
const bytes2 = readBytes(pinPath, 4096, "native-pin");
|
|
34716
34865
|
let value;
|
|
@@ -34776,8 +34925,8 @@ function readPluginJson(path) {
|
|
|
34776
34925
|
var READ_FLAGS, WRITE_FLAGS, uid = () => typeof process.getuid === "function" ? BigInt(process.getuid()) : undefined, missing = (error61) => Boolean(error61 && typeof error61 === "object" && "code" in error61 && error61.code === "ENOENT");
|
|
34777
34926
|
var init_plugin_projection_store = __esm(() => {
|
|
34778
34927
|
init_plugin_projection();
|
|
34779
|
-
READ_FLAGS =
|
|
34780
|
-
WRITE_FLAGS =
|
|
34928
|
+
READ_FLAGS = constants11.O_RDONLY | constants11.O_NOFOLLOW | constants11.O_NONBLOCK;
|
|
34929
|
+
WRITE_FLAGS = constants11.O_WRONLY | constants11.O_CREAT | constants11.O_EXCL | constants11.O_NOFOLLOW | constants11.O_NONBLOCK;
|
|
34781
34930
|
});
|
|
34782
34931
|
|
|
34783
34932
|
// src/lib/selected-manifest.ts
|
|
@@ -34807,7 +34956,7 @@ var init_selected_manifest = __esm(() => {
|
|
|
34807
34956
|
});
|
|
34808
34957
|
|
|
34809
34958
|
// src/lib/plugin-admission.ts
|
|
34810
|
-
import { isAbsolute as
|
|
34959
|
+
import { isAbsolute as isAbsolute15, join as join26, resolve as resolve16 } from "path";
|
|
34811
34960
|
function validatePluginTarget(value) {
|
|
34812
34961
|
pluginKeys(value, ["schemaVersion", "pluginId", "registrations", "native", "resolver"]);
|
|
34813
34962
|
pluginNeed(value.schemaVersion === 1, "Invalid plugin admission target");
|
|
@@ -34817,7 +34966,7 @@ function validatePluginTarget(value) {
|
|
|
34817
34966
|
for (const registration of value.registrations) {
|
|
34818
34967
|
pluginKeys(registration, ["scope", "projectPath"]);
|
|
34819
34968
|
pluginNeed(registration.scope === "user" || registration.scope === "project", "Unsupported plugin registration scope");
|
|
34820
|
-
pluginNeed(registration.scope === "user" ? registration.projectPath === null : typeof registration.projectPath === "string" &&
|
|
34969
|
+
pluginNeed(registration.scope === "user" ? registration.projectPath === null : typeof registration.projectPath === "string" && isAbsolute15(registration.projectPath) && resolve16(registration.projectPath) === registration.projectPath, "Plugin scope requires its exact project path");
|
|
34821
34970
|
const key = JSON.stringify([registration.scope, registration.projectPath]);
|
|
34822
34971
|
pluginNeed(!scopes.has(key), "Duplicate plugin registration scope");
|
|
34823
34972
|
scopes.add(key);
|
|
@@ -34825,7 +34974,7 @@ function validatePluginTarget(value) {
|
|
|
34825
34974
|
for (const key of ["native", "resolver"]) {
|
|
34826
34975
|
pluginKeys(value[key], key === "native" ? ["version", "executable", "digest"] : ["executable", "digest"]);
|
|
34827
34976
|
pluginText(value[key].executable);
|
|
34828
|
-
pluginNeed(
|
|
34977
|
+
pluginNeed(isAbsolute15(value[key].executable) && resolve16(value[key].executable) === value[key].executable, "Plugin executable must have a canonical absolute path");
|
|
34829
34978
|
pluginDigest(value[key].digest);
|
|
34830
34979
|
}
|
|
34831
34980
|
pluginNeed(["2.1.274", "2.1.276"].includes(value.native.version), "Plugin admission requires a certified Claude command-source runtime (2.1.274 or 2.1.276)");
|
|
@@ -34968,12 +35117,12 @@ function pluginResolverCommand(binding) {
|
|
|
34968
35117
|
}
|
|
34969
35118
|
function pluginBindingPath(storeRoot, id) {
|
|
34970
35119
|
pluginNeed(/^[a-f0-9]{64}$/.test(id), "Invalid plugin binding identifier");
|
|
34971
|
-
return
|
|
35120
|
+
return join26(storeRoot, "bindings", `${id}.json`);
|
|
34972
35121
|
}
|
|
34973
35122
|
function pluginReceiptPath(storeRoot, id, digest) {
|
|
34974
35123
|
pluginNeed(/^[a-f0-9]{64}$/.test(id), "Invalid plugin binding identifier");
|
|
34975
35124
|
pluginDigest(digest);
|
|
34976
|
-
return
|
|
35125
|
+
return join26(storeRoot, "receipts", id, `${digest.slice(7)}.json`);
|
|
34977
35126
|
}
|
|
34978
35127
|
function readPluginBinding(storeRoot, id) {
|
|
34979
35128
|
const value = readPluginJson(pluginBindingPath(storeRoot, id));
|
|
@@ -34993,7 +35142,7 @@ function readPluginAdmissionReceipt(storeRoot, id, digest) {
|
|
|
34993
35142
|
pluginNeed(receipt.plan.bindingId === id && receipt.plan.planDigest === digest, "Plugin receipt identity differs from its filename");
|
|
34994
35143
|
const binding = readPluginBinding(storeRoot, id);
|
|
34995
35144
|
pluginNeed(canonicalJson(binding) === canonicalJson(receipt.plan.binding) && receipt.plan.sourceCommand === pluginResolverCommand(binding), "Plugin receipt binding changed");
|
|
34996
|
-
pluginNeed(receipt.materializedPath ===
|
|
35145
|
+
pluginNeed(receipt.materializedPath === join26(storeRoot, "objects", id, digest.slice(7)), "Plugin receipt points outside its immutable materialization");
|
|
34997
35146
|
pluginText(receipt.admittedAt, 64);
|
|
34998
35147
|
pluginNeed(Number.isFinite(Date.parse(receipt.admittedAt)), "Invalid plugin admission time");
|
|
34999
35148
|
return receipt;
|
|
@@ -35010,8 +35159,8 @@ var init_plugin_admission = __esm(() => {
|
|
|
35010
35159
|
});
|
|
35011
35160
|
|
|
35012
35161
|
// src/lib/plugin-discovery.ts
|
|
35013
|
-
import { closeSync as
|
|
35014
|
-
import { basename as basename7, dirname as
|
|
35162
|
+
import { closeSync as closeSync14, constants as constants12, fstatSync as fstatSync14, lstatSync as lstatSync18, openSync as openSync14, opendirSync as opendirSync3, readSync as readSync9 } from "fs";
|
|
35163
|
+
import { basename as basename7, dirname as dirname16, isAbsolute as isAbsolute16, join as join27, resolve as resolve17 } from "path";
|
|
35015
35164
|
function validateManagedPluginWitnesses(value) {
|
|
35016
35165
|
pluginNeed(Array.isArray(value) && value.length > 0 && value.length <= PLUGIN_PROJECTION_LIMITS.registrations, "Invalid managed plugin witness collection");
|
|
35017
35166
|
const seen = new Set;
|
|
@@ -35020,36 +35169,36 @@ function validateManagedPluginWitnesses(value) {
|
|
|
35020
35169
|
pluginNeed(typeof item.bindingId === "string" && /^[a-f0-9]{64}$/.test(item.bindingId) && !seen.has(item.bindingId), "Invalid or duplicate managed plugin witness");
|
|
35021
35170
|
seen.add(item.bindingId);
|
|
35022
35171
|
pluginText(item.storeRoot);
|
|
35023
|
-
pluginNeed(
|
|
35172
|
+
pluginNeed(isAbsolute16(item.storeRoot) && resolve17(item.storeRoot) === item.storeRoot, "Invalid plugin receipt store path");
|
|
35024
35173
|
}
|
|
35025
35174
|
}
|
|
35026
|
-
function
|
|
35175
|
+
function safe4(path) {
|
|
35027
35176
|
pluginText(path);
|
|
35028
|
-
pluginNeed(
|
|
35029
|
-
for (let at = path;; at =
|
|
35030
|
-
pluginNeed(!
|
|
35031
|
-
if (at ===
|
|
35177
|
+
pluginNeed(isAbsolute16(path) && resolve17(path) === path, "Invalid plugin registry path");
|
|
35178
|
+
for (let at = path;; at = dirname16(at)) {
|
|
35179
|
+
pluginNeed(!lstatSync18(at, { throwIfNoEntry: false })?.isSymbolicLink(), "Plugin registry path traverses a symlink");
|
|
35180
|
+
if (at === dirname16(at))
|
|
35032
35181
|
break;
|
|
35033
35182
|
}
|
|
35034
35183
|
}
|
|
35035
35184
|
function readRegistry(path) {
|
|
35036
|
-
|
|
35037
|
-
const initial =
|
|
35185
|
+
safe4(path);
|
|
35186
|
+
const initial = lstatSync18(path);
|
|
35038
35187
|
pluginNeed(initial.isFile() && initial.size <= 1024 * 1024, "Plugin registry is not a bounded regular file");
|
|
35039
|
-
const fd =
|
|
35188
|
+
const fd = openSync14(path, constants12.O_RDONLY | constants12.O_NOFOLLOW | constants12.O_NONBLOCK);
|
|
35040
35189
|
try {
|
|
35041
|
-
const opened =
|
|
35190
|
+
const opened = fstatSync14(fd);
|
|
35042
35191
|
pluginNeed(opened.isFile() && opened.ino === initial.ino && opened.dev === initial.dev, "Plugin registry changed during open");
|
|
35043
35192
|
const bytes = Buffer.alloc(1024 * 1024 + 1);
|
|
35044
35193
|
let length = 0;
|
|
35045
35194
|
while (length < bytes.length) {
|
|
35046
|
-
const count =
|
|
35195
|
+
const count = readSync9(fd, bytes, length, bytes.length - length, null);
|
|
35047
35196
|
if (!count)
|
|
35048
35197
|
break;
|
|
35049
35198
|
length += count;
|
|
35050
35199
|
}
|
|
35051
|
-
const after =
|
|
35052
|
-
|
|
35200
|
+
const after = fstatSync14(fd), current = lstatSync18(path);
|
|
35201
|
+
safe4(path);
|
|
35053
35202
|
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");
|
|
35054
35203
|
let value;
|
|
35055
35204
|
try {
|
|
@@ -35060,7 +35209,7 @@ function readRegistry(path) {
|
|
|
35060
35209
|
pluginNeed(pluginObject(value) && value.version === 2 && pluginObject(value.plugins), "Unsupported native plugin registry schema");
|
|
35061
35210
|
return { value, rawDigest: pluginHash(bytes.subarray(0, length)) };
|
|
35062
35211
|
} finally {
|
|
35063
|
-
|
|
35212
|
+
closeSync14(fd);
|
|
35064
35213
|
}
|
|
35065
35214
|
}
|
|
35066
35215
|
function nativeVersionMatches(version2, receipt) {
|
|
@@ -35078,7 +35227,7 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
35078
35227
|
seen.add(target.pluginId);
|
|
35079
35228
|
const rows = plugins[target.pluginId];
|
|
35080
35229
|
pluginNeed(Array.isArray(rows) && rows.length === target.registrations.length, "Managed plugin registration membership changed");
|
|
35081
|
-
const [name, market] = target.pluginId.split("@"), cacheRoot =
|
|
35230
|
+
const [name, market] = target.pluginId.split("@"), cacheRoot = join27(dirname16(path), "cache", market, name);
|
|
35082
35231
|
const scopes = new Set, approvals = new Map, currentFiles = new Map;
|
|
35083
35232
|
plugins[target.pluginId] = rows.map((row) => {
|
|
35084
35233
|
pluginNeed(pluginObject(row), "Invalid managed plugin registration");
|
|
@@ -35091,7 +35240,7 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
35091
35240
|
pluginText(row.sourceProducerPath);
|
|
35092
35241
|
pluginText(row.lastUpdated, 64);
|
|
35093
35242
|
pluginNeed(Number.isFinite(Date.parse(row.lastUpdated)), "Invalid managed plugin update timestamp");
|
|
35094
|
-
pluginNeed(/^(?:[A-Za-z0-9][A-Za-z0-9._+-]*-)?[a-f0-9]{12}$/.test(row.version) && row.installPath ===
|
|
35243
|
+
pluginNeed(/^(?:[A-Za-z0-9][A-Za-z0-9._+-]*-)?[a-f0-9]{12}$/.test(row.version) && row.installPath === join27(cacheRoot, row.version), "Managed plugin cache path or version is outside its registration");
|
|
35095
35244
|
const approval = (producer) => {
|
|
35096
35245
|
pluginText(producer);
|
|
35097
35246
|
const digest = `sha256:${basename7(producer)}`;
|
|
@@ -35120,8 +35269,8 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
35120
35269
|
}
|
|
35121
35270
|
return Object.fromEntries(Object.entries(row).filter(([key]) => !["version", "installPath", "sourceProducerPath", "previousProducerPaths", "lastUpdated"].includes(key)));
|
|
35122
35271
|
});
|
|
35123
|
-
|
|
35124
|
-
const before =
|
|
35272
|
+
safe4(cacheRoot);
|
|
35273
|
+
const before = lstatSync18(cacheRoot);
|
|
35125
35274
|
pluginNeed(before.isDirectory(), "Invalid managed plugin cache root");
|
|
35126
35275
|
const directory = opendirSync3(cacheRoot), names = [];
|
|
35127
35276
|
try {
|
|
@@ -35134,18 +35283,18 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
35134
35283
|
directory.closeSync();
|
|
35135
35284
|
}
|
|
35136
35285
|
for (const version2 of names.sort()) {
|
|
35137
|
-
const files = pluginFileWitnesses(snapshotPluginTree(
|
|
35286
|
+
const files = pluginFileWitnesses(snapshotPluginTree(join27(cacheRoot, version2), { nativeRuntime: `claude-${target.native.version}` }));
|
|
35138
35287
|
verifiedBytes += files.reduce((total, file2) => total + file2.size, 0);
|
|
35139
35288
|
pluginNeed(verifiedBytes <= 256 * 1024 * 1024, "Managed plugin verification exceeds its aggregate byte budget");
|
|
35140
35289
|
const serialized = JSON.stringify(files);
|
|
35141
|
-
const expected = currentFiles.get(
|
|
35290
|
+
const expected = currentFiles.get(join27(cacheRoot, version2));
|
|
35142
35291
|
pluginNeed(expected === undefined || serialized === expected, "Current native cache differs from its exact registered producer receipt");
|
|
35143
35292
|
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");
|
|
35144
35293
|
}
|
|
35145
35294
|
for (const row of rows)
|
|
35146
35295
|
pluginNeed(names.includes(row.version), "Managed native plugin installation is missing");
|
|
35147
|
-
const after =
|
|
35148
|
-
|
|
35296
|
+
const after = lstatSync18(cacheRoot);
|
|
35297
|
+
safe4(cacheRoot);
|
|
35149
35298
|
pluginNeed(before.dev === after.dev && before.ino === after.ino && before.mtimeMs === after.mtimeMs && before.ctimeMs === after.ctimeMs, "Managed cache version membership changed during verification");
|
|
35150
35299
|
}
|
|
35151
35300
|
pluginNeed(readRegistry(path).rawDigest === snapshot2.rawDigest, "Native plugin registry changed during content verification");
|
|
@@ -35158,50 +35307,50 @@ var init_plugin_discovery = __esm(() => {
|
|
|
35158
35307
|
});
|
|
35159
35308
|
|
|
35160
35309
|
// src/lib/claude-marketplace-registry.ts
|
|
35161
|
-
import { createHash as
|
|
35162
|
-
import { closeSync as
|
|
35163
|
-
import { basename as basename8, dirname as
|
|
35164
|
-
function
|
|
35310
|
+
import { createHash as createHash18 } from "crypto";
|
|
35311
|
+
import { closeSync as closeSync15, constants as constants13, fstatSync as fstatSync15, lstatSync as lstatSync19, openSync as openSync15, readSync as readSync10 } from "fs";
|
|
35312
|
+
import { basename as basename8, dirname as dirname17, isAbsolute as isAbsolute17, resolve as resolve18 } from "path";
|
|
35313
|
+
function need8(value, reason2) {
|
|
35165
35314
|
if (!value)
|
|
35166
35315
|
throw new Error(`Claude marketplace registry ${reason2}`);
|
|
35167
35316
|
}
|
|
35168
|
-
function
|
|
35169
|
-
|
|
35317
|
+
function absolutePath4(value) {
|
|
35318
|
+
need8(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute17(value) && resolve18(value) === value, "requires a normalized absolute path");
|
|
35170
35319
|
}
|
|
35171
35320
|
function parents2(path) {
|
|
35172
35321
|
const result = [];
|
|
35173
|
-
for (let at =
|
|
35174
|
-
const stat2 =
|
|
35175
|
-
|
|
35322
|
+
for (let at = dirname17(path);; at = dirname17(at)) {
|
|
35323
|
+
const stat2 = lstatSync19(at, { bigint: true });
|
|
35324
|
+
need8(stat2.isDirectory() && !stat2.isSymbolicLink(), "path traverses a symlink or non-directory");
|
|
35176
35325
|
result.push([at, stat2]);
|
|
35177
|
-
if (at ===
|
|
35326
|
+
if (at === dirname17(at))
|
|
35178
35327
|
return result;
|
|
35179
35328
|
}
|
|
35180
35329
|
}
|
|
35181
35330
|
function readRegistry2(path, budget2) {
|
|
35182
|
-
|
|
35183
|
-
|
|
35184
|
-
|
|
35185
|
-
const ancestors2 = parents2(path), initial =
|
|
35186
|
-
|
|
35187
|
-
|
|
35188
|
-
const fd =
|
|
35331
|
+
absolutePath4(path);
|
|
35332
|
+
need8(basename8(path) === "known_marketplaces.json", "requires known_marketplaces.json");
|
|
35333
|
+
need8(Number.isSafeInteger(budget2.remaining) && budget2.remaining >= 0, "has an invalid byte budget");
|
|
35334
|
+
const ancestors2 = parents2(path), initial = lstatSync19(path, { bigint: true });
|
|
35335
|
+
need8(initial.isFile() && !initial.isSymbolicLink() && initial.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
|
|
35336
|
+
need8(initial.size <= BigInt(budget2.remaining), "exceeds its aggregate byte limit");
|
|
35337
|
+
const fd = openSync15(path, constants13.O_RDONLY | constants13.O_NOFOLLOW | constants13.O_NONBLOCK);
|
|
35189
35338
|
try {
|
|
35190
|
-
const opened =
|
|
35191
|
-
|
|
35339
|
+
const opened = fstatSync15(fd, { bigint: true });
|
|
35340
|
+
need8(opened.isFile() && sameFile2(initial, opened), "changed during open");
|
|
35192
35341
|
const bytes = Buffer.alloc(Number(opened.size) + 1);
|
|
35193
35342
|
let length = 0;
|
|
35194
35343
|
while (length < bytes.length) {
|
|
35195
|
-
const count =
|
|
35344
|
+
const count = readSync10(fd, bytes, length, bytes.length - length, null);
|
|
35196
35345
|
if (!count)
|
|
35197
35346
|
break;
|
|
35198
35347
|
length += count;
|
|
35199
35348
|
}
|
|
35200
|
-
const after =
|
|
35201
|
-
|
|
35349
|
+
const after = fstatSync15(fd, { bigint: true }), current = lstatSync19(path, { bigint: true });
|
|
35350
|
+
need8(current.isFile() && sameFile2(opened, after) && sameFile2(after, current) && BigInt(length) === opened.size, "changed during read");
|
|
35202
35351
|
for (const [ancestor, before] of ancestors2) {
|
|
35203
|
-
const now =
|
|
35204
|
-
|
|
35352
|
+
const now = lstatSync19(ancestor, { bigint: true });
|
|
35353
|
+
need8(now.isDirectory() && before.dev === now.dev && before.ino === now.ino && before.mode === now.mode, "parent changed during read");
|
|
35205
35354
|
}
|
|
35206
35355
|
budget2.remaining -= length;
|
|
35207
35356
|
try {
|
|
@@ -35210,7 +35359,7 @@ function readRegistry2(path, budget2) {
|
|
|
35210
35359
|
throw new Error("Claude marketplace registry is not strict UTF-8");
|
|
35211
35360
|
}
|
|
35212
35361
|
} finally {
|
|
35213
|
-
|
|
35362
|
+
closeSync15(fd);
|
|
35214
35363
|
}
|
|
35215
35364
|
}
|
|
35216
35365
|
function parse11(text2) {
|
|
@@ -35221,7 +35370,7 @@ function parse11(text2) {
|
|
|
35221
35370
|
at++;
|
|
35222
35371
|
};
|
|
35223
35372
|
function string4() {
|
|
35224
|
-
|
|
35373
|
+
need8(text2[at] === '"', "contains invalid JSON");
|
|
35225
35374
|
const start = at++;
|
|
35226
35375
|
while (at < text2.length) {
|
|
35227
35376
|
const character = text2[at++];
|
|
@@ -35232,7 +35381,7 @@ function parse11(text2) {
|
|
|
35232
35381
|
} catch {
|
|
35233
35382
|
throw new Error("Claude marketplace registry contains invalid JSON string");
|
|
35234
35383
|
}
|
|
35235
|
-
|
|
35384
|
+
need8(value2.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.stringCharacters, "exceeds its string limit");
|
|
35236
35385
|
return value2;
|
|
35237
35386
|
}
|
|
35238
35387
|
if (character === "\\")
|
|
@@ -35241,7 +35390,7 @@ function parse11(text2) {
|
|
|
35241
35390
|
throw new Error("Claude marketplace registry contains an unterminated JSON string");
|
|
35242
35391
|
}
|
|
35243
35392
|
function value(depth) {
|
|
35244
|
-
|
|
35393
|
+
need8(depth <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.depth && ++nodes <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.nodes, "exceeds its nesting or node limit");
|
|
35245
35394
|
space();
|
|
35246
35395
|
const character = text2[at];
|
|
35247
35396
|
if (character === '"')
|
|
@@ -35249,26 +35398,26 @@ function parse11(text2) {
|
|
|
35249
35398
|
if (character === "{" || character === "[") {
|
|
35250
35399
|
at++;
|
|
35251
35400
|
space();
|
|
35252
|
-
const
|
|
35401
|
+
const object6 = character === "{", end = object6 ? "}" : "]", entries = [], items = [], keys2 = new Set;
|
|
35253
35402
|
if (text2[at] !== end)
|
|
35254
35403
|
while (true) {
|
|
35255
|
-
if (
|
|
35404
|
+
if (object6) {
|
|
35256
35405
|
space();
|
|
35257
35406
|
const key = string4();
|
|
35258
|
-
|
|
35259
|
-
|
|
35407
|
+
need8(!keys2.has(key), "contains a duplicate JSON key");
|
|
35408
|
+
keys2.add(key);
|
|
35260
35409
|
space();
|
|
35261
|
-
|
|
35410
|
+
need8(text2[at++] === ":", "contains invalid JSON");
|
|
35262
35411
|
entries.push([key, value(depth + 1)]);
|
|
35263
35412
|
} else
|
|
35264
35413
|
items.push(value(depth + 1));
|
|
35265
35414
|
space();
|
|
35266
35415
|
if (text2[at] === end)
|
|
35267
35416
|
break;
|
|
35268
|
-
|
|
35417
|
+
need8(text2[at++] === ",", "contains invalid JSON");
|
|
35269
35418
|
}
|
|
35270
35419
|
at++;
|
|
35271
|
-
return
|
|
35420
|
+
return object6 ? { kind: "object", entries } : { kind: "array", items };
|
|
35272
35421
|
}
|
|
35273
35422
|
for (const literal2 of ["true", "false", "null"])
|
|
35274
35423
|
if (text2.startsWith(literal2, at)) {
|
|
@@ -35277,21 +35426,21 @@ function parse11(text2) {
|
|
|
35277
35426
|
}
|
|
35278
35427
|
numberPattern.lastIndex = at;
|
|
35279
35428
|
const number4 = numberPattern.exec(text2);
|
|
35280
|
-
|
|
35429
|
+
need8(number4, "contains invalid JSON");
|
|
35281
35430
|
at += number4[0].length;
|
|
35282
35431
|
return { kind: "number", value: number4[0] };
|
|
35283
35432
|
}
|
|
35284
35433
|
const root = value(0);
|
|
35285
35434
|
space();
|
|
35286
|
-
|
|
35287
|
-
|
|
35435
|
+
need8(at === text2.length && root.kind === "object", "requires a JSON object without trailing content");
|
|
35436
|
+
need8(root.entries.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.rows, "exceeds its marketplace row limit");
|
|
35288
35437
|
return root;
|
|
35289
35438
|
}
|
|
35290
|
-
function exactKeys(value,
|
|
35291
|
-
return value?.kind === "object" && value.entries.length ===
|
|
35439
|
+
function exactKeys(value, keys2) {
|
|
35440
|
+
return value?.kind === "object" && value.entries.length === keys2.length && value.entries.every(([key]) => keys2.includes(key));
|
|
35292
35441
|
}
|
|
35293
35442
|
function textField(value) {
|
|
35294
|
-
|
|
35443
|
+
need8(value?.kind === "string" && value.value.length > 0 && !/[\x00-\x1f\x7f]/.test(value.value), "contains an invalid recognized field");
|
|
35295
35444
|
return value.value;
|
|
35296
35445
|
}
|
|
35297
35446
|
function normalizeRow(row, version2 = 1) {
|
|
@@ -35299,7 +35448,7 @@ function normalizeRow(row, version2 = 1) {
|
|
|
35299
35448
|
if (version2 !== 2 || !exactKeys(row, ["source", "installLocation", "lastUpdated", "autoUpdate"]))
|
|
35300
35449
|
return;
|
|
35301
35450
|
const autoUpdate = field2(row, "autoUpdate");
|
|
35302
|
-
|
|
35451
|
+
need8(autoUpdate?.kind === "literal" && (autoUpdate.value === "true" || autoUpdate.value === "false"), "contains an invalid automatic-update preference");
|
|
35303
35452
|
}
|
|
35304
35453
|
const source = field2(row, "source");
|
|
35305
35454
|
if (source?.kind !== "object")
|
|
@@ -35312,29 +35461,29 @@ function normalizeRow(row, version2 = 1) {
|
|
|
35312
35461
|
return;
|
|
35313
35462
|
const sourceLocation = textField(field2(source, location));
|
|
35314
35463
|
if (type.value === "directory")
|
|
35315
|
-
|
|
35316
|
-
|
|
35464
|
+
absolutePath4(sourceLocation);
|
|
35465
|
+
absolutePath4(textField(field2(row, "installLocation")));
|
|
35317
35466
|
const updated = textField(field2(row, "lastUpdated"));
|
|
35318
|
-
|
|
35467
|
+
need8(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(updated), "contains an invalid recognized update timestamp");
|
|
35319
35468
|
const millis = Date.parse(updated);
|
|
35320
|
-
|
|
35469
|
+
need8(Number.isFinite(millis) && new Date(millis).toISOString() === updated, "contains an invalid recognized update timestamp");
|
|
35321
35470
|
row.entries = row.entries.map(([key, value]) => [key, key === "lastUpdated" ? { kind: "validated-update-time" } : value]);
|
|
35322
35471
|
}
|
|
35323
35472
|
function captureClaudeMarketplaceRegistry(path, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
35324
35473
|
const value = parse11(readRegistry2(path, budget2));
|
|
35325
35474
|
for (const [, row] of value.entries)
|
|
35326
35475
|
normalizeRow(row);
|
|
35327
|
-
const sha2562 =
|
|
35476
|
+
const sha2562 = createHash18("sha256").update("hasna.skills.claude-marketplace-registry.v1\x00").update(JSON.stringify(value)).digest("hex");
|
|
35328
35477
|
return { path, hashMode: "claude-marketplace-registry", sha256: sha2562 };
|
|
35329
35478
|
}
|
|
35330
35479
|
function captureClaudeMarketplaceRegistryV2(path, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
35331
35480
|
const value = parse11(readRegistry2(path, budget2));
|
|
35332
35481
|
for (const [, row] of value.entries)
|
|
35333
35482
|
normalizeRow(row, 2);
|
|
35334
|
-
const sha2562 =
|
|
35483
|
+
const sha2562 = createHash18("sha256").update("hasna.skills.claude-marketplace-registry.v2\x00").update(JSON.stringify(value)).digest("hex");
|
|
35335
35484
|
return { path, hashMode: "claude-marketplace-registry-v2", sha256: sha2562 };
|
|
35336
35485
|
}
|
|
35337
|
-
var CLAUDE_MARKETPLACE_REGISTRY_LIMITS, sameFile2 = (a, b) => a.dev === b.dev && a.ino === b.ino && a.mode === b.mode && a.uid === b.uid && a.gid === b.gid && a.nlink === b.nlink && a.size === b.size && a.mtimeNs === b.mtimeNs && a.ctimeNs === b.ctimeNs, field2 = (
|
|
35486
|
+
var CLAUDE_MARKETPLACE_REGISTRY_LIMITS, sameFile2 = (a, b) => a.dev === b.dev && a.ino === b.ino && a.mode === b.mode && a.uid === b.uid && a.gid === b.gid && a.nlink === b.nlink && a.size === b.size && a.mtimeNs === b.mtimeNs && a.ctimeNs === b.ctimeNs, field2 = (object6, key) => object6.entries.find(([name]) => name === key)?.[1];
|
|
35338
35487
|
var init_claude_marketplace_registry = __esm(() => {
|
|
35339
35488
|
CLAUDE_MARKETPLACE_REGISTRY_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
|
|
35340
35489
|
});
|
|
@@ -35353,7 +35502,7 @@ var init_codex_hook_additions_review = __esm(() => {
|
|
|
35353
35502
|
});
|
|
35354
35503
|
|
|
35355
35504
|
// src/lib/codex-hook-discovery-recovery.ts
|
|
35356
|
-
import { createHash as
|
|
35505
|
+
import { createHash as createHash19 } from "crypto";
|
|
35357
35506
|
function assertCodexHookDiscoveryRecovery(binding, witness) {
|
|
35358
35507
|
const proof = proofs2.get(witness);
|
|
35359
35508
|
need6(!!proof && binding.agent === "codex" && witness.discoverySha256 === discoveryDigest(binding), "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
|
|
@@ -35368,13 +35517,13 @@ function verifiesCodexHookDiscoverySource(binding, source, currentDigest, witnes
|
|
|
35368
35517
|
need6(source.sha256 === witness.beforeSha256 && currentDigest === witness.currentSha256, "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
|
|
35369
35518
|
return true;
|
|
35370
35519
|
}
|
|
35371
|
-
var
|
|
35520
|
+
var sha4 = (text2) => createHash19("sha256").update(text2).digest("hex"), fields, discoveryDigest = (binding) => {
|
|
35372
35521
|
const controls = binding.codexDisabledPluginSkills;
|
|
35373
35522
|
if (!Object.hasOwn(binding, "codexDisabledPluginSkills") || Array.isArray(controls) && controls.length === 0) {
|
|
35374
35523
|
const { codexDisabledPluginSkills: _controls, ...withoutControls } = binding;
|
|
35375
|
-
return
|
|
35524
|
+
return sha4(JSON.stringify({ ...withoutControls, codexDisabledPluginSkills: [] }));
|
|
35376
35525
|
}
|
|
35377
|
-
return
|
|
35526
|
+
return sha4(JSON.stringify(binding));
|
|
35378
35527
|
}, proofs2;
|
|
35379
35528
|
var init_codex_hook_discovery_recovery = __esm(() => {
|
|
35380
35529
|
init_codex_hook_trust_files();
|
|
@@ -35386,16 +35535,16 @@ var init_codex_hook_discovery_recovery = __esm(() => {
|
|
|
35386
35535
|
});
|
|
35387
35536
|
|
|
35388
35537
|
// src/lib/agent-discovery.ts
|
|
35389
|
-
import { createHash as
|
|
35390
|
-
import { lstatSync as
|
|
35391
|
-
import { basename as basename9, dirname as
|
|
35538
|
+
import { createHash as createHash20 } from "crypto";
|
|
35539
|
+
import { lstatSync as lstatSync20, readFileSync as readFileSync16, readdirSync as readdirSync7, realpathSync as realpathSync6 } from "fs";
|
|
35540
|
+
import { basename as basename9, dirname as dirname18, isAbsolute as isAbsolute18, join as join28, resolve as resolve19, sep as sep8 } from "path";
|
|
35392
35541
|
import { isDeepStrictEqual as isDeepStrictEqual4 } from "util";
|
|
35393
35542
|
function discoveryExecutable(agent) {
|
|
35394
35543
|
const command = DISCOVERY_RUNTIME_COMMANDS[agent];
|
|
35395
35544
|
const found = command ? Bun.which(command) : null;
|
|
35396
35545
|
if (!command || !found)
|
|
35397
35546
|
return null;
|
|
35398
|
-
const path =
|
|
35547
|
+
const path = resolve19(found), target = realpathOrNull(path);
|
|
35399
35548
|
return target === null ? null : { command, path, target };
|
|
35400
35549
|
}
|
|
35401
35550
|
function parseConfig(text2, path, toml = false) {
|
|
@@ -35408,21 +35557,21 @@ function parseConfig(text2, path, toml = false) {
|
|
|
35408
35557
|
throw new Error(`Invalid native discovery configuration: ${path}`);
|
|
35409
35558
|
}
|
|
35410
35559
|
}
|
|
35411
|
-
function
|
|
35412
|
-
if (!
|
|
35560
|
+
function safe5(path) {
|
|
35561
|
+
if (!isAbsolute18(path) || path.includes("\x00"))
|
|
35413
35562
|
throw new Error("Expected an absolute native discovery path");
|
|
35414
|
-
for (let cursor = path;; cursor =
|
|
35415
|
-
if (
|
|
35563
|
+
for (let cursor = path;; cursor = dirname18(cursor)) {
|
|
35564
|
+
if (lstatSync20(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
35416
35565
|
throw new Error(`Refusing symlink native discovery input: ${cursor}`);
|
|
35417
|
-
if (
|
|
35566
|
+
if (dirname18(cursor) === cursor)
|
|
35418
35567
|
break;
|
|
35419
35568
|
}
|
|
35420
35569
|
}
|
|
35421
35570
|
function read(path, changes) {
|
|
35422
|
-
|
|
35571
|
+
safe5(path);
|
|
35423
35572
|
if (changes?.has(path))
|
|
35424
35573
|
return changes.get(path);
|
|
35425
|
-
const stat2 =
|
|
35574
|
+
const stat2 = lstatSync20(path, { throwIfNoEntry: false });
|
|
35426
35575
|
if (!stat2)
|
|
35427
35576
|
return null;
|
|
35428
35577
|
if (!stat2.isFile() || stat2.size > 16 * 1024 * 1024)
|
|
@@ -35433,8 +35582,8 @@ function assertReviewedClaudeCacheClosures(home, config2, review, canonical8) {
|
|
|
35433
35582
|
const enabledIds = Object.entries(config2.enabledPlugins ?? {}).filter(([, enabled]) => enabled === true).map(([id]) => id);
|
|
35434
35583
|
if (enabledIds.length === 0)
|
|
35435
35584
|
return;
|
|
35436
|
-
const registryPath = canonical8(
|
|
35437
|
-
const cacheAliasRoot =
|
|
35585
|
+
const registryPath = canonical8(join28(home, ".claude/plugins/installed_plugins.json"));
|
|
35586
|
+
const cacheAliasRoot = join28(home, ".claude/plugins/cache");
|
|
35438
35587
|
const cacheRoot = canonical8(cacheAliasRoot);
|
|
35439
35588
|
const registryText = read(registryPath);
|
|
35440
35589
|
if (registryText === null)
|
|
@@ -35442,7 +35591,7 @@ function assertReviewedClaudeCacheClosures(home, config2, review, canonical8) {
|
|
|
35442
35591
|
const registry2 = parseConfig(registryText, registryPath);
|
|
35443
35592
|
if (registry2.version !== 2 || !registry2.plugins || typeof registry2.plugins !== "object" || Array.isArray(registry2.plugins))
|
|
35444
35593
|
throw new Error("Reviewed Claude installed plugin registrations are invalid");
|
|
35445
|
-
const cachePath = (path) => typeof path === "string" &&
|
|
35594
|
+
const cachePath = (path) => typeof path === "string" && isAbsolute18(path) && resolve19(path) === path && [cacheAliasRoot, cacheRoot].some((root) => path === root || path.startsWith(root + sep8));
|
|
35446
35595
|
const activeRoots = new Set;
|
|
35447
35596
|
for (const id of enabledIds) {
|
|
35448
35597
|
const rows = registry2.plugins[id];
|
|
@@ -35454,11 +35603,11 @@ function assertReviewedClaudeCacheClosures(home, config2, review, canonical8) {
|
|
|
35454
35603
|
if (!row || typeof row !== "object" || Array.isArray(row) || typeof row.installPath !== "string") {
|
|
35455
35604
|
throw new Error("Reviewed Claude enabled plugin registration requires an object with an installPath string");
|
|
35456
35605
|
}
|
|
35457
|
-
if ([cacheAliasRoot, cacheRoot].some((root) => row.installPath === root || row.installPath.startsWith(root +
|
|
35606
|
+
if ([cacheAliasRoot, cacheRoot].some((root) => row.installPath === root || row.installPath.startsWith(root + sep8))) {
|
|
35458
35607
|
if (!cachePath(row.installPath) || row.installPath.length > AGENT_POLICY_LIMITS.pathCharacters || row.version !== undefined && (typeof row.version !== "string" || basename9(row.installPath) !== row.version)) {
|
|
35459
35608
|
throw new Error("Reviewed Claude discovery has a malformed active cache registration");
|
|
35460
35609
|
}
|
|
35461
|
-
if (row.scope === "user" && (row.projectPath === undefined || row.projectPath === null)) {} else if (row.scope === "project" && typeof row.projectPath === "string" &&
|
|
35610
|
+
if (row.scope === "user" && (row.projectPath === undefined || row.projectPath === null)) {} else if (row.scope === "project" && typeof row.projectPath === "string" && isAbsolute18(row.projectPath) && resolve19(row.projectPath) === row.projectPath && row.projectPath.length <= AGENT_POLICY_LIMITS.pathCharacters) {} else
|
|
35462
35611
|
throw new Error("Reviewed Claude discovery has an unsupported active cache registration scope");
|
|
35463
35612
|
activeRoots.add(canonical8(row.installPath));
|
|
35464
35613
|
}
|
|
@@ -35475,12 +35624,12 @@ function assertReviewedClaudeCacheClosures(home, config2, review, canonical8) {
|
|
|
35475
35624
|
throw new Error(`Reviewed active Claude cache plugin ${description} is not bound`);
|
|
35476
35625
|
};
|
|
35477
35626
|
for (const root of activeRoots) {
|
|
35478
|
-
|
|
35479
|
-
const rootStat =
|
|
35627
|
+
safe5(root);
|
|
35628
|
+
const rootStat = lstatSync20(root, { throwIfNoEntry: false });
|
|
35480
35629
|
if (!rootStat?.isDirectory() || realpathSync6(root) !== root)
|
|
35481
35630
|
throw new Error("Reviewed Claude active cache plugin root is missing or unsafe");
|
|
35482
|
-
const manifestPath =
|
|
35483
|
-
const manifestStat =
|
|
35631
|
+
const manifestPath = join28(root, ".claude-plugin/plugin.json");
|
|
35632
|
+
const manifestStat = lstatSync20(manifestPath, { throwIfNoEntry: false });
|
|
35484
35633
|
let manifest;
|
|
35485
35634
|
if (manifestStat) {
|
|
35486
35635
|
if (!manifestStat.isFile())
|
|
@@ -35495,37 +35644,37 @@ function assertReviewedClaudeCacheClosures(home, config2, review, canonical8) {
|
|
|
35495
35644
|
} 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)) {
|
|
35496
35645
|
throw new Error("Reviewed Claude active cache plugin manifest absence requires a path-bytes witness");
|
|
35497
35646
|
}
|
|
35498
|
-
const roots = new Set([
|
|
35499
|
-
if (
|
|
35647
|
+
const roots = new Set([join28(root, "skills")]);
|
|
35648
|
+
if (lstatSync20(join28(root, "SKILL.md"), { throwIfNoEntry: false })?.isFile())
|
|
35500
35649
|
roots.add(root);
|
|
35501
35650
|
const declared = manifest?.skills === undefined ? ["./skills"] : typeof manifest.skills === "string" ? [manifest.skills] : manifest.skills;
|
|
35502
35651
|
if (!Array.isArray(declared) || declared.some((path) => typeof path !== "string"))
|
|
35503
35652
|
throw new Error("Reviewed Claude active cache plugin has unsupported skill paths");
|
|
35504
35653
|
for (const value of declared) {
|
|
35505
|
-
const path =
|
|
35506
|
-
if (path !== root && !path.startsWith(root +
|
|
35654
|
+
const path = resolve19(root, value);
|
|
35655
|
+
if (path !== root && !path.startsWith(root + sep8))
|
|
35507
35656
|
throw new Error("Reviewed Claude active cache plugin skill path escapes its root");
|
|
35508
|
-
roots.add(path.endsWith(`${
|
|
35657
|
+
roots.add(path.endsWith(`${sep8}SKILL.md`) ? dirname18(path) : path);
|
|
35509
35658
|
}
|
|
35510
35659
|
for (const skillRoot of roots)
|
|
35511
35660
|
if (!review.roots.includes(skillRoot))
|
|
35512
35661
|
throw new Error("Reviewed Claude active cache plugin skill root is not covered");
|
|
35513
|
-
const hooksPath =
|
|
35514
|
-
const hooksStat =
|
|
35662
|
+
const hooksPath = join28(root, "hooks/hooks.json");
|
|
35663
|
+
const hooksStat = lstatSync20(hooksPath, { throwIfNoEntry: false });
|
|
35515
35664
|
if (hooksStat) {
|
|
35516
35665
|
if (!hooksStat.isFile())
|
|
35517
35666
|
throw new Error("Reviewed Claude plugin hook manifest is unsupported");
|
|
35518
35667
|
requireSource(hooksPath, "hook manifest");
|
|
35519
35668
|
}
|
|
35520
35669
|
if (typeof manifest?.hooks === "string")
|
|
35521
|
-
requireSource(
|
|
35670
|
+
requireSource(resolve19(root, manifest.hooks), "manifest-declared hook source");
|
|
35522
35671
|
}
|
|
35523
35672
|
}
|
|
35524
35673
|
function projectNativeDiscoveryFields(text2, format, fields2, path) {
|
|
35525
|
-
const
|
|
35526
|
-
if (!
|
|
35674
|
+
const object6 = format === "yaml" ? parseHermesConfig(text2) : parseConfig(text2, path, format === "toml");
|
|
35675
|
+
if (!object6 || typeof object6 !== "object" || Array.isArray(object6))
|
|
35527
35676
|
throw new Error("Expected native discovery configuration object");
|
|
35528
|
-
return digest(JSON.stringify(Object.fromEntries(fields2.map((field3) => [field3,
|
|
35677
|
+
return digest(JSON.stringify(Object.fromEntries(fields2.map((field3) => [field3, object6[field3] ?? null]))));
|
|
35529
35678
|
}
|
|
35530
35679
|
function isSupersededSettingsProjection(agent, configPath, source) {
|
|
35531
35680
|
if (agent === "sumi")
|
|
@@ -35538,6 +35687,8 @@ function supersedesSettingsProjection(agent, sources, configPath) {
|
|
|
35538
35687
|
return agent === "codex" && sources.some((source) => source.path === configPath && (source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")));
|
|
35539
35688
|
}
|
|
35540
35689
|
function projected(source, changes, budget2 = discoveryByteBudget()) {
|
|
35690
|
+
if (source.reviewArtifact !== undefined)
|
|
35691
|
+
verifyRetainedReviewArtifact(source);
|
|
35541
35692
|
if (source.hashMode === "sumi-settings-v1") {
|
|
35542
35693
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
35543
35694
|
throw new Error("Sumi settings witnesses require exact typed metadata");
|
|
@@ -35613,9 +35764,9 @@ function absentCodexSkillRoots(binding) {
|
|
|
35613
35764
|
return [];
|
|
35614
35765
|
if (binding.agent !== "codex" || !Array.isArray(controls) || controls.length > 4096)
|
|
35615
35766
|
throw new Error("Invalid disabled Codex discovery proof");
|
|
35616
|
-
if (binding.method !== "reviewed" || controls.every((control) =>
|
|
35767
|
+
if (binding.method !== "reviewed" || controls.every((control) => lstatSync20(control.pluginParent, { throwIfNoEntry: false })))
|
|
35617
35768
|
return [];
|
|
35618
|
-
const cache =
|
|
35769
|
+
const cache = dirname18(dirname18(controls[0].pluginParent)), config2 = join28(dirname18(dirname18(cache)), "config.toml");
|
|
35619
35770
|
const source = binding.sources.find((source2) => source2.path === config2 && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined);
|
|
35620
35771
|
if (!source || projected(source) !== source.sha256)
|
|
35621
35772
|
throw new Error("Missing current disabled Codex configuration witness");
|
|
@@ -35623,8 +35774,8 @@ function absentCodexSkillRoots(binding) {
|
|
|
35623
35774
|
return [...new Set(controls.map((control) => control.pluginParent))].filter((parent) => !codexDirectHookSelects(cache, parent) && absentDisabledCodexPluginParent(cache, parent, controls, rules));
|
|
35624
35775
|
}
|
|
35625
35776
|
function codexDirectHookSelects(cache, root) {
|
|
35626
|
-
const codex =
|
|
35627
|
-
const hooks = read(
|
|
35777
|
+
const codex = dirname18(dirname18(cache)), config2 = Bun.TOML.parse(read(join28(codex, "config.toml")) ?? "");
|
|
35778
|
+
const hooks = read(join28(codex, "hooks.json"));
|
|
35628
35779
|
if (hooks !== null)
|
|
35629
35780
|
hashNativeJsonControls(hooks);
|
|
35630
35781
|
return JSON.stringify(config2.hooks ?? {}).includes(root) || hooks !== null && JSON.stringify(JSON.parse(hooks)).includes(root);
|
|
@@ -35636,7 +35787,7 @@ function retiredCodexRoots(binding) {
|
|
|
35636
35787
|
const controls = binding.codexDisabledPluginSkills;
|
|
35637
35788
|
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)
|
|
35638
35789
|
throw new Error("Invalid retired Codex materialization proof");
|
|
35639
|
-
const cache =
|
|
35790
|
+
const cache = dirname18(dirname18(controls[0].pluginParent)), config2 = join28(dirname18(dirname18(cache)), "config.toml");
|
|
35640
35791
|
const source = binding.sources.find((source2) => source2.path === config2 && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined);
|
|
35641
35792
|
if (!source || projected(source) !== source.sha256)
|
|
35642
35793
|
throw new Error("Missing current retired Codex configuration witness");
|
|
@@ -35644,7 +35795,7 @@ function retiredCodexRoots(binding) {
|
|
|
35644
35795
|
if ((proof.parents ?? []).some((parent) => codexDirectHookSelects(cache, parent) || !reviewedDisabledCodexPluginParent(cache, parent, controls, rules)) || !reviewedCodexPluginCapabilitiesUnchanged(cache, controls, (path) => read(path), rules))
|
|
35645
35796
|
throw new Error("Retired Codex parent capabilities changed");
|
|
35646
35797
|
for (const root of proof.roots) {
|
|
35647
|
-
const manifest = binding.sources.find((source2) => source2.path ===
|
|
35798
|
+
const manifest = binding.sources.find((source2) => source2.path === join28(root, ".codex-plugin/plugin.json") && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined && [undefined, "bytes"].includes(source2.hashMode));
|
|
35648
35799
|
if (!manifest || codexDirectHookSelects(cache, root) || !reviewedRetiredCodexRoot(cache, root, controls, rules, (path) => read(path), true))
|
|
35649
35800
|
throw new Error("Retired Codex materialization changed");
|
|
35650
35801
|
}
|
|
@@ -35653,7 +35804,7 @@ function retiredCodexRoots(binding) {
|
|
|
35653
35804
|
function retainableAbsentSource(source) {
|
|
35654
35805
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined)
|
|
35655
35806
|
return false;
|
|
35656
|
-
return [undefined, "bytes"].includes(source.hashMode) || source.hashMode === "claude-plugin-manifest-v1" && source.sha256 !== null && source.path.endsWith(
|
|
35807
|
+
return [undefined, "bytes"].includes(source.hashMode) || source.hashMode === "claude-plugin-manifest-v1" && source.sha256 !== null && source.path.endsWith(join28(sep8, ".claude-plugin", "plugin.json"));
|
|
35657
35808
|
}
|
|
35658
35809
|
function absentRetiredClaudeRoots(binding) {
|
|
35659
35810
|
if (binding.agent !== "claude" || binding.method !== "reviewed")
|
|
@@ -35662,17 +35813,17 @@ function absentRetiredClaudeRoots(binding) {
|
|
|
35662
35813
|
for (const source of binding.sources) {
|
|
35663
35814
|
if (!retainableAbsentSource(source) || source.sha256 === null)
|
|
35664
35815
|
continue;
|
|
35665
|
-
const marker =
|
|
35816
|
+
const marker = sep8 + ".claude" + sep8 + "plugins" + sep8 + "cache" + sep8, at = source.path.indexOf(marker);
|
|
35666
35817
|
if (at < 0 || source.path.indexOf(marker, at + 1) >= 0)
|
|
35667
35818
|
continue;
|
|
35668
|
-
const cache = source.path.slice(0, at + marker.length - 1), parts = source.path.slice(at + marker.length).split(
|
|
35819
|
+
const cache = source.path.slice(0, at + marker.length - 1), parts = source.path.slice(at + marker.length).split(sep8);
|
|
35669
35820
|
if (parts.length < 4 || parts.slice(0, 3).some((part) => !part || part === "." || part === ".."))
|
|
35670
35821
|
continue;
|
|
35671
|
-
const root =
|
|
35672
|
-
|
|
35673
|
-
if (
|
|
35822
|
+
const root = join28(cache, ...parts.slice(0, 3));
|
|
35823
|
+
safe5(root);
|
|
35824
|
+
if (lstatSync20(root, { throwIfNoEntry: false }))
|
|
35674
35825
|
continue;
|
|
35675
|
-
const claude =
|
|
35826
|
+
const claude = dirname18(dirname18(cache)), settings = join28(claude, "settings.json"), registry2 = join28(claude, "plugins/installed_plugins.json");
|
|
35676
35827
|
const full = (path) => binding.sources.find((item) => item.path === path && item.sha256 !== null && item.format === undefined && item.fields === undefined);
|
|
35677
35828
|
const configSource = full(settings), registrySource = full(registry2);
|
|
35678
35829
|
if (!configSource || !registrySource || projected(configSource) !== configSource.sha256 || projected(registrySource) !== registrySource.sha256)
|
|
@@ -35689,15 +35840,15 @@ function absentRetiredClaudeRoots(binding) {
|
|
|
35689
35840
|
if (!row || typeof row !== "object" || Array.isArray(row))
|
|
35690
35841
|
return null;
|
|
35691
35842
|
const value = row;
|
|
35692
|
-
if (typeof value.installPath !== "string" || /[\x00-\x1f\x7f]/.test(value.installPath) || !
|
|
35843
|
+
if (typeof value.installPath !== "string" || /[\x00-\x1f\x7f]/.test(value.installPath) || !isAbsolute18(value.installPath) || resolve19(value.installPath) !== value.installPath || value.installPath.length > AGENT_POLICY_LIMITS.pathCharacters)
|
|
35693
35844
|
return null;
|
|
35694
35845
|
if (value.scope === "user")
|
|
35695
35846
|
return value.projectPath === undefined || value.projectPath === null ? "user\x00" : null;
|
|
35696
35847
|
if (value.scope === "project")
|
|
35697
|
-
return typeof value.projectPath === "string" && !/[\x00-\x1f\x7f]/.test(value.projectPath) && value.projectPath.length <= AGENT_POLICY_LIMITS.pathCharacters &&
|
|
35848
|
+
return typeof value.projectPath === "string" && !/[\x00-\x1f\x7f]/.test(value.projectPath) && value.projectPath.length <= AGENT_POLICY_LIMITS.pathCharacters && isAbsolute18(value.projectPath) && resolve19(value.projectPath) === value.projectPath ? `project\x00${value.projectPath}` : null;
|
|
35698
35849
|
return null;
|
|
35699
35850
|
};
|
|
35700
|
-
if (Object.values(installed.plugins).some((value) => !Array.isArray(value) || value.some((row) => !row || typeof row.installPath !== "string" || row.installPath === root || row.installPath.startsWith(root +
|
|
35851
|
+
if (Object.values(installed.plugins).some((value) => !Array.isArray(value) || value.some((row) => !row || typeof row.installPath !== "string" || row.installPath === root || row.installPath.startsWith(root + sep8) || root.startsWith(row.installPath + sep8))))
|
|
35701
35852
|
continue;
|
|
35702
35853
|
const rows = installed.plugins[id];
|
|
35703
35854
|
if (!Array.isArray(rows) || rows.length < 1)
|
|
@@ -35715,9 +35866,9 @@ function absentRetiredClaudeRoots(binding) {
|
|
|
35715
35866
|
if (!targetValid || !targetScopes.has("user\x00"))
|
|
35716
35867
|
continue;
|
|
35717
35868
|
const active = rows[0]?.installPath;
|
|
35718
|
-
if (typeof active !== "string" || rows[0]?.version !== basename9(active) ||
|
|
35869
|
+
if (typeof active !== "string" || rows[0]?.version !== basename9(active) || dirname18(active) !== dirname18(root) || active === root || !lstatSync20(active, { throwIfNoEntry: false })?.isDirectory() || realpathSync6(active) !== active)
|
|
35719
35870
|
continue;
|
|
35720
|
-
const activeManifest = full(
|
|
35871
|
+
const activeManifest = full(join28(active, ".claude-plugin/plugin.json"));
|
|
35721
35872
|
if (!activeManifest || projected(activeManifest) !== activeManifest.sha256)
|
|
35722
35873
|
continue;
|
|
35723
35874
|
result.add(root);
|
|
@@ -35733,10 +35884,10 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
35733
35884
|
throw new Error("Hermes discovery requires directory membership coverage; run skills hook install with a fresh discovery review");
|
|
35734
35885
|
const installationRoots = codexInstallationRoots(binding);
|
|
35735
35886
|
const retiredRoots = retiredCodexRoots(binding);
|
|
35736
|
-
const installationInput = (path) => installationRoots.some((root) => path === root || path.startsWith(root +
|
|
35887
|
+
const installationInput = (path) => installationRoots.some((root) => path === root || path.startsWith(root + sep8));
|
|
35737
35888
|
if (binding.directories !== undefined) {
|
|
35738
35889
|
const projected2 = binding.codexInstallationInputs?.directories ?? [];
|
|
35739
|
-
const ancestors2 = binding.directories.filter((directory) => installationRoots.some((root) => root.startsWith(directory.path +
|
|
35890
|
+
const ancestors2 = binding.directories.filter((directory) => installationRoots.some((root) => root.startsWith(directory.path + sep8)));
|
|
35740
35891
|
if (projected2.length !== ancestors2.length || projected2.some((directory) => !ancestors2.some((original) => original.path === directory.path)))
|
|
35741
35892
|
throw new Error("Missing installation input directory projection");
|
|
35742
35893
|
const ordinary = binding.directories.filter((directory) => !installationInput(directory.path) && !ancestors2.includes(directory));
|
|
@@ -35744,7 +35895,7 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
35744
35895
|
const projection = binding.codexRetiredMaterializations.directories;
|
|
35745
35896
|
if (projection.length !== ordinary.length || projection.some((item, index) => item.path !== ordinary[index]?.path))
|
|
35746
35897
|
throw new Error("Missing retired Codex directory projection");
|
|
35747
|
-
const omitted = [...retiredRoots, ...(binding.codexRetiredMaterializations.parents ?? []).filter((parent) => !
|
|
35898
|
+
const omitted = [...retiredRoots, ...(binding.codexRetiredMaterializations.parents ?? []).filter((parent) => !lstatSync20(parent, { throwIfNoEntry: false }))];
|
|
35748
35899
|
if (projection.every((item) => Array.isArray(item.entries)))
|
|
35749
35900
|
verifyDiscoveryDirectoryProjection(projection, omitted);
|
|
35750
35901
|
else {
|
|
@@ -35758,7 +35909,7 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
35758
35909
|
verifyDiscoveryDirectories(ordinary);
|
|
35759
35910
|
verifyDiscoveryDirectories(projected2, installationRoots);
|
|
35760
35911
|
}
|
|
35761
|
-
const absentRoots = [...absentCodexSkillRoots(binding), ...absentRetiredClaudeRoots(binding), ...retiredRoots.filter((root) => !
|
|
35912
|
+
const absentRoots = [...absentCodexSkillRoots(binding), ...absentRetiredClaudeRoots(binding), ...retiredRoots.filter((root) => !lstatSync20(root, { throwIfNoEntry: false }))];
|
|
35762
35913
|
const budget2 = discoveryByteBudget();
|
|
35763
35914
|
for (const source of binding.sources) {
|
|
35764
35915
|
assertMarketplaceBinding(binding, source);
|
|
@@ -35769,11 +35920,11 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
35769
35920
|
if (source.sha256 !== null && !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
35770
35921
|
throw new Error("Invalid native discovery digest");
|
|
35771
35922
|
if (installationInput(source.path)) {
|
|
35772
|
-
|
|
35923
|
+
safe5(source.path);
|
|
35773
35924
|
continue;
|
|
35774
35925
|
}
|
|
35775
|
-
if (absentRoots.some((root) => source.path.startsWith(root +
|
|
35776
|
-
|
|
35926
|
+
if (absentRoots.some((root) => source.path.startsWith(root + sep8)) && retainableAbsentSource(source)) {
|
|
35927
|
+
safe5(source.path);
|
|
35777
35928
|
continue;
|
|
35778
35929
|
}
|
|
35779
35930
|
const current = projected(source, undefined, budget2);
|
|
@@ -35781,10 +35932,10 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
35781
35932
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
35782
35933
|
}
|
|
35783
35934
|
for (const root of binding.roots)
|
|
35784
|
-
|
|
35935
|
+
safe5(root);
|
|
35785
35936
|
for (const root of absentRoots) {
|
|
35786
|
-
|
|
35787
|
-
if (
|
|
35937
|
+
safe5(root);
|
|
35938
|
+
if (lstatSync20(root, { throwIfNoEntry: false }))
|
|
35788
35939
|
throw new Error("Retired native materialization changed during discovery verification");
|
|
35789
35940
|
}
|
|
35790
35941
|
}
|
|
@@ -35794,13 +35945,13 @@ function codexInstallationRoots(binding) {
|
|
|
35794
35945
|
return [];
|
|
35795
35946
|
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)
|
|
35796
35947
|
throw new Error("Invalid native installation input proof");
|
|
35797
|
-
const cache =
|
|
35798
|
-
const config2 =
|
|
35948
|
+
const cache = dirname18(dirname18(proof.plugins[0].pluginParent));
|
|
35949
|
+
const config2 = join28(dirname18(dirname18(cache)), "config.toml"), home = dirname18(dirname18(dirname18(cache)));
|
|
35799
35950
|
const configSource = binding.sources.find((source) => source.path === config2 && source.sha256 !== null && (!source.format || source.format === "toml" && source.fields?.includes("plugins")));
|
|
35800
|
-
const nativeRoots = NATIVE_SKILL_ROOTS.filter(([agent]) => agent === "codex").map(([, path]) =>
|
|
35801
|
-
if (!configSource || proof.plugins.some((input2) => nativeRoots.some((root) => root === input2.sourceRoot || root.startsWith(input2.sourceRoot +
|
|
35951
|
+
const nativeRoots = NATIVE_SKILL_ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => join28(home, path));
|
|
35952
|
+
if (!configSource || proof.plugins.some((input2) => nativeRoots.some((root) => root === input2.sourceRoot || root.startsWith(input2.sourceRoot + sep8) || input2.sourceRoot.startsWith(root + sep8)) || binding.sources.some((source) => basename9(source.path) === "config.toml" && (source.path === input2.sourceRoot || source.path.startsWith(input2.sourceRoot + sep8)))))
|
|
35802
35953
|
throw new Error("Native installation input overlaps configuration or loading roots");
|
|
35803
|
-
if (proof.plugins.some((input2) =>
|
|
35954
|
+
if (proof.plugins.some((input2) => dirname18(dirname18(input2.pluginParent)) !== cache || !binding.sources.some((source) => source.path === join28(input2.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined)))
|
|
35804
35955
|
throw new Error("Missing native installation input source witness");
|
|
35805
35956
|
return reviewedCodexPluginSourceRoots(cache, proof.plugins, (path) => {
|
|
35806
35957
|
const text2 = read(path);
|
|
@@ -35810,7 +35961,7 @@ function codexInstallationRoots(binding) {
|
|
|
35810
35961
|
});
|
|
35811
35962
|
}
|
|
35812
35963
|
function assertMarketplaceBinding(binding, source) {
|
|
35813
|
-
if (source.hashMode === "claude-plugin-manifest-v1" && (binding.agent !== "claude" || basename9(source.path) !== "plugin.json" || !source.path.endsWith(
|
|
35964
|
+
if (source.hashMode === "claude-plugin-manifest-v1" && (binding.agent !== "claude" || basename9(source.path) !== "plugin.json" || !source.path.endsWith(join28(sep8, ".claude-plugin", "plugin.json"))))
|
|
35814
35965
|
throw new Error("Claude plugin manifest witnesses require Claude plugin discovery");
|
|
35815
35966
|
if (source.hashMode === "sumi-settings-v1" && (binding.agent !== "sumi" || binding.method !== "reviewed" || basename9(source.path) !== "sumi.json"))
|
|
35816
35967
|
throw new Error("Sumi settings witnesses require explicit reviewed Sumi configuration");
|
|
@@ -35826,10 +35977,10 @@ function assertMarketplaceBinding(binding, source) {
|
|
|
35826
35977
|
function agentDiscoveryConfigPath(home, agent) {
|
|
35827
35978
|
if (agent === "sumi")
|
|
35828
35979
|
return sumiConfigPath(home);
|
|
35829
|
-
return
|
|
35980
|
+
return join28(home, agent === "hermes" ? ".hermes/config.yaml" : agent === "opencode" ? ".config/opencode/opencode.json" : `.${agent}/${agent === "codex" ? "config.toml" : agent === "cursor" ? "hooks.json" : "settings.json"}`);
|
|
35830
35981
|
}
|
|
35831
35982
|
function resolveAgentDiscovery(options) {
|
|
35832
|
-
const canonical8 = options.canonical ??
|
|
35983
|
+
const canonical8 = options.canonical ?? resolve19, home = resolve19(options.home), agent = options.agent;
|
|
35833
35984
|
const sources = [], roots = new Set, builtinNames = [];
|
|
35834
35985
|
const witness = (path, format, fields2, hashMode) => {
|
|
35835
35986
|
const source = { path: canonical8(path), sha256: null, ...format ? { format, fields: fields2 } : {}, ...hashMode ? { hashMode } : {} };
|
|
@@ -35850,42 +36001,42 @@ function resolveAgentDiscovery(options) {
|
|
|
35850
36001
|
const review = options.reviewed?.agents.find((item) => item.agent === agent);
|
|
35851
36002
|
if (agent === "sumi") {
|
|
35852
36003
|
const directory = sumiConfigDirectory(home);
|
|
35853
|
-
if (witness(
|
|
36004
|
+
if (witness(join28(directory, "sumi.jsonc")) !== null)
|
|
35854
36005
|
unresolved("JSONC configuration requires a supported format adapter");
|
|
35855
|
-
for (const root of [directory,
|
|
36006
|
+
for (const root of [directory, join28(home, ".claude"), join28(home, ".agents")])
|
|
35856
36007
|
for (const name of ["skill", "skills"])
|
|
35857
|
-
roots.add(canonical8(
|
|
36008
|
+
roots.add(canonical8(join28(root, name)));
|
|
35858
36009
|
if (config2.skills !== undefined && (!Array.isArray(config2.skills) || config2.skills.some((path) => typeof path !== "string")))
|
|
35859
36010
|
unresolved("skills must be a string array");
|
|
35860
36011
|
for (const value of config2.skills ?? []) {
|
|
35861
|
-
if (typeof value !== "string" || /[\0$]/.test(value) || !value || !(
|
|
36012
|
+
if (typeof value !== "string" || /[\0$]/.test(value) || !value || !(isAbsolute18(value) || value.startsWith("~/")))
|
|
35862
36013
|
unresolved("remote or relative skill sources need a dedicated discovery adapter");
|
|
35863
|
-
roots.add(canonical8(value.startsWith("~/") ?
|
|
36014
|
+
roots.add(canonical8(value.startsWith("~/") ? join28(home, value.slice(2)) : value));
|
|
35864
36015
|
}
|
|
35865
36016
|
for (const key of ["plugin", "plugins"])
|
|
35866
36017
|
if (config2[key] !== undefined && !Array.isArray(config2[key]))
|
|
35867
36018
|
unresolved(`${key} must be an array`);
|
|
35868
|
-
const plugins = [
|
|
36019
|
+
const plugins = [join28(directory, "plugin"), join28(directory, "plugins")];
|
|
35869
36020
|
for (const path of plugins) {
|
|
35870
|
-
|
|
35871
|
-
if (
|
|
36021
|
+
safe5(path);
|
|
36022
|
+
if (lstatSync20(path, { throwIfNoEntry: false })?.isDirectory())
|
|
35872
36023
|
for (const name of readdirSync7(path).sort()) {
|
|
35873
36024
|
if (name === "skills-cli.js" && path === plugins[1])
|
|
35874
36025
|
continue;
|
|
35875
|
-
const target =
|
|
35876
|
-
if (!
|
|
36026
|
+
const target = join28(path, name);
|
|
36027
|
+
if (!lstatSync20(target).isFile())
|
|
35877
36028
|
unresolved("local plugin packages need a dedicated discovery adapter");
|
|
35878
36029
|
witness(target);
|
|
35879
36030
|
}
|
|
35880
36031
|
}
|
|
35881
36032
|
for (const root of roots) {
|
|
35882
|
-
|
|
35883
|
-
if (
|
|
36033
|
+
safe5(root);
|
|
36034
|
+
if (lstatSync20(root, { throwIfNoEntry: false })?.isDirectory() && readdirSync7(root).some((name) => name.endsWith(".md")))
|
|
35884
36035
|
unresolved("flat markdown skills require a dedicated native migration adapter");
|
|
35885
36036
|
}
|
|
35886
36037
|
}
|
|
35887
36038
|
if (agent === "hermes") {
|
|
35888
|
-
const profile = witness(
|
|
36039
|
+
const profile = witness(join28(home, ".hermes/active_profile"));
|
|
35889
36040
|
if (profile?.trim() && profile.trim() !== "default")
|
|
35890
36041
|
unresolved("a non-default profile is active");
|
|
35891
36042
|
const declared = config2.skills?.external_dirs ?? [], paths = typeof declared === "string" ? [declared] : declared;
|
|
@@ -35899,8 +36050,8 @@ function resolveAgentDiscovery(options) {
|
|
|
35899
36050
|
continue;
|
|
35900
36051
|
if (normalized.startsWith("~") && normalized !== "~" && !normalized.startsWith("~/"))
|
|
35901
36052
|
unresolved("user-specific tilde expansion requires a separate discovery adapter");
|
|
35902
|
-
const path = normalized === "~" ? home : normalized.startsWith("~/") ?
|
|
35903
|
-
|
|
36053
|
+
const path = normalized === "~" ? home : normalized.startsWith("~/") ? join28(home, normalized.slice(2)) : resolve19(home, ".hermes", normalized);
|
|
36054
|
+
safe5(path);
|
|
35904
36055
|
roots.add(path);
|
|
35905
36056
|
}
|
|
35906
36057
|
}
|
|
@@ -35908,24 +36059,24 @@ function resolveAgentDiscovery(options) {
|
|
|
35908
36059
|
const executable = options.executable === undefined ? discoveryExecutable(agent) : options.executable;
|
|
35909
36060
|
if (executable) {
|
|
35910
36061
|
let packageRoot;
|
|
35911
|
-
for (let directory =
|
|
35912
|
-
const path =
|
|
36062
|
+
for (let directory = dirname18(executable.target), depth = 0;depth < 8; directory = dirname18(directory), depth++) {
|
|
36063
|
+
const path = join28(directory, "package.json"), raw = read(path);
|
|
35913
36064
|
if (raw !== null && parseConfig(raw, path).name === "@google/gemini-cli") {
|
|
35914
36065
|
packageRoot = directory;
|
|
35915
36066
|
witness(path);
|
|
35916
36067
|
break;
|
|
35917
36068
|
}
|
|
35918
|
-
if (
|
|
36069
|
+
if (dirname18(directory) === directory)
|
|
35919
36070
|
break;
|
|
35920
36071
|
}
|
|
35921
36072
|
if (!packageRoot)
|
|
35922
36073
|
unresolved("installed Gemini package layout is not recognized");
|
|
35923
|
-
const builtinRoot =
|
|
35924
|
-
|
|
35925
|
-
if (!
|
|
36074
|
+
const builtinRoot = join28(packageRoot, "bundle/builtin");
|
|
36075
|
+
safe5(builtinRoot);
|
|
36076
|
+
if (!lstatSync20(builtinRoot, { throwIfNoEntry: false })?.isDirectory())
|
|
35926
36077
|
unresolved("installed Gemini builtin root is missing");
|
|
35927
36078
|
for (const name of readdirSync7(builtinRoot).sort()) {
|
|
35928
|
-
const text2 = witness(
|
|
36079
|
+
const text2 = witness(join28(builtinRoot, name, "SKILL.md"));
|
|
35929
36080
|
const match = text2?.match(/^---\r?\n[\s\S]*?^name:\s*([a-z0-9][a-z0-9-]*)\s*$/m);
|
|
35930
36081
|
if (!match?.[1] || builtinNames.includes(match[1]))
|
|
35931
36082
|
unresolved("installed Gemini builtin name is missing or ambiguous");
|
|
@@ -35960,10 +36111,10 @@ function resolveAgentDiscovery(options) {
|
|
|
35960
36111
|
throw new Error("Discovery review must include the agent configuration source");
|
|
35961
36112
|
const reviewedSources = supersedesSettingsProjection(agent, review.sources, canonical8(configPath)) ? sources.filter((source) => !isSupersededSettingsProjection(agent, canonical8(configPath), source)) : sources;
|
|
35962
36113
|
const reviewedSourcesWithManifestProjection = review.sources.map((source) => {
|
|
35963
|
-
if (agent !== "claude" || source.sha256 === null || source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || source.hashMode !== undefined && source.hashMode !== "bytes" || basename9(source.path) !== "plugin.json" || !source.path.endsWith(
|
|
36114
|
+
if (agent !== "claude" || source.sha256 === null || source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || source.hashMode !== undefined && source.hashMode !== "bytes" || basename9(source.path) !== "plugin.json" || !source.path.endsWith(join28(sep8, ".claude-plugin", "plugin.json")))
|
|
35964
36115
|
return source;
|
|
35965
|
-
const pluginRoot =
|
|
35966
|
-
const hookStat =
|
|
36116
|
+
const pluginRoot = dirname18(dirname18(source.path)), hooksPath = join28(pluginRoot, "hooks/hooks.json");
|
|
36117
|
+
const hookStat = lstatSync20(hooksPath, { throwIfNoEntry: false });
|
|
35967
36118
|
const text2 = read(source.path);
|
|
35968
36119
|
if (text2 === null)
|
|
35969
36120
|
throw new Error("Reviewed Claude plugin manifest is missing");
|
|
@@ -35977,8 +36128,8 @@ function resolveAgentDiscovery(options) {
|
|
|
35977
36128
|
if (manifest.hooks !== undefined) {
|
|
35978
36129
|
if (typeof manifest.hooks !== "string")
|
|
35979
36130
|
throw new Error("Reviewed Claude plugin manifest has an unsupported hooks target");
|
|
35980
|
-
const declaredHookPath =
|
|
35981
|
-
if (!declaredHookPath.startsWith(pluginRoot +
|
|
36131
|
+
const declaredHookPath = resolve19(pluginRoot, manifest.hooks);
|
|
36132
|
+
if (!declaredHookPath.startsWith(pluginRoot + sep8))
|
|
35982
36133
|
throw new Error("Reviewed Claude plugin hooks target escapes its root");
|
|
35983
36134
|
reviewedHookPaths.add(declaredHookPath);
|
|
35984
36135
|
}
|
|
@@ -35995,40 +36146,40 @@ function resolveAgentDiscovery(options) {
|
|
|
35995
36146
|
}
|
|
35996
36147
|
function plugin(root) {
|
|
35997
36148
|
root = canonical8(root);
|
|
35998
|
-
|
|
35999
|
-
const manifestPath =
|
|
36149
|
+
safe5(root);
|
|
36150
|
+
const manifestPath = join28(root, agent === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json");
|
|
36000
36151
|
const raw = witness(manifestPath, undefined, undefined, agent === "claude" ? "claude-plugin-manifest-v1" : undefined);
|
|
36001
36152
|
if (raw === null)
|
|
36002
36153
|
unresolved("plugin manifest missing");
|
|
36003
36154
|
const manifest = parseConfig(raw, manifestPath);
|
|
36004
|
-
const hooks = witness(
|
|
36155
|
+
const hooks = witness(join28(root, "hooks/hooks.json"));
|
|
36005
36156
|
if (manifest.hooks !== undefined || hooks !== null)
|
|
36006
36157
|
unresolved("plugin hooks require a separate no-skill-injection review");
|
|
36007
|
-
const commands =
|
|
36008
|
-
|
|
36009
|
-
if (agent === "claude" && (manifest.commands !== undefined ||
|
|
36158
|
+
const commands = join28(root, "commands");
|
|
36159
|
+
safe5(commands);
|
|
36160
|
+
if (agent === "claude" && (manifest.commands !== undefined || lstatSync20(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync7(commands).length))
|
|
36010
36161
|
unresolved("legacy command discovery requires retirement or a dedicated format adapter");
|
|
36011
|
-
const rootSkill = witness(
|
|
36162
|
+
const rootSkill = witness(join28(root, "SKILL.md"));
|
|
36012
36163
|
if (rootSkill !== null)
|
|
36013
36164
|
roots.add(root);
|
|
36014
36165
|
const declared = manifest.skills === undefined ? ["./skills"] : typeof manifest.skills === "string" ? [manifest.skills] : manifest.skills;
|
|
36015
36166
|
if (!Array.isArray(declared) || declared.some((path) => typeof path !== "string"))
|
|
36016
36167
|
unresolved("unsupported plugin skill paths");
|
|
36017
36168
|
if (agent === "claude")
|
|
36018
|
-
roots.add(
|
|
36169
|
+
roots.add(join28(root, "skills"));
|
|
36019
36170
|
for (const value of declared) {
|
|
36020
|
-
const path =
|
|
36021
|
-
if (path !== root && !path.startsWith(root +
|
|
36171
|
+
const path = resolve19(root, value);
|
|
36172
|
+
if (path !== root && !path.startsWith(root + sep8))
|
|
36022
36173
|
unresolved("plugin skill path escapes its root");
|
|
36023
|
-
roots.add(path.endsWith(`${
|
|
36174
|
+
roots.add(path.endsWith(`${sep8}SKILL.md`) ? dirname18(path) : path);
|
|
36024
36175
|
}
|
|
36025
36176
|
}
|
|
36026
36177
|
if (agent === "claude") {
|
|
36027
|
-
const registrations = witness(
|
|
36028
|
-
const installed = registrations === null ? {} : parseConfig(registrations,
|
|
36029
|
-
const commands = canonical8(
|
|
36030
|
-
|
|
36031
|
-
if (
|
|
36178
|
+
const registrations = witness(join28(home, ".claude/plugins/installed_plugins.json"));
|
|
36179
|
+
const installed = registrations === null ? {} : parseConfig(registrations, join28(home, ".claude/plugins/installed_plugins.json")).plugins;
|
|
36180
|
+
const commands = canonical8(join28(home, ".claude/commands"));
|
|
36181
|
+
safe5(commands);
|
|
36182
|
+
if (lstatSync20(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync7(commands).length)
|
|
36032
36183
|
unresolved("legacy home command discovery requires a dedicated format adapter");
|
|
36033
36184
|
for (const [id, enabled] of Object.entries(config2.enabledPlugins ?? {})) {
|
|
36034
36185
|
if (enabled === false)
|
|
@@ -36048,37 +36199,37 @@ function resolveAgentDiscovery(options) {
|
|
|
36048
36199
|
unresolved("unsupported plugin enablement");
|
|
36049
36200
|
const split = id.lastIndexOf("@"), name = id.slice(0, split), marketplace = id.slice(split + 1);
|
|
36050
36201
|
const market = config2.marketplaces?.[marketplace] ?? (marketplace === "personal" ? { source_type: "local", source: home } : undefined);
|
|
36051
|
-
if (split < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !
|
|
36202
|
+
if (split < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !isAbsolute18(market.source))
|
|
36052
36203
|
unresolved("enabled plugin marketplace is not an explicit local source");
|
|
36053
|
-
const catalogText = witness(
|
|
36204
|
+
const catalogText = witness(join28(market.source, ".agents/plugins/marketplace.json"));
|
|
36054
36205
|
if (catalogText === null)
|
|
36055
36206
|
unresolved("marketplace catalog missing");
|
|
36056
|
-
const catalog = parseConfig(catalogText,
|
|
36207
|
+
const catalog = parseConfig(catalogText, join28(market.source, ".agents/plugins/marketplace.json")), matches = Array.isArray(catalog.plugins) ? catalog.plugins.filter((item) => item.name === name) : [];
|
|
36057
36208
|
if (matches.length !== 1 || matches[0]?.source?.source !== "local" || typeof matches[0]?.source?.path !== "string")
|
|
36058
36209
|
unresolved("plugin catalog source is missing or ambiguous");
|
|
36059
|
-
plugin(
|
|
36210
|
+
plugin(resolve19(market.source, matches[0].source.path));
|
|
36060
36211
|
}
|
|
36061
36212
|
} else if (agent === "opencode") {
|
|
36062
|
-
if (witness(
|
|
36213
|
+
if (witness(join28(home, ".config/opencode/opencode.jsonc")) !== null || witness(join28(home, ".config/opencode/config.json")) !== null)
|
|
36063
36214
|
unresolved("additional config layers require review");
|
|
36064
36215
|
if ((config2.plugin?.length ?? 0) > 0 || config2.skills?.urls?.length)
|
|
36065
36216
|
unresolved("external plugin or remote skill source");
|
|
36066
36217
|
for (const path of config2.skills?.paths ?? []) {
|
|
36067
|
-
if (typeof path !== "string" || !
|
|
36218
|
+
if (typeof path !== "string" || !isAbsolute18(path))
|
|
36068
36219
|
unresolved("relative or malformed added skill root");
|
|
36069
36220
|
roots.add(path);
|
|
36070
36221
|
}
|
|
36071
|
-
const localPlugins =
|
|
36072
|
-
|
|
36073
|
-
if (
|
|
36222
|
+
const localPlugins = join28(home, ".config/opencode/plugins");
|
|
36223
|
+
safe5(localPlugins);
|
|
36224
|
+
if (lstatSync20(localPlugins, { throwIfNoEntry: false }) && readdirSync7(localPlugins).some((name) => name !== "skills-cli.js"))
|
|
36074
36225
|
unresolved("additional local plugin hooks require review");
|
|
36075
36226
|
} else if (agent === "sumi") {
|
|
36076
|
-
if ((config2.plugin?.length ?? 0) > 0 || (config2.plugins?.length ?? 0) > 0 || sources.some((source) => source.path !== canonical8(configPath) && source.path !== canonical8(
|
|
36227
|
+
if ((config2.plugin?.length ?? 0) > 0 || (config2.plugins?.length ?? 0) > 0 || sources.some((source) => source.path !== canonical8(configPath) && source.path !== canonical8(join28(sumiConfigDirectory(home), "sumi.jsonc")) && source.sha256 !== null))
|
|
36077
36228
|
unresolved("external or foreign local plugins require review");
|
|
36078
36229
|
} else if (agent === "hermes") {
|
|
36079
|
-
for (const directory of [
|
|
36080
|
-
|
|
36081
|
-
if (
|
|
36230
|
+
for (const directory of [join28(home, ".hermes/plugins"), join28(home, ".hermes/hermes-agent")]) {
|
|
36231
|
+
safe5(directory);
|
|
36232
|
+
if (lstatSync20(directory, { throwIfNoEntry: false }))
|
|
36082
36233
|
unresolved("installed runtime/plugin discovery requires reviewed source bindings");
|
|
36083
36234
|
}
|
|
36084
36235
|
if (Bun.which("hermes") || Object.keys(config2.plugins ?? {}).length)
|
|
@@ -36086,24 +36237,24 @@ function resolveAgentDiscovery(options) {
|
|
|
36086
36237
|
} else if (agent === "gemini") {
|
|
36087
36238
|
if (Object.keys(config2.extensions ?? {}).length || config2.skills?.paths?.length)
|
|
36088
36239
|
unresolved("custom extension or skill paths");
|
|
36089
|
-
const directory =
|
|
36090
|
-
|
|
36091
|
-
if (
|
|
36240
|
+
const directory = join28(home, ".gemini/extensions");
|
|
36241
|
+
safe5(directory);
|
|
36242
|
+
if (lstatSync20(directory, { throwIfNoEntry: false }))
|
|
36092
36243
|
for (const name of readdirSync7(directory)) {
|
|
36093
|
-
const root =
|
|
36094
|
-
|
|
36095
|
-
if (!
|
|
36244
|
+
const root = join28(directory, name);
|
|
36245
|
+
safe5(root);
|
|
36246
|
+
if (!lstatSync20(root)?.isDirectory())
|
|
36096
36247
|
continue;
|
|
36097
|
-
const raw = witness(
|
|
36248
|
+
const raw = witness(join28(root, "gemini-extension.json"));
|
|
36098
36249
|
if (raw === null)
|
|
36099
36250
|
unresolved("extension registration missing");
|
|
36100
|
-
const manifest = parseConfig(raw,
|
|
36101
|
-
if (manifest.hooks !== undefined || witness(
|
|
36251
|
+
const manifest = parseConfig(raw, join28(root, "gemini-extension.json"));
|
|
36252
|
+
if (manifest.hooks !== undefined || witness(join28(root, "hooks/hooks.json")) !== null || witness(join28(root, ".gemini-extension-install.json")) !== null)
|
|
36102
36253
|
unresolved("extension hooks or linked registration require review");
|
|
36103
|
-
roots.add(
|
|
36254
|
+
roots.add(join28(root, "skills"));
|
|
36104
36255
|
}
|
|
36105
36256
|
}
|
|
36106
|
-
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([
|
|
36257
|
+
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join28(home, ".hermes/plugins"), join28(home, ".hermes/hermes-agent")].map((path) => canonical8(path))) } : {} };
|
|
36107
36258
|
}
|
|
36108
36259
|
var DISCOVERY_RUNTIME_COMMANDS, realpathOrNull = (path) => {
|
|
36109
36260
|
try {
|
|
@@ -36111,7 +36262,7 @@ var DISCOVERY_RUNTIME_COMMANDS, realpathOrNull = (path) => {
|
|
|
36111
36262
|
} catch {
|
|
36112
36263
|
return null;
|
|
36113
36264
|
}
|
|
36114
|
-
}, digest = (text2) =>
|
|
36265
|
+
}, digest = (text2) => createHash20("sha256").update(text2).digest("hex");
|
|
36115
36266
|
var init_agent_discovery = __esm(() => {
|
|
36116
36267
|
init_sumi_settings_witness();
|
|
36117
36268
|
init_agent_policy_limits();
|
|
@@ -36131,16 +36282,17 @@ var init_agent_discovery = __esm(() => {
|
|
|
36131
36282
|
init_agent_sumi();
|
|
36132
36283
|
init_native_discovery_roots();
|
|
36133
36284
|
init_codex_native_compatibility();
|
|
36285
|
+
init_retained_review_artifacts();
|
|
36134
36286
|
init_agent_discovery_directories();
|
|
36135
36287
|
DISCOVERY_RUNTIME_COMMANDS = Object.freeze({ gemini: "gemini" });
|
|
36136
36288
|
});
|
|
36137
36289
|
|
|
36138
36290
|
// src/lib/authoring-path.ts
|
|
36139
|
-
import { lstatSync as
|
|
36291
|
+
import { lstatSync as lstatSync21, realpathSync as realpathSync7 } from "fs";
|
|
36140
36292
|
import { homedir as homedir3 } from "os";
|
|
36141
|
-
import { basename as basename10, dirname as
|
|
36293
|
+
import { basename as basename10, dirname as dirname19, join as join29, resolve as resolve20, sep as sep9 } from "path";
|
|
36142
36294
|
function pathParts(path) {
|
|
36143
|
-
return
|
|
36295
|
+
return resolve20(path).split(sep9).filter(Boolean);
|
|
36144
36296
|
}
|
|
36145
36297
|
function nativeRootMatch(path) {
|
|
36146
36298
|
const parts = pathParts(path);
|
|
@@ -36154,24 +36306,24 @@ function nativeRootMatch(path) {
|
|
|
36154
36306
|
return;
|
|
36155
36307
|
}
|
|
36156
36308
|
function physicalPath(path) {
|
|
36157
|
-
let cursor =
|
|
36309
|
+
let cursor = resolve20(path);
|
|
36158
36310
|
const suffix = [];
|
|
36159
|
-
while (!
|
|
36311
|
+
while (!lstatSync21(cursor, { throwIfNoEntry: false })) {
|
|
36160
36312
|
suffix.unshift(basename10(cursor));
|
|
36161
|
-
const parent =
|
|
36313
|
+
const parent = dirname19(cursor);
|
|
36162
36314
|
if (parent === cursor)
|
|
36163
|
-
return
|
|
36315
|
+
return resolve20(path);
|
|
36164
36316
|
cursor = parent;
|
|
36165
36317
|
}
|
|
36166
|
-
return
|
|
36318
|
+
return resolve20(realpathSync7(cursor), ...suffix);
|
|
36167
36319
|
}
|
|
36168
36320
|
function contains(root, path) {
|
|
36169
|
-
return path === root || path.startsWith(root +
|
|
36321
|
+
return path === root || path.startsWith(root + sep9);
|
|
36170
36322
|
}
|
|
36171
36323
|
function configuredRoots(home, explicitHome) {
|
|
36172
|
-
const homeData =
|
|
36324
|
+
const homeData = join29(home, ".hasna", "skills");
|
|
36173
36325
|
const homePolicy = readManagedSkillPolicySnapshot(homeData);
|
|
36174
|
-
const configuredPolicy = !explicitHome &&
|
|
36326
|
+
const configuredPolicy = !explicitHome && resolve20(getDataDirReadOnly()) !== resolve20(homeData) ? readManagedSkillPolicySnapshot(getDataDirReadOnly()) : null;
|
|
36175
36327
|
const policy = homePolicy ?? configuredPolicy;
|
|
36176
36328
|
const bridge = policy?.value.bridge;
|
|
36177
36329
|
if (bridge && (typeof bridge.home !== "string" || physicalPath(bridge.home) !== physicalPath(home))) {
|
|
@@ -36200,8 +36352,8 @@ function configuredRoots(home, explicitHome) {
|
|
|
36200
36352
|
admitBinding(binding);
|
|
36201
36353
|
continue;
|
|
36202
36354
|
}
|
|
36203
|
-
const nativeHome =
|
|
36204
|
-
if (!
|
|
36355
|
+
const nativeHome = join29(home, agent === "opencode" ? ".config/opencode" : `.${agent}`);
|
|
36356
|
+
if (!lstatSync21(nativeHome, { throwIfNoEntry: false }))
|
|
36205
36357
|
continue;
|
|
36206
36358
|
roots.push(...resolveAgentDiscovery({ home, agent, canonical: physicalPath }).roots);
|
|
36207
36359
|
}
|
|
@@ -36210,22 +36362,22 @@ function configuredRoots(home, explicitHome) {
|
|
|
36210
36362
|
function assertPortableAuthoringPath(path, options = {}) {
|
|
36211
36363
|
if (typeof path !== "string" || !path || path.includes("\x00"))
|
|
36212
36364
|
throw new Error("Invalid portable authoring path");
|
|
36213
|
-
const lexical =
|
|
36365
|
+
const lexical = resolve20(path);
|
|
36214
36366
|
const physical = physicalPath(lexical);
|
|
36215
36367
|
const candidates = [lexical, physical];
|
|
36216
36368
|
let native = candidates.map(nativeRootMatch).find(Boolean);
|
|
36217
|
-
const home =
|
|
36218
|
-
const defaults = NATIVE_DISCOVERY_ROOTS.map((parts) =>
|
|
36219
|
-
defaults.push(
|
|
36369
|
+
const home = resolve20(options.homeDir ?? homedir3());
|
|
36370
|
+
const defaults = NATIVE_DISCOVERY_ROOTS.map((parts) => join29(home, ...parts));
|
|
36371
|
+
defaults.push(join29(home, ".codex/plugins/cache"), join29(home, ".claude/plugins/cache"), join29(home, ".claude/plugins/synced"), join29(home, ".gemini/extensions"));
|
|
36220
36372
|
for (const root of defaults) {
|
|
36221
|
-
if (candidates.some((candidate) => contains(
|
|
36373
|
+
if (candidates.some((candidate) => contains(resolve20(root), candidate) || contains(physicalPath(root), candidate)))
|
|
36222
36374
|
native ??= root;
|
|
36223
36375
|
}
|
|
36224
36376
|
if (native) {
|
|
36225
36377
|
throw new Error(`Refusing portable Skills authoring below native discovery root '${native}': ${lexical}. Set HASNA_SKILLS_DIR to a private authoring corpus outside native roots.`);
|
|
36226
36378
|
}
|
|
36227
36379
|
for (const root of configuredRoots(home, options.homeDir !== undefined)) {
|
|
36228
|
-
if (candidates.some((candidate) => contains(
|
|
36380
|
+
if (candidates.some((candidate) => contains(resolve20(root), candidate) || contains(physicalPath(root), candidate))) {
|
|
36229
36381
|
throw new Error(`Refusing portable Skills authoring below configured native discovery root: ${lexical}`);
|
|
36230
36382
|
}
|
|
36231
36383
|
}
|
|
@@ -36243,7 +36395,7 @@ var init_authoring_path = __esm(() => {
|
|
|
36243
36395
|
// src/lib/portable-skills.ts
|
|
36244
36396
|
import {
|
|
36245
36397
|
existsSync as existsSync12,
|
|
36246
|
-
mkdirSync as
|
|
36398
|
+
mkdirSync as mkdirSync8,
|
|
36247
36399
|
mkdtempSync,
|
|
36248
36400
|
readdirSync as readdirSync8,
|
|
36249
36401
|
realpathSync as realpathSync8,
|
|
@@ -36252,22 +36404,22 @@ import {
|
|
|
36252
36404
|
statSync as statSync8,
|
|
36253
36405
|
writeFileSync as writeFileSync6
|
|
36254
36406
|
} from "fs";
|
|
36255
|
-
import { basename as basename11, dirname as
|
|
36407
|
+
import { basename as basename11, dirname as dirname20, isAbsolute as isAbsolute19, join as join30, normalize as normalize4, relative as relative6, resolve as resolve21, sep as sep10 } from "path";
|
|
36256
36408
|
function getPortableSkillsRoot(options = {}) {
|
|
36257
36409
|
return resolvePortableSkillsRoot(options, true);
|
|
36258
36410
|
}
|
|
36259
36411
|
function resolvePortableSkillsRoot(options, migrate) {
|
|
36260
36412
|
if (options.rootDir)
|
|
36261
36413
|
return options.rootDir;
|
|
36262
|
-
const appDir = options.homeDir ?
|
|
36263
|
-
const cache =
|
|
36414
|
+
const appDir = options.homeDir ? join30(options.homeDir, ".hasna", "skills") : migrate ? getDataDir() : getDataDirReadOnly();
|
|
36415
|
+
const cache = join30(appDir, SKILLS_CACHE_DIRNAME);
|
|
36264
36416
|
if (isOwnerLayoutMigrated(appDir) && safeIsDirectory(cache))
|
|
36265
36417
|
return cache;
|
|
36266
|
-
const installed =
|
|
36418
|
+
const installed = join30(appDir, INSTALLED_SKILLS_DIRNAME);
|
|
36267
36419
|
return installed;
|
|
36268
36420
|
}
|
|
36269
36421
|
function getPortableSkillPath(name, options = {}) {
|
|
36270
|
-
return
|
|
36422
|
+
return join30(getPortableSkillsRoot(options), normalizePortableSkillName(name));
|
|
36271
36423
|
}
|
|
36272
36424
|
function findPortableSkill(name, options = {}) {
|
|
36273
36425
|
let normalized;
|
|
@@ -36293,7 +36445,7 @@ function listPortableSkills(options = {}) {
|
|
|
36293
36445
|
for (const entry of readdirSync8(root).sort()) {
|
|
36294
36446
|
if (entry.startsWith("."))
|
|
36295
36447
|
continue;
|
|
36296
|
-
const path =
|
|
36448
|
+
const path = join30(root, entry);
|
|
36297
36449
|
if (!safeIsDirectory(path))
|
|
36298
36450
|
continue;
|
|
36299
36451
|
try {
|
|
@@ -36326,9 +36478,9 @@ function isOfficialSkillName(name) {
|
|
|
36326
36478
|
function scaffoldPortableSkill(name, options = {}) {
|
|
36327
36479
|
const skillName = normalizeNewPortableSkillName(name);
|
|
36328
36480
|
const readOnlyRoot = resolvePortableSkillsRoot(options, false);
|
|
36329
|
-
assertPortableAuthoringPath(
|
|
36481
|
+
assertPortableAuthoringPath(join30(readOnlyRoot, skillName), options);
|
|
36330
36482
|
const root = getPortableSkillsRoot(options);
|
|
36331
|
-
const skillPath =
|
|
36483
|
+
const skillPath = join30(root, skillName);
|
|
36332
36484
|
assertPortableAuthoringPath(skillPath, options);
|
|
36333
36485
|
if (existsSync12(skillPath)) {
|
|
36334
36486
|
if (!options.overwrite)
|
|
@@ -36347,27 +36499,27 @@ function scaffoldPortableSkill(name, options = {}) {
|
|
|
36347
36499
|
return { name: skillName, path: skillPath, manifest, created: true };
|
|
36348
36500
|
}
|
|
36349
36501
|
function physicalImportPath(path) {
|
|
36350
|
-
let ancestor =
|
|
36502
|
+
let ancestor = resolve21(path);
|
|
36351
36503
|
const suffix = [];
|
|
36352
36504
|
while (!existsSync12(ancestor)) {
|
|
36353
36505
|
suffix.unshift(basename11(ancestor));
|
|
36354
|
-
ancestor =
|
|
36506
|
+
ancestor = dirname20(ancestor);
|
|
36355
36507
|
}
|
|
36356
|
-
return
|
|
36508
|
+
return join30(realpathSync8(ancestor), ...suffix);
|
|
36357
36509
|
}
|
|
36358
36510
|
function assertDisjointImportPaths(source, destination) {
|
|
36359
36511
|
const sourcePath = realpathSync8(source);
|
|
36360
36512
|
const destinationPath = physicalImportPath(destination);
|
|
36361
36513
|
const contains2 = (parent, child2) => {
|
|
36362
36514
|
const path = relative6(parent, child2);
|
|
36363
|
-
return path === "" || !
|
|
36515
|
+
return path === "" || !isAbsolute19(path) && path !== ".." && !path.startsWith(`..${sep10}`);
|
|
36364
36516
|
};
|
|
36365
36517
|
if (contains2(sourcePath, destinationPath) || contains2(destinationPath, sourcePath)) {
|
|
36366
36518
|
throw new Error("Source and destination skill directories must not overlap");
|
|
36367
36519
|
}
|
|
36368
36520
|
}
|
|
36369
36521
|
function portPortableSkill(sourcePath, options = {}) {
|
|
36370
|
-
const absoluteSource =
|
|
36522
|
+
const absoluteSource = normalize4(sourcePath);
|
|
36371
36523
|
if (!existsSync12(absoluteSource) || !statSync8(absoluteSource).isDirectory()) {
|
|
36372
36524
|
throw new Error(`Skill source directory not found: ${sourcePath}`);
|
|
36373
36525
|
}
|
|
@@ -36379,11 +36531,11 @@ function portPortableSkill(sourcePath, options = {}) {
|
|
|
36379
36531
|
const via = explicitName ? `Name '${skillName}' matches a bundled official skill.` : `Inferred name '${skillName}'${sourceSlug && sourceSlug !== skillName ? ` (from source folder '${basename11(absoluteSource)}')` : ""} matches a bundled official skill.`;
|
|
36380
36532
|
throw new Error(`${via} Importing it would shadow the official '${skillName}'. ` + `Pass --name to choose a different name, or --allow-shadow to override deliberately.`);
|
|
36381
36533
|
}
|
|
36382
|
-
const readOnlyDestination =
|
|
36534
|
+
const readOnlyDestination = join30(resolvePortableSkillsRoot(options, false), skillName);
|
|
36383
36535
|
assertPortableAuthoringPath(readOnlyDestination, options);
|
|
36384
36536
|
assertDisjointImportPaths(absoluteSource, readOnlyDestination);
|
|
36385
36537
|
const root = getPortableSkillsRoot(options);
|
|
36386
|
-
const destination =
|
|
36538
|
+
const destination = join30(root, skillName);
|
|
36387
36539
|
assertPortableAuthoringPath(destination, options);
|
|
36388
36540
|
assertDisjointImportPaths(absoluteSource, destination);
|
|
36389
36541
|
if (existsSync12(destination)) {
|
|
@@ -36391,7 +36543,7 @@ function portPortableSkill(sourcePath, options = {}) {
|
|
|
36391
36543
|
throw new Error(`Skill '${skillName}' already exists at ${destination}`);
|
|
36392
36544
|
rmSync3(destination, { recursive: true, force: true });
|
|
36393
36545
|
}
|
|
36394
|
-
|
|
36546
|
+
mkdirSync8(dirname20(destination), { recursive: true });
|
|
36395
36547
|
copySkillDirectory(absoluteSource, destination);
|
|
36396
36548
|
const base = {
|
|
36397
36549
|
...inferred,
|
|
@@ -36415,8 +36567,8 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
36415
36567
|
const warnings = [...base.warnings];
|
|
36416
36568
|
let manifest;
|
|
36417
36569
|
if (existsSync12(skillPath)) {
|
|
36418
|
-
const skillJsonPath =
|
|
36419
|
-
const skillMdPath =
|
|
36570
|
+
const skillJsonPath = join30(skillPath, "skill.json");
|
|
36571
|
+
const skillMdPath = join30(skillPath, "SKILL.md");
|
|
36420
36572
|
if (!existsSync12(skillJsonPath) && !existsSync12(skillMdPath)) {
|
|
36421
36573
|
add3(issues, "portable.manifest_missing", "Missing portable manifest: expected SKILL.md frontmatter and/or skill.json");
|
|
36422
36574
|
}
|
|
@@ -36436,7 +36588,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
36436
36588
|
add3(issues, "portable.version_missing", "Portable manifest missing version");
|
|
36437
36589
|
}
|
|
36438
36590
|
const contractIssues = validatePortableManifestContract(manifest, {
|
|
36439
|
-
strict: existsSync12(
|
|
36591
|
+
strict: existsSync12(join30(skillPath, "skill.json")),
|
|
36440
36592
|
skillPath
|
|
36441
36593
|
});
|
|
36442
36594
|
for (const issue2 of contractIssues)
|
|
@@ -36476,7 +36628,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
36476
36628
|
add3(issues, "portable.command_entry_unsafe", `Command '${command.name}' entry '${command.entry}' must stay inside the skill directory`);
|
|
36477
36629
|
continue;
|
|
36478
36630
|
}
|
|
36479
|
-
const entryPath =
|
|
36631
|
+
const entryPath = join30(skillPath, command.entry);
|
|
36480
36632
|
if (!existsSync12(entryPath))
|
|
36481
36633
|
add3(issues, "portable.command_entry_missing", `Command '${command.name}' entry '${command.entry}' is missing`);
|
|
36482
36634
|
else if (statSync8(entryPath).isDirectory())
|
|
@@ -36487,7 +36639,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
36487
36639
|
} catch (error61) {
|
|
36488
36640
|
add3(issues, "portable.manifest_invalid", error61.message);
|
|
36489
36641
|
}
|
|
36490
|
-
if (manifest?.kind !== "instruction" && !existsSync12(
|
|
36642
|
+
if (manifest?.kind !== "instruction" && !existsSync12(join30(skillPath, "AGENTS.md"))) {
|
|
36491
36643
|
add3(issues, "portable.agents_missing", "Missing AGENTS.md with build-out instructions for coding agents");
|
|
36492
36644
|
}
|
|
36493
36645
|
}
|
|
@@ -36525,9 +36677,9 @@ function safeIsDirectory(path) {
|
|
|
36525
36677
|
}
|
|
36526
36678
|
}
|
|
36527
36679
|
function isSafeRelativePath2(value) {
|
|
36528
|
-
if (!value.trim() ||
|
|
36680
|
+
if (!value.trim() || isAbsolute19(value))
|
|
36529
36681
|
return false;
|
|
36530
|
-
const normalized =
|
|
36682
|
+
const normalized = normalize4(value).replace(/\\/g, "/");
|
|
36531
36683
|
return normalized !== ".." && !normalized.startsWith("../") && !normalized.includes("/../");
|
|
36532
36684
|
}
|
|
36533
36685
|
function add3(target, code, message) {
|
|
@@ -36715,7 +36867,7 @@ var init_search = __esm(() => {
|
|
|
36715
36867
|
|
|
36716
36868
|
// src/lib/registry.ts
|
|
36717
36869
|
import { existsSync as existsSync13, readFileSync as readFileSync17, readdirSync as readdirSync9 } from "fs";
|
|
36718
|
-
import { join as
|
|
36870
|
+
import { join as join31 } from "path";
|
|
36719
36871
|
function parseSkillMdFrontmatter(content) {
|
|
36720
36872
|
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
36721
36873
|
if (!match)
|
|
@@ -36756,7 +36908,7 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
36756
36908
|
for (const entry of entries) {
|
|
36757
36909
|
if (!entry.isDirectory())
|
|
36758
36910
|
continue;
|
|
36759
|
-
const skillMdPath =
|
|
36911
|
+
const skillMdPath = join31(dir, entry.name, "SKILL.md");
|
|
36760
36912
|
if (!existsSync13(skillMdPath))
|
|
36761
36913
|
continue;
|
|
36762
36914
|
let content;
|
|
@@ -36776,7 +36928,7 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
36776
36928
|
category: fm.category || "Development Tools",
|
|
36777
36929
|
tags: fm.tags || [],
|
|
36778
36930
|
...fm.kind ? { kind: fm.kind } : {},
|
|
36779
|
-
...isHostedMetadataSkillDir(
|
|
36931
|
+
...isHostedMetadataSkillDir(join31(dir, entry.name)) ? { serverOwned: true } : {},
|
|
36780
36932
|
source
|
|
36781
36933
|
});
|
|
36782
36934
|
}
|
|
@@ -36792,8 +36944,8 @@ function findExtensionSkillPath(name) {
|
|
|
36792
36944
|
for (const entry of entries) {
|
|
36793
36945
|
if (!entry.isDirectory())
|
|
36794
36946
|
continue;
|
|
36795
|
-
const skillDir =
|
|
36796
|
-
const skillMdPath =
|
|
36947
|
+
const skillDir = join31(config2.extensionsDir, entry.name);
|
|
36948
|
+
const skillMdPath = join31(skillDir, "SKILL.md");
|
|
36797
36949
|
if (!existsSync13(skillMdPath))
|
|
36798
36950
|
continue;
|
|
36799
36951
|
let content;
|
|
@@ -37210,7 +37362,7 @@ var init_v4 = __esm(() => {
|
|
|
37210
37362
|
});
|
|
37211
37363
|
|
|
37212
37364
|
// src/lib/canonical-json.ts
|
|
37213
|
-
import { createHash as
|
|
37365
|
+
import { createHash as createHash21 } from "crypto";
|
|
37214
37366
|
function canonicalJson2(value, maximumBytes = 2 * 1024 * 1024) {
|
|
37215
37367
|
return canonicalJsonAtDepth(value, maximumBytes, 64);
|
|
37216
37368
|
}
|
|
@@ -37254,7 +37406,7 @@ function canonicalJsonAtDepth(value, maximumBytes, maximumDepth) {
|
|
|
37254
37406
|
return visit3(value, 0);
|
|
37255
37407
|
}
|
|
37256
37408
|
function canonicalJsonSha256(value, maximumBytes) {
|
|
37257
|
-
return
|
|
37409
|
+
return createHash21("sha256").update(canonicalJson2(value, maximumBytes)).digest("hex");
|
|
37258
37410
|
}
|
|
37259
37411
|
var init_canonical_json = () => {};
|
|
37260
37412
|
|
|
@@ -37597,7 +37749,7 @@ function invitationFailure(value, status) {
|
|
|
37597
37749
|
function invitationInput(action, input2) {
|
|
37598
37750
|
if (!record4(input2))
|
|
37599
37751
|
return inputFailure();
|
|
37600
|
-
const
|
|
37752
|
+
const keys2 = {
|
|
37601
37753
|
list: ["after"],
|
|
37602
37754
|
get: ["invitationId"],
|
|
37603
37755
|
issue: ["email", "role", "idempotencyKey", "confirm"],
|
|
@@ -37605,7 +37757,7 @@ function invitationInput(action, input2) {
|
|
|
37605
37757
|
revoke: ["invitationId", "expectedGeneration", "confirm"],
|
|
37606
37758
|
accept: ["invitationId", "token", "confirm"]
|
|
37607
37759
|
};
|
|
37608
|
-
if (Object.keys(input2).some((key) => !
|
|
37760
|
+
if (Object.keys(input2).some((key) => !keys2[action].includes(key)) || action !== "list" && keys2[action].some((key) => !Object.hasOwn(input2, key)))
|
|
37609
37761
|
return inputFailure();
|
|
37610
37762
|
const value = { ...input2 };
|
|
37611
37763
|
if (action === "list") {
|
|
@@ -38004,14 +38156,14 @@ var init_remote_workspace_leave = __esm(() => {
|
|
|
38004
38156
|
});
|
|
38005
38157
|
|
|
38006
38158
|
// src/lib/auth-store.ts
|
|
38007
|
-
import { chmodSync, existsSync as existsSync14, mkdirSync as
|
|
38008
|
-
import { basename as basename12, dirname as
|
|
38159
|
+
import { chmodSync, existsSync as existsSync14, mkdirSync as mkdirSync9, readFileSync as readFileSync18, renameSync as renameSync4, statSync as statSync9, unlinkSync as unlinkSync4, writeFileSync as writeFileSync7 } from "fs";
|
|
38160
|
+
import { basename as basename12, dirname as dirname21, join as join32 } from "path";
|
|
38009
38161
|
function getAuthFilePath(env = process.env) {
|
|
38010
38162
|
return skillsCredentialFilePath(env);
|
|
38011
38163
|
}
|
|
38012
38164
|
function getIdentityFilePath(env = process.env) {
|
|
38013
38165
|
const file2 = skillsCredentialFilePath(env);
|
|
38014
|
-
return
|
|
38166
|
+
return join32(dirname21(file2), basename12(file2).replace(/^credentials/, "identity") + ".json");
|
|
38015
38167
|
}
|
|
38016
38168
|
function getApiUrl(action, env = process.env, options = {}) {
|
|
38017
38169
|
return requireSkillsApiOrigin(action, env, options);
|
|
@@ -38093,15 +38245,15 @@ function runQuoteReceipt(value) {
|
|
|
38093
38245
|
return value;
|
|
38094
38246
|
}
|
|
38095
38247
|
function parseRemoteRunQuote(value) {
|
|
38096
|
-
const quote3 =
|
|
38248
|
+
const quote3 = object6(value);
|
|
38097
38249
|
runQuoteReceipt(quote3.quoteReceipt);
|
|
38098
|
-
const pricing =
|
|
38250
|
+
const pricing = object6(quote3.pricing);
|
|
38099
38251
|
if (typeof quote3.skill !== "string" || !/^[a-z0-9][a-z0-9-]*$/.test(quote3.skill))
|
|
38100
38252
|
throw new Error("Invalid quoted skill");
|
|
38101
38253
|
const costCents = creditCount(pricing.costCredits ?? pricing.costCents);
|
|
38102
38254
|
if (pricing.costCredits !== undefined && pricing.costCents !== undefined && pricing.costCents !== costCents)
|
|
38103
38255
|
throw new Error("Inconsistent quoted credit count");
|
|
38104
|
-
if (quote3.availability &&
|
|
38256
|
+
if (quote3.availability && object6(quote3.availability).status !== "available")
|
|
38105
38257
|
throw new Error("This skill is unavailable for remote execution");
|
|
38106
38258
|
return { ...quote3, skill: quote3.skill, pricing: { ...pricing, costCredits: costCents, costCents, formattedCost: `${costCents} credits` } };
|
|
38107
38259
|
}
|
|
@@ -38110,7 +38262,7 @@ function parseRemoteCreditPacks(value) {
|
|
|
38110
38262
|
throw new Error("Invalid credit pack response");
|
|
38111
38263
|
const ids = new Set;
|
|
38112
38264
|
return value.map((value2) => {
|
|
38113
|
-
const row =
|
|
38265
|
+
const row = object6(value2);
|
|
38114
38266
|
const counts = [row.credits, row.creditsCents, row.amountCents].filter((value3) => value3 !== undefined).map(creditCount);
|
|
38115
38267
|
if (!counts.length || counts[0] === 0 || counts.some((count) => count !== counts[0]))
|
|
38116
38268
|
throw new Error("Inconsistent credit pack counts");
|
|
@@ -38125,7 +38277,7 @@ function parseRemoteCreditPacks(value) {
|
|
|
38125
38277
|
});
|
|
38126
38278
|
}
|
|
38127
38279
|
function parseRemoteBillingStatus(value) {
|
|
38128
|
-
const row =
|
|
38280
|
+
const row = object6(value);
|
|
38129
38281
|
const counts = [row.creditBalance, row.balanceCents].filter((value2) => value2 !== undefined).map(creditCount);
|
|
38130
38282
|
if (!counts.length || counts.some((count) => count !== counts[0]))
|
|
38131
38283
|
throw new Error("Inconsistent credit balance");
|
|
@@ -38137,7 +38289,7 @@ function parseRemoteBillingStatus(value) {
|
|
|
38137
38289
|
};
|
|
38138
38290
|
}
|
|
38139
38291
|
function parseRemoteCheckout(value) {
|
|
38140
|
-
const row =
|
|
38292
|
+
const row = object6(value);
|
|
38141
38293
|
if (typeof row.url !== "string")
|
|
38142
38294
|
throw new Error("Invalid checkout URL");
|
|
38143
38295
|
const url2 = new URL(row.url);
|
|
@@ -38145,7 +38297,7 @@ function parseRemoteCheckout(value) {
|
|
|
38145
38297
|
throw new Error("Invalid checkout URL");
|
|
38146
38298
|
return { url: row.url };
|
|
38147
38299
|
}
|
|
38148
|
-
function
|
|
38300
|
+
function object6(value) {
|
|
38149
38301
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
38150
38302
|
throw new Error("Invalid Skills server response");
|
|
38151
38303
|
return value;
|
|
@@ -38239,10 +38391,10 @@ async function readQuoteUnavailableCode(response) {
|
|
|
38239
38391
|
let timer;
|
|
38240
38392
|
let deadlineExceeded = false;
|
|
38241
38393
|
const expired = Symbol("quote body deadline");
|
|
38242
|
-
const deadline = new Promise((
|
|
38394
|
+
const deadline = new Promise((resolve22) => {
|
|
38243
38395
|
timer = setTimeout(() => {
|
|
38244
38396
|
deadlineExceeded = true;
|
|
38245
|
-
|
|
38397
|
+
resolve22(expired);
|
|
38246
38398
|
reader.cancel().catch(() => {});
|
|
38247
38399
|
}, 1500);
|
|
38248
38400
|
});
|
|
@@ -39385,8 +39537,8 @@ function invitationEmailIds(invitationId, challengeId) {
|
|
|
39385
39537
|
return { invitationId, challengeId };
|
|
39386
39538
|
}
|
|
39387
39539
|
function invitationEmailInput(action, input2) {
|
|
39388
|
-
const
|
|
39389
|
-
if (!record8(input2) || Object.keys(input2).length !==
|
|
39540
|
+
const keys2 = ["invitationId", "token", "challengeId", "confirm", ...action === "accept" ? ["code"] : []];
|
|
39541
|
+
if (!record8(input2) || Object.keys(input2).length !== keys2.length || keys2.some((key) => !Object.hasOwn(input2, key)))
|
|
39390
39542
|
throw new InvitationEmailInputError;
|
|
39391
39543
|
const value = { ...input2 };
|
|
39392
39544
|
const ids = invitationEmailIds(value.invitationId, value.challengeId);
|
|
@@ -39480,7 +39632,7 @@ var init_remote_invitation_recovery = __esm(() => {
|
|
|
39480
39632
|
});
|
|
39481
39633
|
|
|
39482
39634
|
// src/lib/remote-private-publications.ts
|
|
39483
|
-
import { createHash as
|
|
39635
|
+
import { createHash as createHash22 } from "crypto";
|
|
39484
39636
|
function checkedPublicationDeclaration(value) {
|
|
39485
39637
|
if (!exact(value, ["idempotencyKey", "version", "expectedCurrentVersionId", "manifestText", "archiveSha256", "archiveByteSize"]) || !publicationUuid(value.idempotencyKey) || !(value.expectedCurrentVersionId === null || publicationUuid(value.expectedCurrentVersionId)) || typeof value.version !== "string" || !value.version || value.version.length > 128 || /[\p{Cc}\p{Cs}]/u.test(value.version) || typeof value.manifestText !== "string" || Buffer.byteLength(value.manifestText) > 16384 || !hash3(value.archiveSha256) || !Number.isSafeInteger(value.archiveByteSize) || Number(value.archiveByteSize) < 1 || Number(value.archiveByteSize) > PRIVATE_PUBLICATION_MAX_BYTES)
|
|
39486
39638
|
return bad();
|
|
@@ -39725,12 +39877,12 @@ class RemotePrivatePublicationsClient {
|
|
|
39725
39877
|
previous = view;
|
|
39726
39878
|
if (!["queued", "verifying"].includes(view.state) || Date.now() >= until)
|
|
39727
39879
|
return view;
|
|
39728
|
-
await new Promise((
|
|
39880
|
+
await new Promise((resolve22) => {
|
|
39729
39881
|
const timer = setTimeout(done, Math.min(1000, until - Date.now()));
|
|
39730
39882
|
function done() {
|
|
39731
39883
|
clearTimeout(timer);
|
|
39732
39884
|
options.signal?.removeEventListener("abort", done);
|
|
39733
|
-
|
|
39885
|
+
resolve22();
|
|
39734
39886
|
}
|
|
39735
39887
|
options.signal?.addEventListener("abort", done, { once: true });
|
|
39736
39888
|
});
|
|
@@ -39741,7 +39893,7 @@ var PRIVATE_PUBLICATION_MAX_BYTES, failures2, PrivatePublicationError, bad = ()
|
|
|
39741
39893
|
throw new PrivatePublicationError("INVALID_PUBLICATION_INPUT", "Invalid publication input or recovery data.");
|
|
39742
39894
|
}, invalid4 = () => {
|
|
39743
39895
|
throw new PrivatePublicationError("INVALID_PUBLICATION_RESPONSE", "The server returned an invalid publication result.");
|
|
39744
|
-
}, 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), hash3 = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v), record9 = (v) => !!v && typeof v === "object" && !Array.isArray(v), exact = (v,
|
|
39896
|
+
}, publicationUuid = (v) => typeof v === "string" && /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(v), hash3 = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v), record9 = (v) => !!v && typeof v === "object" && !Array.isArray(v), exact = (v, keys2) => record9(v) && Object.keys(v).sort().join(",") === keys2.sort().join(","), date5 = (v) => typeof v === "string" && /^\d{4}-\d\d-\d\dT[0-9:.]+(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/.test(v) && Number.isFinite(Date.parse(v)), publicationSha256 = (bytes) => createHash22("sha256").update(bytes).digest("hex");
|
|
39745
39897
|
var init_remote_private_publications = __esm(() => {
|
|
39746
39898
|
init_fleet_credentials();
|
|
39747
39899
|
init_remote_workspace_selection();
|
|
@@ -40018,10 +40170,10 @@ var init_remote_auth = __esm(() => {
|
|
|
40018
40170
|
});
|
|
40019
40171
|
|
|
40020
40172
|
// src/lib/workspace-profile.ts
|
|
40021
|
-
import { constants as
|
|
40173
|
+
import { constants as constants14, closeSync as closeSync16, fstatSync as fstatSync16, lstatSync as lstatSync22, mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync2, openSync as openSync16, readFileSync as readFileSync19, renameSync as renameSync5, rmSync as rmSync4, writeFileSync as writeFileSync8 } from "fs";
|
|
40022
40174
|
function stat2(path) {
|
|
40023
40175
|
try {
|
|
40024
|
-
return
|
|
40176
|
+
return lstatSync22(path);
|
|
40025
40177
|
} catch (error61) {
|
|
40026
40178
|
if (error61.code === "ENOENT")
|
|
40027
40179
|
return null;
|
|
@@ -40031,14 +40183,14 @@ function stat2(path) {
|
|
|
40031
40183
|
function safeText(file2) {
|
|
40032
40184
|
if (stat2(file2) === null)
|
|
40033
40185
|
return null;
|
|
40034
|
-
const fd =
|
|
40186
|
+
const fd = openSync16(file2, constants14.O_RDONLY | constants14.O_NOFOLLOW | constants14.O_NONBLOCK);
|
|
40035
40187
|
try {
|
|
40036
|
-
const s =
|
|
40188
|
+
const s = fstatSync16(fd);
|
|
40037
40189
|
if (!s.isFile() || s.size > 65536 || ![256, 384].includes(s.mode & 4095) || process.getuid && s.uid !== process.getuid())
|
|
40038
40190
|
return fail("The selected profile must use bounded owner-only regular files.");
|
|
40039
40191
|
return readFileSync19(fd, "utf8");
|
|
40040
40192
|
} finally {
|
|
40041
|
-
|
|
40193
|
+
closeSync16(fd);
|
|
40042
40194
|
}
|
|
40043
40195
|
}
|
|
40044
40196
|
function checkIdentityMetadata(file2, identity3) {
|
|
@@ -40250,8 +40402,8 @@ var init_recurring_customer = __esm(() => {
|
|
|
40250
40402
|
});
|
|
40251
40403
|
|
|
40252
40404
|
// src/lib/recurring-recovery.ts
|
|
40253
|
-
import { constants as
|
|
40254
|
-
import { dirname as
|
|
40405
|
+
import { constants as constants15, closeSync as closeSync17, fsyncSync as fsyncSync5, fstatSync as fstatSync17, lstatSync as lstatSync23, mkdirSync as mkdirSync11, openSync as openSync17, readSync as readSync11, realpathSync as realpathSync9, renameSync as renameSync6, unlinkSync as unlinkSync5, writeFileSync as writeFileSync9 } from "fs";
|
|
40406
|
+
import { dirname as dirname22, isAbsolute as isAbsolute20, join as join33, resolve as resolve22 } from "path";
|
|
40255
40407
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
40256
40408
|
|
|
40257
40409
|
class RecoveryOwner {
|
|
@@ -40259,14 +40411,14 @@ class RecoveryOwner {
|
|
|
40259
40411
|
parents = [];
|
|
40260
40412
|
constructor(directory) {
|
|
40261
40413
|
this.directory = directory;
|
|
40262
|
-
if (!
|
|
40414
|
+
if (!isAbsolute20(directory) || resolve22(directory) !== directory || realpathSync9(directory) !== directory)
|
|
40263
40415
|
invalid5();
|
|
40264
|
-
for (let path = directory;; path =
|
|
40265
|
-
const stat3 =
|
|
40416
|
+
for (let path = directory;; path = dirname22(path)) {
|
|
40417
|
+
const stat3 = lstatSync23(path);
|
|
40266
40418
|
if (!stat3.isDirectory() || stat3.isSymbolicLink())
|
|
40267
40419
|
invalid5();
|
|
40268
40420
|
this.parents.push({ path, dev: stat3.dev, ino: stat3.ino });
|
|
40269
|
-
if (path ===
|
|
40421
|
+
if (path === dirname22(path))
|
|
40270
40422
|
break;
|
|
40271
40423
|
}
|
|
40272
40424
|
this.assert();
|
|
@@ -40275,59 +40427,59 @@ class RecoveryOwner {
|
|
|
40275
40427
|
if (realpathSync9(this.directory) !== this.directory)
|
|
40276
40428
|
invalid5();
|
|
40277
40429
|
for (const prior of this.parents) {
|
|
40278
|
-
const now =
|
|
40430
|
+
const now = lstatSync23(prior.path);
|
|
40279
40431
|
if (!now.isDirectory() || now.isSymbolicLink() || now.dev !== prior.dev || now.ino !== prior.ino)
|
|
40280
40432
|
invalid5();
|
|
40281
40433
|
}
|
|
40282
|
-
const own2 =
|
|
40434
|
+
const own2 = lstatSync23(this.directory);
|
|
40283
40435
|
if ((own2.mode & 511) !== 448 || (own2.mode & 3584) !== 0 || process.getuid && own2.uid !== process.getuid())
|
|
40284
40436
|
invalid5();
|
|
40285
40437
|
}
|
|
40286
40438
|
read(name) {
|
|
40287
40439
|
this.assert();
|
|
40288
|
-
const fd =
|
|
40440
|
+
const fd = openSync17(join33(this.directory, name), constants15.O_RDONLY | constants15.O_NOFOLLOW | constants15.O_NONBLOCK);
|
|
40289
40441
|
try {
|
|
40290
|
-
const before =
|
|
40442
|
+
const before = fstatSync17(fd);
|
|
40291
40443
|
if (!before.isFile() || before.nlink !== 1 || (before.mode & 4095) !== 384 || before.size < 1 || before.size > 8192 || process.getuid && before.uid !== process.getuid())
|
|
40292
40444
|
invalid5();
|
|
40293
40445
|
const bytes = Buffer.alloc(before.size + 1);
|
|
40294
40446
|
let size = 0;
|
|
40295
40447
|
while (size < bytes.length) {
|
|
40296
|
-
const n2 =
|
|
40448
|
+
const n2 = readSync11(fd, bytes, size, bytes.length - size, size);
|
|
40297
40449
|
if (!n2)
|
|
40298
40450
|
break;
|
|
40299
40451
|
size += n2;
|
|
40300
40452
|
}
|
|
40301
|
-
const after =
|
|
40453
|
+
const after = fstatSync17(fd), path = lstatSync23(join33(this.directory, name));
|
|
40302
40454
|
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())
|
|
40303
40455
|
invalid5();
|
|
40304
40456
|
this.assert();
|
|
40305
40457
|
return new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, size));
|
|
40306
40458
|
} finally {
|
|
40307
|
-
|
|
40459
|
+
closeSync17(fd);
|
|
40308
40460
|
}
|
|
40309
40461
|
}
|
|
40310
40462
|
write(name, value) {
|
|
40311
40463
|
this.assert();
|
|
40312
40464
|
const bytes = canonicalJson2(value, 8192) + `
|
|
40313
40465
|
`;
|
|
40314
|
-
const fd =
|
|
40466
|
+
const fd = openSync17(join33(this.directory, name), constants15.O_WRONLY | constants15.O_CREAT | constants15.O_EXCL | constants15.O_NOFOLLOW, 384);
|
|
40315
40467
|
try {
|
|
40316
40468
|
writeFileSync9(fd, bytes);
|
|
40317
|
-
|
|
40469
|
+
fsyncSync5(fd);
|
|
40318
40470
|
} finally {
|
|
40319
|
-
|
|
40471
|
+
closeSync17(fd);
|
|
40320
40472
|
}
|
|
40321
40473
|
this.assert();
|
|
40322
40474
|
this.sync();
|
|
40323
40475
|
}
|
|
40324
40476
|
sync() {
|
|
40325
40477
|
this.assert();
|
|
40326
|
-
const fd =
|
|
40478
|
+
const fd = openSync17(this.directory, constants15.O_RDONLY | constants15.O_NOFOLLOW);
|
|
40327
40479
|
try {
|
|
40328
|
-
|
|
40480
|
+
fsyncSync5(fd);
|
|
40329
40481
|
} finally {
|
|
40330
|
-
|
|
40482
|
+
closeSync17(fd);
|
|
40331
40483
|
}
|
|
40332
40484
|
}
|
|
40333
40485
|
saveState(state, expected) {
|
|
@@ -40338,30 +40490,30 @@ class RecoveryOwner {
|
|
|
40338
40490
|
if (this.read("state.json") !== expected)
|
|
40339
40491
|
invalid5();
|
|
40340
40492
|
this.assert();
|
|
40341
|
-
renameSync6(
|
|
40493
|
+
renameSync6(join33(this.directory, name), join33(this.directory, "state.json"));
|
|
40342
40494
|
this.sync();
|
|
40343
40495
|
}
|
|
40344
40496
|
async locked(action) {
|
|
40345
40497
|
this.assert();
|
|
40346
40498
|
let fd;
|
|
40347
40499
|
try {
|
|
40348
|
-
fd =
|
|
40500
|
+
fd = openSync17(join33(this.directory, "operation.lock"), constants15.O_WRONLY | constants15.O_CREAT | constants15.O_EXCL | constants15.O_NOFOLLOW, 384);
|
|
40349
40501
|
} catch {
|
|
40350
40502
|
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.");
|
|
40351
40503
|
}
|
|
40352
|
-
const owner2 =
|
|
40504
|
+
const owner2 = fstatSync17(fd);
|
|
40353
40505
|
try {
|
|
40354
40506
|
writeFileSync9(fd, JSON.stringify({ pid: process.pid }));
|
|
40355
|
-
|
|
40507
|
+
fsyncSync5(fd);
|
|
40356
40508
|
this.sync();
|
|
40357
40509
|
return await action();
|
|
40358
40510
|
} finally {
|
|
40359
|
-
|
|
40511
|
+
closeSync17(fd);
|
|
40360
40512
|
this.assert();
|
|
40361
|
-
const now =
|
|
40513
|
+
const now = lstatSync23(join33(this.directory, "operation.lock"));
|
|
40362
40514
|
if (owner2.dev !== now.dev || owner2.ino !== now.ino || !now.isFile() || now.isSymbolicLink())
|
|
40363
40515
|
invalid5();
|
|
40364
|
-
unlinkSync5(
|
|
40516
|
+
unlinkSync5(join33(this.directory, "operation.lock"));
|
|
40365
40517
|
this.sync();
|
|
40366
40518
|
}
|
|
40367
40519
|
}
|
|
@@ -40394,9 +40546,9 @@ function base(customer, organizationId) {
|
|
|
40394
40546
|
};
|
|
40395
40547
|
}
|
|
40396
40548
|
function create(directory, intent) {
|
|
40397
|
-
if (!
|
|
40549
|
+
if (!isAbsolute20(directory) || resolve22(directory) !== directory || realpathSync9(dirname22(directory)) !== dirname22(directory))
|
|
40398
40550
|
invalid5();
|
|
40399
|
-
|
|
40551
|
+
mkdirSync11(directory, { mode: 448 });
|
|
40400
40552
|
const owner2 = new RecoveryOwner(directory), checked = intentSchema.parse(intent), intentSha256 = canonicalJsonSha256(checked);
|
|
40401
40553
|
owner2.write(`intent-${intentSha256}.json`, checked);
|
|
40402
40554
|
owner2.write("state.json", { contractVersion: 1, intentSha256, phase: "prepared", consentId: null });
|
|
@@ -40519,7 +40671,7 @@ async function continueRecurringRecovery(customer, directory, options) {
|
|
|
40519
40671
|
throw error61;
|
|
40520
40672
|
}
|
|
40521
40673
|
}
|
|
40522
|
-
var uuid12,
|
|
40674
|
+
var uuid12, sha5, common, intentSchema, stateSchema, invalid5 = () => {
|
|
40523
40675
|
throw new RecurringCustomerError("RECURRING_RECOVERY_INVALID", "The original recovery directory or record is invalid or changed. Preserve it; do not create a replacement activation automatically.");
|
|
40524
40676
|
};
|
|
40525
40677
|
var init_recurring_recovery = __esm(() => {
|
|
@@ -40529,7 +40681,7 @@ var init_recurring_recovery = __esm(() => {
|
|
|
40529
40681
|
init_remote_recurring();
|
|
40530
40682
|
init_recurring_customer();
|
|
40531
40683
|
uuid12 = exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/);
|
|
40532
|
-
|
|
40684
|
+
sha5 = exports_external.string().regex(/^[a-f0-9]{64}$/);
|
|
40533
40685
|
common = exports_external.object({
|
|
40534
40686
|
contractVersion: exports_external.literal(1),
|
|
40535
40687
|
apiOrigin: exports_external.string().min(1).max(4096),
|
|
@@ -40542,7 +40694,7 @@ var init_recurring_recovery = __esm(() => {
|
|
|
40542
40694
|
common.extend({
|
|
40543
40695
|
operation: exports_external.literal("activate"),
|
|
40544
40696
|
draftId: uuid12,
|
|
40545
|
-
termsSha256:
|
|
40697
|
+
termsSha256: sha5,
|
|
40546
40698
|
approvalDeadline: exports_external.string().datetime(),
|
|
40547
40699
|
approval: recurringActivationSchema
|
|
40548
40700
|
}).strict(),
|
|
@@ -40550,14 +40702,14 @@ var init_recurring_recovery = __esm(() => {
|
|
|
40550
40702
|
]);
|
|
40551
40703
|
stateSchema = exports_external.object({
|
|
40552
40704
|
contractVersion: exports_external.literal(1),
|
|
40553
|
-
intentSha256:
|
|
40705
|
+
intentSha256: sha5,
|
|
40554
40706
|
phase: exports_external.enum(["prepared", "pending", "observed"]),
|
|
40555
40707
|
consentId: uuid12.nullable()
|
|
40556
40708
|
}).strict();
|
|
40557
40709
|
});
|
|
40558
40710
|
|
|
40559
40711
|
// src/lib/recurring-surface.ts
|
|
40560
|
-
import { isAbsolute as
|
|
40712
|
+
import { isAbsolute as isAbsolute21 } from "path";
|
|
40561
40713
|
function recurringMcpSchema(action) {
|
|
40562
40714
|
return action === "activate" ? recurringSurfaceSchemas.activate.extend({ code, confirm: exports_external.literal(true) }) : recurringSurfaceSchemas[action];
|
|
40563
40715
|
}
|
|
@@ -40662,7 +40814,7 @@ var init_recurring_surface = __esm(() => {
|
|
|
40662
40814
|
uuid13 = exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/);
|
|
40663
40815
|
context = { userId: uuid13.optional(), membershipId: uuid13.optional() };
|
|
40664
40816
|
page2 = { limit: exports_external.number().int().min(1).max(100).optional(), cursor: exports_external.string().min(1).max(2048).optional() };
|
|
40665
|
-
directory = exports_external.string().max(4096).refine(
|
|
40817
|
+
directory = exports_external.string().max(4096).refine(isAbsolute21, "Use an absolute recovery directory");
|
|
40666
40818
|
email4 = exports_external.string().trim().toLowerCase().email().max(254);
|
|
40667
40819
|
code = exports_external.string().regex(/^\d{6}$/);
|
|
40668
40820
|
recurringSurfaceSchemas = {
|
|
@@ -42491,21 +42643,21 @@ var init_credential_state = __esm(() => {
|
|
|
42491
42643
|
});
|
|
42492
42644
|
|
|
42493
42645
|
// src/lib/run-state.ts
|
|
42494
|
-
import { createHash as
|
|
42495
|
-
import { existsSync as existsSync15, mkdirSync as
|
|
42496
|
-
import { extname, join as
|
|
42646
|
+
import { createHash as createHash23, randomBytes } from "crypto";
|
|
42647
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync12, readFileSync as readFileSync20, readdirSync as readdirSync10, statSync as statSync10, writeFileSync as writeFileSync10 } from "fs";
|
|
42648
|
+
import { extname, join as join34, relative as relative7 } from "path";
|
|
42497
42649
|
function createSkillRun(params, targetDir = process.cwd()) {
|
|
42498
42650
|
const now = new Date;
|
|
42499
42651
|
const id = createRunId(now);
|
|
42500
42652
|
const day = now.toISOString().slice(0, 10);
|
|
42501
42653
|
const skillName = normalizeSkillName(params.skill);
|
|
42502
42654
|
const root = getProjectStateDir(targetDir);
|
|
42503
|
-
const runDir =
|
|
42504
|
-
const logsDir =
|
|
42505
|
-
const exportDir =
|
|
42506
|
-
|
|
42507
|
-
|
|
42508
|
-
|
|
42655
|
+
const runDir = join34(root, "runs", day, id);
|
|
42656
|
+
const logsDir = join34(runDir, "logs");
|
|
42657
|
+
const exportDir = join34(root, "exports", skillName, id);
|
|
42658
|
+
mkdirSync12(logsDir, { recursive: true });
|
|
42659
|
+
mkdirSync12(exportDir, { recursive: true });
|
|
42660
|
+
mkdirSync12(join34(root, "tmp"), { recursive: true });
|
|
42509
42661
|
const record10 = {
|
|
42510
42662
|
id,
|
|
42511
42663
|
skill: skillName,
|
|
@@ -42557,22 +42709,22 @@ function updateSkillRun(context2, patch) {
|
|
|
42557
42709
|
return context2.record;
|
|
42558
42710
|
}
|
|
42559
42711
|
function writeRunLogs(context2, stdout = "", stderr = "") {
|
|
42560
|
-
writeFileSync10(
|
|
42561
|
-
writeFileSync10(
|
|
42712
|
+
writeFileSync10(join34(context2.logsDir, "stdout.log"), stdout);
|
|
42713
|
+
writeFileSync10(join34(context2.logsDir, "stderr.log"), stderr);
|
|
42562
42714
|
}
|
|
42563
42715
|
function appendRunEvent(context2, event, data = {}) {
|
|
42564
42716
|
const line = JSON.stringify({ ts: new Date().toISOString(), event, ...data }) + `
|
|
42565
42717
|
`;
|
|
42566
|
-
const path =
|
|
42718
|
+
const path = join34(context2.runDir, "events.ndjson");
|
|
42567
42719
|
const previous = existsSync15(path) ? readFileSync20(path, "utf-8") : "";
|
|
42568
42720
|
writeFileSync10(path, previous + line);
|
|
42569
42721
|
}
|
|
42570
42722
|
function findSkillRun(runId, targetDir = process.cwd()) {
|
|
42571
|
-
const runsRoot =
|
|
42723
|
+
const runsRoot = join34(getProjectStateDir(targetDir), "runs");
|
|
42572
42724
|
if (!existsSync15(runsRoot))
|
|
42573
42725
|
return null;
|
|
42574
42726
|
for (const day of readdirSync10(runsRoot)) {
|
|
42575
|
-
const record10 = readRunRecord(
|
|
42727
|
+
const record10 = readRunRecord(join34(runsRoot, day, runId));
|
|
42576
42728
|
if (record10)
|
|
42577
42729
|
return record10;
|
|
42578
42730
|
}
|
|
@@ -42589,11 +42741,11 @@ function skillRunEnv(context2) {
|
|
|
42589
42741
|
};
|
|
42590
42742
|
}
|
|
42591
42743
|
function writeRunRecord(context2) {
|
|
42592
|
-
writeFileSync10(
|
|
42744
|
+
writeFileSync10(join34(context2.runDir, "run.json"), JSON.stringify(context2.record, null, 2) + `
|
|
42593
42745
|
`);
|
|
42594
42746
|
}
|
|
42595
42747
|
function writeArtifactsManifest(context2, artifacts) {
|
|
42596
|
-
writeFileSync10(
|
|
42748
|
+
writeFileSync10(join34(context2.runDir, "artifacts.json"), JSON.stringify({ runId: context2.record.id, artifacts }, null, 2) + `
|
|
42597
42749
|
`);
|
|
42598
42750
|
}
|
|
42599
42751
|
function collectRunArtifacts(context2) {
|
|
@@ -42606,14 +42758,14 @@ function collectRunArtifacts(context2) {
|
|
|
42606
42758
|
artifacts.push({
|
|
42607
42759
|
path: toProjectRelative(context2.targetDir, path),
|
|
42608
42760
|
mime: mimeForPath(path),
|
|
42609
|
-
sha256:
|
|
42761
|
+
sha256: createHash23("sha256").update(bytes).digest("hex"),
|
|
42610
42762
|
sizeBytes: stat3.size
|
|
42611
42763
|
});
|
|
42612
42764
|
}
|
|
42613
42765
|
return artifacts.sort((a, b) => a.path.localeCompare(b.path));
|
|
42614
42766
|
}
|
|
42615
42767
|
function readRunRecord(runDir) {
|
|
42616
|
-
const path =
|
|
42768
|
+
const path = join34(runDir, "run.json");
|
|
42617
42769
|
if (!existsSync15(path))
|
|
42618
42770
|
return null;
|
|
42619
42771
|
try {
|
|
@@ -42625,7 +42777,7 @@ function readRunRecord(runDir) {
|
|
|
42625
42777
|
function walkFiles(dir) {
|
|
42626
42778
|
const files = [];
|
|
42627
42779
|
for (const entry of readdirSync10(dir)) {
|
|
42628
|
-
const full =
|
|
42780
|
+
const full = join34(dir, entry);
|
|
42629
42781
|
if (statSync10(full).isDirectory())
|
|
42630
42782
|
files.push(...walkFiles(full));
|
|
42631
42783
|
else
|
|
@@ -42878,11 +43030,11 @@ var init_cloud_executions = __esm(() => {
|
|
|
42878
43030
|
// node_modules/@hasna/secrets/dist/sdk.js
|
|
42879
43031
|
import { isIP as isIP2 } from "net";
|
|
42880
43032
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
42881
|
-
import { closeSync as
|
|
43033
|
+
import { closeSync as closeSync18, fstatSync as fstatSync18, openSync as openSync18, readFileSync as readFileSync21 } from "fs";
|
|
42882
43034
|
import { O_NOFOLLOW as O_NOFOLLOW3, O_NONBLOCK as O_NONBLOCK3, O_RDONLY as O_RDONLY3 } from "constants";
|
|
42883
43035
|
import { createRequire as createRequire2 } from "module";
|
|
42884
43036
|
import { hostname as osHostname2 } from "os";
|
|
42885
|
-
import { isAbsolute as
|
|
43037
|
+
import { isAbsolute as isAbsolute22, join as join35 } from "path";
|
|
42886
43038
|
import { createRequire as createRequire22 } from "module";
|
|
42887
43039
|
function envToken2(name) {
|
|
42888
43040
|
return name.toUpperCase().replace(/-/g, "_");
|
|
@@ -42906,21 +43058,21 @@ function homeDir2(env) {
|
|
|
42906
43058
|
}
|
|
42907
43059
|
function absoluteOverride2(env, key) {
|
|
42908
43060
|
const value = env[key]?.trim();
|
|
42909
|
-
return value &&
|
|
43061
|
+
return value && isAbsolute22(value) ? value : null;
|
|
42910
43062
|
}
|
|
42911
43063
|
function hasnaHomeDir2(env) {
|
|
42912
43064
|
const override = absoluteOverride2(env, HASNA_HOME_ENV_KEY2);
|
|
42913
43065
|
if (override)
|
|
42914
43066
|
return override;
|
|
42915
43067
|
const home = homeDir2(env);
|
|
42916
|
-
return home ?
|
|
43068
|
+
return home ? join35(home, HASNA_HOME_DIR2) : null;
|
|
42917
43069
|
}
|
|
42918
43070
|
function appConfigDir2(name, env) {
|
|
42919
43071
|
const configRoot = absoluteOverride2(env, HASNA_CONFIG_HOME_ENV_KEY2);
|
|
42920
43072
|
if (configRoot)
|
|
42921
|
-
return
|
|
43073
|
+
return join35(configRoot, name);
|
|
42922
43074
|
const root = hasnaHomeDir2(env);
|
|
42923
|
-
return root ?
|
|
43075
|
+
return root ? join35(root, name, CONFIG_SUBDIR2) : null;
|
|
42924
43076
|
}
|
|
42925
43077
|
function credentialDiskSourceList2(name, env, profile = null) {
|
|
42926
43078
|
if (!SAFE_APP_SLUG2.test(name))
|
|
@@ -42929,7 +43081,7 @@ function credentialDiskSourceList2(name, env, profile = null) {
|
|
|
42929
43081
|
if (!directory2)
|
|
42930
43082
|
return [];
|
|
42931
43083
|
const file2 = profile ? `${CREDENTIALS_FILE2}-${profile}` : CREDENTIALS_FILE2;
|
|
42932
|
-
return [{ path:
|
|
43084
|
+
return [{ path: join35(directory2, file2), tier: "disk" }];
|
|
42933
43085
|
}
|
|
42934
43086
|
function credentialDiskSources2(name, env) {
|
|
42935
43087
|
return credentialDiskSourceList2(name, env, null).map((s) => s.path);
|
|
@@ -42983,7 +43135,7 @@ function readAppConfigFile2(path) {
|
|
|
42983
43135
|
};
|
|
42984
43136
|
let fd = -1;
|
|
42985
43137
|
try {
|
|
42986
|
-
fd =
|
|
43138
|
+
fd = openSync18(path, O_RDONLY3 | O_NOFOLLOW3 | O_NONBLOCK3);
|
|
42987
43139
|
} catch (error61) {
|
|
42988
43140
|
const code2 = error61.code;
|
|
42989
43141
|
if (code2 === "ENOENT" || code2 === "ENOTDIR")
|
|
@@ -42993,7 +43145,7 @@ function readAppConfigFile2(path) {
|
|
|
42993
43145
|
unsafe(`the path could not be opened (${code2 ?? "unknown error"})`);
|
|
42994
43146
|
}
|
|
42995
43147
|
try {
|
|
42996
|
-
const before =
|
|
43148
|
+
const before = fstatSync18(fd);
|
|
42997
43149
|
if (!before.isFile())
|
|
42998
43150
|
unsafe("the path is not a regular file");
|
|
42999
43151
|
if (!configFileModeAllowed2(before.mode)) {
|
|
@@ -43005,14 +43157,14 @@ function readAppConfigFile2(path) {
|
|
|
43005
43157
|
if (before.size > MAX_CREDENTIAL_FILE_BYTES2)
|
|
43006
43158
|
unsafe("the file exceeds the size limit");
|
|
43007
43159
|
const bytes = readFileSync21(fd);
|
|
43008
|
-
const after =
|
|
43160
|
+
const after = fstatSync18(fd);
|
|
43009
43161
|
if (!configFileReadsCoherent2(before, after)) {
|
|
43010
43162
|
unsafe("the file changed while being read");
|
|
43011
43163
|
}
|
|
43012
43164
|
return parseEnvFile2(bytes.toString("utf8"));
|
|
43013
43165
|
} finally {
|
|
43014
43166
|
if (fd !== -1)
|
|
43015
|
-
|
|
43167
|
+
closeSync18(fd);
|
|
43016
43168
|
}
|
|
43017
43169
|
}
|
|
43018
43170
|
function readCredentialFile2(path, apiKeyKeys) {
|
|
@@ -43030,8 +43182,8 @@ function readCredentialFile2(path, apiKeyKeys) {
|
|
|
43030
43182
|
}
|
|
43031
43183
|
return values[0] ?? null;
|
|
43032
43184
|
}
|
|
43033
|
-
function appConfigDiskValue2(name, env,
|
|
43034
|
-
const wanted =
|
|
43185
|
+
function appConfigDiskValue2(name, env, keys2) {
|
|
43186
|
+
const wanted = keys2.filter((key) => !CREDENTIAL_SHAPED_KEY2.test(key));
|
|
43035
43187
|
if (wanted.length === 0)
|
|
43036
43188
|
return null;
|
|
43037
43189
|
for (const path of credentialDiskSources2(name, env)) {
|
|
@@ -43138,8 +43290,8 @@ function validateAndSealResolvedCredential(appName, credential) {
|
|
|
43138
43290
|
...credential.pointerVaultKey !== undefined ? { pointerVaultKey: credential.pointerVaultKey } : {}
|
|
43139
43291
|
});
|
|
43140
43292
|
}
|
|
43141
|
-
function firstEnvValue2(env,
|
|
43142
|
-
for (const key of
|
|
43293
|
+
function firstEnvValue2(env, keys2) {
|
|
43294
|
+
for (const key of keys2) {
|
|
43143
43295
|
if (!Object.prototype.hasOwnProperty.call(env, key))
|
|
43144
43296
|
continue;
|
|
43145
43297
|
const value = env[key]?.trim();
|
|
@@ -43216,12 +43368,12 @@ function keychainConfigValue2(name, env, options = {}) {
|
|
|
43216
43368
|
return readKeychainItem2(name, env, "api-url", options);
|
|
43217
43369
|
}
|
|
43218
43370
|
function snapshotClientEnvironment2(name, env) {
|
|
43219
|
-
const
|
|
43371
|
+
const keys2 = clientTransportEnvKeys2(name);
|
|
43220
43372
|
const ambient = isAmbientEnvironment2(env);
|
|
43221
43373
|
const snapshot2 = Object.create(null);
|
|
43222
43374
|
for (const key of [
|
|
43223
|
-
...
|
|
43224
|
-
...
|
|
43375
|
+
...keys2.apiUrlKeys,
|
|
43376
|
+
...keys2.apiKeyKeys,
|
|
43225
43377
|
credentialOverrideEnvKey2(name),
|
|
43226
43378
|
credentialPointerEnvKey2(name),
|
|
43227
43379
|
CREDENTIAL_PROFILE_ENV_KEY2,
|
|
@@ -43548,8 +43700,8 @@ function toV1BaseUrl2(apiUrl) {
|
|
|
43548
43700
|
}
|
|
43549
43701
|
function resolveClientTransportSnapshot(name, env = process.env, options = {}) {
|
|
43550
43702
|
env = snapshotClientEnvironment2(name, env);
|
|
43551
|
-
const
|
|
43552
|
-
const definedUrlEntries =
|
|
43703
|
+
const keys2 = clientTransportEnvKeys2(name);
|
|
43704
|
+
const definedUrlEntries = keys2.apiUrlKeys.filter((key) => Object.prototype.hasOwnProperty.call(env, key) && env[key] !== undefined).map((key) => ({ key, raw: String(env[key]) }));
|
|
43553
43705
|
const blankUrl = definedUrlEntries.find((entry) => entry.raw.trim().length === 0);
|
|
43554
43706
|
if (blankUrl) {
|
|
43555
43707
|
throw new ClientTransportConfigurationError2(name, `${blankUrl.key} is set but blank; public clients require an explicit HTTPS API URL and never select local storage.`, [blankUrl.key]);
|
|
@@ -43564,7 +43716,7 @@ function resolveClientTransportSnapshot(name, env = process.env, options = {}) {
|
|
|
43564
43716
|
}
|
|
43565
43717
|
const envUrlHit = usableUrlEntries[0] ?? null;
|
|
43566
43718
|
const keychainUrlHit = keychainConfigValue2(name, env, options.credentials?.keychain);
|
|
43567
|
-
const diskConfigUrlHit = appConfigDiskValue2(name, env,
|
|
43719
|
+
const diskConfigUrlHit = appConfigDiskValue2(name, env, keys2.apiUrlKeys);
|
|
43568
43720
|
if (diskConfigUrlHit?.unusable) {
|
|
43569
43721
|
throw new ClientTransportConfigurationError2(name, `${diskConfigUrlHit.key} in ${diskConfigUrlHit.path} is declared but blank or malformed; public clients require a valid HTTPS service authority.`, [diskConfigUrlHit.path]);
|
|
43570
43722
|
}
|
|
@@ -43580,14 +43732,14 @@ function resolveClientTransportSnapshot(name, env = process.env, options = {}) {
|
|
|
43580
43732
|
}
|
|
43581
43733
|
const warnings = [];
|
|
43582
43734
|
if (configuredUrl && !envUrlHit) {
|
|
43583
|
-
warnings.push(`No ${
|
|
43735
|
+
warnings.push(`No ${keys2.apiUrlKeys[0]} in the environment; the server URL in ${configuredUrl.key} was used, so this client connects to the server. ` + `Keep that entry aligned with the intended service authority.`);
|
|
43584
43736
|
}
|
|
43585
43737
|
const credential = resolveCredential2(name, env, options.credentials);
|
|
43586
43738
|
if (!credential) {
|
|
43587
43739
|
const diskHint = credentialDiskSourcesForMessage(name, env);
|
|
43588
|
-
const lead = configuredUrl ? `${configuredUrl.key} selects the HTTP server for '${name}', but no API key could be resolved` : `${
|
|
43589
|
-
warnings.push(`${lead}; refusing to create an unauthenticated client \u2014 public clients never fall back to SQLite or another local store. ` + `Looked in the Keychain (macOS only), then for a credential file at ${diskHint}, then for ${
|
|
43590
|
-
throw new ClientTransportConfigurationError2(name, warnings.join(" "), [configuredUrl?.key ??
|
|
43740
|
+
const lead = configuredUrl ? `${configuredUrl.key} selects the HTTP server for '${name}', but no API key could be resolved` : `${keys2.apiUrlKeys[0]} is not set and no API key could be resolved for '${name}'; a credential is required before the default fleet gateway authority applies`;
|
|
43741
|
+
warnings.push(`${lead}; refusing to create an unauthenticated client \u2014 public clients never fall back to SQLite or another local store. ` + `Looked in the Keychain (macOS only), then for a credential file at ${diskHint}, then for ${keys2.apiKeyKeys[0]} in the environment.`);
|
|
43742
|
+
throw new ClientTransportConfigurationError2(name, warnings.join(" "), [configuredUrl?.key ?? keys2.apiUrlKeys[0]]);
|
|
43591
43743
|
}
|
|
43592
43744
|
if (credential.warning)
|
|
43593
43745
|
warnings.push(credential.warning);
|
|
@@ -43599,7 +43751,7 @@ function resolveClientTransportSnapshot(name, env = process.env, options = {}) {
|
|
|
43599
43751
|
urlHit = { key: DEFAULT_AUTHORITY_SOURCE, value: defaultFleetGatewayBaseUrl2(name) };
|
|
43600
43752
|
} catch (error61) {
|
|
43601
43753
|
const message = error61 instanceof Error ? error61.message : String(error61);
|
|
43602
|
-
throw new ClientTransportConfigurationError2(name, `No ${
|
|
43754
|
+
throw new ClientTransportConfigurationError2(name, `No ${keys2.apiUrlKeys[0]} is configured and the default fleet gateway authority cannot be composed for '${name}': ${message}`, [keys2.apiUrlKeys[0]]);
|
|
43603
43755
|
}
|
|
43604
43756
|
}
|
|
43605
43757
|
const apiUrlSource = urlHit.key;
|
|
@@ -44043,7 +44195,7 @@ function createSecretsClientFromEnv(env = process.env, overrides = {}) {
|
|
|
44043
44195
|
});
|
|
44044
44196
|
return new SecretsClient({ ...clientOverrides, baseUrl, apiKey });
|
|
44045
44197
|
}
|
|
44046
|
-
var __esm2 = (fn, res) => () => (fn && (res = fn(fn = 0)), res), CREDENTIAL_PROFILE_ENV_KEY2 = "HASNA_PROFILE", CredentialResolutionError2, CredentialFileUnsafeError2, HASNA_HOME_ENV_KEY2 = "HASNA_HOME", HASNA_CONFIG_HOME_ENV_KEY2 = "HASNA_CONFIG_HOME", KEYCHAIN_STATION_ENV_KEY2 = "HASNA_STATION", HASNA_HOME_DIR2 = ".hasna", CONFIG_SUBDIR2 = "config", CREDENTIALS_FILE2 = "credentials", KEYCHAIN_SECURITY_BIN2 = "/usr/bin/security", KEYCHAIN_SERVICE_PREFIX2 = "hasna.credentials", KEYCHAIN_ITEM_NOT_FOUND_STATUS2 = 44, KEYCHAIN_SPAWN_TIMEOUT_MS2 = 1e4, MAX_CREDENTIAL_FILE_BYTES2, SAFE_APP_SLUG2, SAFE_PROFILE2, ILLEGAL_IN_HEADER_VALUE2, VAULT_POINTER_SHAPE2, CREDENTIAL_SHAPED_KEY2, INSPECT_CUSTOM2, CREDENTIAL_SEAL2, CALLER_SUPPLIED_CREDENTIAL_PROVIDER_SOURCE = "caller-supplied CredentialProvider", AMBIENT_ENVIRONMENT2, SECRETS_PACKAGE_SPECIFIER, requireSecretsSdk2, DEFAULT_FLEET_GATEWAY_ORIGIN2 = "https://api.hasna.com", DEFAULT_AUTHORITY_SOURCE = "default", ASCII_CONTROL_PATTERN2, DNS_LABEL_PATTERN2, ClientTransportConfigurationError2, HasnaHttpError, DEFAULT_RETRY_STATUSES, IDEMPOTENT_METHODS2, AUTHORITY_OVERRIDE_HEADERS2, defaultSleep = (ms) => new Promise((
|
|
44198
|
+
var __esm2 = (fn, res) => () => (fn && (res = fn(fn = 0)), res), CREDENTIAL_PROFILE_ENV_KEY2 = "HASNA_PROFILE", CredentialResolutionError2, CredentialFileUnsafeError2, HASNA_HOME_ENV_KEY2 = "HASNA_HOME", HASNA_CONFIG_HOME_ENV_KEY2 = "HASNA_CONFIG_HOME", KEYCHAIN_STATION_ENV_KEY2 = "HASNA_STATION", HASNA_HOME_DIR2 = ".hasna", CONFIG_SUBDIR2 = "config", CREDENTIALS_FILE2 = "credentials", KEYCHAIN_SECURITY_BIN2 = "/usr/bin/security", KEYCHAIN_SERVICE_PREFIX2 = "hasna.credentials", KEYCHAIN_ITEM_NOT_FOUND_STATUS2 = 44, KEYCHAIN_SPAWN_TIMEOUT_MS2 = 1e4, MAX_CREDENTIAL_FILE_BYTES2, SAFE_APP_SLUG2, SAFE_PROFILE2, ILLEGAL_IN_HEADER_VALUE2, VAULT_POINTER_SHAPE2, CREDENTIAL_SHAPED_KEY2, INSPECT_CUSTOM2, CREDENTIAL_SEAL2, CALLER_SUPPLIED_CREDENTIAL_PROVIDER_SOURCE = "caller-supplied CredentialProvider", AMBIENT_ENVIRONMENT2, SECRETS_PACKAGE_SPECIFIER, requireSecretsSdk2, DEFAULT_FLEET_GATEWAY_ORIGIN2 = "https://api.hasna.com", DEFAULT_AUTHORITY_SOURCE = "default", ASCII_CONTROL_PATTERN2, DNS_LABEL_PATTERN2, ClientTransportConfigurationError2, HasnaHttpError, DEFAULT_RETRY_STATUSES, IDEMPOTENT_METHODS2, AUTHORITY_OVERRIDE_HEADERS2, defaultSleep = (ms) => new Promise((resolve23) => setTimeout(resolve23, ms)), init_transport2, MAX_CREDENTIAL_FILE_BYTES22, INSPECT_CUSTOM22, CREDENTIAL_SEAL22, AMBIENT_ENVIRONMENT22, SECRETS_PACKAGE_SPECIFIER2, requireSecretsSdk22, IDEMPOTENT_METHODS22, AUTHORITY_OVERRIDE_HEADERS22, init_storage, PATHS_RESOLVER_APP_SLUG_RE2, SQLITE_SIDECAR_FILES, LEGACY_SERVICE_FILES, init_data_dir, SecretsTestIsolationError, TEST_ENTRYPOINT_RE, init_test_isolation, init_client, ApiError;
|
|
44047
44199
|
var init_sdk = __esm(() => {
|
|
44048
44200
|
init_transport2 = __esm2(() => {
|
|
44049
44201
|
CredentialResolutionError2 = class CredentialResolutionError3 extends Error {
|
|
@@ -44178,14 +44330,14 @@ var init_sdk = __esm(() => {
|
|
|
44178
44330
|
});
|
|
44179
44331
|
|
|
44180
44332
|
// src/lib/execution-secrets.ts
|
|
44181
|
-
import { constants as
|
|
44333
|
+
import { constants as constants16, closeSync as closeSync19, fstatSync as fstatSync19, openSync as openSync19, readSync as readSync12, realpathSync as realpathSync10 } from "fs";
|
|
44182
44334
|
import { hostname as stationHostname } from "os";
|
|
44183
44335
|
function selectedSecretBindingsTemplate(scope, names, createClient = createSecretsClientFromEnv) {
|
|
44184
44336
|
let secretsAuthority;
|
|
44185
44337
|
try {
|
|
44186
44338
|
secretsAuthority = createClient().baseUrl;
|
|
44187
44339
|
} catch {
|
|
44188
|
-
return
|
|
44340
|
+
return refuse4("LOCAL_SECRET_UNAVAILABLE", "Configure the Secrets CLI authority and authentication before preparing execution bindings.");
|
|
44189
44341
|
}
|
|
44190
44342
|
const { authority, workspaceId, profileRevision, slug: slug2, version: version2, bundleDigest } = scope.selection;
|
|
44191
44343
|
return {
|
|
@@ -44196,14 +44348,14 @@ function selectedSecretBindingsTemplate(scope, names, createClient = createSecre
|
|
|
44196
44348
|
bindings: Object.fromEntries(names.map((name) => [name, ""]))
|
|
44197
44349
|
};
|
|
44198
44350
|
}
|
|
44199
|
-
function
|
|
44351
|
+
function refuse4(code2, message) {
|
|
44200
44352
|
throw new SkillSelectionError(code2, message);
|
|
44201
44353
|
}
|
|
44202
44354
|
function record10(value) {
|
|
44203
44355
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
44204
44356
|
}
|
|
44205
|
-
function exactKeys2(value,
|
|
44206
|
-
return Object.keys(value).length ===
|
|
44357
|
+
function exactKeys2(value, keys2) {
|
|
44358
|
+
return Object.keys(value).length === keys2.length && keys2.every((key) => Object.hasOwn(value, key));
|
|
44207
44359
|
}
|
|
44208
44360
|
function identifier3(value) {
|
|
44209
44361
|
return typeof value === "string" && value.length > 0 && value.length <= 2048 && !/[\x00-\x20\x7f]/.test(value);
|
|
@@ -44212,29 +44364,29 @@ function declaredSecretNames(value) {
|
|
|
44212
44364
|
if (value === undefined)
|
|
44213
44365
|
return [];
|
|
44214
44366
|
if (!Array.isArray(value) || value.length > 32 || value.some((name) => typeof name !== "string" || !/^[A-Z][A-Z0-9_]{0,127}$/.test(name)) || new Set(value).size !== value.length) {
|
|
44215
|
-
return
|
|
44367
|
+
return refuse4("INVALID_SKILL_MANIFEST", "Runtime environment references must be unique uppercase identifiers (at most 32).");
|
|
44216
44368
|
}
|
|
44217
44369
|
if (value.some((name) => /^(?:PATH|HOME|TMPDIR|TEMP|TMP|LANG|LC_ALL|TERM|SHELL|ENV|BASH_ENV|IFS|NODE_OPTIONS|NODE_PATH)$/.test(name) || /^(?:SKILLS_|BUN_|PYTHON|LD_|DYLD_)/.test(name))) {
|
|
44218
|
-
return
|
|
44370
|
+
return refuse4("INVALID_SKILL_MANIFEST", "Runtime environment references cannot override execution controls.");
|
|
44219
44371
|
}
|
|
44220
44372
|
return value;
|
|
44221
44373
|
}
|
|
44222
44374
|
function validateSelectedSecretBindings(value, scope, names) {
|
|
44223
44375
|
if (!record10(value) || !exactKeys2(value, ["schema", "selection", "consumer", "secretsAuthority", "bindings"]) || value.schema !== "hasna.skills-secret-bindings.v1" || !record10(value.selection) || !exactKeys2(value.selection, ["authority", "workspaceId", "profileId", "profileRevision", "slug", "version", "bundleDigest"]) || !record10(value.consumer) || !exactKeys2(value.consumer, ["stationId", "workspaceDirectory"]) || !record10(value.bindings)) {
|
|
44224
|
-
return
|
|
44376
|
+
return refuse4("INVALID_SECRET_BINDINGS", "Secret bindings do not match the hasna.skills-secret-bindings.v1 contract.");
|
|
44225
44377
|
}
|
|
44226
44378
|
for (const [key, expected] of Object.entries({ authority: scope.selection.authority, workspaceId: scope.selection.workspaceId, profileId: scope.profileId, profileRevision: scope.selection.profileRevision, slug: scope.selection.slug, version: scope.selection.version, bundleDigest: scope.selection.bundleDigest })) {
|
|
44227
44379
|
if (value.selection[key] !== expected)
|
|
44228
|
-
return
|
|
44380
|
+
return refuse4("SECRET_BINDING_SCOPE_MISMATCH", "Secret bindings do not match the exact selected authority, workspace, profile, revision, version and digest.");
|
|
44229
44381
|
}
|
|
44230
44382
|
let workspaceDirectory;
|
|
44231
44383
|
try {
|
|
44232
44384
|
workspaceDirectory = realpathSync10(scope.cwd);
|
|
44233
44385
|
} catch {
|
|
44234
|
-
return
|
|
44386
|
+
return refuse4("SECRET_BINDING_CONSUMER_MISMATCH", "The execution workspace cannot be resolved.");
|
|
44235
44387
|
}
|
|
44236
44388
|
if (value.consumer.stationId !== (process.env.HASNA_STATION || stationHostname()) || value.consumer.workspaceDirectory !== workspaceDirectory) {
|
|
44237
|
-
return
|
|
44389
|
+
return refuse4("SECRET_BINDING_CONSUMER_MISMATCH", "Secret bindings do not match this station and canonical workspace directory.");
|
|
44238
44390
|
}
|
|
44239
44391
|
try {
|
|
44240
44392
|
if (!identifier3(value.secretsAuthority))
|
|
@@ -44243,10 +44395,10 @@ function validateSelectedSecretBindings(value, scope, names) {
|
|
|
44243
44395
|
if (url2.protocol !== "https:" && !(url2.protocol === "http:" && ["127.0.0.1", "[::1]", "localhost"].includes(url2.hostname)) || url2.username || url2.password || url2.search || url2.hash || !url2.pathname.endsWith("/v1") || url2.href !== value.secretsAuthority)
|
|
44244
44396
|
throw new Error;
|
|
44245
44397
|
} catch {
|
|
44246
|
-
return
|
|
44398
|
+
return refuse4("INVALID_SECRET_BINDINGS", "Secret bindings require a canonical HTTPS Secrets /v1 authority (loopback HTTP is allowed).");
|
|
44247
44399
|
}
|
|
44248
44400
|
if (!exactKeys2(value.bindings, names) || Object.values(value.bindings).some((key) => !identifier3(key) || !/^[A-Za-z0-9][A-Za-z0-9._/-]*$/.test(key) || key.split("/").some((part) => !part || part === "." || part === ".."))) {
|
|
44249
|
-
return
|
|
44401
|
+
return refuse4("INVALID_SECRET_BINDINGS", "Bind every declared environment name exactly once to a vault key; undeclared bindings and values are refused.");
|
|
44250
44402
|
}
|
|
44251
44403
|
return structuredClone(value);
|
|
44252
44404
|
}
|
|
@@ -44257,10 +44409,10 @@ async function resolveSelectedSecrets(bindings, createClient = createSecretsClie
|
|
|
44257
44409
|
try {
|
|
44258
44410
|
client = createClient();
|
|
44259
44411
|
} catch {
|
|
44260
|
-
return
|
|
44412
|
+
return refuse4("LOCAL_SECRET_UNAVAILABLE", "The configured Secrets client could not authenticate. No ambient credential fallback was attempted.");
|
|
44261
44413
|
}
|
|
44262
44414
|
if (client.baseUrl !== bindings.secretsAuthority)
|
|
44263
|
-
return
|
|
44415
|
+
return refuse4("SECRET_BINDING_AUTHORITY_MISMATCH", "The configured Secrets authority differs from the reviewed binding. No secret was requested.");
|
|
44264
44416
|
const env = {};
|
|
44265
44417
|
const signal = AbortSignal.timeout(15000);
|
|
44266
44418
|
try {
|
|
@@ -44272,7 +44424,7 @@ async function resolveSelectedSecrets(bindings, createClient = createSecretsClie
|
|
|
44272
44424
|
}
|
|
44273
44425
|
return env;
|
|
44274
44426
|
} catch {
|
|
44275
|
-
return
|
|
44427
|
+
return refuse4("LOCAL_SECRET_UNAVAILABLE", "A declared secret could not be resolved, was invalid, or has expired. The skill was not started; no fallback was attempted.");
|
|
44276
44428
|
}
|
|
44277
44429
|
}
|
|
44278
44430
|
function redactExecutionSecrets(text3, env) {
|
|
@@ -44300,7 +44452,7 @@ function grantIdentifier(v) {
|
|
|
44300
44452
|
function grantRecord(v) {
|
|
44301
44453
|
return !!v && typeof v === "object" && !Array.isArray(v);
|
|
44302
44454
|
}
|
|
44303
|
-
function
|
|
44455
|
+
function keys2(v, required2, optional2 = []) {
|
|
44304
44456
|
return required2.every((k) => Object.hasOwn(v, k)) && Object.keys(v).every((k) => required2.includes(k) || optional2.includes(k));
|
|
44305
44457
|
}
|
|
44306
44458
|
function invalid6() {
|
|
@@ -44328,10 +44480,10 @@ function grantWorkspace(v) {
|
|
|
44328
44480
|
return flavor.isAbsolute(v) && flavor.normalize(v) === v;
|
|
44329
44481
|
}
|
|
44330
44482
|
function selection(v) {
|
|
44331
|
-
return grantRecord(v) &&
|
|
44483
|
+
return grantRecord(v) && keys2(v, ["slug", "version", "bundleDigest"]) && grantIdentifier(v.slug) && isValidSkillVersion(v.version) && typeof v.bundleDigest === "string" && /^sha256:[a-f0-9]{64}$/.test(v.bundleDigest);
|
|
44332
44484
|
}
|
|
44333
44485
|
function validateExecutionGrantRequest(value) {
|
|
44334
|
-
if (!grantRecord(value) || !
|
|
44486
|
+
if (!grantRecord(value) || !keys2(value, ["selection", "consumer"]) || !grantRecord(value.selection) || !keys2(value.selection, [
|
|
44335
44487
|
"authority",
|
|
44336
44488
|
"workspaceId",
|
|
44337
44489
|
"profileId",
|
|
@@ -44339,7 +44491,7 @@ function validateExecutionGrantRequest(value) {
|
|
|
44339
44491
|
"slug",
|
|
44340
44492
|
"version",
|
|
44341
44493
|
"bundleDigest"
|
|
44342
|
-
]) || !grantRecord(value.consumer) || !
|
|
44494
|
+
]) || !grantRecord(value.consumer) || !keys2(value.consumer, ["stationId", "workspaceDirectory"]))
|
|
44343
44495
|
invalid6();
|
|
44344
44496
|
const { selection: s, consumer: c } = value;
|
|
44345
44497
|
if (!selection({
|
|
@@ -44420,10 +44572,10 @@ __export(exports_selected_run, {
|
|
|
44420
44572
|
prepareSelectedSecretBindings: () => prepareSelectedSecretBindings,
|
|
44421
44573
|
executeSelectedLocal: () => executeSelectedLocal
|
|
44422
44574
|
});
|
|
44423
|
-
import { createHash as
|
|
44575
|
+
import { createHash as createHash24 } from "crypto";
|
|
44424
44576
|
import { spawn as spawn2 } from "child_process";
|
|
44425
|
-
import { mkdirSync as
|
|
44426
|
-
import { dirname as
|
|
44577
|
+
import { mkdirSync as mkdirSync13, mkdtempSync as mkdtempSync3, writeFileSync as writeFileSync11, realpathSync as realpathSync11 } from "fs";
|
|
44578
|
+
import { dirname as dirname23, join as join36, resolve as resolve23 } from "path";
|
|
44427
44579
|
import { tmpdir, hostname as stationHostname2 } from "os";
|
|
44428
44580
|
async function resolveSelectedRun(spec, profileId, options = {}) {
|
|
44429
44581
|
const context2 = await resolveSelectionContext(profileId, options);
|
|
@@ -44503,7 +44655,7 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
44503
44655
|
throw new SkillSelectionError("INVALID_SECRET_BINDINGS", "Explicit environment values must be bounded strings without NUL bytes.");
|
|
44504
44656
|
secretEnv[name] = value;
|
|
44505
44657
|
}
|
|
44506
|
-
const runDirectory = mkdtempSync3(
|
|
44658
|
+
const runDirectory = mkdtempSync3(join36(tmpdir(), "skills-execution-"));
|
|
44507
44659
|
const paths = new SkillEntryPaths;
|
|
44508
44660
|
for (const entry of entries) {
|
|
44509
44661
|
paths.add(entry.path, 100, () => {
|
|
@@ -44511,12 +44663,12 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
44511
44663
|
}, () => {
|
|
44512
44664
|
throw new SkillSelectionError("INVALID_BUNDLE_PATH", "The execution bundle path exceeds its limit.");
|
|
44513
44665
|
});
|
|
44514
|
-
const destination =
|
|
44515
|
-
|
|
44666
|
+
const destination = join36(runDirectory, entry.path);
|
|
44667
|
+
mkdirSync13(dirname23(destination), { recursive: true, mode: 448 });
|
|
44516
44668
|
writeFileSync11(destination, entry.bytes, { flag: "wx", mode: entry.mode & 511 });
|
|
44517
44669
|
}
|
|
44518
44670
|
env.SKILLS_INPUT_JSON = input2;
|
|
44519
|
-
env.SKILLS_WORKSPACE_DIR =
|
|
44671
|
+
env.SKILLS_WORKSPACE_DIR = resolve23(options.cwd ?? process.cwd());
|
|
44520
44672
|
env.SKILLS_RUN_DIR = runDirectory;
|
|
44521
44673
|
if (runtime.version) {
|
|
44522
44674
|
const version2 = await subprocess([executable, ...runtimeName === "bun" ? ["--no-env-file"] : [], "--version"], runDirectory, env, "", Math.min(timeoutMs, 5000));
|
|
@@ -44539,20 +44691,20 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
44539
44691
|
}
|
|
44540
44692
|
if (bindings)
|
|
44541
44693
|
secretEnv = await resolveSelectedSecrets(bindings, options.createSecretsClient);
|
|
44542
|
-
const result = await subprocess([executable, ...runtimeName === "bun" ? ["--no-env-file"] : [],
|
|
44694
|
+
const result = await subprocess([executable, ...runtimeName === "bun" ? ["--no-env-file"] : [], join36(runDirectory, declaredEntry), ...args], runDirectory, { ...env, ...secretEnv }, input2, timeoutMs);
|
|
44543
44695
|
result.stdout = redactExecutionSecrets(result.stdout, secretEnv);
|
|
44544
44696
|
result.stderr = redactExecutionSecrets(result.stderr, secretEnv);
|
|
44545
44697
|
const receipt = {
|
|
44546
44698
|
selection: selection2,
|
|
44547
44699
|
target: "local",
|
|
44548
44700
|
runtime: runtimeName,
|
|
44549
|
-
inputDigest: `sha256:${
|
|
44701
|
+
inputDigest: `sha256:${createHash24("sha256").update(input2).digest("hex")}`,
|
|
44550
44702
|
runDirectory,
|
|
44551
44703
|
...executionGrant ? { executionGrant } : {},
|
|
44552
44704
|
...bindings ? { secretBinding: { schema: bindings.schema, selection: bindings.selection, consumer: bindings.consumer, secretsAuthority: bindings.secretsAuthority, bindings: bindings.bindings } } : {},
|
|
44553
44705
|
...result
|
|
44554
44706
|
};
|
|
44555
|
-
writeFileSync11(
|
|
44707
|
+
writeFileSync11(join36(runDirectory, ".execution-receipt.json"), JSON.stringify({ ...receipt, stdout: undefined, stderr: undefined }), { mode: 384 });
|
|
44556
44708
|
return receipt;
|
|
44557
44709
|
}
|
|
44558
44710
|
async function subprocess(command, cwd, env, input2, timeoutMs) {
|
|
@@ -44742,7 +44894,7 @@ var init_blog_article = __esm(() => {
|
|
|
44742
44894
|
|
|
44743
44895
|
// src/mcp/operation-tools.ts
|
|
44744
44896
|
import { existsSync as existsSync16, readdirSync as readdirSync11, statSync as statSync11 } from "fs";
|
|
44745
|
-
import { join as
|
|
44897
|
+
import { join as join37 } from "path";
|
|
44746
44898
|
function registerOperationTools(server) {
|
|
44747
44899
|
server.registerTool("cloud_skill_eligibility", {
|
|
44748
44900
|
title: "Cloud Skill Eligibility",
|
|
@@ -45219,7 +45371,7 @@ function registerOperationTools(server) {
|
|
|
45219
45371
|
if (exists) {
|
|
45220
45372
|
try {
|
|
45221
45373
|
skillCount = readdirSync11(agentSkillsPath).filter((f) => {
|
|
45222
|
-
const full =
|
|
45374
|
+
const full = join37(agentSkillsPath, f);
|
|
45223
45375
|
return !f.startsWith(".") && statSync11(full).isDirectory();
|
|
45224
45376
|
}).length;
|
|
45225
45377
|
} catch {}
|
|
@@ -45286,17 +45438,17 @@ var init_operation_tools = __esm(() => {
|
|
|
45286
45438
|
});
|
|
45287
45439
|
|
|
45288
45440
|
// src/lib/feedback.ts
|
|
45289
|
-
import { appendFileSync, existsSync as existsSync17, mkdirSync as
|
|
45290
|
-
import { dirname as
|
|
45441
|
+
import { appendFileSync, existsSync as existsSync17, mkdirSync as mkdirSync14 } from "fs";
|
|
45442
|
+
import { dirname as dirname24, join as join38 } from "path";
|
|
45291
45443
|
import { Database } from "bun:sqlite";
|
|
45292
45444
|
function getFeedbackDbPath() {
|
|
45293
|
-
return
|
|
45445
|
+
return join38(getDataDir(), "skills.db");
|
|
45294
45446
|
}
|
|
45295
45447
|
function getFeedbackDb() {
|
|
45296
45448
|
const dbPath = getFeedbackDbPath();
|
|
45297
|
-
const dir =
|
|
45449
|
+
const dir = dirname24(dbPath);
|
|
45298
45450
|
if (!existsSync17(dir))
|
|
45299
|
-
|
|
45451
|
+
mkdirSync14(dir, { recursive: true });
|
|
45300
45452
|
const db = new Database(dbPath);
|
|
45301
45453
|
db.exec("PRAGMA journal_mode = WAL");
|
|
45302
45454
|
db.exec([
|
|
@@ -45322,10 +45474,10 @@ function saveFeedback(input2) {
|
|
|
45322
45474
|
throw new Error("Feedback message is required");
|
|
45323
45475
|
const category = input2.category ?? "general";
|
|
45324
45476
|
if (isApiMode()) {
|
|
45325
|
-
const path =
|
|
45326
|
-
const dir =
|
|
45477
|
+
const path = join38(getDataDir(), "feedback.jsonl");
|
|
45478
|
+
const dir = dirname24(path);
|
|
45327
45479
|
if (!existsSync17(dir))
|
|
45328
|
-
|
|
45480
|
+
mkdirSync14(dir, { recursive: true });
|
|
45329
45481
|
appendFileSync(path, JSON.stringify({ message, category, email: input2.email ?? null, agent: input2.agent ?? null, version: input2.version ?? null, createdAt: new Date().toISOString() }) + `
|
|
45330
45482
|
`);
|
|
45331
45483
|
return { saved: true, category, path };
|
|
@@ -45486,10 +45638,10 @@ var init_resource_meta_tools = __esm(() => {
|
|
|
45486
45638
|
});
|
|
45487
45639
|
|
|
45488
45640
|
// src/lib/scheduler.ts
|
|
45489
|
-
import { existsSync as existsSync18, readFileSync as readFileSync22, writeFileSync as writeFileSync12, mkdirSync as
|
|
45490
|
-
import { join as
|
|
45641
|
+
import { existsSync as existsSync18, readFileSync as readFileSync22, writeFileSync as writeFileSync12, mkdirSync as mkdirSync15 } from "fs";
|
|
45642
|
+
import { join as join39 } from "path";
|
|
45491
45643
|
function getSchedulesPath(targetDir = process.cwd()) {
|
|
45492
|
-
return
|
|
45644
|
+
return join39(targetDir, ".skills", "schedules.json");
|
|
45493
45645
|
}
|
|
45494
45646
|
function loadSchedules(targetDir = process.cwd()) {
|
|
45495
45647
|
const path = getSchedulesPath(targetDir);
|
|
@@ -45502,9 +45654,9 @@ function loadSchedules(targetDir = process.cwd()) {
|
|
|
45502
45654
|
}
|
|
45503
45655
|
function saveSchedules(data, targetDir = process.cwd()) {
|
|
45504
45656
|
const path = getSchedulesPath(targetDir);
|
|
45505
|
-
const dir =
|
|
45657
|
+
const dir = join39(targetDir, ".skills");
|
|
45506
45658
|
if (!existsSync18(dir))
|
|
45507
|
-
|
|
45659
|
+
mkdirSync15(dir, { recursive: true });
|
|
45508
45660
|
writeFileSync12(path, JSON.stringify(data, null, 2));
|
|
45509
45661
|
}
|
|
45510
45662
|
function validateCronField(expr, min, max, label) {
|
|
@@ -45774,16 +45926,16 @@ var init_schedule_tools = __esm(() => {
|
|
|
45774
45926
|
});
|
|
45775
45927
|
|
|
45776
45928
|
// src/lib/native-storage.ts
|
|
45777
|
-
import { createHash as
|
|
45929
|
+
import { createHash as createHash25, createHmac } from "crypto";
|
|
45778
45930
|
import {
|
|
45779
45931
|
existsSync as existsSync19,
|
|
45780
|
-
mkdirSync as
|
|
45932
|
+
mkdirSync as mkdirSync16,
|
|
45781
45933
|
readFileSync as readFileSync23,
|
|
45782
45934
|
readdirSync as readdirSync12,
|
|
45783
45935
|
statSync as statSync12,
|
|
45784
45936
|
writeFileSync as writeFileSync13
|
|
45785
45937
|
} from "fs";
|
|
45786
|
-
import { dirname as
|
|
45938
|
+
import { dirname as dirname25, join as join40, normalize as normalize5, relative as relative8, sep as sep11 } from "path";
|
|
45787
45939
|
function resolveSkillsNativeStorageConfig(env = process.env) {
|
|
45788
45940
|
assertNoRetiredModeEnvVars(env, {
|
|
45789
45941
|
app: SKILLS_ENV_NAMESPACE,
|
|
@@ -45824,7 +45976,7 @@ function getSkillsNativeStorageStatus(options = {}) {
|
|
|
45824
45976
|
local: {
|
|
45825
45977
|
dataDir: getDataDir(),
|
|
45826
45978
|
projectStateDir: getProjectStateDir(targetDir),
|
|
45827
|
-
feedbackDbPath:
|
|
45979
|
+
feedbackDbPath: join40(getDataDir(), "skills.db")
|
|
45828
45980
|
},
|
|
45829
45981
|
remote: {
|
|
45830
45982
|
databaseConfigured: Boolean(config2.databaseUrl),
|
|
@@ -45851,7 +46003,7 @@ function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
|
|
|
45851
46003
|
files.push({
|
|
45852
46004
|
path: relativePath,
|
|
45853
46005
|
sizeBytes: bytes.byteLength,
|
|
45854
|
-
sha256:
|
|
46006
|
+
sha256: createHash25("sha256").update(bytes).digest("hex"),
|
|
45855
46007
|
...options.includeFileContents ? { contentBase64: Buffer.from(bytes).toString("base64") } : {}
|
|
45856
46008
|
});
|
|
45857
46009
|
}
|
|
@@ -45905,7 +46057,7 @@ function parsePositiveInteger(value) {
|
|
|
45905
46057
|
function walkFiles2(dir) {
|
|
45906
46058
|
const files = [];
|
|
45907
46059
|
for (const entry of readdirSync12(dir)) {
|
|
45908
|
-
const full =
|
|
46060
|
+
const full = join40(dir, entry);
|
|
45909
46061
|
const stats = statSync12(full);
|
|
45910
46062
|
if (stats.isDirectory())
|
|
45911
46063
|
files.push(...walkFiles2(full));
|
|
@@ -46143,20 +46295,20 @@ var init_private_publication_customer = __esm(() => {
|
|
|
46143
46295
|
});
|
|
46144
46296
|
|
|
46145
46297
|
// src/lib/private-publication-recovery.ts
|
|
46146
|
-
import { constants as
|
|
46147
|
-
import { dirname as
|
|
46298
|
+
import { constants as constants17, closeSync as closeSync20, fsyncSync as fsyncSync6, fstatSync as fstatSync20, lstatSync as lstatSync24, mkdirSync as mkdirSync17, openSync as openSync20, readSync as readSync13, realpathSync as realpathSync12, renameSync as renameSync7, unlinkSync as unlinkSync6, writeFileSync as writeFileSync14 } from "fs";
|
|
46299
|
+
import { dirname as dirname26, isAbsolute as isAbsolute23, join as join41, resolve as resolve24 } from "path";
|
|
46148
46300
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
46149
46301
|
function safeDirectory(directory2) {
|
|
46150
|
-
if (!
|
|
46302
|
+
if (!isAbsolute23(directory2) || directory2 !== resolve24(directory2) || realpathSync12(directory2) !== directory2)
|
|
46151
46303
|
return fail2();
|
|
46152
|
-
for (let path = directory2;; path =
|
|
46153
|
-
const stat3 =
|
|
46304
|
+
for (let path = directory2;; path = dirname26(path)) {
|
|
46305
|
+
const stat3 = lstatSync24(path);
|
|
46154
46306
|
if (!stat3.isDirectory() || stat3.isSymbolicLink())
|
|
46155
46307
|
return fail2();
|
|
46156
|
-
if (path ===
|
|
46308
|
+
if (path === dirname26(path))
|
|
46157
46309
|
break;
|
|
46158
46310
|
}
|
|
46159
|
-
const own2 =
|
|
46311
|
+
const own2 = lstatSync24(directory2);
|
|
46160
46312
|
if ((own2.mode & 63) !== 0 || process.getuid && own2.uid !== process.getuid())
|
|
46161
46313
|
return fail2();
|
|
46162
46314
|
return { dev: own2.dev, ino: own2.ino };
|
|
@@ -46167,36 +46319,36 @@ function unchangedDirectory(directory2, identity3) {
|
|
|
46167
46319
|
return fail2();
|
|
46168
46320
|
}
|
|
46169
46321
|
function readOwned(directory2, name, max) {
|
|
46170
|
-
const identity3 = safeDirectory(directory2), file2 =
|
|
46171
|
-
const fd =
|
|
46322
|
+
const identity3 = safeDirectory(directory2), file2 = join41(directory2, name);
|
|
46323
|
+
const fd = openSync20(file2, constants17.O_RDONLY | constants17.O_NOFOLLOW);
|
|
46172
46324
|
try {
|
|
46173
|
-
const stat3 =
|
|
46325
|
+
const stat3 = fstatSync20(fd);
|
|
46174
46326
|
if (!stat3.isFile() || stat3.nlink !== 1 || stat3.size > max || stat3.size < 1 || (stat3.mode & 63) !== 0 || process.getuid && stat3.uid !== process.getuid())
|
|
46175
46327
|
return fail2();
|
|
46176
46328
|
const buffer = Buffer.alloc(Math.min(max, stat3.size) + 1);
|
|
46177
46329
|
let length = 0;
|
|
46178
46330
|
while (length < buffer.length) {
|
|
46179
|
-
const count =
|
|
46331
|
+
const count = readSync13(fd, buffer, length, buffer.length - length, length);
|
|
46180
46332
|
if (count === 0)
|
|
46181
46333
|
break;
|
|
46182
46334
|
length += count;
|
|
46183
46335
|
}
|
|
46184
|
-
const bytes = buffer.subarray(0, length), after =
|
|
46336
|
+
const bytes = buffer.subarray(0, length), after = fstatSync20(fd);
|
|
46185
46337
|
unchangedDirectory(directory2, identity3);
|
|
46186
46338
|
if (bytes.length !== stat3.size || stat3.size !== after.size || stat3.mtimeMs !== after.mtimeMs || stat3.ctimeMs !== after.ctimeMs)
|
|
46187
46339
|
return fail2();
|
|
46188
46340
|
return bytes;
|
|
46189
46341
|
} finally {
|
|
46190
|
-
|
|
46342
|
+
closeSync20(fd);
|
|
46191
46343
|
}
|
|
46192
46344
|
}
|
|
46193
46345
|
function writeOwned(directory2, name, bytes) {
|
|
46194
|
-
const fd =
|
|
46346
|
+
const fd = openSync20(join41(directory2, name), constants17.O_WRONLY | constants17.O_CREAT | constants17.O_EXCL | constants17.O_NOFOLLOW, 384);
|
|
46195
46347
|
try {
|
|
46196
46348
|
writeFileSync14(fd, bytes);
|
|
46197
|
-
|
|
46349
|
+
fsyncSync6(fd);
|
|
46198
46350
|
} finally {
|
|
46199
|
-
|
|
46351
|
+
closeSync20(fd);
|
|
46200
46352
|
}
|
|
46201
46353
|
}
|
|
46202
46354
|
function save(directory2, value) {
|
|
@@ -46204,12 +46356,12 @@ function save(directory2, value) {
|
|
|
46204
46356
|
writeOwned(directory2, temporary, JSON.stringify(value) + `
|
|
46205
46357
|
`);
|
|
46206
46358
|
unchangedDirectory(directory2, identity3);
|
|
46207
|
-
renameSync7(
|
|
46208
|
-
const fd =
|
|
46359
|
+
renameSync7(join41(directory2, temporary), join41(directory2, "receipt.json"));
|
|
46360
|
+
const fd = openSync20(directory2, constants17.O_RDONLY | constants17.O_NOFOLLOW);
|
|
46209
46361
|
try {
|
|
46210
|
-
|
|
46362
|
+
fsyncSync6(fd);
|
|
46211
46363
|
} finally {
|
|
46212
|
-
|
|
46364
|
+
closeSync20(fd);
|
|
46213
46365
|
}
|
|
46214
46366
|
}
|
|
46215
46367
|
function bind(client, receipt) {
|
|
@@ -46217,23 +46369,23 @@ function bind(client, receipt) {
|
|
|
46217
46369
|
throw new PrivatePublicationError("PUBLICATION_IDENTITY_CHANGED", "The fresh session does not match the recovery directory's server, account and membership.");
|
|
46218
46370
|
}
|
|
46219
46371
|
async function locked(directory2, action) {
|
|
46220
|
-
const identity3 = safeDirectory(directory2), file2 =
|
|
46372
|
+
const identity3 = safeDirectory(directory2), file2 = join41(directory2, "operation.lock");
|
|
46221
46373
|
let fd;
|
|
46222
46374
|
try {
|
|
46223
|
-
fd =
|
|
46375
|
+
fd = openSync20(file2, constants17.O_WRONLY | constants17.O_CREAT | constants17.O_EXCL | constants17.O_NOFOLLOW, 384);
|
|
46224
46376
|
} catch {
|
|
46225
46377
|
throw new PrivatePublicationError("PUBLICATION_RECOVERY_BUSY", "Another operation holds this recovery directory. If it crashed, confirm that process has stopped before explicitly removing operation.lock and resuming.");
|
|
46226
46378
|
}
|
|
46227
|
-
const lock =
|
|
46379
|
+
const lock = fstatSync20(fd);
|
|
46228
46380
|
try {
|
|
46229
46381
|
writeFileSync14(fd, JSON.stringify({ pid: process.pid }) + `
|
|
46230
46382
|
`);
|
|
46231
|
-
|
|
46383
|
+
fsyncSync6(fd);
|
|
46232
46384
|
return await action();
|
|
46233
46385
|
} finally {
|
|
46234
|
-
|
|
46386
|
+
closeSync20(fd);
|
|
46235
46387
|
unchangedDirectory(directory2, identity3);
|
|
46236
|
-
const now =
|
|
46388
|
+
const now = lstatSync24(file2);
|
|
46237
46389
|
if (now.dev !== lock.dev || now.ino !== lock.ino || !now.isFile() || now.isSymbolicLink())
|
|
46238
46390
|
fail2();
|
|
46239
46391
|
unlinkSync6(file2);
|
|
@@ -46285,15 +46437,15 @@ async function preparePrivatePublication(client, sourceDirectory, recoveryDirect
|
|
|
46285
46437
|
phase: "prepared",
|
|
46286
46438
|
intent: null
|
|
46287
46439
|
};
|
|
46288
|
-
if (!
|
|
46440
|
+
if (!isAbsolute23(recoveryDirectory) || resolve24(recoveryDirectory) !== recoveryDirectory || realpathSync12(dirname26(recoveryDirectory)) !== dirname26(recoveryDirectory))
|
|
46289
46441
|
return fail2();
|
|
46290
|
-
|
|
46442
|
+
mkdirSync17(recoveryDirectory, { mode: 448 });
|
|
46291
46443
|
safeDirectory(recoveryDirectory);
|
|
46292
|
-
const parent =
|
|
46444
|
+
const parent = openSync20(dirname26(recoveryDirectory), constants17.O_RDONLY | constants17.O_NOFOLLOW);
|
|
46293
46445
|
try {
|
|
46294
|
-
|
|
46446
|
+
fsyncSync6(parent);
|
|
46295
46447
|
} finally {
|
|
46296
|
-
|
|
46448
|
+
closeSync20(parent);
|
|
46297
46449
|
}
|
|
46298
46450
|
writeOwned(recoveryDirectory, "bundle.tgz", packed.bytes);
|
|
46299
46451
|
save(recoveryDirectory, receipt);
|
|
@@ -46386,10 +46538,10 @@ var init_private_publication_recovery = __esm(() => {
|
|
|
46386
46538
|
});
|
|
46387
46539
|
|
|
46388
46540
|
// src/mcp/private-publication-tools.ts
|
|
46389
|
-
import { isAbsolute as
|
|
46541
|
+
import { isAbsolute as isAbsolute24 } from "path";
|
|
46390
46542
|
function registerPrivatePublicationTools(server) {
|
|
46391
46543
|
const uuid9 = exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/);
|
|
46392
|
-
const directory2 = exports_external.string().max(4096).refine(
|
|
46544
|
+
const directory2 = exports_external.string().max(4096).refine(isAbsolute24, "Use an absolute local directory");
|
|
46393
46545
|
const verification2 = { email: exports_external.string().email().max(254), code: exports_external.string().regex(/^\d{6}$/), userId: uuid9, membershipId: uuid9, recoveryDirectory: directory2 };
|
|
46394
46546
|
const description = "Manage a private source publication using fresh workspace-bound verification and a host-local recovery directory. Publishing requires explicit UUID current-version comparison and upload consent. Resume reuses immutable saved bytes and intent; an uncertain PUT is finalized for server verification, never uploaded twice. Sessions and signed URLs are not returned or persisted. Private execution is unavailable. Host request history may contain the supplied verification code.";
|
|
46395
46547
|
const handler = (action) => async (value) => {
|
|
@@ -46822,19 +46974,19 @@ async function connectMcpForNode() {
|
|
|
46822
46974
|
return { server: server2, transport };
|
|
46823
46975
|
}
|
|
46824
46976
|
function readBody(req) {
|
|
46825
|
-
return new Promise((
|
|
46977
|
+
return new Promise((resolve25, reject) => {
|
|
46826
46978
|
const chunks = [];
|
|
46827
46979
|
req.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
|
|
46828
46980
|
req.on("end", () => {
|
|
46829
46981
|
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
46830
46982
|
if (!raw.trim()) {
|
|
46831
|
-
|
|
46983
|
+
resolve25(undefined);
|
|
46832
46984
|
return;
|
|
46833
46985
|
}
|
|
46834
46986
|
try {
|
|
46835
|
-
|
|
46987
|
+
resolve25(JSON.parse(raw));
|
|
46836
46988
|
} catch {
|
|
46837
|
-
|
|
46989
|
+
resolve25(undefined);
|
|
46838
46990
|
}
|
|
46839
46991
|
});
|
|
46840
46992
|
req.on("error", reject);
|
|
@@ -46876,9 +47028,9 @@ async function startSkillsMcpHttpServer(options = {}) {
|
|
|
46876
47028
|
}
|
|
46877
47029
|
}
|
|
46878
47030
|
});
|
|
46879
|
-
await new Promise((
|
|
47031
|
+
await new Promise((resolve25, reject) => {
|
|
46880
47032
|
httpServer.once("error", reject);
|
|
46881
|
-
httpServer.listen(port, hostname4, () =>
|
|
47033
|
+
httpServer.listen(port, hostname4, () => resolve25());
|
|
46882
47034
|
});
|
|
46883
47035
|
const address = httpServer.address();
|
|
46884
47036
|
const listenPort = typeof address === "object" && address ? address.port : port;
|