@hasna/skills 0.10.60 → 0.10.62
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 -7
- package/bin/index.js +855 -455
- package/bin/mcp.js +19044 -36576
- package/bin/migrate.js +10 -4
- package/bin/server.js +10 -4
- package/bin/worker.js +10 -4
- package/dist/cli/commands/runtime-copyfile.d.ts +1 -0
- package/dist/cli/commands/runtime-launcher.d.ts +19 -11
- package/dist/index.js +1638 -1054
- package/dist/lib/agent-adapters.d.ts +2 -2
- package/dist/lib/agent-install-selection.d.ts +11 -0
- package/dist/lib/agent-sumi.d.ts +29 -3
- package/dist/lib/kernel-lock-assets.d.ts +2 -0
- package/dist/native/kernel-lock-acl-darwin +0 -0
- package/dist/runtime-prerequisites.d.ts +9 -0
- package/dist/runtime-prerequisites.js +3089 -0
- package/dist/sdk/index.js +2042 -1458
- package/dist/server/launcher-environment-policy.d.ts +11 -0
- package/docs/runtime-activation.md +23 -0
- package/native/kernel-lock-acl-darwin +0 -0
- package/package.json +9 -3
package/bin/index.js
CHANGED
|
@@ -36888,7 +36888,7 @@ var package_default;
|
|
|
36888
36888
|
var init_package = __esm(() => {
|
|
36889
36889
|
package_default = {
|
|
36890
36890
|
name: "@hasna/skills",
|
|
36891
|
-
version: "0.10.
|
|
36891
|
+
version: "0.10.62",
|
|
36892
36892
|
description: "Skills library for AI coding agents",
|
|
36893
36893
|
type: "module",
|
|
36894
36894
|
bin: {
|
|
@@ -36925,9 +36925,11 @@ var init_package = __esm(() => {
|
|
|
36925
36925
|
"!dist/test-preload.d.ts",
|
|
36926
36926
|
"!dist/platform",
|
|
36927
36927
|
"bin/",
|
|
36928
|
+
"native/kernel-lock-acl-darwin",
|
|
36928
36929
|
"migrations/",
|
|
36929
36930
|
"docs/skill-standard.md",
|
|
36930
36931
|
"docs/plugin-admission.md",
|
|
36932
|
+
"docs/runtime-activation.md",
|
|
36931
36933
|
"schemas/",
|
|
36932
36934
|
"LICENSE",
|
|
36933
36935
|
"README.md",
|
|
@@ -36938,8 +36940,8 @@ var init_package = __esm(() => {
|
|
|
36938
36940
|
types: "./dist/index.d.ts",
|
|
36939
36941
|
scripts: {
|
|
36940
36942
|
clean: "rm -rf bin/ dist/",
|
|
36941
|
-
build: "bun run clean && bun build --external @hasna/contracts/kernel-lock ./src/cli/index.tsx --outdir ./bin --target bun && bun build --external @
|
|
36942
|
-
"build:js": "rm -rf dist && bun build
|
|
36943
|
+
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",
|
|
36944
|
+
"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",
|
|
36943
36945
|
test: "bun test --timeout 30000",
|
|
36944
36946
|
dev: "bun run ./src/cli/index.tsx",
|
|
36945
36947
|
"dev:watch": "bun --watch run ./src/cli/index.tsx",
|
|
@@ -37016,6 +37018,10 @@ var init_package = __esm(() => {
|
|
|
37016
37018
|
homepage: "https://github.com/hasna/skills/tree/main/apps/skills",
|
|
37017
37019
|
bugs: {
|
|
37018
37020
|
url: "https://github.com/hasna/skills/issues"
|
|
37021
|
+
},
|
|
37022
|
+
skillsRuntimePrerequisites: {
|
|
37023
|
+
version: 1,
|
|
37024
|
+
entry: "dist/runtime-prerequisites.js"
|
|
37019
37025
|
}
|
|
37020
37026
|
};
|
|
37021
37027
|
});
|
|
@@ -39899,7 +39905,7 @@ var init_agent_adapters = __esm(() => {
|
|
|
39899
39905
|
codex: { root: ".codex/skills", config: ".codex/hooks.json", events: ["UserPromptSubmit", "SessionStart", "SubagentStart"], promptContext: true },
|
|
39900
39906
|
gemini: { root: ".gemini/skills", config: ".gemini/settings.json", events: ["BeforeAgent", "SessionStart"], promptContext: true },
|
|
39901
39907
|
opencode: { root: ".config/opencode/skills", config: ".config/opencode/opencode.json", events: ["chat.message"], promptContext: true },
|
|
39902
|
-
sumi: { root:
|
|
39908
|
+
sumi: { root: null, config: null, events: ["prompt", "context"], promptContext: true },
|
|
39903
39909
|
hermes: { root: ".hermes/skills", config: ".hermes/config.yaml", events: ["pre_llm_call", "pre_tool_call"], promptContext: true, promptFailureMode: "open", toolFailureMode: "supervised-child-errors-block", requiresNativeTrust: true },
|
|
39904
39910
|
cursor: { root: ".cursor/skills", config: ".cursor/hooks.json", events: ["beforeSubmitPrompt", "sessionStart"], promptContext: false }
|
|
39905
39911
|
};
|
|
@@ -54091,37 +54097,136 @@ var init_agent_codex = __esm(() => {
|
|
|
54091
54097
|
});
|
|
54092
54098
|
|
|
54093
54099
|
// src/lib/agent-sumi.ts
|
|
54094
|
-
import {
|
|
54095
|
-
import {
|
|
54096
|
-
|
|
54100
|
+
import { spawnSync as spawnSync3 } from "child_process";
|
|
54101
|
+
import { accessSync as accessSync2, constants as constants11, existsSync as existsSync12, lstatSync as lstatSync18, realpathSync as realpathSync8, statSync as statSync9 } from "fs";
|
|
54102
|
+
import { delimiter as delimiter2, isAbsolute as isAbsolute15, join as join27, resolve as resolve15 } from "path";
|
|
54103
|
+
function recordWithKeys(value, keys2) {
|
|
54104
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === keys2.length && keys2.every((key) => Object.hasOwn(value, key));
|
|
54105
|
+
}
|
|
54106
|
+
function absolutePath3(value) {
|
|
54107
|
+
return typeof value === "string" && value.length > 0 && value.length <= 32768 && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute15(value) && resolve15(value) === value;
|
|
54108
|
+
}
|
|
54109
|
+
function absoluteInput(value) {
|
|
54110
|
+
return value.length > 0 && value.length <= 32768 && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute15(value);
|
|
54111
|
+
}
|
|
54112
|
+
function resolveSumiPathsCommand(pathValue) {
|
|
54113
|
+
if (!pathValue)
|
|
54114
|
+
return null;
|
|
54115
|
+
for (const directory of pathValue.split(delimiter2)) {
|
|
54116
|
+
if (!directory || /[\x00-\x1f\x7f]/.test(directory))
|
|
54117
|
+
continue;
|
|
54118
|
+
const candidate = resolve15(directory, "sumi-paths");
|
|
54119
|
+
try {
|
|
54120
|
+
accessSync2(candidate, constants11.X_OK);
|
|
54121
|
+
if (statSync9(candidate).isFile())
|
|
54122
|
+
return candidate;
|
|
54123
|
+
} catch {}
|
|
54124
|
+
}
|
|
54125
|
+
return null;
|
|
54126
|
+
}
|
|
54127
|
+
function validPathPlan(value, home, cwd2) {
|
|
54128
|
+
if (!recordWithKeys(value, ["schemaVersion", "kind", "home", "cwd", "roots", "legacyRoots", "configFiles", "skillRoots"]))
|
|
54129
|
+
return false;
|
|
54130
|
+
if (value.schemaVersion !== 1 || value.kind !== "sumi-paths" || value.home !== resolve15(home) || value.cwd !== resolve15(cwd2))
|
|
54131
|
+
return false;
|
|
54132
|
+
if (!recordWithKeys(value.roots, SUMI_PATH_KEYS) || !recordWithKeys(value.legacyRoots, SUMI_PATH_KEYS))
|
|
54133
|
+
return false;
|
|
54134
|
+
for (const key of SUMI_PATH_KEYS) {
|
|
54135
|
+
if (!absolutePath3(value.roots[key]))
|
|
54136
|
+
return false;
|
|
54137
|
+
if (value.legacyRoots[key] !== null && !absolutePath3(value.legacyRoots[key]))
|
|
54138
|
+
return false;
|
|
54139
|
+
}
|
|
54140
|
+
if (!recordWithKeys(value.configFiles, ["canonical", "legacy"]) || !recordWithKeys(value.skillRoots, ["canonical", "legacy"]))
|
|
54141
|
+
return false;
|
|
54142
|
+
if (!absolutePath3(value.configFiles.canonical) || !absolutePath3(value.skillRoots.canonical))
|
|
54143
|
+
return false;
|
|
54144
|
+
if (value.configFiles.legacy !== null && !absolutePath3(value.configFiles.legacy))
|
|
54145
|
+
return false;
|
|
54146
|
+
if (value.skillRoots.legacy !== null && !absolutePath3(value.skillRoots.legacy))
|
|
54147
|
+
return false;
|
|
54148
|
+
const configRoot = value.roots.config;
|
|
54149
|
+
const legacyConfigRoot = value.legacyRoots.config;
|
|
54150
|
+
if (typeof configRoot !== "string" || legacyConfigRoot !== null && typeof legacyConfigRoot !== "string")
|
|
54151
|
+
return false;
|
|
54152
|
+
if (value.configFiles.canonical !== join27(configRoot, "sumi.json") || value.skillRoots.canonical !== join27(configRoot, "skills"))
|
|
54153
|
+
return false;
|
|
54154
|
+
if (legacyConfigRoot === null)
|
|
54155
|
+
return value.configFiles.legacy === null && value.skillRoots.legacy === null;
|
|
54156
|
+
return value.configFiles.legacy === join27(legacyConfigRoot, "sumi.json") && value.skillRoots.legacy === join27(legacyConfigRoot, "skills");
|
|
54157
|
+
}
|
|
54158
|
+
function sumiPathPlan(home, cwd2 = process.cwd(), env3 = process.env) {
|
|
54097
54159
|
for (const key of ["SUMI_CONFIG", "SUMI_CONFIG_CONTENT"])
|
|
54098
54160
|
if (env3[key] !== undefined)
|
|
54099
|
-
throw new
|
|
54100
|
-
|
|
54101
|
-
|
|
54102
|
-
const
|
|
54103
|
-
const
|
|
54104
|
-
|
|
54105
|
-
|
|
54106
|
-
|
|
54107
|
-
|
|
54108
|
-
|
|
54109
|
-
|
|
54110
|
-
|
|
54161
|
+
throw new SumiPathResolverError("SUMI_PATH_CONFIG_UNSUPPORTED");
|
|
54162
|
+
if (!absoluteInput(home) || !absoluteInput(cwd2))
|
|
54163
|
+
throw new SumiPathResolverError("SUMI_PATH_INPUT_REFUSED");
|
|
54164
|
+
const runtimePath = process.env.PATH ?? "";
|
|
54165
|
+
const executable2 = resolveSumiPathsCommand(runtimePath);
|
|
54166
|
+
if (!executable2 || !isAbsolute15(executable2))
|
|
54167
|
+
throw new SumiPathResolverError("SUMI_PATH_RESOLVER_UNAVAILABLE");
|
|
54168
|
+
const childEnv = { PATH: runtimePath };
|
|
54169
|
+
for (const key of SUMI_PATH_SELECTORS)
|
|
54170
|
+
if (env3[key] !== undefined)
|
|
54171
|
+
childEnv[key] = env3[key];
|
|
54172
|
+
let child2;
|
|
54173
|
+
try {
|
|
54174
|
+
child2 = spawnSync3(executable2, ["--json", "--home", resolve15(home), "--cwd", resolve15(cwd2)], {
|
|
54175
|
+
cwd: resolve15(cwd2),
|
|
54176
|
+
env: childEnv,
|
|
54177
|
+
encoding: "buffer",
|
|
54178
|
+
timeout: 3000,
|
|
54179
|
+
maxBuffer: SUMI_PATH_OUTPUT_LIMIT,
|
|
54180
|
+
shell: false
|
|
54181
|
+
});
|
|
54182
|
+
} catch {
|
|
54183
|
+
throw new SumiPathResolverError("SUMI_PATH_RESOLVER_UNAVAILABLE");
|
|
54184
|
+
}
|
|
54185
|
+
const stdoutBytes = child2.stdout === null ? 0 : Buffer.byteLength(child2.stdout);
|
|
54186
|
+
const stderrBytes = child2.stderr === null ? 0 : Buffer.byteLength(child2.stderr);
|
|
54187
|
+
if (child2.error || child2.signal || !child2.stdout || stdoutBytes > SUMI_PATH_OUTPUT_LIMIT || stderrBytes > 0) {
|
|
54188
|
+
throw new SumiPathResolverError("SUMI_PATH_RESOLVER_UNAVAILABLE");
|
|
54189
|
+
}
|
|
54190
|
+
let result2;
|
|
54191
|
+
try {
|
|
54192
|
+
result2 = JSON.parse(child2.stdout.toString("utf8"));
|
|
54193
|
+
} catch {
|
|
54194
|
+
throw new SumiPathResolverError("SUMI_PATH_RESOLVER_INVALID_RESPONSE");
|
|
54195
|
+
}
|
|
54196
|
+
if (recordWithKeys(result2, ["schemaVersion", "kind", "code"]) && result2.schemaVersion === 1 && result2.kind === "sumi-paths-error" && (result2.code === "SUMI_PATH_INPUT_REFUSED" || result2.code === "SUMI_PATH_CONFIG_UNSUPPORTED") && child2.status === 2) {
|
|
54197
|
+
throw new SumiPathResolverError(result2.code);
|
|
54198
|
+
}
|
|
54199
|
+
if (child2.status !== 0 || !validPathPlan(result2, home, cwd2))
|
|
54200
|
+
throw new SumiPathResolverError("SUMI_PATH_RESOLVER_INVALID_RESPONSE");
|
|
54201
|
+
return result2;
|
|
54202
|
+
}
|
|
54203
|
+
function selectedConfigDirectory(plan) {
|
|
54204
|
+
const canonical7 = plan.roots.config, legacy = plan.legacyRoots.config;
|
|
54205
|
+
if (legacy === null)
|
|
54206
|
+
return existsSync12(canonical7) ? realpathSync8(canonical7) : canonical7;
|
|
54207
|
+
const canonicalStat = lstatSync18(canonical7, { throwIfNoEntry: false }), legacyStat = lstatSync18(legacy, { throwIfNoEntry: false });
|
|
54208
|
+
if (canonicalStat && legacyStat && realpathSync8(canonical7) !== realpathSync8(legacy))
|
|
54111
54209
|
throw new Error("Sumi config roots conflict; complete native home adoption before Skills integration");
|
|
54112
|
-
const
|
|
54113
|
-
if (!existsSync12(
|
|
54114
|
-
return
|
|
54115
|
-
const physical = realpathSync8(
|
|
54116
|
-
if ((
|
|
54210
|
+
const selected = canonicalStat ? canonical7 : legacyStat ? legacy : canonical7;
|
|
54211
|
+
if (!existsSync12(selected))
|
|
54212
|
+
return selected;
|
|
54213
|
+
const physical = realpathSync8(selected);
|
|
54214
|
+
if ((canonicalStat?.isSymbolicLink() || legacyStat?.isSymbolicLink()) && ![canonical7, legacy].includes(physical))
|
|
54117
54215
|
throw new Error("Sumi config alias must resolve to its canonical or legacy root");
|
|
54118
54216
|
return physical;
|
|
54119
54217
|
}
|
|
54120
|
-
function
|
|
54121
|
-
return
|
|
54218
|
+
function sumiConfigDirectory(home, env3 = process.env, cwd2 = process.cwd()) {
|
|
54219
|
+
return selectedConfigDirectory(sumiPathPlan(home, cwd2, env3));
|
|
54220
|
+
}
|
|
54221
|
+
function sumiSkillRoots(home, cwd2 = process.cwd(), env3 = process.env) {
|
|
54222
|
+
const plan = sumiPathPlan(home, cwd2, env3);
|
|
54223
|
+
return [join27(selectedConfigDirectory(plan), "skills")];
|
|
54224
|
+
}
|
|
54225
|
+
function sumiBridgeRoot(home, cwd2 = process.cwd(), env3 = process.env) {
|
|
54226
|
+
return sumiSkillRoots(home, cwd2, env3)[0];
|
|
54122
54227
|
}
|
|
54123
|
-
function sumiConfigPath(home) {
|
|
54124
|
-
return join27(sumiConfigDirectory(home), "sumi.json");
|
|
54228
|
+
function sumiConfigPath(home, cwd2 = process.cwd(), env3 = process.env) {
|
|
54229
|
+
return join27(sumiConfigDirectory(home, env3, cwd2), "sumi.json");
|
|
54125
54230
|
}
|
|
54126
54231
|
function renderSumiPlugin(command, profile) {
|
|
54127
54232
|
return renderSumiPluginVersion(command, profile, false);
|
|
@@ -54207,8 +54312,19 @@ export default {
|
|
|
54207
54312
|
};
|
|
54208
54313
|
`;
|
|
54209
54314
|
}
|
|
54210
|
-
var SUMI_SKILL_PERMISSIONS;
|
|
54315
|
+
var SUMI_PATH_SELECTORS, SUMI_PATH_KEYS, SUMI_PATH_OUTPUT_LIMIT, SumiPathResolverError, SUMI_SKILL_PERMISSIONS;
|
|
54211
54316
|
var init_agent_sumi = __esm(() => {
|
|
54317
|
+
SUMI_PATH_SELECTORS = ["SUMI_HOME", "SUMI_CONFIG_DIR", "XDG_DATA_HOME", "XDG_CACHE_HOME", "XDG_CONFIG_HOME", "XDG_STATE_HOME"];
|
|
54318
|
+
SUMI_PATH_KEYS = ["data", "cache", "config", "state"];
|
|
54319
|
+
SUMI_PATH_OUTPUT_LIMIT = 128 * 1024;
|
|
54320
|
+
SumiPathResolverError = class SumiPathResolverError extends Error {
|
|
54321
|
+
code;
|
|
54322
|
+
constructor(code) {
|
|
54323
|
+
super(`Sumi path discovery refused (${code})`);
|
|
54324
|
+
this.code = code;
|
|
54325
|
+
this.name = "SumiPathResolverError";
|
|
54326
|
+
}
|
|
54327
|
+
};
|
|
54212
54328
|
SUMI_SKILL_PERMISSIONS = [
|
|
54213
54329
|
{ action: "skill", resource: "*", effect: "deny" },
|
|
54214
54330
|
{ action: "skill", resource: "skills-cli", effect: "allow" }
|
|
@@ -54216,9 +54332,9 @@ var init_agent_sumi = __esm(() => {
|
|
|
54216
54332
|
});
|
|
54217
54333
|
|
|
54218
54334
|
// src/lib/codex-hook-trust-files.ts
|
|
54219
|
-
import { closeSync as closeSync10, constants as
|
|
54335
|
+
import { closeSync as closeSync10, constants as constants12, fstatSync as fstatSync10, fsyncSync as fsyncSync3, lstatSync as lstatSync19, openSync as openSync10, readlinkSync as readlinkSync5, readSync as readSync8, writeFileSync as writeFileSync5 } from "fs";
|
|
54220
54336
|
import { createHash as createHash18 } from "crypto";
|
|
54221
|
-
import { dirname as dirname15, isAbsolute as
|
|
54337
|
+
import { dirname as dirname15, isAbsolute as isAbsolute16, resolve as resolve16 } from "path";
|
|
54222
54338
|
function need6(value, code) {
|
|
54223
54339
|
if (!value)
|
|
54224
54340
|
throw new Error(`CODEX_HOOK_TRUST_${code}`);
|
|
@@ -54238,7 +54354,7 @@ function safeParents(file) {
|
|
|
54238
54354
|
function directAliasTarget(link2) {
|
|
54239
54355
|
const text2 = readlinkSync5(link2), parts = text2.split("/");
|
|
54240
54356
|
let first = 0;
|
|
54241
|
-
if (
|
|
54357
|
+
if (isAbsolute16(text2))
|
|
54242
54358
|
first = 1;
|
|
54243
54359
|
else
|
|
54244
54360
|
while (parts[first] === "..")
|
|
@@ -54254,7 +54370,7 @@ function snapshot(file, privateFile = false, options = {}) {
|
|
|
54254
54370
|
const initial2 = lstatSync19(file, { bigint: true });
|
|
54255
54371
|
need6(initial2.isFile() && initial2.uid === BigInt(process.getuid()) && (initial2.nlink === 1n || readOnlyPackage && initial2.nlink > 1n) && (initial2.mode & 0o022n) === 0n && (!privateFile || (initial2.mode & 0o777n) === 0o600n), "UNSAFE_FILE");
|
|
54256
54372
|
need6(initial2.size <= 8n * 1024n * 1024n, "FILE_BOUND");
|
|
54257
|
-
const fd = openSync10(file,
|
|
54373
|
+
const fd = openSync10(file, constants12.O_RDONLY | constants12.O_NOFOLLOW | constants12.O_NONBLOCK);
|
|
54258
54374
|
try {
|
|
54259
54375
|
const before2 = fstatSync10(fd, { bigint: true });
|
|
54260
54376
|
need6(sameStat(initial2, before2), "INPUT_CHANGED");
|
|
@@ -54279,7 +54395,7 @@ function unchanged2(before2) {
|
|
|
54279
54395
|
}
|
|
54280
54396
|
function save(file, content) {
|
|
54281
54397
|
safeParents(file);
|
|
54282
|
-
const fd = openSync10(file,
|
|
54398
|
+
const fd = openSync10(file, constants12.O_WRONLY | constants12.O_CREAT | constants12.O_EXCL | constants12.O_NOFOLLOW, 384);
|
|
54283
54399
|
try {
|
|
54284
54400
|
writeFileSync5(fd, content);
|
|
54285
54401
|
fsyncSync3(fd);
|
|
@@ -54290,35 +54406,152 @@ function save(file, content) {
|
|
|
54290
54406
|
var sameStat = (a, b) => ["dev", "ino", "uid", "nlink", "mode", "size", "mtimeNs", "ctimeNs"].every((key) => a[key] === b[key]);
|
|
54291
54407
|
var init_codex_hook_trust_files = () => {};
|
|
54292
54408
|
|
|
54409
|
+
// src/server/launcher-environment-policy.ts
|
|
54410
|
+
function renderLegacyPinnedLauncher(binding) {
|
|
54411
|
+
const names = LEGACY_ENV_NAMES.join(" ");
|
|
54412
|
+
const prefixes = LEGACY_ENV_PREFIXES.join("|");
|
|
54413
|
+
return [
|
|
54414
|
+
"#!/bin/sh -p",
|
|
54415
|
+
`# ${LEGACY_PINNED_LAUNCHER_SCHEMA}`,
|
|
54416
|
+
"# Written by `skills self-update`; rewrite it with `skills self-update`, do not edit by hand.",
|
|
54417
|
+
"# Runs the exact Skills entry below under one exact Bun from one trusted directory with",
|
|
54418
|
+
"# no working-directory configuration (no bunfig.toml, no .env, no macros, no auto-install)",
|
|
54419
|
+
"# and only the environment names allowed here. Everything else, BUN_* and NODE_OPTIONS",
|
|
54420
|
+
"# included, never reaches the runtime. The CLI returns to the caller's directory itself.",
|
|
54421
|
+
"# `-p` keeps the caller's exported functions and shell options out of this shell.",
|
|
54422
|
+
"set -eu",
|
|
54423
|
+
`${LAUNCH_CWD_VARIABLE2}=$(pwd -P 2>/dev/null || :)`,
|
|
54424
|
+
`export ${LAUNCH_CWD_VARIABLE2}`,
|
|
54425
|
+
`set -- '${binding.runtime}' ${PINNED_LAUNCHER_BUN_FLAGS.join(" ")} '--cwd=${binding.cwd}' '${binding.entry}' "$@"`,
|
|
54426
|
+
"hasna_skills_env=$(LC_ALL=C /usr/bin/awk 'BEGIN {",
|
|
54427
|
+
` n = split("${names}", exact, " ")`,
|
|
54428
|
+
" for (i = 1; i <= n; i++) allow[exact[i]] = 1",
|
|
54429
|
+
" for (name in ENVIRON) {",
|
|
54430
|
+
" if (name !~ /^[A-Za-z_][A-Za-z0-9_]*$/) continue",
|
|
54431
|
+
` if (name == "LC_ALL" || (!(name in allow) && name !~ /^(${prefixes})_/)) continue`,
|
|
54432
|
+
' value = ENVIRON[name]; quoted = ""',
|
|
54433
|
+
' while ((k = index(value, "\\047")) > 0) { quoted = quoted substr(value, 1, k - 1) "\\047\\\\\\047\\047"; value = substr(value, k + 1) }',
|
|
54434
|
+
' printf "\\047%s=%s\\047 ", name, quoted value',
|
|
54435
|
+
" }",
|
|
54436
|
+
"}')",
|
|
54437
|
+
'eval "set -- $hasna_skills_env \\"\\$@\\""',
|
|
54438
|
+
'if [ "${LC_ALL+x}" = x ]; then set -- "LC_ALL=$LC_ALL" "$@"; fi',
|
|
54439
|
+
'exec /usr/bin/env -i "$@"',
|
|
54440
|
+
""
|
|
54441
|
+
].join(`
|
|
54442
|
+
`);
|
|
54443
|
+
}
|
|
54444
|
+
function isStorageLocatorEnvironmentName(name) {
|
|
54445
|
+
return storageLocators.has(name);
|
|
54446
|
+
}
|
|
54447
|
+
var LEGACY_PINNED_LAUNCHER_SCHEMA = "hasna-skills-pinned-launcher-v1", LAUNCH_CWD_VARIABLE2 = "HASNA_SKILLS_LAUNCH_CWD", PINNED_LAUNCHER_BUN_FLAGS, LEGACY_ENV_NAMES, LEGACY_ENV_PREFIXES, SERVER_LAUNCHER_ENV_NAMES, STORAGE_LOCATOR_ENV_NAMES, storageLocators, CLIENT_LAUNCHER_STORAGE_DENY_AWK = ` if (name == "DATABASE_URL" || name == "HASNA_SKILLS_DATABASE_URL" || name == "SKILLS_DATABASE_URL") continue`;
|
|
54448
|
+
var init_launcher_environment_policy = __esm(() => {
|
|
54449
|
+
PINNED_LAUNCHER_BUN_FLAGS = ["--config=/dev/null", "--no-env-file", "--no-macros", "--no-install"];
|
|
54450
|
+
LEGACY_ENV_NAMES = [
|
|
54451
|
+
"HOME",
|
|
54452
|
+
"PATH",
|
|
54453
|
+
"TMPDIR",
|
|
54454
|
+
"TERM",
|
|
54455
|
+
"TERM_PROGRAM",
|
|
54456
|
+
"TERM_PROGRAM_VERSION",
|
|
54457
|
+
"COLORTERM",
|
|
54458
|
+
"LANG",
|
|
54459
|
+
"USER",
|
|
54460
|
+
"LOGNAME",
|
|
54461
|
+
"SHELL",
|
|
54462
|
+
"TZ",
|
|
54463
|
+
"NO_COLOR",
|
|
54464
|
+
"FORCE_COLOR",
|
|
54465
|
+
"CI",
|
|
54466
|
+
"COLUMNS",
|
|
54467
|
+
"LINES",
|
|
54468
|
+
"EDITOR",
|
|
54469
|
+
"VISUAL",
|
|
54470
|
+
"PAGER",
|
|
54471
|
+
"SSH_AUTH_SOCK",
|
|
54472
|
+
"DATABASE_URL",
|
|
54473
|
+
"TERMINAL_CWD",
|
|
54474
|
+
"CODEX_HOME",
|
|
54475
|
+
"HERMES_HOME",
|
|
54476
|
+
"HERMES_ENABLE_PROJECT_PLUGINS",
|
|
54477
|
+
"HOST",
|
|
54478
|
+
"PORT",
|
|
54479
|
+
"NODE_ENV",
|
|
54480
|
+
"AGENT_ID",
|
|
54481
|
+
"ECS_CONTAINER_METADATA_URI_V4"
|
|
54482
|
+
];
|
|
54483
|
+
LEGACY_ENV_PREFIXES = ["HASNA", "SKILLS", "SKILL", "MCP", "XDG", "LC", "AWS"];
|
|
54484
|
+
SERVER_LAUNCHER_ENV_NAMES = ["DATABASE_URL"];
|
|
54485
|
+
STORAGE_LOCATOR_ENV_NAMES = ["DATABASE_URL", "HASNA_SKILLS_DATABASE_URL", "SKILLS_DATABASE_URL"];
|
|
54486
|
+
storageLocators = new Set(STORAGE_LOCATOR_ENV_NAMES);
|
|
54487
|
+
});
|
|
54488
|
+
|
|
54293
54489
|
// src/cli/commands/runtime-launcher.ts
|
|
54294
54490
|
import { createHash as createHash19 } from "crypto";
|
|
54295
|
-
import { closeSync as closeSync11, constants as
|
|
54296
|
-
import { isAbsolute as
|
|
54297
|
-
function pinnedLauncherEnvironment(env3) {
|
|
54491
|
+
import { closeSync as closeSync11, constants as constants13, fchmodSync, fstatSync as fstatSync11, fsyncSync as fsyncSync4, lstatSync as lstatSync20, openSync as openSync11, readFileSync as readFileSync15, readlinkSync as readlinkSync6, realpathSync as realpathSync9, symlinkSync, writeSync as writeSync2 } from "fs";
|
|
54492
|
+
import { isAbsolute as isAbsolute17 } from "path";
|
|
54493
|
+
function pinnedLauncherEnvironment(env3, profile = "client") {
|
|
54494
|
+
assertLauncherProfile(profile);
|
|
54298
54495
|
const result2 = {};
|
|
54299
|
-
for (const
|
|
54300
|
-
if (
|
|
54496
|
+
for (const name of Object.keys(env3)) {
|
|
54497
|
+
if (!ENV_NAME.test(name))
|
|
54498
|
+
continue;
|
|
54499
|
+
const storageLocator = isStorageLocatorEnvironmentName(name);
|
|
54500
|
+
if (storageLocator && profile === "client")
|
|
54301
54501
|
continue;
|
|
54302
|
-
|
|
54502
|
+
if (!storageLocator && !ENV_EXACT.has(name) && !ENV_PREFIX.test(name))
|
|
54503
|
+
continue;
|
|
54504
|
+
const value = env3[name];
|
|
54505
|
+
if (value !== undefined)
|
|
54506
|
+
result2[name] = value;
|
|
54303
54507
|
}
|
|
54304
54508
|
return result2;
|
|
54305
54509
|
}
|
|
54510
|
+
function assertLauncherProfile(profile) {
|
|
54511
|
+
if (profile !== "client" && profile !== "server")
|
|
54512
|
+
throw new Error("LAUNCHER_PROFILE_INVALID");
|
|
54513
|
+
}
|
|
54514
|
+
function launcherProfileForBin(name, entry) {
|
|
54515
|
+
const bins = {
|
|
54516
|
+
skills: ["bin/index.js", "client"],
|
|
54517
|
+
"skills-mcp": ["bin/mcp.js", "client"],
|
|
54518
|
+
"skills-serve": ["bin/server.js", "server"],
|
|
54519
|
+
"skills-server": ["bin/server.js", "server"],
|
|
54520
|
+
"skills-worker": ["bin/worker.js", "server"],
|
|
54521
|
+
"skills-maintenance": ["bin/maintenance.js", "server"],
|
|
54522
|
+
"skills-migrate": ["bin/migrate.js", "server"]
|
|
54523
|
+
};
|
|
54524
|
+
const contract = bins[name];
|
|
54525
|
+
if (!contract || entry !== contract[0])
|
|
54526
|
+
throw new Error("LAUNCHER_BIN_CONTRACT_INVALID");
|
|
54527
|
+
return contract[1];
|
|
54528
|
+
}
|
|
54306
54529
|
function sha2562(bytes) {
|
|
54307
54530
|
return createHash19("sha256").update(bytes).digest("hex");
|
|
54308
54531
|
}
|
|
54309
54532
|
function assertLauncherPath(value, code) {
|
|
54310
|
-
if (typeof value !== "string" || !
|
|
54533
|
+
if (typeof value !== "string" || !isAbsolute17(value) || /['\x00-\x1f\x7f]/.test(value))
|
|
54311
54534
|
throw new Error(code);
|
|
54312
54535
|
}
|
|
54313
54536
|
function renderPinnedLauncher(binding) {
|
|
54314
54537
|
assertLauncherPath(binding.runtime, "LAUNCHER_RUNTIME_PATH_INVALID");
|
|
54315
54538
|
assertLauncherPath(binding.cwd, "LAUNCHER_CWD_PATH_INVALID");
|
|
54316
54539
|
assertLauncherPath(binding.entry, "LAUNCHER_ENTRY_PATH_INVALID");
|
|
54317
|
-
|
|
54540
|
+
if (binding.format === "v1") {
|
|
54541
|
+
if (binding.profile !== undefined)
|
|
54542
|
+
throw new Error("LAUNCHER_PROFILE_INVALID");
|
|
54543
|
+
return renderLegacyPinnedLauncher(binding);
|
|
54544
|
+
}
|
|
54545
|
+
if (binding.format !== undefined && binding.format !== "v2")
|
|
54546
|
+
throw new Error("LAUNCHER_FORMAT_INVALID");
|
|
54547
|
+
const profile = binding.profile === undefined ? "client" : binding.profile;
|
|
54548
|
+
assertLauncherProfile(profile);
|
|
54549
|
+
const names = [...PINNED_LAUNCHER_ENV_NAMES, ...profile === "server" ? SERVER_LAUNCHER_ENV_NAMES : []].join(" ");
|
|
54318
54550
|
const prefixes = PINNED_LAUNCHER_ENV_PREFIXES.join("|");
|
|
54319
54551
|
return [
|
|
54320
54552
|
"#!/bin/sh -p",
|
|
54321
54553
|
`# ${PINNED_LAUNCHER_SCHEMA}`,
|
|
54554
|
+
`# environment-profile: ${profile}`,
|
|
54322
54555
|
"# Written by `skills self-update`; rewrite it with `skills self-update`, do not edit by hand.",
|
|
54323
54556
|
"# Runs the exact Skills entry below under one exact Bun from one trusted directory with",
|
|
54324
54557
|
"# no working-directory configuration (no bunfig.toml, no .env, no macros, no auto-install)",
|
|
@@ -54326,15 +54559,16 @@ function renderPinnedLauncher(binding) {
|
|
|
54326
54559
|
"# included, never reaches the runtime. The CLI returns to the caller's directory itself.",
|
|
54327
54560
|
"# `-p` keeps the caller's exported functions and shell options out of this shell.",
|
|
54328
54561
|
"set -eu",
|
|
54329
|
-
`${
|
|
54330
|
-
`export ${
|
|
54331
|
-
`set -- '${binding.runtime}' ${
|
|
54562
|
+
`${LAUNCH_CWD_VARIABLE3}=$(pwd -P 2>/dev/null || :)`,
|
|
54563
|
+
`export ${LAUNCH_CWD_VARIABLE3}`,
|
|
54564
|
+
`set -- '${binding.runtime}' ${PINNED_LAUNCHER_BUN_FLAGS2.join(" ")} '--cwd=${binding.cwd}' '${binding.entry}' "$@"`,
|
|
54332
54565
|
"hasna_skills_env=$(LC_ALL=C /usr/bin/awk 'BEGIN {",
|
|
54333
54566
|
` n = split("${names}", exact, " ")`,
|
|
54334
54567
|
" for (i = 1; i <= n; i++) allow[exact[i]] = 1",
|
|
54335
54568
|
" for (name in ENVIRON) {",
|
|
54336
54569
|
" if (name !~ /^[A-Za-z_][A-Za-z0-9_]*$/) continue",
|
|
54337
54570
|
` if (name == "LC_ALL" || (!(name in allow) && name !~ /^(${prefixes})_/)) continue`,
|
|
54571
|
+
...profile === "client" ? [CLIENT_LAUNCHER_STORAGE_DENY_AWK] : [],
|
|
54338
54572
|
' value = ENVIRON[name]; quoted = ""',
|
|
54339
54573
|
' while ((k = index(value, "\\047")) > 0) { quoted = quoted substr(value, 1, k - 1) "\\047\\\\\\047\\047"; value = substr(value, k + 1) }',
|
|
54340
54574
|
' printf "\\047%s=%s\\047 ", name, quoted value',
|
|
@@ -54351,7 +54585,19 @@ function parsePinnedLauncher(text2) {
|
|
|
54351
54585
|
const match = COMMAND_LINE.exec(text2);
|
|
54352
54586
|
if (!match)
|
|
54353
54587
|
return null;
|
|
54354
|
-
|
|
54588
|
+
let metadata;
|
|
54589
|
+
if (text2.split(`
|
|
54590
|
+
`)[1] === `# ${LEGACY_PINNED_LAUNCHER_SCHEMA}`)
|
|
54591
|
+
metadata = { format: "v1" };
|
|
54592
|
+
else if (text2.split(`
|
|
54593
|
+
`)[1] === `# ${PINNED_LAUNCHER_SCHEMA}`) {
|
|
54594
|
+
const profile = /^# environment-profile: (client|server)$/m.exec(text2)?.[1];
|
|
54595
|
+
if (!profile)
|
|
54596
|
+
return null;
|
|
54597
|
+
metadata = { format: "v2", profile };
|
|
54598
|
+
} else
|
|
54599
|
+
return null;
|
|
54600
|
+
const binding = { runtime: match[1], cwd: match[2], entry: match[3], ...metadata };
|
|
54355
54601
|
try {
|
|
54356
54602
|
if (renderPinnedLauncher(binding) !== text2)
|
|
54357
54603
|
return null;
|
|
@@ -54398,7 +54644,7 @@ function inspectLauncher(path) {
|
|
|
54398
54644
|
const binding = parsePinnedLauncher(text2);
|
|
54399
54645
|
if (!binding)
|
|
54400
54646
|
return { kind: "foreign" };
|
|
54401
|
-
return { kind: "pinned", runtime: binding.runtime, cwd: binding.cwd, target: binding.entry, sha256: sha2562(text2), text: text2 };
|
|
54647
|
+
return { kind: "pinned", format: binding.format, profile: binding.profile, runtime: binding.runtime, cwd: binding.cwd, target: binding.entry, sha256: sha2562(text2), text: text2 };
|
|
54402
54648
|
}
|
|
54403
54649
|
function launcherTarget(path) {
|
|
54404
54650
|
const inspected = inspectLauncher(path);
|
|
@@ -54415,17 +54661,22 @@ function launcherIs(path, state) {
|
|
|
54415
54661
|
}
|
|
54416
54662
|
if (state.shape === "symlink")
|
|
54417
54663
|
return inspected.kind === "symlink" && inspected.linkTarget === state.linkTarget && inspected.target === state.target;
|
|
54418
|
-
return inspected.kind === "pinned" && inspected.sha256 === state.sha256 && inspected.runtime === state.runtime && inspected.cwd === state.cwd && inspected.target === state.target;
|
|
54664
|
+
return inspected.kind === "pinned" && inspected.sha256 === state.sha256 && inspected.runtime === state.runtime && inspected.cwd === state.cwd && inspected.target === state.target && inspected.format === (state.format ?? "v1") && inspected.profile === state.profile;
|
|
54419
54665
|
}
|
|
54420
54666
|
function pinnedLauncherText(state) {
|
|
54421
|
-
|
|
54667
|
+
if (state.format === "v2")
|
|
54668
|
+
assertLauncherProfile(state.profile);
|
|
54669
|
+
const text2 = renderPinnedLauncher({ runtime: state.runtime, cwd: state.cwd, entry: state.target, format: state.format === undefined ? "v1" : state.format, profile: state.profile });
|
|
54422
54670
|
if (sha2562(text2) !== state.sha256)
|
|
54423
54671
|
throw new Error("LAUNCHER_TEXT_DIGEST_MISMATCH");
|
|
54424
54672
|
return text2;
|
|
54425
54673
|
}
|
|
54426
|
-
function pinnedLauncherState(runtime, cwd2, target) {
|
|
54427
|
-
const
|
|
54428
|
-
|
|
54674
|
+
function pinnedLauncherState(runtime, cwd2, target, metadata = { format: "v2", profile: "client" }) {
|
|
54675
|
+
const format = metadata.format === undefined ? "v1" : metadata.format, profile = metadata.profile;
|
|
54676
|
+
if (format === "v2")
|
|
54677
|
+
assertLauncherProfile(profile);
|
|
54678
|
+
const text2 = renderPinnedLauncher({ runtime, cwd: cwd2, entry: target, format, profile });
|
|
54679
|
+
return { shape: "pinned", runtime, cwd: cwd2, target, sha256: sha2562(text2), format, ...profile ? { profile } : {} };
|
|
54429
54680
|
}
|
|
54430
54681
|
function materializeLauncher(path, state) {
|
|
54431
54682
|
if (state.shape === "symlink") {
|
|
@@ -54435,7 +54686,7 @@ function materializeLauncher(path, state) {
|
|
|
54435
54686
|
return;
|
|
54436
54687
|
}
|
|
54437
54688
|
const text2 = pinnedLauncherText(state);
|
|
54438
|
-
const fd = openSync11(path,
|
|
54689
|
+
const fd = openSync11(path, constants13.O_WRONLY | constants13.O_CREAT | constants13.O_EXCL | constants13.O_NOFOLLOW, 493);
|
|
54439
54690
|
try {
|
|
54440
54691
|
const bytes = Buffer.from(text2, "utf8");
|
|
54441
54692
|
let written = 0;
|
|
@@ -54491,9 +54742,10 @@ function assertPinnedLauncherShell() {
|
|
|
54491
54742
|
if (probe.exitCode !== 0)
|
|
54492
54743
|
throw new Error("LAUNCHER_SHELL_UNSUPPORTED");
|
|
54493
54744
|
}
|
|
54494
|
-
var PINNED_LAUNCHER_SCHEMA = "hasna-skills-pinned-launcher-
|
|
54745
|
+
var PINNED_LAUNCHER_SCHEMA = "hasna-skills-pinned-launcher-v2", LAUNCH_CWD_VARIABLE3 = "HASNA_SKILLS_LAUNCH_CWD", PINNED_LAUNCHER_BUN_FLAGS2, PINNED_LAUNCHER_ENV_NAMES, PINNED_LAUNCHER_ENV_PREFIXES, ENV_NAME, ENV_PREFIX, ENV_EXACT, COMMAND_LINE, PINNED_LAUNCHER_MAX_BYTES;
|
|
54495
54746
|
var init_runtime_launcher = __esm(() => {
|
|
54496
|
-
|
|
54747
|
+
init_launcher_environment_policy();
|
|
54748
|
+
PINNED_LAUNCHER_BUN_FLAGS2 = ["--config=/dev/null", "--no-env-file", "--no-macros", "--no-install"];
|
|
54497
54749
|
PINNED_LAUNCHER_ENV_NAMES = [
|
|
54498
54750
|
"HOME",
|
|
54499
54751
|
"PATH",
|
|
@@ -54516,7 +54768,6 @@ var init_runtime_launcher = __esm(() => {
|
|
|
54516
54768
|
"VISUAL",
|
|
54517
54769
|
"PAGER",
|
|
54518
54770
|
"SSH_AUTH_SOCK",
|
|
54519
|
-
"DATABASE_URL",
|
|
54520
54771
|
"TERMINAL_CWD",
|
|
54521
54772
|
"CODEX_HOME",
|
|
54522
54773
|
"HERMES_HOME",
|
|
@@ -54531,16 +54782,32 @@ var init_runtime_launcher = __esm(() => {
|
|
|
54531
54782
|
ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
54532
54783
|
ENV_PREFIX = new RegExp(`^(${PINNED_LAUNCHER_ENV_PREFIXES.join("|")})_`);
|
|
54533
54784
|
ENV_EXACT = new Set(PINNED_LAUNCHER_ENV_NAMES);
|
|
54534
|
-
COMMAND_LINE = new RegExp(`^set -- '([^']+)' ${
|
|
54785
|
+
COMMAND_LINE = new RegExp(`^set -- '([^']+)' ${PINNED_LAUNCHER_BUN_FLAGS2.join(" ")} '--cwd=([^']+)' '([^']+)' "\\$@"$`, "m");
|
|
54535
54786
|
PINNED_LAUNCHER_MAX_BYTES = 16 * 1024;
|
|
54536
54787
|
});
|
|
54537
54788
|
|
|
54538
54789
|
// src/lib/agent-integration.ts
|
|
54539
54790
|
import { createHash as createHash20, randomUUID as randomUUID6 } from "crypto";
|
|
54540
54791
|
import { isDeepStrictEqual as isDeepStrictEqual7 } from "util";
|
|
54541
|
-
import { existsSync as existsSync13, lstatSync as lstatSync21, statSync as
|
|
54542
|
-
import { dirname as dirname16, join as join28, resolve as resolve17, relative as relative6, isAbsolute as
|
|
54792
|
+
import { existsSync as existsSync13, lstatSync as lstatSync21, statSync as statSync10, mkdirSync as mkdirSync6, readFileSync as readFileSync16, readdirSync as readdirSync8, opendirSync as opendirSync3, readlinkSync as readlinkSync7, realpathSync as realpathSync10, renameSync as renameSync3, rmdirSync as rmdirSync2, writeFileSync as writeFileSync6, unlinkSync as unlinkSync4, chmodSync, openSync as openSync12, closeSync as closeSync12, fsyncSync as fsyncSync5, fstatSync as fstatSync12, readSync as readSync9, constants as constants14, linkSync as linkSync2 } from "fs";
|
|
54793
|
+
import { dirname as dirname16, join as join28, resolve as resolve17, relative as relative6, isAbsolute as isAbsolute18, sep as sep7 } from "path";
|
|
54543
54794
|
import { homedir as homedir3 } from "os";
|
|
54795
|
+
function nativeAgentRoot(home, agent, cwd2 = process.cwd()) {
|
|
54796
|
+
if (agent === "sumi")
|
|
54797
|
+
return sumiBridgeRoot(home, cwd2);
|
|
54798
|
+
const root = AGENT_ADAPTERS[agent].root;
|
|
54799
|
+
if (typeof root !== "string")
|
|
54800
|
+
throw new Error(`Native skill root is unavailable for ${agent}`);
|
|
54801
|
+
return join28(home, root);
|
|
54802
|
+
}
|
|
54803
|
+
function nativeAgentConfig(home, agent, cwd2 = process.cwd()) {
|
|
54804
|
+
if (agent === "sumi")
|
|
54805
|
+
return sumiConfigPath(home, cwd2);
|
|
54806
|
+
const config = AGENT_ADAPTERS[agent].config;
|
|
54807
|
+
if (typeof config !== "string")
|
|
54808
|
+
throw new Error(`Native configuration path is unavailable for ${agent}`);
|
|
54809
|
+
return join28(home, config);
|
|
54810
|
+
}
|
|
54544
54811
|
function hasTrustedDarwinAcl(fd, allowDenyOnly = false) {
|
|
54545
54812
|
try {
|
|
54546
54813
|
const { dlopen, read: read2, ptr } = __require("bun:ffi");
|
|
@@ -54603,7 +54870,7 @@ function isSystemRootAlias(path) {
|
|
|
54603
54870
|
throw new Error("Writable system alias directory");
|
|
54604
54871
|
} else if ((stat.mode & 0o1000n) === 0n)
|
|
54605
54872
|
throw new Error("Unprotected system temporary directory");
|
|
54606
|
-
const fd = openSync12(directory,
|
|
54873
|
+
const fd = openSync12(directory, constants14.O_RDONLY | constants14.O_DIRECTORY | constants14.O_NOFOLLOW);
|
|
54607
54874
|
try {
|
|
54608
54875
|
if (directoryIdentity(fstatSync12(fd, { bigint: true })) !== directoryIdentity(stat) || !hasTrustedDarwinAcl(fd) || directoryIdentity(fstatSync12(fd, { bigint: true })) !== directoryIdentity(stat))
|
|
54609
54876
|
throw new Error("Unverified system alias directory ACL");
|
|
@@ -54648,7 +54915,7 @@ function readRootAlias(home, agent) {
|
|
|
54648
54915
|
if (!targetStat?.isDirectory())
|
|
54649
54916
|
throw new Error(`Agent root alias must target an existing directory: ${alias}`);
|
|
54650
54917
|
const target = realpathSync10(targetPath), inside = relative6(realHome, target);
|
|
54651
|
-
if (!inside || inside === ".." || inside.startsWith(`..${sep7}`) ||
|
|
54918
|
+
if (!inside || inside === ".." || inside.startsWith(`..${sep7}`) || isAbsolute18(inside))
|
|
54652
54919
|
throw new Error(`Agent root alias target must be inside the real home: ${alias}`);
|
|
54653
54920
|
return { agent, home: realHome, alias, target, link: link2, aliasIdentity: `${stat.dev}:${stat.ino}:${stat.ctimeNs}`, targetIdentity: `${targetStat.dev}:${targetStat.ino}` };
|
|
54654
54921
|
}
|
|
@@ -54674,13 +54941,13 @@ function disabledCodexSkillPaths(config, aliases) {
|
|
|
54674
54941
|
const rows = skills.config;
|
|
54675
54942
|
if (!Array.isArray(rows))
|
|
54676
54943
|
return [];
|
|
54677
|
-
if (rows.some((entry) => !entry || typeof entry !== "object" || Array.isArray(entry) || typeof entry.enabled !== "boolean" || entry.path !== undefined === (entry.name !== undefined) || entry.path !== undefined && (typeof entry.path !== "string" || !
|
|
54944
|
+
if (rows.some((entry) => !entry || typeof entry !== "object" || Array.isArray(entry) || typeof entry.enabled !== "boolean" || entry.path !== undefined === (entry.name !== undefined) || entry.path !== undefined && (typeof entry.path !== "string" || !isAbsolute18(entry.path)) || entry.name !== undefined && (typeof entry.name !== "string" || !entry.name.trim())))
|
|
54678
54945
|
return [];
|
|
54679
54946
|
if (rows.some((entry) => entry.name !== undefined && entry.enabled !== false))
|
|
54680
54947
|
return [];
|
|
54681
54948
|
const settings = new Map;
|
|
54682
54949
|
for (const entry of rows) {
|
|
54683
|
-
if (typeof entry.path !== "string" || !
|
|
54950
|
+
if (typeof entry.path !== "string" || !isAbsolute18(entry.path))
|
|
54684
54951
|
continue;
|
|
54685
54952
|
let document3;
|
|
54686
54953
|
try {
|
|
@@ -54712,7 +54979,7 @@ function readNativeBytes(path, maximum = 64 * 1024 * 1024) {
|
|
|
54712
54979
|
const before2 = lstatSync21(path);
|
|
54713
54980
|
if (!before2.isFile() || before2.size > maximum)
|
|
54714
54981
|
throw new Error("Unsupported or oversized native skill file");
|
|
54715
|
-
const descriptor = openSync12(path,
|
|
54982
|
+
const descriptor = openSync12(path, constants14.O_RDONLY | constants14.O_NOFOLLOW | constants14.O_NONBLOCK);
|
|
54716
54983
|
try {
|
|
54717
54984
|
const opened = fstatSync12(descriptor);
|
|
54718
54985
|
if (!opened.isFile() || opened.dev !== before2.dev || opened.ino !== before2.ino || opened.size !== before2.size)
|
|
@@ -54785,16 +55052,16 @@ function parseNativeMigrationTargetManifest(input) {
|
|
|
54785
55052
|
throw new Error("Invalid native migration target fields");
|
|
54786
55053
|
if (!ROOTS.some(([agent]) => agent === item.agent))
|
|
54787
55054
|
throw new Error(`Unsupported native migration target agent: ${item.agent}`);
|
|
54788
|
-
if (!
|
|
55055
|
+
if (!isAbsolute18(item.projectRoot) || resolve17(item.projectRoot) !== item.projectRoot)
|
|
54789
55056
|
throw new Error(`Native migration target project root must be an existing absolute directory: ${item.projectRoot}`);
|
|
54790
55057
|
const projectRoot = canonicalSystemPath(item.projectRoot);
|
|
54791
55058
|
if (!existsSync13(projectRoot) || !lstatSync21(projectRoot).isDirectory())
|
|
54792
55059
|
throw new Error(`Native migration target project root must be an existing absolute directory: ${item.projectRoot}`);
|
|
54793
55060
|
assertSafePath(projectRoot);
|
|
54794
|
-
if (
|
|
55061
|
+
if (isAbsolute18(item.path) || item.path.includes("\\") || item.path.length === 0 || item.path.includes("\x00"))
|
|
54795
55062
|
throw new Error(`Native migration target path must be normalized and project-relative: ${item.path}`);
|
|
54796
55063
|
const resolved = resolve17(projectRoot, item.path), normalized = relative6(projectRoot, resolved);
|
|
54797
|
-
if (!normalized || normalized === ".." || normalized.startsWith(`..${sep7}`) ||
|
|
55064
|
+
if (!normalized || normalized === ".." || normalized.startsWith(`..${sep7}`) || isAbsolute18(normalized) || normalized !== item.path)
|
|
54798
55065
|
throw new Error(`Native migration target path escapes or is not normalized: ${item.path}`);
|
|
54799
55066
|
if (!/^[0-9a-f]{64}$/.test(item.treeSha256))
|
|
54800
55067
|
throw new Error(`Invalid native migration tree digest for ${item.path}`);
|
|
@@ -54815,13 +55082,13 @@ function selectNativeMigrationTargets(inventory, manifest) {
|
|
|
54815
55082
|
const identities = new Set;
|
|
54816
55083
|
const selected = [];
|
|
54817
55084
|
for (const target of manifest.targets) {
|
|
54818
|
-
if (!
|
|
55085
|
+
if (!isAbsolute18(target.projectRoot) || resolve17(target.projectRoot) !== target.projectRoot)
|
|
54819
55086
|
throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
|
|
54820
55087
|
const projectRoot = canonicalSystemPath(target.projectRoot), normalized = relative6(projectRoot, resolve17(projectRoot, target.path));
|
|
54821
55088
|
if (!existsSync13(projectRoot) || !lstatSync21(projectRoot).isDirectory())
|
|
54822
55089
|
throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
|
|
54823
55090
|
assertSafePath(projectRoot);
|
|
54824
|
-
if (
|
|
55091
|
+
if (isAbsolute18(target.path) || target.path.includes("\\") || target.path.includes("\x00") || !normalized || normalized === ".." || normalized.startsWith(`..${sep7}`) || normalized !== target.path || !/^[0-9a-f]{64}$/.test(target.treeSha256))
|
|
54825
55092
|
throw new Error(`Invalid native migration target: ${target.path}`);
|
|
54826
55093
|
const identity6 = `${target.agent}\x00${canonicalSystemPath(projectRoot)}\x00${normalized}`;
|
|
54827
55094
|
if (identities.has(identity6))
|
|
@@ -54864,25 +55131,32 @@ function isCodexSkillDiscoveryInput(path) {
|
|
|
54864
55131
|
}
|
|
54865
55132
|
function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
54866
55133
|
home = canonicalSystemPath(home);
|
|
54867
|
-
if (options.reviewedCacheAlias !== undefined && (!options.includeVendor || !
|
|
55134
|
+
if (options.reviewedCacheAlias !== undefined && (!options.includeVendor || !isAbsolute18(options.reviewedCacheAlias) || resolve17(options.reviewedCacheAlias) !== options.reviewedCacheAlias))
|
|
54868
55135
|
throw new Error("A reviewed cache alias requires vendor inventory and an exact absolute path");
|
|
54869
|
-
if (options.disabledVendorPaths?.some((path) => !
|
|
55136
|
+
if (options.disabledVendorPaths?.some((path) => !isAbsolute18(path) || resolve17(path) !== path))
|
|
54870
55137
|
throw new Error("Disabled vendor paths must be exact absolute paths");
|
|
54871
55138
|
const reviewedCacheAlias = options.reviewedCacheAlias === undefined ? undefined : canonicalSystemPath(options.reviewedCacheAlias);
|
|
54872
55139
|
const disabledVendorPaths = new Set((options.disabledVendorPaths ?? []).map(canonicalSystemPath));
|
|
54873
55140
|
const aliases = rootAliases(home, options.allowRootAliases);
|
|
54874
55141
|
const selectedAgents = options.agents ? new Set(options.agents) : undefined;
|
|
54875
55142
|
const includesAgent = (agent) => !selectedAgents || selectedAgents.has(agent);
|
|
54876
|
-
const rootDefinitions = selectedAgents ? ROOTS.filter(([agent, path]) => selectedAgents.has(agent) || selectedAgents.has("hermes") && agent === "codex" && path === ".agents/skills") : ROOTS;
|
|
55143
|
+
const rootDefinitions = selectedAgents ? ROOTS.filter(([agent, path]) => agent !== "sumi" && selectedAgents.has(agent) || selectedAgents.has("hermes") && agent === "codex" && path === ".agents/skills") : ROOTS.filter(([agent]) => agent !== "sumi");
|
|
54877
55144
|
const roots = rootDefinitions.map(([agent, path]) => [agent, canonicalAgentPath(join28(home, path), aliases)]);
|
|
54878
|
-
const
|
|
55145
|
+
const includesSumi = !selectedAgents || selectedAgents.has("sumi");
|
|
55146
|
+
if (includesSumi)
|
|
55147
|
+
for (const path of sumiSkillRoots(home))
|
|
55148
|
+
roots.push(["sumi", canonicalAgentPath(path, aliases)]);
|
|
55149
|
+
const bridgePaths = Object.entries(AGENT_ADAPTERS).filter(([agent]) => agent !== "sumi" || includesSumi).map(([agent]) => canonicalAgentPath(join28(nativeAgentRoot(home, agent), CLI_BRIDGE_NAME), aliases));
|
|
54879
55150
|
for (const project of projectAncestorDirectories([...options.projectDirs ?? [], ...options.projectDir ? [options.projectDir] : []])) {
|
|
54880
55151
|
for (const [agent, path] of rootDefinitions)
|
|
54881
55152
|
roots.push([agent, canonicalAgentPath(join28(project, path), aliases)]);
|
|
54882
|
-
if (selectedAgents?.has("sumi"))
|
|
55153
|
+
if (selectedAgents?.has("sumi")) {
|
|
55154
|
+
for (const path of sumiSkillRoots(home, project))
|
|
55155
|
+
roots.push(["sumi", canonicalAgentPath(path, aliases)]);
|
|
54883
55156
|
for (const directory of [".claude", ".agents"])
|
|
54884
55157
|
for (const name of ["skill", "skills"])
|
|
54885
55158
|
roots.push(["sumi", canonicalAgentPath(join28(project, directory, name), aliases)]);
|
|
55159
|
+
}
|
|
54886
55160
|
}
|
|
54887
55161
|
const installationInputs = options.codexInstallationInputRoots ?? [];
|
|
54888
55162
|
if (installationInputs.some((input) => resolve17(input) !== input || realpathSync10(input) !== input || roots.some(([agent, path]) => agent === "codex" && (path === input || path.startsWith(input + sep7) || input.startsWith(path + sep7)))))
|
|
@@ -54900,7 +55174,7 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
54900
55174
|
let reviewedCacheAliasFound = false;
|
|
54901
55175
|
function verifiedSiblingCacheAlias(agent, path, parent) {
|
|
54902
55176
|
const link2 = readlinkSync7(path), lexicalTarget = resolve17(parent, link2);
|
|
54903
|
-
if (
|
|
55177
|
+
if (isAbsolute18(link2) ? link2 !== lexicalTarget : dirname16(link2) !== ".")
|
|
54904
55178
|
return false;
|
|
54905
55179
|
const target = canonicalSystemPath(lexicalTarget);
|
|
54906
55180
|
if (dirname16(target) !== parent)
|
|
@@ -54980,7 +55254,7 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
54980
55254
|
continue;
|
|
54981
55255
|
const child2 = join28(path, name);
|
|
54982
55256
|
if (isVendor && lstatSync21(child2, { throwIfNoEntry: false })?.isSymbolicLink()) {
|
|
54983
|
-
const target =
|
|
55257
|
+
const target = statSync10(child2, { throwIfNoEntry: false });
|
|
54984
55258
|
if (target?.isFile() || pluginCache && target?.isDirectory() && verifiedSiblingCacheAlias(agent, child2, path)) {
|
|
54985
55259
|
scan.entries++;
|
|
54986
55260
|
continue;
|
|
@@ -55244,8 +55518,7 @@ function planAgentIntegration(options) {
|
|
|
55244
55518
|
if (!INTEGRATION_AGENTS.includes(agent))
|
|
55245
55519
|
throw new Error(`Unsupported agent: ${agent}`);
|
|
55246
55520
|
const { command, profileId: profileId2 } = bindings.get(agent);
|
|
55247
|
-
const
|
|
55248
|
-
const bridgePath = canonicalAgentPath(join28(agent === "sumi" ? sumiBridgeRoot(home) : join28(home, adapter.root), CLI_BRIDGE_NAME), aliases);
|
|
55521
|
+
const bridgePath = canonicalAgentPath(join28(nativeAgentRoot(home, agent, options.projectDir ?? process.cwd()), CLI_BRIDGE_NAME), aliases);
|
|
55249
55522
|
assertSafePath(bridgePath);
|
|
55250
55523
|
if (existsSync13(bridgePath) && !isOwnedCliBridge(bridgePath, [bridgePath]))
|
|
55251
55524
|
throw new Error(`Refusing to overwrite an unrecognized or modified Skills bridge: ${bridgePath}`);
|
|
@@ -55254,7 +55527,7 @@ function planAgentIntegration(options) {
|
|
|
55254
55527
|
if (before3 !== after3)
|
|
55255
55528
|
changes.push({ path: path2, before: before3, after: after3 });
|
|
55256
55529
|
}
|
|
55257
|
-
const path = canonicalAgentPath(
|
|
55530
|
+
const path = canonicalAgentPath(nativeAgentConfig(home, agent, options.projectDir ?? process.cwd()), aliases);
|
|
55258
55531
|
const before2 = readOptional(path);
|
|
55259
55532
|
if (agent === "hermes") {
|
|
55260
55533
|
const supervisorPath = join28(dataDir3, "agent-hooks", "hermes.js"), supervisorBefore = readOptional(supervisorPath), supervisorAfter = renderHermesSupervisor(command, profileId2);
|
|
@@ -55279,7 +55552,7 @@ function planAgentIntegration(options) {
|
|
|
55279
55552
|
if (config.permissions !== undefined && (!Array.isArray(config.permissions) || config.permissions.some((rule) => !rule || typeof rule.action !== "string" || typeof rule.resource !== "string" || !["allow", "deny", "ask"].includes(rule.effect))))
|
|
55280
55553
|
throw new Error("Expected Sumi native permission rules");
|
|
55281
55554
|
config.permissions = [...(config.permissions ?? []).filter((rule) => rule.action !== "skill"), ...SUMI_SKILL_PERMISSIONS];
|
|
55282
|
-
const pluginPath = join28(sumiConfigDirectory(home), "plugins", "skills-cli.js"), pluginBefore = readOptional(pluginPath);
|
|
55555
|
+
const pluginPath = join28(sumiConfigDirectory(home, process.env, options.projectDir ?? process.cwd()), "plugins", "skills-cli.js"), pluginBefore = readOptional(pluginPath);
|
|
55283
55556
|
const pluginAfter = renderSumiPlugin(command, profileId2);
|
|
55284
55557
|
const priorCommand = policy.bridge?.commands?.sumi, priorProfile = policy.bridge?.profiles?.sumi ?? policy.profileId;
|
|
55285
55558
|
if (pluginBefore !== null && pluginBefore !== pluginAfter && !(typeof priorCommand === "string" && typeof priorProfile === "string" && isManagedSumiPlugin(pluginBefore, priorCommand, priorProfile)))
|
|
@@ -55370,7 +55643,7 @@ function projectedHookAcl(path, observed) {
|
|
|
55370
55643
|
if (process.platform !== "darwin")
|
|
55371
55644
|
return;
|
|
55372
55645
|
const identity6 = observed.isDirectory() ? (stat) => `${stat.dev}:${stat.ino}:${stat.uid}:${stat.mode}` : (stat) => `${stat.dev}:${stat.ino}:${stat.ctimeNs}:${stat.uid}:${stat.mode}:${stat.nlink}:${stat.size}:${stat.mtimeNs}`;
|
|
55373
|
-
const fd = openSync12(path,
|
|
55646
|
+
const fd = openSync12(path, constants14.O_RDONLY | constants14.O_NOFOLLOW | constants14.O_NONBLOCK | (observed.isDirectory() ? constants14.O_DIRECTORY : 0));
|
|
55374
55647
|
try {
|
|
55375
55648
|
if (identity6(fstatSync12(fd, { bigint: true })) !== identity6(observed) || !hasTrustedDarwinAcl(fd, true) || identity6(fstatSync12(fd, { bigint: true })) !== identity6(observed) || identity6(lstatSync21(path, { bigint: true })) !== identity6(observed))
|
|
55376
55649
|
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
@@ -55380,7 +55653,7 @@ function projectedHookAcl(path, observed) {
|
|
|
55380
55653
|
}
|
|
55381
55654
|
function projectedHookExecutable(command, expectedResolved) {
|
|
55382
55655
|
try {
|
|
55383
|
-
if (!
|
|
55656
|
+
if (!isAbsolute18(command) || /[\0\r\n]/.test(command) || resolve17(command) !== command)
|
|
55384
55657
|
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
55385
55658
|
command = canonicalSystemPath(command);
|
|
55386
55659
|
const parents2 = (file = command) => {
|
|
@@ -55600,7 +55873,7 @@ function planAgentSettingsWitnessUpgrade(options) {
|
|
|
55600
55873
|
const binding = policy.bridge?.discovery?.[options.agent];
|
|
55601
55874
|
if (!binding || binding.agent !== options.agent || binding.method !== "reviewed")
|
|
55602
55875
|
throw new Error("Settings witness upgrade requires an existing reviewed native binding");
|
|
55603
|
-
const configPath = canonicalAgentPath(options.agent === "sumi" ?
|
|
55876
|
+
const configPath = canonicalAgentPath(options.agent === "sumi" ? nativeAgentConfig(home, "sumi", options.projectDir ?? process.cwd()) : join28(home, options.agent === "claude" ? ".claude/settings.json" : ".codex/config.toml"), aliases);
|
|
55604
55877
|
const settings = readOptional(configPath);
|
|
55605
55878
|
if (settings === null || sha3(settings) !== options.expectedSettingsSha256)
|
|
55606
55879
|
throw new Error("Native settings preimage changed");
|
|
@@ -55778,7 +56051,7 @@ function applyAgentIntegrationUnlocked(plan, options = {}, assertCurrent) {
|
|
|
55778
56051
|
}
|
|
55779
56052
|
function syncArchiveDirectory(path) {
|
|
55780
56053
|
assertSafePath(path);
|
|
55781
|
-
const descriptor = openSync12(path,
|
|
56054
|
+
const descriptor = openSync12(path, constants14.O_RDONLY | constants14.O_DIRECTORY | constants14.O_NOFOLLOW | constants14.O_NONBLOCK);
|
|
55782
56055
|
try {
|
|
55783
56056
|
fsyncSync5(descriptor);
|
|
55784
56057
|
} finally {
|
|
@@ -55790,7 +56063,7 @@ function writeArchiveJournal(path, value) {
|
|
|
55790
56063
|
const temporary = `${path}.skills-${randomUUID6()}`;
|
|
55791
56064
|
let descriptor;
|
|
55792
56065
|
try {
|
|
55793
|
-
descriptor = openSync12(temporary,
|
|
56066
|
+
descriptor = openSync12(temporary, constants14.O_WRONLY | constants14.O_CREAT | constants14.O_EXCL | constants14.O_NOFOLLOW, 384);
|
|
55794
56067
|
writeFileSync6(descriptor, `${JSON.stringify(value)}
|
|
55795
56068
|
`);
|
|
55796
56069
|
fsyncSync5(descriptor);
|
|
@@ -55824,7 +56097,7 @@ function archiveNativeSkillsUnlocked(inventory, options, assertCurrent) {
|
|
|
55824
56097
|
recheckRootAliases(aliases);
|
|
55825
56098
|
for (const entry of inventory.filter((entry2) => entry2.bridge)) {
|
|
55826
56099
|
const adapter = AGENT_ADAPTERS[entry.agent];
|
|
55827
|
-
const expected = adapter && entry.bridgeHome ? canonicalAgentPath(join28(
|
|
56100
|
+
const expected = adapter && entry.bridgeHome ? canonicalAgentPath(join28(nativeAgentRoot(entry.bridgeHome, entry.agent), CLI_BRIDGE_NAME), aliases) : undefined;
|
|
55828
56101
|
if (!expected || treeHash(entry.path) !== entry.hash || !isOwnedCliBridge(entry.path, [expected]))
|
|
55829
56102
|
throw new Error(`Skills bridge changed after planning: ${entry.path}`);
|
|
55830
56103
|
}
|
|
@@ -55948,7 +56221,7 @@ function isInertCodexPluginCacheCopy(entry, cache3, allowedHostPaths, read2) {
|
|
|
55948
56221
|
return false;
|
|
55949
56222
|
const document3 = join28(entry.path, "SKILL.md");
|
|
55950
56223
|
const inside = relative6(cache3, entry.path);
|
|
55951
|
-
if (!inside ||
|
|
56224
|
+
if (!inside || isAbsolute18(inside) || inside.split(sep7).some((segment) => segment === ".."))
|
|
55952
56225
|
return false;
|
|
55953
56226
|
assertSafePath(entry.path);
|
|
55954
56227
|
if (!lstatSync21(cache3).isDirectory() || !lstatSync21(entry.path).isDirectory() || !lstatSync21(document3).isFile())
|
|
@@ -55980,14 +56253,14 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
|
|
|
55980
56253
|
if (!Array.isArray(aliases))
|
|
55981
56254
|
throw new Error("NATIVE_SKILL_DRIFT: invalid root alias binding");
|
|
55982
56255
|
recheckRootAliases(aliases);
|
|
55983
|
-
const expected = canonicalAgentPath(join28(
|
|
56256
|
+
const expected = canonicalAgentPath(join28(nativeAgentRoot(home, agent, options.projectDir ?? process.cwd()), CLI_BRIDGE_NAME), aliases);
|
|
55984
56257
|
if (!isOwnedCliBridge(expected, [expected]))
|
|
55985
56258
|
throw new Error("NATIVE_SKILL_DRIFT: the native Skills bridge is missing or modified; repair it before continuing");
|
|
55986
56259
|
const roots = projectAncestorDirectories([options.projectDir ?? process.cwd(), ...options.projectDirs ?? [], ...agent === "hermes" && process.env.TERMINAL_CWD ? [process.cwd()] : []]);
|
|
55987
56260
|
const visible = (entry) => entry.agent === agent || ["codex", "gemini", "opencode", "hermes", "sumi"].includes(agent) && entry.path.includes(`${sep7}.agents${sep7}skills${sep7}`) || ["opencode", "sumi"].includes(agent) && entry.agent === "claude";
|
|
55988
56261
|
const discovery = provenDiscovery ?? binding.discovery?.[agent];
|
|
55989
56262
|
assertProjectDiscovery(agent, [...roots], home, (path) => canonicalAgentPath(path, aliases), discovery);
|
|
55990
|
-
const configPath = canonicalAgentPath(
|
|
56263
|
+
const configPath = canonicalAgentPath(nativeAgentConfig(home, agent, options.projectDir ?? process.cwd()), aliases), config = agent === "hermes" ? parseHermesConfig(readOptional(configPath)) : jsonObject(readOptional(configPath), configPath);
|
|
55991
56264
|
const command = binding.commands?.[agent], profile = binding.profiles?.[agent];
|
|
55992
56265
|
if (typeof command !== "string" || typeof profile !== "string")
|
|
55993
56266
|
throw new Error("NATIVE_SKILL_DRIFT: the native hook command/profile binding is missing");
|
|
@@ -55999,7 +56272,7 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
|
|
|
55999
56272
|
throw new Error("NATIVE_SKILL_DRIFT: Hermes supervisor binding changed; run skills hook install");
|
|
56000
56273
|
assertHermesProtection(home, config, command, profile, supervisor);
|
|
56001
56274
|
} else if (agent === "sumi") {
|
|
56002
|
-
if (JSON.stringify(config.permissions?.filter((rule) => rule.action === "skill")) !== JSON.stringify(SUMI_SKILL_PERMISSIONS) || !isManagedSumiPlugin(readOptional(join28(sumiConfigDirectory(home), "plugins", "skills-cli.js")), command, profile))
|
|
56275
|
+
if (JSON.stringify(config.permissions?.filter((rule) => rule.action === "skill")) !== JSON.stringify(SUMI_SKILL_PERMISSIONS) || !isManagedSumiPlugin(readOptional(join28(sumiConfigDirectory(home, process.env, options.projectDir ?? process.cwd()), "plugins", "skills-cli.js")), command, profile))
|
|
56003
56276
|
throw new Error("NATIVE_SKILL_DRIFT: Sumi bridge protection changed; run skills hook install");
|
|
56004
56277
|
} else if (agent === "opencode") {
|
|
56005
56278
|
if (JSON.stringify(config.permission?.skill) !== JSON.stringify({ "*": "deny", [CLI_BRIDGE_NAME]: "allow" }) || readOptional(join28(home, ".config", "opencode", "plugins", "skills-cli.js")) !== renderOpenCodePlugin(command, profile))
|
|
@@ -56105,7 +56378,7 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
|
|
|
56105
56378
|
return escaped.length > 768 ? `${escaped.slice(0, 384)}...${escaped.slice(-381)}` : escaped;
|
|
56106
56379
|
});
|
|
56107
56380
|
const remaining = unexpected.length - paths.length;
|
|
56108
|
-
throw new Error(`NATIVE_SKILL_DRIFT: ${unexpected.length} unexpected native skill copies were found: ${paths.join(", ")}${remaining ? `; ${remaining} more` : ""}. Review skills migrate native --project <working-directory> --include-unmanaged --include-vendor --json before continuing; it inventories that directory and its ancestors. Use --apply after reviewing the archive plan.${adapterRefusal ? ` Native policy adapter refused: ${adapterRefusal}` : ""}`);
|
|
56381
|
+
throw new Error(`NATIVE_SKILL_DRIFT: ${unexpected.length} unexpected native skill copies were found: ${paths.join(", ")}${remaining ? `; ${remaining} more` : ""}. Review skills migrate native --agent ${agent} --project <working-directory> --include-unmanaged --include-vendor --json before continuing; it inventories that directory and its ancestors. Use --apply after reviewing the archive plan.${adapterRefusal ? ` Native policy adapter refused: ${adapterRefusal}` : ""}`);
|
|
56109
56382
|
}
|
|
56110
56383
|
recheckRootAliases(aliases);
|
|
56111
56384
|
}
|
|
@@ -56170,7 +56443,7 @@ var init_agent_integration = __esm(() => {
|
|
|
56170
56443
|
});
|
|
56171
56444
|
|
|
56172
56445
|
// src/lib/home-migration.ts
|
|
56173
|
-
import { existsSync as existsSync14, mkdirSync as mkdirSync7, readdirSync as readdirSync9, renameSync as renameSync4, rmSync, statSync as
|
|
56446
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync7, readdirSync as readdirSync9, renameSync as renameSync4, rmSync, statSync as statSync11, writeFileSync as writeFileSync7 } from "fs";
|
|
56174
56447
|
import { join as join29 } from "path";
|
|
56175
56448
|
function layoutMigrationRecordPath(appDir) {
|
|
56176
56449
|
return join29(appDir, SKILLS_CACHE_DIRNAME, LAYOUT_MIGRATION_RECORD);
|
|
@@ -56183,7 +56456,7 @@ function migrationAppDir(homeDir2) {
|
|
|
56183
56456
|
}
|
|
56184
56457
|
function looksLikeSkillDirectory(path) {
|
|
56185
56458
|
try {
|
|
56186
|
-
if (!
|
|
56459
|
+
if (!statSync11(path).isDirectory())
|
|
56187
56460
|
return false;
|
|
56188
56461
|
} catch {
|
|
56189
56462
|
return false;
|
|
@@ -56315,7 +56588,7 @@ import {
|
|
|
56315
56588
|
readdirSync as readdirSync10,
|
|
56316
56589
|
renameSync as renameSync5,
|
|
56317
56590
|
rmSync as rmSync2,
|
|
56318
|
-
statSync as
|
|
56591
|
+
statSync as statSync12,
|
|
56319
56592
|
writeFileSync as writeFileSync8
|
|
56320
56593
|
} from "fs";
|
|
56321
56594
|
import { homedir as homedir4 } from "os";
|
|
@@ -56432,7 +56705,7 @@ function containsSkillDirectories(path) {
|
|
|
56432
56705
|
}
|
|
56433
56706
|
function isDirectory(path) {
|
|
56434
56707
|
try {
|
|
56435
|
-
return
|
|
56708
|
+
return statSync12(path).isDirectory();
|
|
56436
56709
|
} catch {
|
|
56437
56710
|
return false;
|
|
56438
56711
|
}
|
|
@@ -57962,8 +58235,8 @@ var init_plugin_projection = __esm(() => {
|
|
|
57962
58235
|
|
|
57963
58236
|
// src/lib/plugin-projection-store.ts
|
|
57964
58237
|
import { createHash as createHash22, randomUUID as randomUUID7 } from "crypto";
|
|
57965
|
-
import { constants as
|
|
57966
|
-
import { dirname as dirname18, isAbsolute as
|
|
58238
|
+
import { constants as constants15, closeSync as closeSync13, fchmodSync as fchmodSync2, fstatSync as fstatSync13, fsyncSync as fsyncSync6, linkSync as linkSync3, lstatSync as lstatSync23, mkdirSync as mkdirSync10, openSync as openSync13, opendirSync as opendirSync4, readSync as readSync10, renameSync as renameSync6, rmdirSync as rmdirSync3, rmSync as rmSync4, unlinkSync as unlinkSync5, writeSync as writeSync3 } from "fs";
|
|
58239
|
+
import { dirname as dirname18, isAbsolute as isAbsolute19, join as join34, parse as parse6, resolve as resolve18 } from "path";
|
|
57967
58240
|
function stat(path) {
|
|
57968
58241
|
try {
|
|
57969
58242
|
return lstatSync23(path, { bigint: true });
|
|
@@ -57974,7 +58247,7 @@ function stat(path) {
|
|
|
57974
58247
|
}
|
|
57975
58248
|
}
|
|
57976
58249
|
function canonical7(path) {
|
|
57977
|
-
pluginNeed(typeof path === "string" && path.length <= 8192 &&
|
|
58250
|
+
pluginNeed(typeof path === "string" && path.length <= 8192 && isAbsolute19(path) && resolve18(path) === path && !/[\x00-\x1f\x7f]/.test(path), "Plugin storage paths must be canonical absolute paths");
|
|
57978
58251
|
}
|
|
57979
58252
|
function owner(stats, system = false) {
|
|
57980
58253
|
const current = uid();
|
|
@@ -58324,8 +58597,8 @@ function pluginExecutableDigest(path) {
|
|
|
58324
58597
|
var READ_FLAGS, WRITE_FLAGS, uid = () => typeof process.getuid === "function" ? BigInt(process.getuid()) : undefined, missing = (error) => Boolean(error && typeof error === "object" && "code" in error && error.code === "ENOENT");
|
|
58325
58598
|
var init_plugin_projection_store = __esm(() => {
|
|
58326
58599
|
init_plugin_projection();
|
|
58327
|
-
READ_FLAGS =
|
|
58328
|
-
WRITE_FLAGS =
|
|
58600
|
+
READ_FLAGS = constants15.O_RDONLY | constants15.O_NOFOLLOW | constants15.O_NONBLOCK;
|
|
58601
|
+
WRITE_FLAGS = constants15.O_WRONLY | constants15.O_CREAT | constants15.O_EXCL | constants15.O_NOFOLLOW | constants15.O_NONBLOCK;
|
|
58329
58602
|
});
|
|
58330
58603
|
|
|
58331
58604
|
// src/lib/selected-manifest.ts
|
|
@@ -58356,7 +58629,7 @@ var init_selected_manifest = __esm(() => {
|
|
|
58356
58629
|
|
|
58357
58630
|
// src/lib/plugin-admission.ts
|
|
58358
58631
|
import { homedir as homedir6 } from "os";
|
|
58359
|
-
import { isAbsolute as
|
|
58632
|
+
import { isAbsolute as isAbsolute20, join as join35, resolve as resolve19 } from "path";
|
|
58360
58633
|
function pluginAdmissionRoot() {
|
|
58361
58634
|
return join35(homedir6(), ".hasna", "skills", "plugin-admission");
|
|
58362
58635
|
}
|
|
@@ -58369,7 +58642,7 @@ function validatePluginTarget(value) {
|
|
|
58369
58642
|
for (const registration of value.registrations) {
|
|
58370
58643
|
pluginKeys(registration, ["scope", "projectPath"]);
|
|
58371
58644
|
pluginNeed(registration.scope === "user" || registration.scope === "project", "Unsupported plugin registration scope");
|
|
58372
|
-
pluginNeed(registration.scope === "user" ? registration.projectPath === null : typeof registration.projectPath === "string" &&
|
|
58645
|
+
pluginNeed(registration.scope === "user" ? registration.projectPath === null : typeof registration.projectPath === "string" && isAbsolute20(registration.projectPath) && resolve19(registration.projectPath) === registration.projectPath, "Plugin scope requires its exact project path");
|
|
58373
58646
|
const key = JSON.stringify([registration.scope, registration.projectPath]);
|
|
58374
58647
|
pluginNeed(!scopes.has(key), "Duplicate plugin registration scope");
|
|
58375
58648
|
scopes.add(key);
|
|
@@ -58377,7 +58650,7 @@ function validatePluginTarget(value) {
|
|
|
58377
58650
|
for (const key of ["native", "resolver"]) {
|
|
58378
58651
|
pluginKeys(value[key], key === "native" ? ["version", "executable", "digest"] : ["executable", "digest"]);
|
|
58379
58652
|
pluginText(value[key].executable);
|
|
58380
|
-
pluginNeed(
|
|
58653
|
+
pluginNeed(isAbsolute20(value[key].executable) && resolve19(value[key].executable) === value[key].executable, "Plugin executable must have a canonical absolute path");
|
|
58381
58654
|
pluginDigest(value[key].digest);
|
|
58382
58655
|
}
|
|
58383
58656
|
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)");
|
|
@@ -58527,7 +58800,7 @@ function pluginResolverCommand(binding) {
|
|
|
58527
58800
|
}
|
|
58528
58801
|
function root(options) {
|
|
58529
58802
|
const path = options.storeRoot ?? pluginAdmissionRoot();
|
|
58530
|
-
pluginNeed(
|
|
58803
|
+
pluginNeed(isAbsolute20(path) && resolve19(path) === path, "Invalid plugin admission store root");
|
|
58531
58804
|
return path;
|
|
58532
58805
|
}
|
|
58533
58806
|
function pluginBindingPath(storeRoot, id) {
|
|
@@ -58734,8 +59007,8 @@ var init_plugin_admission = __esm(() => {
|
|
|
58734
59007
|
});
|
|
58735
59008
|
|
|
58736
59009
|
// src/lib/plugin-discovery.ts
|
|
58737
|
-
import { closeSync as closeSync14, constants as
|
|
58738
|
-
import { basename as basename10, dirname as dirname19, isAbsolute as
|
|
59010
|
+
import { closeSync as closeSync14, constants as constants16, fstatSync as fstatSync14, lstatSync as lstatSync24, openSync as openSync14, opendirSync as opendirSync5, readSync as readSync11 } from "fs";
|
|
59011
|
+
import { basename as basename10, dirname as dirname19, isAbsolute as isAbsolute21, join as join36, resolve as resolve20 } from "path";
|
|
58739
59012
|
function validateManagedPluginWitnesses(value) {
|
|
58740
59013
|
pluginNeed(Array.isArray(value) && value.length > 0 && value.length <= PLUGIN_PROJECTION_LIMITS.registrations, "Invalid managed plugin witness collection");
|
|
58741
59014
|
const seen = new Set;
|
|
@@ -58744,12 +59017,12 @@ function validateManagedPluginWitnesses(value) {
|
|
|
58744
59017
|
pluginNeed(typeof item.bindingId === "string" && /^[a-f0-9]{64}$/.test(item.bindingId) && !seen.has(item.bindingId), "Invalid or duplicate managed plugin witness");
|
|
58745
59018
|
seen.add(item.bindingId);
|
|
58746
59019
|
pluginText(item.storeRoot);
|
|
58747
|
-
pluginNeed(
|
|
59020
|
+
pluginNeed(isAbsolute21(item.storeRoot) && resolve20(item.storeRoot) === item.storeRoot, "Invalid plugin receipt store path");
|
|
58748
59021
|
}
|
|
58749
59022
|
}
|
|
58750
59023
|
function safe3(path) {
|
|
58751
59024
|
pluginText(path);
|
|
58752
|
-
pluginNeed(
|
|
59025
|
+
pluginNeed(isAbsolute21(path) && resolve20(path) === path, "Invalid plugin registry path");
|
|
58753
59026
|
for (let at2 = path;; at2 = dirname19(at2)) {
|
|
58754
59027
|
pluginNeed(!lstatSync24(at2, { throwIfNoEntry: false })?.isSymbolicLink(), "Plugin registry path traverses a symlink");
|
|
58755
59028
|
if (at2 === dirname19(at2))
|
|
@@ -58760,7 +59033,7 @@ function readRegistry(path) {
|
|
|
58760
59033
|
safe3(path);
|
|
58761
59034
|
const initial2 = lstatSync24(path);
|
|
58762
59035
|
pluginNeed(initial2.isFile() && initial2.size <= 1024 * 1024, "Plugin registry is not a bounded regular file");
|
|
58763
|
-
const fd = openSync14(path,
|
|
59036
|
+
const fd = openSync14(path, constants16.O_RDONLY | constants16.O_NOFOLLOW | constants16.O_NONBLOCK);
|
|
58764
59037
|
try {
|
|
58765
59038
|
const opened = fstatSync14(fd);
|
|
58766
59039
|
pluginNeed(opened.isFile() && opened.ino === initial2.ino && opened.dev === initial2.dev, "Plugin registry changed during open");
|
|
@@ -58886,14 +59159,14 @@ var init_plugin_discovery = __esm(() => {
|
|
|
58886
59159
|
|
|
58887
59160
|
// src/lib/claude-marketplace-registry.ts
|
|
58888
59161
|
import { createHash as createHash23 } from "crypto";
|
|
58889
|
-
import { closeSync as closeSync15, constants as
|
|
58890
|
-
import { basename as basename11, dirname as dirname20, isAbsolute as
|
|
59162
|
+
import { closeSync as closeSync15, constants as constants17, fstatSync as fstatSync15, lstatSync as lstatSync25, openSync as openSync15, readSync as readSync12 } from "fs";
|
|
59163
|
+
import { basename as basename11, dirname as dirname20, isAbsolute as isAbsolute22, resolve as resolve21 } from "path";
|
|
58891
59164
|
function need7(value, reason2) {
|
|
58892
59165
|
if (!value)
|
|
58893
59166
|
throw new Error(`Claude marketplace registry ${reason2}`);
|
|
58894
59167
|
}
|
|
58895
|
-
function
|
|
58896
|
-
need7(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) &&
|
|
59168
|
+
function absolutePath4(value) {
|
|
59169
|
+
need7(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute22(value) && resolve21(value) === value, "requires a normalized absolute path");
|
|
58897
59170
|
}
|
|
58898
59171
|
function parents2(path) {
|
|
58899
59172
|
const result2 = [];
|
|
@@ -58906,13 +59179,13 @@ function parents2(path) {
|
|
|
58906
59179
|
}
|
|
58907
59180
|
}
|
|
58908
59181
|
function readRegistry2(path, budget2) {
|
|
58909
|
-
|
|
59182
|
+
absolutePath4(path);
|
|
58910
59183
|
need7(basename11(path) === "known_marketplaces.json", "requires known_marketplaces.json");
|
|
58911
59184
|
need7(Number.isSafeInteger(budget2.remaining) && budget2.remaining >= 0, "has an invalid byte budget");
|
|
58912
59185
|
const ancestors2 = parents2(path), initial2 = lstatSync25(path, { bigint: true });
|
|
58913
59186
|
need7(initial2.isFile() && !initial2.isSymbolicLink() && initial2.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
|
|
58914
59187
|
need7(initial2.size <= BigInt(budget2.remaining), "exceeds its aggregate byte limit");
|
|
58915
|
-
const fd = openSync15(path,
|
|
59188
|
+
const fd = openSync15(path, constants17.O_RDONLY | constants17.O_NOFOLLOW | constants17.O_NONBLOCK);
|
|
58916
59189
|
try {
|
|
58917
59190
|
const opened = fstatSync15(fd, { bigint: true });
|
|
58918
59191
|
need7(opened.isFile() && sameFile2(initial2, opened), "changed during open");
|
|
@@ -59039,8 +59312,8 @@ function normalizeRow(row, version = 1) {
|
|
|
59039
59312
|
return;
|
|
59040
59313
|
const sourceLocation = textField(field2(source, location));
|
|
59041
59314
|
if (type.value === "directory")
|
|
59042
|
-
|
|
59043
|
-
|
|
59315
|
+
absolutePath4(sourceLocation);
|
|
59316
|
+
absolutePath4(textField(field2(row, "installLocation")));
|
|
59044
59317
|
const updated = textField(field2(row, "lastUpdated"));
|
|
59045
59318
|
need7(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(updated), "contains an invalid recognized update timestamp");
|
|
59046
59319
|
const millis = Date.parse(updated);
|
|
@@ -59201,7 +59474,7 @@ var fail3 = () => new Error('CODEX_HOOK_TRUST_UNSUPPORTED_LAYOUT: preserve and c
|
|
|
59201
59474
|
var init_codex_hook_trust_layout = () => {};
|
|
59202
59475
|
|
|
59203
59476
|
// src/lib/codex-hook-additions-review.ts
|
|
59204
|
-
import { isAbsolute as
|
|
59477
|
+
import { isAbsolute as isAbsolute23 } from "path";
|
|
59205
59478
|
import { isDeepStrictEqual as isDeepStrictEqual9 } from "util";
|
|
59206
59479
|
function exactKeys2(value, keys2) {
|
|
59207
59480
|
need6(value && typeof value === "object" && !Array.isArray(value) && isDeepStrictEqual9(Object.keys(value).sort(), [...keys2].sort()), "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
|
|
@@ -59215,7 +59488,7 @@ function readReviewedAdditionTrustStates(proof, before2, current, journalHooks)
|
|
|
59215
59488
|
return captured.states;
|
|
59216
59489
|
}
|
|
59217
59490
|
function reviewNativeHookAdditions(options) {
|
|
59218
|
-
need6(
|
|
59491
|
+
need6(isAbsolute23(options.path), "RECONCILE_ADDITIONS_REVIEW_PATH");
|
|
59219
59492
|
const reviewFile = snapshot(options.path, true), review = JSON.parse(reviewFile.text);
|
|
59220
59493
|
exactKeys2(review, ["version", "kind", "reason", "producerEvidence", "journalIntentSha256", "policySha256", "configCurrentSha256", "hooksCurrentSha256", "producerBefore", "additions"]);
|
|
59221
59494
|
need6((review.version === 1 || review.version === 2) && review.kind === "native-hook-additions" && text2(review.reason) && text2(review.producerEvidence), "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
|
|
@@ -59223,7 +59496,7 @@ function reviewNativeHookAdditions(options) {
|
|
|
59223
59496
|
need6(hash2(review[name]) && review[name] === expected, "RECONCILE_ADDITIONS_REVIEW_CHANGED");
|
|
59224
59497
|
exactKeys2(review.producerBefore, ["configPath", "configSha256", "hooksPath", "hooksSha256"]);
|
|
59225
59498
|
const before2 = review.producerBefore;
|
|
59226
|
-
need6(
|
|
59499
|
+
need6(isAbsolute23(before2.configPath) && isAbsolute23(before2.hooksPath) && hash2(before2.configSha256) && hash2(before2.hooksSha256), "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
|
|
59227
59500
|
const producerConfig = snapshot(before2.configPath, true), producerHooks = snapshot(before2.hooksPath, true);
|
|
59228
59501
|
need6(producerConfig.sha256 === before2.configSha256 && producerHooks.sha256 === before2.hooksSha256 && producerHooks.sha256 === options.hooksBefore.sha256, "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
|
|
59229
59502
|
const original = structure(options.configBefore.text), producer = structure(producerConfig.text), expectedProducer = structuredClone(original), originalKeys = options.journalHooks.map((hook) => hook.key);
|
|
@@ -59316,13 +59589,13 @@ function createCodexHookDiscoveryRecovery(binding, before2, current, hooks, addi
|
|
|
59316
59589
|
need6(isDeepStrictEqual10(expected, actual) && codexTrustReconcileWitness(before2.text, keys2) === codexTrustReconcileWitness(current.text, keys2) && codexTrustUnmanagedSemantic(before2.text, keys2) === codexTrustUnmanagedSemantic(current.text, keys2), "RECONCILE_DISCOVERY_TRUST_WITNESS");
|
|
59317
59590
|
unchanged2(before2);
|
|
59318
59591
|
unchanged2(current);
|
|
59319
|
-
const witness = Object.freeze({ configPath: current.file, beforeSha256: before2.sha256, currentSha256: current.sha256, discoverySha256:
|
|
59592
|
+
const witness = Object.freeze({ configPath: current.file, beforeSha256: before2.sha256, currentSha256: current.sha256, discoverySha256: discoveryDigest(binding), typedProjectionSha256: projection });
|
|
59320
59593
|
proofs2.set(witness, { before: before2, current, recheckAdditions });
|
|
59321
59594
|
return witness;
|
|
59322
59595
|
}
|
|
59323
59596
|
function assertCodexHookDiscoveryRecovery(binding, witness) {
|
|
59324
59597
|
const proof = proofs2.get(witness);
|
|
59325
|
-
need6(!!proof && binding.agent === "codex" && witness.discoverySha256 ===
|
|
59598
|
+
need6(!!proof && binding.agent === "codex" && witness.discoverySha256 === discoveryDigest(binding), "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
|
|
59326
59599
|
unchanged2(proof.before);
|
|
59327
59600
|
unchanged2(proof.current);
|
|
59328
59601
|
proof.recheckAdditions();
|
|
@@ -59334,7 +59607,14 @@ function verifiesCodexHookDiscoverySource(binding, source, currentDigest, witnes
|
|
|
59334
59607
|
need6(source.sha256 === witness.beforeSha256 && currentDigest === witness.currentSha256, "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
|
|
59335
59608
|
return true;
|
|
59336
59609
|
}
|
|
59337
|
-
var sha4 = (text3) => createHash24("sha256").update(text3).digest("hex"), fields, structure2 = (text3) => JSON.parse(JSON.stringify(Bun.TOML.parse(text3))),
|
|
59610
|
+
var sha4 = (text3) => createHash24("sha256").update(text3).digest("hex"), fields, structure2 = (text3) => JSON.parse(JSON.stringify(Bun.TOML.parse(text3))), discoveryDigest = (binding) => {
|
|
59611
|
+
const controls = binding.codexDisabledPluginSkills;
|
|
59612
|
+
if (!Object.hasOwn(binding, "codexDisabledPluginSkills") || Array.isArray(controls) && controls.length === 0) {
|
|
59613
|
+
const { codexDisabledPluginSkills: _controls, ...withoutControls } = binding;
|
|
59614
|
+
return sha4(JSON.stringify({ ...withoutControls, codexDisabledPluginSkills: [] }));
|
|
59615
|
+
}
|
|
59616
|
+
return sha4(JSON.stringify(binding));
|
|
59617
|
+
}, proofs2;
|
|
59338
59618
|
var init_codex_hook_discovery_recovery = __esm(() => {
|
|
59339
59619
|
init_codex_hook_trust_files();
|
|
59340
59620
|
init_codex_hook_trust_layout();
|
|
@@ -59347,7 +59627,7 @@ var init_codex_hook_discovery_recovery = __esm(() => {
|
|
|
59347
59627
|
// src/lib/agent-discovery.ts
|
|
59348
59628
|
import { createHash as createHash25 } from "crypto";
|
|
59349
59629
|
import { lstatSync as lstatSync26, readFileSync as readFileSync21, readdirSync as readdirSync11, realpathSync as realpathSync11 } from "fs";
|
|
59350
|
-
import { basename as basename12, dirname as dirname21, isAbsolute as
|
|
59630
|
+
import { basename as basename12, dirname as dirname21, isAbsolute as isAbsolute24, join as join37, resolve as resolve22, sep as sep8 } from "path";
|
|
59351
59631
|
import { isDeepStrictEqual as isDeepStrictEqual11 } from "util";
|
|
59352
59632
|
function discoveryRootUnresolved(agent, command, detail) {
|
|
59353
59633
|
return new Error(`${DISCOVERY_ROOT_UNRESOLVED}: ${agent} discovery cannot resolve its "${command}" executable: ${detail}. The reviewed discovery is unchanged; this is an environment gap, not drift.`);
|
|
@@ -59381,7 +59661,7 @@ function parseConfig(text3, path, toml = false) {
|
|
|
59381
59661
|
}
|
|
59382
59662
|
}
|
|
59383
59663
|
function safe4(path) {
|
|
59384
|
-
if (!
|
|
59664
|
+
if (!isAbsolute24(path) || path.includes("\x00"))
|
|
59385
59665
|
throw new Error("Expected an absolute native discovery path");
|
|
59386
59666
|
for (let cursor = path;; cursor = dirname21(cursor)) {
|
|
59387
59667
|
if (lstatSync26(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
@@ -59401,19 +59681,20 @@ function read2(path, changes) {
|
|
|
59401
59681
|
throw new Error(`Unsupported or oversized native discovery input: ${path}`);
|
|
59402
59682
|
return readFileSync21(path, "utf8");
|
|
59403
59683
|
}
|
|
59404
|
-
function assertReviewedClaudeCacheClosures(home, config, review) {
|
|
59684
|
+
function assertReviewedClaudeCacheClosures(home, config, review, canonical8) {
|
|
59405
59685
|
const enabledIds = Object.entries(config.enabledPlugins ?? {}).filter(([, enabled]) => enabled === true).map(([id]) => id);
|
|
59406
59686
|
if (enabledIds.length === 0)
|
|
59407
59687
|
return;
|
|
59408
|
-
const registryPath = join37(home, ".claude/plugins/installed_plugins.json");
|
|
59409
|
-
const
|
|
59688
|
+
const registryPath = canonical8(join37(home, ".claude/plugins/installed_plugins.json"));
|
|
59689
|
+
const cacheAliasRoot = join37(home, ".claude/plugins/cache");
|
|
59690
|
+
const cacheRoot = canonical8(cacheAliasRoot);
|
|
59410
59691
|
const registryText = read2(registryPath);
|
|
59411
59692
|
if (registryText === null)
|
|
59412
59693
|
return;
|
|
59413
59694
|
const registry = parseConfig(registryText, registryPath);
|
|
59414
59695
|
if (registry.version !== 2 || !registry.plugins || typeof registry.plugins !== "object" || Array.isArray(registry.plugins))
|
|
59415
59696
|
throw new Error("Reviewed Claude installed plugin registrations are invalid");
|
|
59416
|
-
const cachePath = (path) => typeof path === "string" &&
|
|
59697
|
+
const cachePath = (path) => typeof path === "string" && isAbsolute24(path) && resolve22(path) === path && [cacheAliasRoot, cacheRoot].some((root2) => path === root2 || path.startsWith(root2 + sep8));
|
|
59417
59698
|
const activeRoots = new Set;
|
|
59418
59699
|
for (const id of enabledIds) {
|
|
59419
59700
|
const rows = registry.plugins[id];
|
|
@@ -59425,13 +59706,13 @@ function assertReviewedClaudeCacheClosures(home, config, review) {
|
|
|
59425
59706
|
if (!row || typeof row !== "object" || Array.isArray(row) || typeof row.installPath !== "string") {
|
|
59426
59707
|
throw new Error("Reviewed Claude enabled plugin registration requires an object with an installPath string");
|
|
59427
59708
|
}
|
|
59428
|
-
if (
|
|
59709
|
+
if ([cacheAliasRoot, cacheRoot].some((root2) => row.installPath === root2 || row.installPath.startsWith(root2 + sep8))) {
|
|
59429
59710
|
if (!cachePath(row.installPath) || row.installPath.length > AGENT_POLICY_LIMITS.pathCharacters || row.version !== undefined && (typeof row.version !== "string" || basename12(row.installPath) !== row.version)) {
|
|
59430
59711
|
throw new Error("Reviewed Claude discovery has a malformed active cache registration");
|
|
59431
59712
|
}
|
|
59432
|
-
if (row.scope === "user" && (row.projectPath === undefined || row.projectPath === null)) {} else if (row.scope === "project" && typeof row.projectPath === "string" &&
|
|
59713
|
+
if (row.scope === "user" && (row.projectPath === undefined || row.projectPath === null)) {} else if (row.scope === "project" && typeof row.projectPath === "string" && isAbsolute24(row.projectPath) && resolve22(row.projectPath) === row.projectPath && row.projectPath.length <= AGENT_POLICY_LIMITS.pathCharacters) {} else
|
|
59433
59714
|
throw new Error("Reviewed Claude discovery has an unsupported active cache registration scope");
|
|
59434
|
-
activeRoots.add(row.installPath);
|
|
59715
|
+
activeRoots.add(canonical8(row.installPath));
|
|
59435
59716
|
}
|
|
59436
59717
|
}
|
|
59437
59718
|
}
|
|
@@ -59676,12 +59957,12 @@ function absentRetiredClaudeRoots(binding) {
|
|
|
59676
59957
|
if (!row || typeof row !== "object" || Array.isArray(row))
|
|
59677
59958
|
return null;
|
|
59678
59959
|
const value = row;
|
|
59679
|
-
if (typeof value.installPath !== "string" || /[\x00-\x1f\x7f]/.test(value.installPath) || !
|
|
59960
|
+
if (typeof value.installPath !== "string" || /[\x00-\x1f\x7f]/.test(value.installPath) || !isAbsolute24(value.installPath) || resolve22(value.installPath) !== value.installPath || value.installPath.length > AGENT_POLICY_LIMITS.pathCharacters)
|
|
59680
59961
|
return null;
|
|
59681
59962
|
if (value.scope === "user")
|
|
59682
59963
|
return value.projectPath === undefined || value.projectPath === null ? "user\x00" : null;
|
|
59683
59964
|
if (value.scope === "project")
|
|
59684
|
-
return typeof value.projectPath === "string" && !/[\x00-\x1f\x7f]/.test(value.projectPath) && value.projectPath.length <= AGENT_POLICY_LIMITS.pathCharacters &&
|
|
59965
|
+
return typeof value.projectPath === "string" && !/[\x00-\x1f\x7f]/.test(value.projectPath) && value.projectPath.length <= AGENT_POLICY_LIMITS.pathCharacters && isAbsolute24(value.projectPath) && resolve22(value.projectPath) === value.projectPath ? `project\x00${value.projectPath}` : null;
|
|
59685
59966
|
return null;
|
|
59686
59967
|
};
|
|
59687
59968
|
if (Object.values(installed.plugins).some((value) => !Array.isArray(value) || value.some((row) => !row || typeof row.installPath !== "string" || row.installPath === root2 || row.installPath.startsWith(root2 + sep8) || root2.startsWith(row.installPath + sep8))))
|
|
@@ -59945,7 +60226,7 @@ function resolveAgentDiscovery(options) {
|
|
|
59945
60226
|
if (config.skills !== undefined && (!Array.isArray(config.skills) || config.skills.some((path) => typeof path !== "string")))
|
|
59946
60227
|
unresolved("skills must be a string array");
|
|
59947
60228
|
for (const value of config.skills ?? []) {
|
|
59948
|
-
if (typeof value !== "string" || /[\0$]/.test(value) || !value || !(
|
|
60229
|
+
if (typeof value !== "string" || /[\0$]/.test(value) || !value || !(isAbsolute24(value) || value.startsWith("~/")))
|
|
59949
60230
|
unresolved("remote or relative skill sources need a dedicated discovery adapter");
|
|
59950
60231
|
roots.add(canonical8(value.startsWith("~/") ? join37(home, value.slice(2)) : value));
|
|
59951
60232
|
}
|
|
@@ -60075,7 +60356,7 @@ function resolveAgentDiscovery(options) {
|
|
|
60075
60356
|
return { path: source.path, sha256: manifestSha256, hashMode: "claude-plugin-manifest-v1" };
|
|
60076
60357
|
});
|
|
60077
60358
|
if (agent === "claude")
|
|
60078
|
-
assertReviewedClaudeCacheClosures(home, config, review);
|
|
60359
|
+
assertReviewedClaudeCacheClosures(home, config, review, canonical8);
|
|
60079
60360
|
const combined = [...reviewedSources, ...reviewedSourcesWithManifestProjection];
|
|
60080
60361
|
const unique = combined.filter((source, index) => combined.findIndex((candidate2) => isDeepStrictEqual11(candidate2, source)) === index);
|
|
60081
60362
|
return { ...supplied, roots: [...new Set([...roots, ...supplied.roots])].sort(), sources: unique, ...agent === "gemini" ? { builtinNames } : {} };
|
|
@@ -60135,7 +60416,7 @@ function resolveAgentDiscovery(options) {
|
|
|
60135
60416
|
unresolved("unsupported plugin enablement");
|
|
60136
60417
|
const split2 = id.lastIndexOf("@"), name = id.slice(0, split2), marketplace = id.slice(split2 + 1);
|
|
60137
60418
|
const market = config.marketplaces?.[marketplace] ?? (marketplace === "personal" ? { source_type: "local", source: home } : undefined);
|
|
60138
|
-
if (split2 < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !
|
|
60419
|
+
if (split2 < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !isAbsolute24(market.source))
|
|
60139
60420
|
unresolved("enabled plugin marketplace is not an explicit local source");
|
|
60140
60421
|
const catalogText = witness(join37(market.source, ".agents/plugins/marketplace.json"));
|
|
60141
60422
|
if (catalogText === null)
|
|
@@ -60151,7 +60432,7 @@ function resolveAgentDiscovery(options) {
|
|
|
60151
60432
|
if ((config.plugin?.length ?? 0) > 0 || config.skills?.urls?.length)
|
|
60152
60433
|
unresolved("external plugin or remote skill source");
|
|
60153
60434
|
for (const path of config.skills?.paths ?? []) {
|
|
60154
|
-
if (typeof path !== "string" || !
|
|
60435
|
+
if (typeof path !== "string" || !isAbsolute24(path))
|
|
60155
60436
|
unresolved("relative or malformed added skill root");
|
|
60156
60437
|
roots.add(path);
|
|
60157
60438
|
}
|
|
@@ -60336,10 +60617,10 @@ import {
|
|
|
60336
60617
|
realpathSync as realpathSync13,
|
|
60337
60618
|
renameSync as renameSync7,
|
|
60338
60619
|
rmSync as rmSync5,
|
|
60339
|
-
statSync as
|
|
60620
|
+
statSync as statSync13,
|
|
60340
60621
|
writeFileSync as writeFileSync10
|
|
60341
60622
|
} from "fs";
|
|
60342
|
-
import { basename as basename14, dirname as dirname23, isAbsolute as
|
|
60623
|
+
import { basename as basename14, dirname as dirname23, isAbsolute as isAbsolute25, join as join39, normalize as normalize4, relative as relative7, resolve as resolve24, sep as sep10 } from "path";
|
|
60343
60624
|
function getPortableSkillsRoot(options = {}) {
|
|
60344
60625
|
return resolvePortableSkillsRoot(options, true);
|
|
60345
60626
|
}
|
|
@@ -60367,7 +60648,7 @@ function findPortableSkill(name, options = {}) {
|
|
|
60367
60648
|
return null;
|
|
60368
60649
|
}
|
|
60369
60650
|
const path = getPortableSkillPath(normalized, options);
|
|
60370
|
-
if (!existsSync19(path) || !
|
|
60651
|
+
if (!existsSync19(path) || !statSync13(path).isDirectory())
|
|
60371
60652
|
return null;
|
|
60372
60653
|
try {
|
|
60373
60654
|
return summarizePortableSkill(path, normalized);
|
|
@@ -60438,7 +60719,7 @@ function scaffoldPortableSkill(name, options = {}) {
|
|
|
60438
60719
|
}
|
|
60439
60720
|
function portPortableSkillDirectory(sourceDir, options = {}) {
|
|
60440
60721
|
const absoluteSource = normalize4(sourceDir);
|
|
60441
|
-
if (!existsSync19(absoluteSource) || !
|
|
60722
|
+
if (!existsSync19(absoluteSource) || !statSync13(absoluteSource).isDirectory()) {
|
|
60442
60723
|
throw new Error(`Import directory not found: ${sourceDir}`);
|
|
60443
60724
|
}
|
|
60444
60725
|
const continueOnError = options.continueOnError ?? true;
|
|
@@ -60497,7 +60778,7 @@ function assertDisjointImportPaths(source, destination) {
|
|
|
60497
60778
|
const destinationPath = physicalImportPath(destination);
|
|
60498
60779
|
const contains2 = (parent, child2) => {
|
|
60499
60780
|
const path = relative7(parent, child2);
|
|
60500
|
-
return path === "" || !
|
|
60781
|
+
return path === "" || !isAbsolute25(path) && path !== ".." && !path.startsWith(`..${sep10}`);
|
|
60501
60782
|
};
|
|
60502
60783
|
if (contains2(sourcePath, destinationPath) || contains2(destinationPath, sourcePath)) {
|
|
60503
60784
|
throw new Error("Source and destination skill directories must not overlap");
|
|
@@ -60505,7 +60786,7 @@ function assertDisjointImportPaths(source, destination) {
|
|
|
60505
60786
|
}
|
|
60506
60787
|
function portPortableSkill(sourcePath, options = {}) {
|
|
60507
60788
|
const absoluteSource = normalize4(sourcePath);
|
|
60508
|
-
if (!existsSync19(absoluteSource) || !
|
|
60789
|
+
if (!existsSync19(absoluteSource) || !statSync13(absoluteSource).isDirectory()) {
|
|
60509
60790
|
throw new Error(`Skill source directory not found: ${sourcePath}`);
|
|
60510
60791
|
}
|
|
60511
60792
|
const inferred = readPortableSkillManifestForImport(absoluteSource);
|
|
@@ -60668,7 +60949,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
60668
60949
|
const entryPath = join39(skillPath, command.entry);
|
|
60669
60950
|
if (!existsSync19(entryPath))
|
|
60670
60951
|
add4(issues, "portable.command_entry_missing", `Command '${command.name}' entry '${command.entry}' is missing`);
|
|
60671
|
-
else if (
|
|
60952
|
+
else if (statSync13(entryPath).isDirectory())
|
|
60672
60953
|
add4(issues, "portable.command_entry_directory", `Command '${command.name}' entry '${command.entry}' must be a file`);
|
|
60673
60954
|
}
|
|
60674
60955
|
}
|
|
@@ -60708,13 +60989,13 @@ function summarizePortableSkill(skillPath, fallbackName) {
|
|
|
60708
60989
|
}
|
|
60709
60990
|
function safeIsDirectory(path) {
|
|
60710
60991
|
try {
|
|
60711
|
-
return
|
|
60992
|
+
return statSync13(path).isDirectory();
|
|
60712
60993
|
} catch {
|
|
60713
60994
|
return false;
|
|
60714
60995
|
}
|
|
60715
60996
|
}
|
|
60716
60997
|
function isSafeRelativePath2(value) {
|
|
60717
|
-
if (!value.trim() ||
|
|
60998
|
+
if (!value.trim() || isAbsolute25(value))
|
|
60718
60999
|
return false;
|
|
60719
61000
|
const normalized = normalize4(value).replace(/\\/g, "/");
|
|
60720
61001
|
return normalized !== ".." && !normalized.startsWith("../") && !normalized.includes("/../");
|
|
@@ -62721,7 +63002,7 @@ var require_cli_spinners = __commonJS((exports, module) => {
|
|
|
62721
63002
|
});
|
|
62722
63003
|
|
|
62723
63004
|
// src/lib/auth-store.ts
|
|
62724
|
-
import { chmodSync as chmodSync2, existsSync as existsSync21, mkdirSync as mkdirSync12, readFileSync as readFileSync25, renameSync as renameSync8, statSync as
|
|
63005
|
+
import { chmodSync as chmodSync2, existsSync as existsSync21, mkdirSync as mkdirSync12, readFileSync as readFileSync25, renameSync as renameSync8, statSync as statSync14, unlinkSync as unlinkSync6, writeFileSync as writeFileSync11 } from "fs";
|
|
62725
63006
|
import { basename as basename15, dirname as dirname24, join as join41 } from "path";
|
|
62726
63007
|
function getAuthFilePath(env3 = process.env) {
|
|
62727
63008
|
return skillsCredentialFilePath(env3);
|
|
@@ -62935,7 +63216,7 @@ function getApiUrl(action, env3 = process.env, options = {}) {
|
|
|
62935
63216
|
}
|
|
62936
63217
|
function credentialFileMode(env3 = process.env) {
|
|
62937
63218
|
try {
|
|
62938
|
-
return
|
|
63219
|
+
return statSync14(skillsCredentialFilePath(env3)).mode & 511;
|
|
62939
63220
|
} catch {
|
|
62940
63221
|
return null;
|
|
62941
63222
|
}
|
|
@@ -65168,8 +65449,8 @@ var cuid, cuid2, ulid, xid, ksuid, nanoid, duration, extendedDuration, guid, uui
|
|
|
65168
65449
|
if (!version)
|
|
65169
65450
|
return /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/;
|
|
65170
65451
|
return new RegExp(`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${version}[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$`);
|
|
65171
|
-
}, uuid42, uuid6, uuid7, email2, html5Email, rfc5322Email, unicodeEmail, idnEmail, browserEmail, _emoji = `^[\\p{Extended_Pictographic}\\p{Emoji_Component}]+$`, ipv4, ipv6, mac = (
|
|
65172
|
-
const escapedDelim = escapeRegex(
|
|
65452
|
+
}, uuid42, uuid6, uuid7, email2, html5Email, rfc5322Email, unicodeEmail, idnEmail, browserEmail, _emoji = `^[\\p{Extended_Pictographic}\\p{Emoji_Component}]+$`, ipv4, ipv6, mac = (delimiter3) => {
|
|
65453
|
+
const escapedDelim = escapeRegex(delimiter3 ?? ":");
|
|
65173
65454
|
return new RegExp(`^(?:[0-9A-F]{2}${escapedDelim}){5}[0-9A-F]{2}$|^(?:[0-9a-f]{2}${escapedDelim}){5}[0-9a-f]{2}$`);
|
|
65174
65455
|
}, cidrv4, cidrv6, base64, base64url, hostname2, domain, httpProtocol, e164, creditCard, dateSource = `(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))`, date2, string = (params) => {
|
|
65175
65456
|
const regex2 = params ? `[\\s\\S]{${params?.minimum ?? 0},${params?.maximum ?? ""}}` : `[\\s\\S]*`;
|
|
@@ -88469,7 +88750,7 @@ var init_init = __esm(() => {
|
|
|
88469
88750
|
});
|
|
88470
88751
|
|
|
88471
88752
|
// src/lib/home-adoption.ts
|
|
88472
|
-
import { constants as
|
|
88753
|
+
import { constants as constants18, closeSync as closeSync16, fstatSync as fstatSync16, lstatSync as lstatSync28, openSync as openSync16, readSync as readSync14, existsSync as existsSync25, mkdirSync as mkdirSync15, readdirSync as readdirSync15, readFileSync as readFileSync30, rmSync as rmSync7, statSync as statSync15, writeFileSync as writeFileSync15 } from "fs";
|
|
88473
88754
|
import { homedir as homedir8 } from "os";
|
|
88474
88755
|
import { join as join47 } from "path";
|
|
88475
88756
|
function indexCanonicalCorpus(corpusRoot) {
|
|
@@ -88505,7 +88786,7 @@ function selectedHomeNames(options, index, homeDir2, agents) {
|
|
|
88505
88786
|
continue;
|
|
88506
88787
|
const present = agents.some((agent) => {
|
|
88507
88788
|
try {
|
|
88508
|
-
return
|
|
88789
|
+
return statSync15(join47(agentGlobalSkillsDir(agent, homeDir2), name)).isDirectory();
|
|
88509
88790
|
} catch {
|
|
88510
88791
|
return false;
|
|
88511
88792
|
}
|
|
@@ -88539,7 +88820,7 @@ function scanUnmarkedHomes(options = {}) {
|
|
|
88539
88820
|
continue;
|
|
88540
88821
|
const dir = join47(home, skill);
|
|
88541
88822
|
try {
|
|
88542
|
-
if (!
|
|
88823
|
+
if (!statSync15(dir).isDirectory())
|
|
88543
88824
|
continue;
|
|
88544
88825
|
} catch {
|
|
88545
88826
|
continue;
|
|
@@ -88552,7 +88833,7 @@ function scanUnmarkedHomes(options = {}) {
|
|
|
88552
88833
|
if (!existsSync25(skillMdPath))
|
|
88553
88834
|
continue;
|
|
88554
88835
|
const hash5 = hashSkillMarkdownFile(skillMdPath);
|
|
88555
|
-
const mtime =
|
|
88836
|
+
const mtime = statSync15(skillMdPath).mtime.toISOString();
|
|
88556
88837
|
const entry = { agent, skill, home, path: dir, hash: hash5, mtime };
|
|
88557
88838
|
const canonicalHash = index.get(skill);
|
|
88558
88839
|
if (canonicalHash === undefined) {
|
|
@@ -88647,7 +88928,7 @@ function pruneOwnership(dir) {
|
|
|
88647
88928
|
const markerPath = join47(dir, SYNC_MARKER_FILE), markerPathBefore = lstatSync28(markerPath);
|
|
88648
88929
|
if (!markerPathBefore.isFile())
|
|
88649
88930
|
return;
|
|
88650
|
-
descriptor = openSync16(markerPath,
|
|
88931
|
+
descriptor = openSync16(markerPath, constants18.O_RDONLY | constants18.O_NOFOLLOW | constants18.O_NONBLOCK);
|
|
88651
88932
|
const before2 = fstatSync16(descriptor);
|
|
88652
88933
|
if (!before2.isFile() || before2.dev !== markerPathBefore.dev || before2.ino !== markerPathBefore.ino || before2.size !== markerPathBefore.size || before2.mtimeMs !== markerPathBefore.mtimeMs || before2.ctimeMs !== markerPathBefore.ctimeMs || before2.size < 1 || before2.size > 65536)
|
|
88653
88934
|
return;
|
|
@@ -88698,7 +88979,7 @@ function pruneStrayHomes(options = {}) {
|
|
|
88698
88979
|
continue;
|
|
88699
88980
|
const dir = join47(home, skill);
|
|
88700
88981
|
try {
|
|
88701
|
-
if (!
|
|
88982
|
+
if (!statSync15(dir).isDirectory())
|
|
88702
88983
|
continue;
|
|
88703
88984
|
} catch {
|
|
88704
88985
|
continue;
|
|
@@ -88756,7 +89037,7 @@ var init_home_adoption = __esm(() => {
|
|
|
88756
89037
|
});
|
|
88757
89038
|
|
|
88758
89039
|
// src/lib/home-census.ts
|
|
88759
|
-
import { existsSync as existsSync26, readFileSync as readFileSync31, readdirSync as readdirSync16, statSync as
|
|
89040
|
+
import { existsSync as existsSync26, readFileSync as readFileSync31, readdirSync as readdirSync16, statSync as statSync16 } from "fs";
|
|
88760
89041
|
import { homedir as homedir9 } from "os";
|
|
88761
89042
|
import { join as join48 } from "path";
|
|
88762
89043
|
function sortEntries(entries) {
|
|
@@ -88801,7 +89082,7 @@ function censusHomeDrift(options = {}) {
|
|
|
88801
89082
|
continue;
|
|
88802
89083
|
const dir = join48(home, skill);
|
|
88803
89084
|
try {
|
|
88804
|
-
if (!
|
|
89085
|
+
if (!statSync16(dir).isDirectory())
|
|
88805
89086
|
continue;
|
|
88806
89087
|
} catch {
|
|
88807
89088
|
continue;
|
|
@@ -88872,13 +89153,13 @@ var init_home_census = __esm(() => {
|
|
|
88872
89153
|
});
|
|
88873
89154
|
|
|
88874
89155
|
// src/cli/env-assignment.ts
|
|
88875
|
-
import { closeSync as closeSync17, constants as
|
|
89156
|
+
import { closeSync as closeSync17, constants as constants19, fstatSync as fstatSync17, ftruncateSync as ftruncateSync2, lstatSync as lstatSync29, openSync as openSync17, readFileSync as readFileSync32, writeSync as writeSync4 } from "fs";
|
|
88876
89157
|
function serializeValue(value) {
|
|
88877
89158
|
if (controls.test(value))
|
|
88878
89159
|
throw new EnvAssignmentError("Environment values cannot contain control characters or newlines.");
|
|
88879
89160
|
if (/^[A-Za-z0-9_./:@+=,-]*$/.test(value))
|
|
88880
89161
|
return value;
|
|
88881
|
-
const quote3 = ["'", "`", '"'].find((
|
|
89162
|
+
const quote3 = ["'", "`", '"'].find((delimiter3) => !value.includes(delimiter3) && (delimiter3 !== '"' || !value.includes("\\")));
|
|
88882
89163
|
const trailingSlashes = value.match(/\\+$/)?.[0].length ?? 0;
|
|
88883
89164
|
if (!quote3 || trailingSlashes % 2 !== 0 || value.endsWith("\\$")) {
|
|
88884
89165
|
throw new EnvAssignmentError("Cannot safely encode this environment value; incompatible quote/backslash combinations require manual editing.");
|
|
@@ -88960,7 +89241,7 @@ function setEnvAssignment(path, assignment) {
|
|
|
88960
89241
|
})();
|
|
88961
89242
|
if (previous && !previous.isFile())
|
|
88962
89243
|
throw new EnvAssignmentError("The project .env must be a regular file, not a symlink or special file.");
|
|
88963
|
-
descriptor = openSync17(path, previous ?
|
|
89244
|
+
descriptor = openSync17(path, previous ? constants19.O_RDWR | constants19.O_NOFOLLOW | constants19.O_NONBLOCK : constants19.O_WRONLY | constants19.O_CREAT | constants19.O_EXCL | constants19.O_NOFOLLOW, 384);
|
|
88964
89245
|
const opened = fstatSync17(descriptor);
|
|
88965
89246
|
if (!opened.isFile() || previous && (opened.ino !== previous.ino || opened.dev !== previous.dev)) {
|
|
88966
89247
|
throw new EnvAssignmentError("The project .env changed while opening it; retry with a regular file.");
|
|
@@ -89054,7 +89335,7 @@ var exports_diagnostic = {};
|
|
|
89054
89335
|
__export(exports_diagnostic, {
|
|
89055
89336
|
registerDiagnostic: () => registerDiagnostic
|
|
89056
89337
|
});
|
|
89057
|
-
import { existsSync as existsSync27, readFileSync as readFileSync33, readdirSync as readdirSync17, statSync as
|
|
89338
|
+
import { existsSync as existsSync27, readFileSync as readFileSync33, readdirSync as readdirSync17, statSync as statSync17 } from "fs";
|
|
89058
89339
|
import { join as join49 } from "path";
|
|
89059
89340
|
import { execSync as execSync2 } from "child_process";
|
|
89060
89341
|
function registerDiagnostic(parent) {
|
|
@@ -89247,7 +89528,7 @@ function handleWhoami(options) {
|
|
|
89247
89528
|
let skillCount = 0;
|
|
89248
89529
|
if (exists)
|
|
89249
89530
|
try {
|
|
89250
|
-
skillCount = readdirSync17(agentSkillsPath).filter((f) => !f.startsWith(".") &&
|
|
89531
|
+
skillCount = readdirSync17(agentSkillsPath).filter((f) => !f.startsWith(".") && statSync17(join49(agentSkillsPath, f)).isDirectory()).length;
|
|
89251
89532
|
} catch {}
|
|
89252
89533
|
agentConfigs.push({ agent, label: AGENT_LABELS[agent], path: agentSkillsPath, exists, skillCount });
|
|
89253
89534
|
}
|
|
@@ -89505,12 +89786,12 @@ var init_cloud_executions = __esm(() => {
|
|
|
89505
89786
|
|
|
89506
89787
|
// node_modules/@hasna/secrets/dist/sdk.js
|
|
89507
89788
|
import { isIP as isIP3 } from "net";
|
|
89508
|
-
import { spawnSync as
|
|
89789
|
+
import { spawnSync as spawnSync4 } from "child_process";
|
|
89509
89790
|
import { closeSync as closeSync18, fstatSync as fstatSync18, openSync as openSync18, readFileSync as readFileSync34 } from "fs";
|
|
89510
89791
|
import { O_NOFOLLOW as O_NOFOLLOW3, O_NONBLOCK as O_NONBLOCK3, O_RDONLY as O_RDONLY3 } from "constants";
|
|
89511
89792
|
import { createRequire as createRequire2 } from "module";
|
|
89512
89793
|
import { hostname as osHostname2 } from "os";
|
|
89513
|
-
import { isAbsolute as
|
|
89794
|
+
import { isAbsolute as isAbsolute26, join as join50 } from "path";
|
|
89514
89795
|
import { createRequire as createRequire22 } from "module";
|
|
89515
89796
|
function envToken2(name) {
|
|
89516
89797
|
return name.toUpperCase().replace(/-/g, "_");
|
|
@@ -89534,7 +89815,7 @@ function homeDir2(env3) {
|
|
|
89534
89815
|
}
|
|
89535
89816
|
function absoluteOverride2(env3, key) {
|
|
89536
89817
|
const value = env3[key]?.trim();
|
|
89537
|
-
return value &&
|
|
89818
|
+
return value && isAbsolute26(value) ? value : null;
|
|
89538
89819
|
}
|
|
89539
89820
|
function hasnaHomeDir2(env3) {
|
|
89540
89821
|
const override = absoluteOverride2(env3, HASNA_HOME_ENV_KEY2);
|
|
@@ -89780,7 +90061,7 @@ function isAmbientEnvironment2(env3) {
|
|
|
89780
90061
|
return env3 === process.env || env3[AMBIENT_ENVIRONMENT2] === true;
|
|
89781
90062
|
}
|
|
89782
90063
|
function defaultKeychainRunner2(argv) {
|
|
89783
|
-
const result2 =
|
|
90064
|
+
const result2 = spawnSync4(KEYCHAIN_SECURITY_BIN2, [...argv], {
|
|
89784
90065
|
encoding: "utf8",
|
|
89785
90066
|
stdio: ["ignore", "pipe", "pipe"],
|
|
89786
90067
|
timeout: KEYCHAIN_SPAWN_TIMEOUT_MS2
|
|
@@ -90806,7 +91087,7 @@ var init_sdk = __esm(() => {
|
|
|
90806
91087
|
});
|
|
90807
91088
|
|
|
90808
91089
|
// src/lib/execution-secrets.ts
|
|
90809
|
-
import { constants as
|
|
91090
|
+
import { constants as constants20, closeSync as closeSync19, fstatSync as fstatSync19, openSync as openSync19, readSync as readSync15, realpathSync as realpathSync14 } from "fs";
|
|
90810
91091
|
import { hostname as stationHostname } from "os";
|
|
90811
91092
|
function selectedSecretBindingsTemplate(scope, names, createClient2 = createSecretsClientFromEnv) {
|
|
90812
91093
|
let secretsAuthority;
|
|
@@ -90850,7 +91131,7 @@ function declaredSecretNames(value) {
|
|
|
90850
91131
|
function readSelectedSecretBindings(path) {
|
|
90851
91132
|
let fd;
|
|
90852
91133
|
try {
|
|
90853
|
-
fd = openSync19(path,
|
|
91134
|
+
fd = openSync19(path, constants20.O_RDONLY | constants20.O_NOFOLLOW | constants20.O_NONBLOCK);
|
|
90854
91135
|
const stat2 = fstatSync19(fd);
|
|
90855
91136
|
if (!stat2.isFile() || stat2.size > 65536)
|
|
90856
91137
|
throw new Error;
|
|
@@ -95499,7 +95780,7 @@ var init_runs = __esm(() => {
|
|
|
95499
95780
|
|
|
95500
95781
|
// src/lib/run-state.ts
|
|
95501
95782
|
import { createHash as createHash33, randomBytes } from "crypto";
|
|
95502
|
-
import { existsSync as existsSync28, mkdirSync as mkdirSync17, readFileSync as readFileSync35, readdirSync as readdirSync18, statSync as
|
|
95783
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync17, readFileSync as readFileSync35, readdirSync as readdirSync18, statSync as statSync18, writeFileSync as writeFileSync17 } from "fs";
|
|
95503
95784
|
import { extname, join as join52, relative as relative8 } from "path";
|
|
95504
95785
|
function createSkillRun(params, targetDir = process.cwd()) {
|
|
95505
95786
|
const now3 = new Date;
|
|
@@ -95581,7 +95862,7 @@ function listSkillRuns(targetDir = process.cwd(), limit = 50) {
|
|
|
95581
95862
|
const records = [];
|
|
95582
95863
|
for (const day of readdirSync18(runsRoot).sort().reverse()) {
|
|
95583
95864
|
const dayDir = join52(runsRoot, day);
|
|
95584
|
-
if (!
|
|
95865
|
+
if (!statSync18(dayDir).isDirectory())
|
|
95585
95866
|
continue;
|
|
95586
95867
|
for (const runId2 of readdirSync18(dayDir).sort().reverse()) {
|
|
95587
95868
|
const record11 = readRunRecord(join52(dayDir, runId2));
|
|
@@ -95630,7 +95911,7 @@ function collectRunArtifacts(context) {
|
|
|
95630
95911
|
return [];
|
|
95631
95912
|
const artifacts = [];
|
|
95632
95913
|
for (const path of walkFiles(context.exportDir)) {
|
|
95633
|
-
const stat2 =
|
|
95914
|
+
const stat2 = statSync18(path);
|
|
95634
95915
|
const bytes = readFileSync35(path);
|
|
95635
95916
|
artifacts.push({
|
|
95636
95917
|
path: toProjectRelative(context.targetDir, path),
|
|
@@ -95655,7 +95936,7 @@ function walkFiles(dir) {
|
|
|
95655
95936
|
const files = [];
|
|
95656
95937
|
for (const entry of readdirSync18(dir)) {
|
|
95657
95938
|
const full = join52(dir, entry);
|
|
95658
|
-
if (
|
|
95939
|
+
if (statSync18(full).isDirectory())
|
|
95659
95940
|
files.push(...walkFiles(full));
|
|
95660
95941
|
else
|
|
95661
95942
|
files.push(full);
|
|
@@ -99592,11 +99873,11 @@ var require_codegen = __commonJS((exports) => {
|
|
|
99592
99873
|
const rhs = this.rhs === undefined ? "" : ` = ${this.rhs}`;
|
|
99593
99874
|
return `${varKind} ${this.name}${rhs};` + _n;
|
|
99594
99875
|
}
|
|
99595
|
-
optimizeNames(names,
|
|
99876
|
+
optimizeNames(names, constants21) {
|
|
99596
99877
|
if (!names[this.name.str])
|
|
99597
99878
|
return;
|
|
99598
99879
|
if (this.rhs)
|
|
99599
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
99880
|
+
this.rhs = optimizeExpr(this.rhs, names, constants21);
|
|
99600
99881
|
return this;
|
|
99601
99882
|
}
|
|
99602
99883
|
get names() {
|
|
@@ -99614,10 +99895,10 @@ var require_codegen = __commonJS((exports) => {
|
|
|
99614
99895
|
render({ _n }) {
|
|
99615
99896
|
return `${this.lhs} = ${this.rhs};` + _n;
|
|
99616
99897
|
}
|
|
99617
|
-
optimizeNames(names,
|
|
99898
|
+
optimizeNames(names, constants21) {
|
|
99618
99899
|
if (this.lhs instanceof code_1.Name && !names[this.lhs.str] && !this.sideEffects)
|
|
99619
99900
|
return;
|
|
99620
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
99901
|
+
this.rhs = optimizeExpr(this.rhs, names, constants21);
|
|
99621
99902
|
return this;
|
|
99622
99903
|
}
|
|
99623
99904
|
get names() {
|
|
@@ -99683,8 +99964,8 @@ var require_codegen = __commonJS((exports) => {
|
|
|
99683
99964
|
optimizeNodes() {
|
|
99684
99965
|
return `${this.code}` ? this : undefined;
|
|
99685
99966
|
}
|
|
99686
|
-
optimizeNames(names,
|
|
99687
|
-
this.code = optimizeExpr(this.code, names,
|
|
99967
|
+
optimizeNames(names, constants21) {
|
|
99968
|
+
this.code = optimizeExpr(this.code, names, constants21);
|
|
99688
99969
|
return this;
|
|
99689
99970
|
}
|
|
99690
99971
|
get names() {
|
|
@@ -99714,12 +99995,12 @@ var require_codegen = __commonJS((exports) => {
|
|
|
99714
99995
|
}
|
|
99715
99996
|
return nodes.length > 0 ? this : undefined;
|
|
99716
99997
|
}
|
|
99717
|
-
optimizeNames(names,
|
|
99998
|
+
optimizeNames(names, constants21) {
|
|
99718
99999
|
const { nodes } = this;
|
|
99719
100000
|
let i = nodes.length;
|
|
99720
100001
|
while (i--) {
|
|
99721
100002
|
const n2 = nodes[i];
|
|
99722
|
-
if (n2.optimizeNames(names,
|
|
100003
|
+
if (n2.optimizeNames(names, constants21))
|
|
99723
100004
|
continue;
|
|
99724
100005
|
subtractNames(names, n2.names);
|
|
99725
100006
|
nodes.splice(i, 1);
|
|
@@ -99776,12 +100057,12 @@ var require_codegen = __commonJS((exports) => {
|
|
|
99776
100057
|
return;
|
|
99777
100058
|
return this;
|
|
99778
100059
|
}
|
|
99779
|
-
optimizeNames(names,
|
|
100060
|
+
optimizeNames(names, constants21) {
|
|
99780
100061
|
var _a3;
|
|
99781
|
-
this.else = (_a3 = this.else) === null || _a3 === undefined ? undefined : _a3.optimizeNames(names,
|
|
99782
|
-
if (!(super.optimizeNames(names,
|
|
100062
|
+
this.else = (_a3 = this.else) === null || _a3 === undefined ? undefined : _a3.optimizeNames(names, constants21);
|
|
100063
|
+
if (!(super.optimizeNames(names, constants21) || this.else))
|
|
99783
100064
|
return;
|
|
99784
|
-
this.condition = optimizeExpr(this.condition, names,
|
|
100065
|
+
this.condition = optimizeExpr(this.condition, names, constants21);
|
|
99785
100066
|
return this;
|
|
99786
100067
|
}
|
|
99787
100068
|
get names() {
|
|
@@ -99806,10 +100087,10 @@ var require_codegen = __commonJS((exports) => {
|
|
|
99806
100087
|
render(opts) {
|
|
99807
100088
|
return `for(${this.iteration})` + super.render(opts);
|
|
99808
100089
|
}
|
|
99809
|
-
optimizeNames(names,
|
|
99810
|
-
if (!super.optimizeNames(names,
|
|
100090
|
+
optimizeNames(names, constants21) {
|
|
100091
|
+
if (!super.optimizeNames(names, constants21))
|
|
99811
100092
|
return;
|
|
99812
|
-
this.iteration = optimizeExpr(this.iteration, names,
|
|
100093
|
+
this.iteration = optimizeExpr(this.iteration, names, constants21);
|
|
99813
100094
|
return this;
|
|
99814
100095
|
}
|
|
99815
100096
|
get names() {
|
|
@@ -99847,10 +100128,10 @@ var require_codegen = __commonJS((exports) => {
|
|
|
99847
100128
|
render(opts) {
|
|
99848
100129
|
return `for(${this.varKind} ${this.name} ${this.loop} ${this.iterable})` + super.render(opts);
|
|
99849
100130
|
}
|
|
99850
|
-
optimizeNames(names,
|
|
99851
|
-
if (!super.optimizeNames(names,
|
|
100131
|
+
optimizeNames(names, constants21) {
|
|
100132
|
+
if (!super.optimizeNames(names, constants21))
|
|
99852
100133
|
return;
|
|
99853
|
-
this.iterable = optimizeExpr(this.iterable, names,
|
|
100134
|
+
this.iterable = optimizeExpr(this.iterable, names, constants21);
|
|
99854
100135
|
return this;
|
|
99855
100136
|
}
|
|
99856
100137
|
get names() {
|
|
@@ -99895,11 +100176,11 @@ var require_codegen = __commonJS((exports) => {
|
|
|
99895
100176
|
(_b = this.finally) === null || _b === undefined || _b.optimizeNodes();
|
|
99896
100177
|
return this;
|
|
99897
100178
|
}
|
|
99898
|
-
optimizeNames(names,
|
|
100179
|
+
optimizeNames(names, constants21) {
|
|
99899
100180
|
var _a3, _b;
|
|
99900
|
-
super.optimizeNames(names,
|
|
99901
|
-
(_a3 = this.catch) === null || _a3 === undefined || _a3.optimizeNames(names,
|
|
99902
|
-
(_b = this.finally) === null || _b === undefined || _b.optimizeNames(names,
|
|
100181
|
+
super.optimizeNames(names, constants21);
|
|
100182
|
+
(_a3 = this.catch) === null || _a3 === undefined || _a3.optimizeNames(names, constants21);
|
|
100183
|
+
(_b = this.finally) === null || _b === undefined || _b.optimizeNames(names, constants21);
|
|
99903
100184
|
return this;
|
|
99904
100185
|
}
|
|
99905
100186
|
get names() {
|
|
@@ -100173,7 +100454,7 @@ var require_codegen = __commonJS((exports) => {
|
|
|
100173
100454
|
function addExprNames(names, from) {
|
|
100174
100455
|
return from instanceof code_1._CodeOrName ? addNames(names, from.names) : names;
|
|
100175
100456
|
}
|
|
100176
|
-
function optimizeExpr(expr, names,
|
|
100457
|
+
function optimizeExpr(expr, names, constants21) {
|
|
100177
100458
|
if (expr instanceof code_1.Name)
|
|
100178
100459
|
return replaceName(expr);
|
|
100179
100460
|
if (!canOptimize(expr))
|
|
@@ -100188,14 +100469,14 @@ var require_codegen = __commonJS((exports) => {
|
|
|
100188
100469
|
return items;
|
|
100189
100470
|
}, []));
|
|
100190
100471
|
function replaceName(n2) {
|
|
100191
|
-
const c =
|
|
100472
|
+
const c = constants21[n2.str];
|
|
100192
100473
|
if (c === undefined || names[n2.str] !== 1)
|
|
100193
100474
|
return n2;
|
|
100194
100475
|
delete names[n2.str];
|
|
100195
100476
|
return c;
|
|
100196
100477
|
}
|
|
100197
100478
|
function canOptimize(e2) {
|
|
100198
|
-
return e2 instanceof code_1._Code && e2._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 &&
|
|
100479
|
+
return e2 instanceof code_1._Code && e2._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants21[c.str] !== undefined);
|
|
100199
100480
|
}
|
|
100200
100481
|
}
|
|
100201
100482
|
function subtractNames(names, from) {
|
|
@@ -107671,7 +107952,7 @@ var init_remote_customer_operations = __esm(() => {
|
|
|
107671
107952
|
});
|
|
107672
107953
|
|
|
107673
107954
|
// src/lib/workspace-profile.ts
|
|
107674
|
-
import { constants as
|
|
107955
|
+
import { constants as constants21, closeSync as closeSync20, fstatSync as fstatSync20, lstatSync as lstatSync30, mkdirSync as mkdirSync18, mkdtempSync as mkdtempSync5, openSync as openSync20, readFileSync as readFileSync36, renameSync as renameSync11, rmSync as rmSync8, writeFileSync as writeFileSync18 } from "fs";
|
|
107675
107956
|
import { dirname as dirname28, join as join53 } from "path";
|
|
107676
107957
|
function stat2(path) {
|
|
107677
107958
|
try {
|
|
@@ -107685,7 +107966,7 @@ function stat2(path) {
|
|
|
107685
107966
|
function safeText(file2) {
|
|
107686
107967
|
if (stat2(file2) === null)
|
|
107687
107968
|
return null;
|
|
107688
|
-
const fd = openSync20(file2,
|
|
107969
|
+
const fd = openSync20(file2, constants21.O_RDONLY | constants21.O_NOFOLLOW | constants21.O_NONBLOCK);
|
|
107689
107970
|
try {
|
|
107690
107971
|
const s = fstatSync20(fd);
|
|
107691
107972
|
if (!s.isFile() || s.size > 65536 || ![256, 384].includes(s.mode & 4095) || process.getuid && s.uid !== process.getuid())
|
|
@@ -108039,8 +108320,8 @@ var init_recurring_customer = __esm(() => {
|
|
|
108039
108320
|
});
|
|
108040
108321
|
|
|
108041
108322
|
// src/lib/recurring-recovery.ts
|
|
108042
|
-
import { constants as
|
|
108043
|
-
import { dirname as dirname29, isAbsolute as
|
|
108323
|
+
import { constants as constants22, closeSync as closeSync21, fsyncSync as fsyncSync7, fstatSync as fstatSync21, lstatSync as lstatSync31, mkdirSync as mkdirSync19, openSync as openSync21, readSync as readSync16, realpathSync as realpathSync16, renameSync as renameSync12, unlinkSync as unlinkSync8, writeFileSync as writeFileSync19 } from "fs";
|
|
108324
|
+
import { dirname as dirname29, isAbsolute as isAbsolute27, join as join54, resolve as resolve27 } from "path";
|
|
108044
108325
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
108045
108326
|
|
|
108046
108327
|
class RecoveryOwner {
|
|
@@ -108048,7 +108329,7 @@ class RecoveryOwner {
|
|
|
108048
108329
|
parents = [];
|
|
108049
108330
|
constructor(directory) {
|
|
108050
108331
|
this.directory = directory;
|
|
108051
|
-
if (!
|
|
108332
|
+
if (!isAbsolute27(directory) || resolve27(directory) !== directory || realpathSync16(directory) !== directory)
|
|
108052
108333
|
invalid6();
|
|
108053
108334
|
for (let path = directory;; path = dirname29(path)) {
|
|
108054
108335
|
const stat3 = lstatSync31(path);
|
|
@@ -108074,7 +108355,7 @@ class RecoveryOwner {
|
|
|
108074
108355
|
}
|
|
108075
108356
|
read(name) {
|
|
108076
108357
|
this.assert();
|
|
108077
|
-
const fd = openSync21(join54(this.directory, name),
|
|
108358
|
+
const fd = openSync21(join54(this.directory, name), constants22.O_RDONLY | constants22.O_NOFOLLOW | constants22.O_NONBLOCK);
|
|
108078
108359
|
try {
|
|
108079
108360
|
const before2 = fstatSync21(fd);
|
|
108080
108361
|
if (!before2.isFile() || before2.nlink !== 1 || (before2.mode & 4095) !== 384 || before2.size < 1 || before2.size > 8192 || process.getuid && before2.uid !== process.getuid())
|
|
@@ -108100,7 +108381,7 @@ class RecoveryOwner {
|
|
|
108100
108381
|
this.assert();
|
|
108101
108382
|
const bytes = canonicalJson2(value, 8192) + `
|
|
108102
108383
|
`;
|
|
108103
|
-
const fd = openSync21(join54(this.directory, name),
|
|
108384
|
+
const fd = openSync21(join54(this.directory, name), constants22.O_WRONLY | constants22.O_CREAT | constants22.O_EXCL | constants22.O_NOFOLLOW, 384);
|
|
108104
108385
|
try {
|
|
108105
108386
|
writeFileSync19(fd, bytes);
|
|
108106
108387
|
fsyncSync7(fd);
|
|
@@ -108112,7 +108393,7 @@ class RecoveryOwner {
|
|
|
108112
108393
|
}
|
|
108113
108394
|
sync() {
|
|
108114
108395
|
this.assert();
|
|
108115
|
-
const fd = openSync21(this.directory,
|
|
108396
|
+
const fd = openSync21(this.directory, constants22.O_RDONLY | constants22.O_NOFOLLOW);
|
|
108116
108397
|
try {
|
|
108117
108398
|
fsyncSync7(fd);
|
|
108118
108399
|
} finally {
|
|
@@ -108134,7 +108415,7 @@ class RecoveryOwner {
|
|
|
108134
108415
|
this.assert();
|
|
108135
108416
|
let fd;
|
|
108136
108417
|
try {
|
|
108137
|
-
fd = openSync21(join54(this.directory, "operation.lock"),
|
|
108418
|
+
fd = openSync21(join54(this.directory, "operation.lock"), constants22.O_WRONLY | constants22.O_CREAT | constants22.O_EXCL | constants22.O_NOFOLLOW, 384);
|
|
108138
108419
|
} catch {
|
|
108139
108420
|
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.");
|
|
108140
108421
|
}
|
|
@@ -108183,7 +108464,7 @@ function base2(customer, organizationId) {
|
|
|
108183
108464
|
};
|
|
108184
108465
|
}
|
|
108185
108466
|
function create3(directory, intent) {
|
|
108186
|
-
if (!
|
|
108467
|
+
if (!isAbsolute27(directory) || resolve27(directory) !== directory || realpathSync16(dirname29(directory)) !== dirname29(directory))
|
|
108187
108468
|
invalid6();
|
|
108188
108469
|
mkdirSync19(directory, { mode: 448 });
|
|
108189
108470
|
const owner2 = new RecoveryOwner(directory), checked = intentSchema.parse(intent), intentSha256 = canonicalJsonSha256(checked);
|
|
@@ -108346,7 +108627,7 @@ var init_recurring_recovery = __esm(() => {
|
|
|
108346
108627
|
});
|
|
108347
108628
|
|
|
108348
108629
|
// src/lib/recurring-surface.ts
|
|
108349
|
-
import { isAbsolute as
|
|
108630
|
+
import { isAbsolute as isAbsolute28 } from "path";
|
|
108350
108631
|
function recurringMcpSchema(action) {
|
|
108351
108632
|
return action === "activate" ? recurringSurfaceSchemas.activate.extend({ code, confirm: exports_external.literal(true) }) : recurringSurfaceSchemas[action];
|
|
108352
108633
|
}
|
|
@@ -108451,7 +108732,7 @@ var init_recurring_surface = __esm(() => {
|
|
|
108451
108732
|
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}$/);
|
|
108452
108733
|
context = { userId: uuid12.optional(), membershipId: uuid12.optional() };
|
|
108453
108734
|
page2 = { limit: exports_external.number().int().min(1).max(100).optional(), cursor: exports_external.string().min(1).max(2048).optional() };
|
|
108454
|
-
directory = exports_external.string().max(4096).refine(
|
|
108735
|
+
directory = exports_external.string().max(4096).refine(isAbsolute28, "Use an absolute recovery directory");
|
|
108455
108736
|
email4 = exports_external.string().trim().toLowerCase().email().max(254);
|
|
108456
108737
|
code = exports_external.string().regex(/^\d{6}$/);
|
|
108457
108738
|
recurringSurfaceSchemas = {
|
|
@@ -109823,7 +110104,7 @@ var init_run_routing = __esm(() => {
|
|
|
109823
110104
|
});
|
|
109824
110105
|
|
|
109825
110106
|
// src/mcp/operation-tools.ts
|
|
109826
|
-
import { existsSync as existsSync29, readdirSync as readdirSync19, statSync as
|
|
110107
|
+
import { existsSync as existsSync29, readdirSync as readdirSync19, statSync as statSync19 } from "fs";
|
|
109827
110108
|
import { join as join55 } from "path";
|
|
109828
110109
|
function registerOperationTools(server) {
|
|
109829
110110
|
server.registerTool("cloud_skill_eligibility", {
|
|
@@ -110302,7 +110583,7 @@ function registerOperationTools(server) {
|
|
|
110302
110583
|
try {
|
|
110303
110584
|
skillCount = readdirSync19(agentSkillsPath).filter((f) => {
|
|
110304
110585
|
const full = join55(agentSkillsPath, f);
|
|
110305
|
-
return !f.startsWith(".") &&
|
|
110586
|
+
return !f.startsWith(".") && statSync19(full).isDirectory();
|
|
110306
110587
|
}).length;
|
|
110307
110588
|
} catch {}
|
|
110308
110589
|
}
|
|
@@ -110889,7 +111170,7 @@ import {
|
|
|
110889
111170
|
mkdirSync as mkdirSync22,
|
|
110890
111171
|
readFileSync as readFileSync38,
|
|
110891
111172
|
readdirSync as readdirSync20,
|
|
110892
|
-
statSync as
|
|
111173
|
+
statSync as statSync20,
|
|
110893
111174
|
writeFileSync as writeFileSync21
|
|
110894
111175
|
} from "fs";
|
|
110895
111176
|
import { dirname as dirname31, join as join58, normalize as normalize5, relative as relative9, sep as sep11 } from "path";
|
|
@@ -111015,7 +111296,7 @@ function walkFiles2(dir) {
|
|
|
111015
111296
|
const files = [];
|
|
111016
111297
|
for (const entry of readdirSync20(dir)) {
|
|
111017
111298
|
const full = join58(dir, entry);
|
|
111018
|
-
const stats =
|
|
111299
|
+
const stats = statSync20(full);
|
|
111019
111300
|
if (stats.isDirectory())
|
|
111020
111301
|
files.push(...walkFiles2(full));
|
|
111021
111302
|
else
|
|
@@ -111252,11 +111533,11 @@ var init_private_publication_customer = __esm(() => {
|
|
|
111252
111533
|
});
|
|
111253
111534
|
|
|
111254
111535
|
// src/lib/private-publication-recovery.ts
|
|
111255
|
-
import { constants as
|
|
111256
|
-
import { dirname as dirname32, isAbsolute as
|
|
111536
|
+
import { constants as constants23, closeSync as closeSync23, fsyncSync as fsyncSync8, fstatSync as fstatSync23, lstatSync as lstatSync32, mkdirSync as mkdirSync23, openSync as openSync23, readSync as readSync17, realpathSync as realpathSync17, renameSync as renameSync13, unlinkSync as unlinkSync9, writeFileSync as writeFileSync22 } from "fs";
|
|
111537
|
+
import { dirname as dirname32, isAbsolute as isAbsolute29, join as join59, resolve as resolve28 } from "path";
|
|
111257
111538
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
111258
111539
|
function safeDirectory(directory2) {
|
|
111259
|
-
if (!
|
|
111540
|
+
if (!isAbsolute29(directory2) || directory2 !== resolve28(directory2) || realpathSync17(directory2) !== directory2)
|
|
111260
111541
|
return fail5();
|
|
111261
111542
|
for (let path = directory2;; path = dirname32(path)) {
|
|
111262
111543
|
const stat3 = lstatSync32(path);
|
|
@@ -111277,7 +111558,7 @@ function unchangedDirectory(directory2, identity6) {
|
|
|
111277
111558
|
}
|
|
111278
111559
|
function readOwned(directory2, name, max2) {
|
|
111279
111560
|
const identity6 = safeDirectory(directory2), file2 = join59(directory2, name);
|
|
111280
|
-
const fd = openSync23(file2,
|
|
111561
|
+
const fd = openSync23(file2, constants23.O_RDONLY | constants23.O_NOFOLLOW);
|
|
111281
111562
|
try {
|
|
111282
111563
|
const stat3 = fstatSync23(fd);
|
|
111283
111564
|
if (!stat3.isFile() || stat3.nlink !== 1 || stat3.size > max2 || stat3.size < 1 || (stat3.mode & 63) !== 0 || process.getuid && stat3.uid !== process.getuid())
|
|
@@ -111300,7 +111581,7 @@ function readOwned(directory2, name, max2) {
|
|
|
111300
111581
|
}
|
|
111301
111582
|
}
|
|
111302
111583
|
function writeOwned(directory2, name, bytes) {
|
|
111303
|
-
const fd = openSync23(join59(directory2, name),
|
|
111584
|
+
const fd = openSync23(join59(directory2, name), constants23.O_WRONLY | constants23.O_CREAT | constants23.O_EXCL | constants23.O_NOFOLLOW, 384);
|
|
111304
111585
|
try {
|
|
111305
111586
|
writeFileSync22(fd, bytes);
|
|
111306
111587
|
fsyncSync8(fd);
|
|
@@ -111314,7 +111595,7 @@ function save2(directory2, value) {
|
|
|
111314
111595
|
`);
|
|
111315
111596
|
unchangedDirectory(directory2, identity6);
|
|
111316
111597
|
renameSync13(join59(directory2, temporary), join59(directory2, "receipt.json"));
|
|
111317
|
-
const fd = openSync23(directory2,
|
|
111598
|
+
const fd = openSync23(directory2, constants23.O_RDONLY | constants23.O_NOFOLLOW);
|
|
111318
111599
|
try {
|
|
111319
111600
|
fsyncSync8(fd);
|
|
111320
111601
|
} finally {
|
|
@@ -111329,7 +111610,7 @@ async function locked(directory2, action) {
|
|
|
111329
111610
|
const identity6 = safeDirectory(directory2), file2 = join59(directory2, "operation.lock");
|
|
111330
111611
|
let fd;
|
|
111331
111612
|
try {
|
|
111332
|
-
fd = openSync23(file2,
|
|
111613
|
+
fd = openSync23(file2, constants23.O_WRONLY | constants23.O_CREAT | constants23.O_EXCL | constants23.O_NOFOLLOW, 384);
|
|
111333
111614
|
} catch {
|
|
111334
111615
|
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.");
|
|
111335
111616
|
}
|
|
@@ -111394,11 +111675,11 @@ async function preparePrivatePublication(client2, sourceDirectory, recoveryDirec
|
|
|
111394
111675
|
phase: "prepared",
|
|
111395
111676
|
intent: null
|
|
111396
111677
|
};
|
|
111397
|
-
if (!
|
|
111678
|
+
if (!isAbsolute29(recoveryDirectory) || resolve28(recoveryDirectory) !== recoveryDirectory || realpathSync17(dirname32(recoveryDirectory)) !== dirname32(recoveryDirectory))
|
|
111398
111679
|
return fail5();
|
|
111399
111680
|
mkdirSync23(recoveryDirectory, { mode: 448 });
|
|
111400
111681
|
safeDirectory(recoveryDirectory);
|
|
111401
|
-
const parent = openSync23(dirname32(recoveryDirectory),
|
|
111682
|
+
const parent = openSync23(dirname32(recoveryDirectory), constants23.O_RDONLY | constants23.O_NOFOLLOW);
|
|
111402
111683
|
try {
|
|
111403
111684
|
fsyncSync8(parent);
|
|
111404
111685
|
} finally {
|
|
@@ -111495,10 +111776,10 @@ var init_private_publication_recovery = __esm(() => {
|
|
|
111495
111776
|
});
|
|
111496
111777
|
|
|
111497
111778
|
// src/mcp/private-publication-tools.ts
|
|
111498
|
-
import { isAbsolute as
|
|
111779
|
+
import { isAbsolute as isAbsolute30 } from "path";
|
|
111499
111780
|
function registerPrivatePublicationTools(server) {
|
|
111500
111781
|
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}$/);
|
|
111501
|
-
const directory2 = exports_external.string().max(4096).refine(
|
|
111782
|
+
const directory2 = exports_external.string().max(4096).refine(isAbsolute30, "Use an absolute local directory");
|
|
111502
111783
|
const verification2 = { email: exports_external.string().email().max(254), code: exports_external.string().regex(/^\d{6}$/), userId: uuid9, membershipId: uuid9, recoveryDirectory: directory2 };
|
|
111503
111784
|
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.";
|
|
111504
111785
|
const handler = (action) => async (value) => {
|
|
@@ -112277,6 +112558,7 @@ var init_reviewed_runtime_lock = __esm(() => {
|
|
|
112277
112558
|
import { createHash as createHash36, randomUUID as randomUUID10 } from "crypto";
|
|
112278
112559
|
import { Readable } from "stream";
|
|
112279
112560
|
import { createGunzip as createGunzip2 } from "zlib";
|
|
112561
|
+
import { spawnSync as spawnSync5 } from "child_process";
|
|
112280
112562
|
import {
|
|
112281
112563
|
chmodSync as chmodSync4,
|
|
112282
112564
|
copyFileSync,
|
|
@@ -112290,44 +112572,108 @@ import {
|
|
|
112290
112572
|
renameSync as renameSync14,
|
|
112291
112573
|
writeFileSync as writeFileSync24
|
|
112292
112574
|
} from "fs";
|
|
112293
|
-
import { basename as basename17, delimiter as
|
|
112575
|
+
import { basename as basename17, delimiter as delimiter3, dirname as dirname34, isAbsolute as isAbsolute31, join as join61, relative as relative10, resolve as resolve29, sep as sep12 } from "path";
|
|
112294
112576
|
function oldLauncherState(item) {
|
|
112295
112577
|
if (item.oldShape === "pinned")
|
|
112296
|
-
return { shape: "pinned", runtime: item.oldRuntime, cwd: item.oldCwd, target: item.oldTarget, sha256: item.oldSha256 };
|
|
112578
|
+
return { shape: "pinned", runtime: item.oldRuntime, cwd: item.oldCwd, target: item.oldTarget, sha256: item.oldSha256, format: item.oldFormat, profile: item.oldProfile };
|
|
112297
112579
|
return { shape: "symlink", linkTarget: item.oldLinkTarget, target: item.oldTarget };
|
|
112298
112580
|
}
|
|
112299
112581
|
function newLauncherState(item) {
|
|
112300
112582
|
if (item.newShape === "pinned")
|
|
112301
|
-
return { shape: "pinned", runtime: item.newRuntime, cwd: item.newCwd, target: item.newTarget, sha256: item.newSha256 };
|
|
112583
|
+
return { shape: "pinned", runtime: item.newRuntime, cwd: item.newCwd, target: item.newTarget, sha256: item.newSha256, format: item.newFormat, profile: item.newProfile };
|
|
112302
112584
|
return { shape: "symlink", linkTarget: item.newTarget, target: item.newTarget };
|
|
112303
112585
|
}
|
|
112304
|
-
function assertLauncherRecordShapes(item) {
|
|
112586
|
+
function assertLauncherRecordShapes(item, expectedProfile) {
|
|
112305
112587
|
const hex3 = /^[a-f0-9]{64}$/;
|
|
112306
112588
|
for (const side of ["old", "new"]) {
|
|
112307
112589
|
const shape = item[`${side}Shape`], runtime = item[`${side}Runtime`], cwd2 = item[`${side}Cwd`], sha6 = item[`${side}Sha256`];
|
|
112590
|
+
const format = item[`${side}Format`], profile = item[`${side}Profile`];
|
|
112308
112591
|
if (shape === undefined) {
|
|
112309
|
-
if (runtime !== undefined || cwd2 !== undefined || sha6 !== undefined)
|
|
112592
|
+
if (runtime !== undefined || cwd2 !== undefined || sha6 !== undefined || format !== undefined || profile !== undefined)
|
|
112310
112593
|
throw new Error("RECEIPT_LAUNCHER_SHAPE_INVALID");
|
|
112311
112594
|
continue;
|
|
112312
112595
|
}
|
|
112313
112596
|
if (shape === "symlink") {
|
|
112314
|
-
if (runtime !== undefined || cwd2 !== undefined || sha6 !== undefined)
|
|
112597
|
+
if (runtime !== undefined || cwd2 !== undefined || sha6 !== undefined || format !== undefined || profile !== undefined)
|
|
112315
112598
|
throw new Error("RECEIPT_LAUNCHER_SHAPE_INVALID");
|
|
112316
112599
|
continue;
|
|
112317
112600
|
}
|
|
112318
|
-
if (shape !== "pinned" || typeof runtime !== "string" || !
|
|
112601
|
+
if (shape !== "pinned" || typeof runtime !== "string" || !isAbsolute31(runtime) || typeof cwd2 !== "string" || !isAbsolute31(cwd2) || typeof sha6 !== "string" || !hex3.test(sha6)) {
|
|
112319
112602
|
throw new Error("RECEIPT_LAUNCHER_SHAPE_INVALID");
|
|
112320
112603
|
}
|
|
112321
112604
|
const target = side === "old" ? item.oldTarget : item.newTarget;
|
|
112322
112605
|
if (side === "old" && item.oldLinkTarget !== item.oldTarget)
|
|
112323
112606
|
throw new Error("RECEIPT_LAUNCHER_SHAPE_INVALID");
|
|
112324
|
-
if (
|
|
112607
|
+
if (format === "v2" && profile !== expectedProfile)
|
|
112325
112608
|
throw new Error("RECEIPT_LAUNCHER_SHAPE_INVALID");
|
|
112609
|
+
try {
|
|
112610
|
+
pinnedLauncherText({ runtime, cwd: cwd2, target, sha256: sha6, format, profile });
|
|
112611
|
+
} catch {
|
|
112612
|
+
throw new Error("RECEIPT_LAUNCHER_SHAPE_INVALID");
|
|
112613
|
+
}
|
|
112326
112614
|
}
|
|
112327
112615
|
}
|
|
112328
|
-
function pinnedRecordFields(runtime, cwd2, target) {
|
|
112329
|
-
const state = pinnedLauncherState(runtime, cwd2, target);
|
|
112330
|
-
return { newShape: "pinned", newRuntime: state.runtime, newCwd: state.cwd, newSha256: state.sha256 };
|
|
112616
|
+
function pinnedRecordFields(runtime, cwd2, target, profile) {
|
|
112617
|
+
const state = pinnedLauncherState(runtime, cwd2, target, { format: "v2", profile });
|
|
112618
|
+
return { newShape: "pinned", newRuntime: state.runtime, newCwd: state.cwd, newSha256: state.sha256, newFormat: state.format, newProfile: state.profile };
|
|
112619
|
+
}
|
|
112620
|
+
function verifyTargetPrerequisites(manifest, packageRoot, home, cwd2, pathValue) {
|
|
112621
|
+
const declaration = manifest.skillsRuntimePrerequisites;
|
|
112622
|
+
if (declaration === undefined)
|
|
112623
|
+
return { status: "not-declared" };
|
|
112624
|
+
const contract = object10(declaration, "RUNTIME_PREREQUISITE_CONTRACT_INVALID");
|
|
112625
|
+
if (Object.keys(contract).length !== 2 || contract.version !== 1 || contract.entry !== "dist/runtime-prerequisites.js") {
|
|
112626
|
+
throw new Error("RUNTIME_PREREQUISITE_CONTRACT_INVALID");
|
|
112627
|
+
}
|
|
112628
|
+
const entry = join61(packageRoot, contract.entry);
|
|
112629
|
+
if (!entryExists(entry) || !lstatSync33(entry).isFile() || lstatSync33(entry).isSymbolicLink())
|
|
112630
|
+
throw new Error("RUNTIME_PREREQUISITE_ENTRY_MISSING");
|
|
112631
|
+
const entrySha256 = hash5(readFileSync40(entry));
|
|
112632
|
+
const env3 = { HOME: home, PATH: pathValue, BUN_RUNTIME_TRANSPILER_CACHE_PATH: "0" };
|
|
112633
|
+
for (const key of ["HASNA_SKILLS_DIR", "HASNA_SKILLS_HOME", "SKILLS_HOME", "HASNA_DATA_HOME", "XDG_DATA_HOME", "XDG_CONFIG_HOME", "XDG_CACHE_HOME", "XDG_STATE_HOME", "SUMI_HOME", "SUMI_CONFIG_DIR", "HERMES_HOME"]) {
|
|
112634
|
+
if (process.env[key] !== undefined)
|
|
112635
|
+
env3[key] = process.env[key];
|
|
112636
|
+
}
|
|
112637
|
+
for (const key of ["SUMI_CONFIG", "SUMI_CONFIG_CONTENT"])
|
|
112638
|
+
if (process.env[key] !== undefined)
|
|
112639
|
+
env3[key] = "";
|
|
112640
|
+
const child2 = spawnSync5(pinnedLauncherRuntime(), [...PINNED_LAUNCHER_BUN_FLAGS2, entry, home, cwd2], {
|
|
112641
|
+
cwd: dirname34(packageRoot),
|
|
112642
|
+
env: env3,
|
|
112643
|
+
encoding: "buffer",
|
|
112644
|
+
timeout: 5000,
|
|
112645
|
+
maxBuffer: 128 * 1024,
|
|
112646
|
+
shell: false
|
|
112647
|
+
});
|
|
112648
|
+
if (child2.error || child2.signal || !child2.stdout || child2.stderr?.byteLength)
|
|
112649
|
+
throw new Error("RUNTIME_PREREQUISITE_CHECK_UNAVAILABLE");
|
|
112650
|
+
let result2;
|
|
112651
|
+
try {
|
|
112652
|
+
result2 = object10(JSON.parse(child2.stdout.toString("utf8")), "RUNTIME_PREREQUISITE_RESPONSE_INVALID");
|
|
112653
|
+
} catch {
|
|
112654
|
+
throw new Error("RUNTIME_PREREQUISITE_RESPONSE_INVALID");
|
|
112655
|
+
}
|
|
112656
|
+
if (Object.keys(result2).length !== 5 || result2.schema !== "skills.runtime-prerequisites.v1" || result2.targetVersion !== manifest.version || typeof result2.ok !== "boolean" || !Array.isArray(result2.checked) || result2.checked.length > 1 || result2.checked.some((value) => value !== "sumi-paths"))
|
|
112657
|
+
throw new Error("RUNTIME_PREREQUISITE_RESPONSE_INVALID");
|
|
112658
|
+
const codes = [
|
|
112659
|
+
"RUNTIME_CONSUMER_DISCOVERY_REFUSED",
|
|
112660
|
+
"RUNTIME_PREREQUISITE_INPUT_REFUSED",
|
|
112661
|
+
"SUMI_PATH_INPUT_REFUSED",
|
|
112662
|
+
"SUMI_PATH_CONFIG_UNSUPPORTED",
|
|
112663
|
+
"SUMI_PATH_RESOLVER_UNAVAILABLE",
|
|
112664
|
+
"SUMI_PATH_RESOLVER_INVALID_RESPONSE",
|
|
112665
|
+
"SUMI_PATH_DISCOVERY_REFUSED"
|
|
112666
|
+
];
|
|
112667
|
+
if (!result2.ok) {
|
|
112668
|
+
if (child2.status !== 2 || typeof result2.code !== "string" || !codes.includes(result2.code))
|
|
112669
|
+
throw new Error("RUNTIME_PREREQUISITE_RESPONSE_INVALID");
|
|
112670
|
+
throw new Error(`RUNTIME_PREREQUISITE_REFUSED_${result2.code}`);
|
|
112671
|
+
}
|
|
112672
|
+
if (child2.status !== 0 || result2.code !== null)
|
|
112673
|
+
throw new Error("RUNTIME_PREREQUISITE_RESPONSE_INVALID");
|
|
112674
|
+
if (hash5(readFileSync40(entry)) !== entrySha256)
|
|
112675
|
+
throw new Error("RUNTIME_PREREQUISITE_ENTRY_CHANGED");
|
|
112676
|
+
return { status: "verified", schema: result2.schema, targetVersion: result2.targetVersion, entry: contract.entry, entrySha256, checked: result2.checked };
|
|
112331
112677
|
}
|
|
112332
112678
|
function object10(value, code2) {
|
|
112333
112679
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
@@ -112339,7 +112685,7 @@ function hash5(bytes) {
|
|
|
112339
112685
|
}
|
|
112340
112686
|
function isWithin(parent, child2) {
|
|
112341
112687
|
const rel = relative10(parent, child2);
|
|
112342
|
-
return rel === "" || !rel.startsWith(`..${sep12}`) && rel !== ".." && !
|
|
112688
|
+
return rel === "" || !rel.startsWith(`..${sep12}`) && rel !== ".." && !isAbsolute31(rel);
|
|
112343
112689
|
}
|
|
112344
112690
|
function entryExists(path) {
|
|
112345
112691
|
try {
|
|
@@ -112388,7 +112734,7 @@ function packageBins(pkg) {
|
|
|
112388
112734
|
const entries = typeof raw === "string" ? [[PACKAGE_NAME.slice(PACKAGE_NAME.lastIndexOf("/") + 1), raw]] : raw && typeof raw === "object" && !Array.isArray(raw) ? Object.entries(raw) : [];
|
|
112389
112735
|
const output2 = {};
|
|
112390
112736
|
for (const [name, value] of entries) {
|
|
112391
|
-
if (!/^[a-zA-Z0-9._-]+$/.test(name) || typeof value !== "string" || !value ||
|
|
112737
|
+
if (!/^[a-zA-Z0-9._-]+$/.test(name) || typeof value !== "string" || !value || isAbsolute31(value)) {
|
|
112392
112738
|
throw new Error("PACKAGE_BIN_INVALID");
|
|
112393
112739
|
}
|
|
112394
112740
|
const normalized = value.replaceAll("\\", "/");
|
|
@@ -112451,7 +112797,7 @@ function resolveRuntimeLayout(homeInput, pathInput) {
|
|
|
112451
112797
|
}
|
|
112452
112798
|
const launchers = [];
|
|
112453
112799
|
const seenDirectories = new Set;
|
|
112454
|
-
for (const rawDir of pathInput.split(
|
|
112800
|
+
for (const rawDir of pathInput.split(delimiter3).filter(Boolean)) {
|
|
112455
112801
|
const dir = resolve29(rawDir);
|
|
112456
112802
|
if (seenDirectories.has(dir))
|
|
112457
112803
|
continue;
|
|
@@ -112481,7 +112827,7 @@ function resolveRuntimeLayout(homeInput, pathInput) {
|
|
|
112481
112827
|
throw new Error("LAUNCHER_SYMLINK_CHAIN_UNSUPPORTED");
|
|
112482
112828
|
launchers.push({ path, oldTarget: actual, oldLinkTarget: launcher.linkTarget, newTarget, backupPath, oldShape: "symlink" });
|
|
112483
112829
|
} else {
|
|
112484
|
-
launchers.push({ path, oldTarget: actual, oldLinkTarget: actual, newTarget, backupPath, oldShape: "pinned", oldRuntime: launcher.runtime, oldCwd: launcher.cwd, oldSha256: launcher.sha256 });
|
|
112830
|
+
launchers.push({ path, oldTarget: actual, oldLinkTarget: actual, newTarget, backupPath, oldShape: "pinned", oldRuntime: launcher.runtime, oldCwd: launcher.cwd, oldSha256: launcher.sha256, oldFormat: launcher.format, oldProfile: launcher.profile });
|
|
112485
112831
|
}
|
|
112486
112832
|
}
|
|
112487
112833
|
}
|
|
@@ -113110,14 +113456,14 @@ function adoptCopyfileAliases(options = {}) {
|
|
|
113110
113456
|
const actual = launcher.target;
|
|
113111
113457
|
const oldLinkTarget = launcher.kind === "symlink" ? launcher.linkTarget : actual;
|
|
113112
113458
|
const newTarget = join61(layout.currentPackageRoot, target);
|
|
113113
|
-
if (actual === newTarget && launcher.kind === "pinned")
|
|
113459
|
+
if (actual === newTarget && launcher.kind === "pinned" && launcher.format === "v2" && launcher.profile === launcherProfileForBin(name, target))
|
|
113114
113460
|
continue;
|
|
113115
113461
|
const chain = inspectAliasPackageChain(home, path, oldLinkTarget, actual, target);
|
|
113116
113462
|
const source = validateAliasSource(home, name, actual);
|
|
113117
113463
|
const backupPath = `${path}.skills-alias-prev-${id2}`;
|
|
113118
113464
|
if (entryExists(backupPath))
|
|
113119
113465
|
throw new Error("ALIAS_BACKUP_COLLISION");
|
|
113120
|
-
const oldFields = launcher.kind === "symlink" ? { oldShape: "symlink" } : { oldShape: "pinned", oldRuntime: launcher.runtime, oldCwd: launcher.cwd, oldSha256: launcher.sha256 };
|
|
113466
|
+
const oldFields = launcher.kind === "symlink" ? { oldShape: "symlink" } : { oldShape: "pinned", oldRuntime: launcher.runtime, oldCwd: launcher.cwd, oldSha256: launcher.sha256, oldFormat: launcher.format, oldProfile: launcher.profile };
|
|
113121
113467
|
aliases.push({
|
|
113122
113468
|
path,
|
|
113123
113469
|
oldTarget: actual,
|
|
@@ -113127,7 +113473,7 @@ function adoptCopyfileAliases(options = {}) {
|
|
|
113127
113473
|
newTarget,
|
|
113128
113474
|
backupPath,
|
|
113129
113475
|
...oldFields,
|
|
113130
|
-
...pinnedRecordFields(launcherRuntime, currentRuntime, newTarget),
|
|
113476
|
+
...pinnedRecordFields(launcherRuntime, currentRuntime, newTarget, launcherProfileForBin(name, target)),
|
|
113131
113477
|
...chain ? { chain } : {}
|
|
113132
113478
|
});
|
|
113133
113479
|
}
|
|
@@ -113247,7 +113593,7 @@ function rollbackCopyfileAliases(receiptId, options = {}) {
|
|
|
113247
113593
|
throw new Error("ALIAS_RECEIPT_LAUNCHER_INVALID");
|
|
113248
113594
|
}
|
|
113249
113595
|
inspectAliasPackageChain(home, item.path, item.oldLinkTarget, item.oldTarget, target, item.chain, true);
|
|
113250
|
-
assertLauncherRecordShapes(item);
|
|
113596
|
+
assertLauncherRecordShapes(item, launcherProfileForBin(name, target));
|
|
113251
113597
|
seen.add(item.path);
|
|
113252
113598
|
assertOwnedSafePath(dirname34(item.path), home, true);
|
|
113253
113599
|
const source = validateAliasSource(home, name, item.oldTarget);
|
|
@@ -113319,7 +113665,7 @@ async function updateCopyfileRuntime(version2, options = {}) {
|
|
|
113319
113665
|
throw new Error("REVIEWED_LOCK_INPUT_PAIR_REQUIRED");
|
|
113320
113666
|
if (!policy)
|
|
113321
113667
|
throw new Error("REVIEWED_LOCK_RELEASE_AGE_REQUIRED");
|
|
113322
|
-
if (!
|
|
113668
|
+
if (!isAbsolute31(options.reviewedLock))
|
|
113323
113669
|
throw new Error("REVIEWED_LOCK_ABSOLUTE_PATH_REQUIRED");
|
|
113324
113670
|
assertNoSymlinkAncestors(dirname34(options.reviewedLock));
|
|
113325
113671
|
const stat3 = lstatSync33(options.reviewedLock);
|
|
@@ -113352,7 +113698,7 @@ async function updateCopyfileRuntime(version2, options = {}) {
|
|
|
113352
113698
|
const launcherRuntime = pinnedLauncherRuntime();
|
|
113353
113699
|
const launchers = layout.launchers.map((item) => {
|
|
113354
113700
|
const newTarget = join61(finalPath, "node_modules", "@hasna", "skills", layout.bin[basename17(item.path)]);
|
|
113355
|
-
return { ...item, newTarget, ...pinnedRecordFields(launcherRuntime, finalPath, newTarget) };
|
|
113701
|
+
return { ...item, newTarget, ...pinnedRecordFields(launcherRuntime, finalPath, newTarget, launcherProfileForBin(basename17(item.path), layout.bin[basename17(item.path)])) };
|
|
113356
113702
|
});
|
|
113357
113703
|
const releaseLock = acquireRuntimeLock(layout.runtimeRoot);
|
|
113358
113704
|
let switched = [];
|
|
@@ -113448,6 +113794,15 @@ async function updateCopyfileRuntime(version2, options = {}) {
|
|
|
113448
113794
|
rollbackCompletedLaunchers: []
|
|
113449
113795
|
};
|
|
113450
113796
|
writeJsonPrivate(join61(stagePath, "rollout-receipt.json"), receipt);
|
|
113797
|
+
try {
|
|
113798
|
+
receipt.prerequisites = verifyTargetPrerequisites(installed.data, installedPackage, home, resolve29(options.cwd ?? process.env[LAUNCH_CWD_VARIABLE3] ?? process.cwd()), options.pathValue ?? process.env.PATH ?? "");
|
|
113799
|
+
} catch (error61) {
|
|
113800
|
+
const code2 = error61 instanceof Error && /^RUNTIME_PREREQUISITE_[A-Z_]+$/.test(error61.message) ? error61.message : "RUNTIME_PREREQUISITE_CHECK_UNAVAILABLE";
|
|
113801
|
+
receipt.prerequisites = { status: "refused", code: code2 };
|
|
113802
|
+
persistReceipt(join61(stagePath, "rollout-receipt.json"), receipt);
|
|
113803
|
+
throw new Error(code2);
|
|
113804
|
+
}
|
|
113805
|
+
persistReceipt(join61(stagePath, "rollout-receipt.json"), receipt);
|
|
113451
113806
|
const finalNodeModules = join61(stagePackage, "node_modules");
|
|
113452
113807
|
const stagedNodeModules = join61(stagePath, "node_modules");
|
|
113453
113808
|
renameSync14(finalNodeModules, stagedNodeModules);
|
|
@@ -113481,7 +113836,7 @@ async function updateCopyfileRuntime(version2, options = {}) {
|
|
|
113481
113836
|
}
|
|
113482
113837
|
receipt.state = "switched";
|
|
113483
113838
|
persistReceipt(join61(finalPath, "rollout-receipt.json"), receipt);
|
|
113484
|
-
return { updated: true, version: version2, currentVersion: layout.currentVersion, receiptId: id2, runtimeRoot: finalPath, tarballSha256: artifact.sha256, tarballIntegrity: artifact.integrity, runtimeTreeSha256: stagedTree.digest, launcherCount: launchers.length, configCount: configPreimages.length, ...policy ? { dependencyPolicy: { ...policy, npmVersion } } : {}, ...reviewedLockBytes ? { reviewedLockSha256: options.reviewedLockSha256 } : {} };
|
|
113839
|
+
return { updated: true, version: version2, currentVersion: layout.currentVersion, receiptId: id2, runtimeRoot: finalPath, tarballSha256: artifact.sha256, tarballIntegrity: artifact.integrity, runtimeTreeSha256: stagedTree.digest, launcherCount: launchers.length, configCount: configPreimages.length, prerequisites: receipt.prerequisites, ...policy ? { dependencyPolicy: { ...policy, npmVersion } } : {}, ...reviewedLockBytes ? { reviewedLockSha256: options.reviewedLockSha256 } : {} };
|
|
113485
113840
|
} catch (error61) {
|
|
113486
113841
|
if (switched.length > 0 || moved) {
|
|
113487
113842
|
let rollbackFailed = false;
|
|
@@ -113566,10 +113921,10 @@ function rollbackCopyfileRuntime(receiptId, options = {}) {
|
|
|
113566
113921
|
const seen = new Set;
|
|
113567
113922
|
for (const item of receipt.launchers) {
|
|
113568
113923
|
const bin = oldBins[basename17(item.path)];
|
|
113569
|
-
if (!bin || !
|
|
113924
|
+
if (!bin || !isAbsolute31(item.path) || seen.has(item.path) || item.oldTarget !== join61(receipt.currentPackageRoot, bin) || item.newTarget !== join61(receipt.targetPackageRoot, bin) || !/^.+\.skills-prev-[0-9a-f-]{36}$/.test(item.backupPath) || !item.backupPath.startsWith(`${item.path}.skills-prev-`) || typeof item.oldLinkTarget !== "string" || resolve29(dirname34(item.path), item.oldLinkTarget) !== item.oldTarget)
|
|
113570
113925
|
throw new Error("RECEIPT_LAUNCHER_BINDING_INVALID");
|
|
113571
113926
|
assertNoSymlinkAncestors(dirname34(item.path));
|
|
113572
|
-
assertLauncherRecordShapes(item);
|
|
113927
|
+
assertLauncherRecordShapes(item, launcherProfileForBin(basename17(item.path), bin));
|
|
113573
113928
|
seen.add(item.path);
|
|
113574
113929
|
const oldState = oldLauncherState(item), newState = newLauncherState(item);
|
|
113575
113930
|
let activeTarget;
|
|
@@ -113635,7 +113990,7 @@ __export(exports_runtime, {
|
|
|
113635
113990
|
});
|
|
113636
113991
|
import { createHash as createHash37, randomUUID as randomUUID11 } from "crypto";
|
|
113637
113992
|
import { lstatSync as lstatSync34, mkdirSync as mkdirSync26, readFileSync as readFileSync41, writeFileSync as writeFileSync25 } from "fs";
|
|
113638
|
-
import { basename as basename18, isAbsolute as
|
|
113993
|
+
import { basename as basename18, isAbsolute as isAbsolute32, join as join62 } from "path";
|
|
113639
113994
|
import { createInterface } from "readline";
|
|
113640
113995
|
function registerRuntime(parent) {
|
|
113641
113996
|
parent.command("run").argument("<skill>", "Skill name").argument("[args...]", "Arguments to pass to the skill; use -- to end Skills options").allowUnknownOption(true).passThroughOptions(true).option("--json", "Output result as JSON", false).option("--remote", "Run on the configured server, using its catalog and quote", false).option("--target <target>", "Execution target: local or cloud").option("--secret-bindings <path>", "Reviewed, exact-selection local execution vault bindings (JSON file)").option("--secret-bindings-template", "Print a scoped bindings template without resolving secrets or running the skill", false).option("--input <json>", "Structured cloud execution input").option("--skill-version <version>", "Exact selected skill version").option("--selection-profile <id>", "Selected Skills profile").option("--session <id>", "Pinned Skills session").option("--cached", "Use the explicit verified selected cache", false).option("--yes", "Approve the server's quoted credit cost for this run", false).option("--idempotency-key <key>", "Reuse this key when retrying the same remote submission").option("--file <path>", "Attach a local input file to a remote run (repeatable)", (value, prior) => [...prior, value], []).option("--wait", "Poll remote runs until a terminal status", false).option("--poll-interval-ms <ms>", "Remote polling interval in milliseconds", "1000").option("--poll-timeout-ms <ms>", "Maximum time to wait for a remote run", "300000").description("Run a skill directly").action(async (name, args2, options, command) => {
|
|
@@ -113834,7 +114189,7 @@ Updating ${name}...
|
|
|
113834
114189
|
async function readUpdatedVersion(bunExecutable) {
|
|
113835
114190
|
const output2 = await readUpdateCommand([bunExecutable, "pm", "bin", "-g"]);
|
|
113836
114191
|
const globalBin = output2.replace(/\r?\n$/, "");
|
|
113837
|
-
if (!globalBin || !
|
|
114192
|
+
if (!globalBin || !isAbsolute32(globalBin) || /[\r\n\0]/.test(globalBin))
|
|
113838
114193
|
throw new Error("Update bin discovery failed");
|
|
113839
114194
|
const installed = Bun.which("skills", { PATH: globalBin, cwd: globalBin });
|
|
113840
114195
|
const selected = Bun.which("skills");
|
|
@@ -114889,10 +115244,10 @@ var exports_recurring = {};
|
|
|
114889
115244
|
__export(exports_recurring, {
|
|
114890
115245
|
registerRecurringCommands: () => registerRecurringCommands
|
|
114891
115246
|
});
|
|
114892
|
-
import { constants as
|
|
115247
|
+
import { constants as constants24, closeSync as closeSync25, fstatSync as fstatSync25, lstatSync as lstatSync35, openSync as openSync25, readSync as readSync18 } from "fs";
|
|
114893
115248
|
import { createInterface as createInterface2 } from "readline";
|
|
114894
115249
|
function readRequest(path) {
|
|
114895
|
-
const fd = openSync25(path,
|
|
115250
|
+
const fd = openSync25(path, constants24.O_RDONLY | constants24.O_NOFOLLOW | constants24.O_NONBLOCK);
|
|
114896
115251
|
try {
|
|
114897
115252
|
const before2 = fstatSync25(fd);
|
|
114898
115253
|
if (!before2.isFile() || before2.size > 1048576 || before2.size < 1)
|
|
@@ -115189,7 +115544,7 @@ var init_completion = __esm(() => {
|
|
|
115189
115544
|
});
|
|
115190
115545
|
|
|
115191
115546
|
// src/lib/portable-snapshot-filter.ts
|
|
115192
|
-
import { readdirSync as readdirSync22, statSync as
|
|
115547
|
+
import { readdirSync as readdirSync22, statSync as statSync21 } from "fs";
|
|
115193
115548
|
import { homedir as homedir11 } from "os";
|
|
115194
115549
|
import { join as join63, sep as sep13 } from "path";
|
|
115195
115550
|
function isExcludedSkillFileName(fileName) {
|
|
@@ -115257,7 +115612,7 @@ function walkEntries(absoluteRoot) {
|
|
|
115257
115612
|
}
|
|
115258
115613
|
function isRegularFile(filePath) {
|
|
115259
115614
|
try {
|
|
115260
|
-
return
|
|
115615
|
+
return statSync21(filePath).isFile();
|
|
115261
115616
|
} catch {
|
|
115262
115617
|
return false;
|
|
115263
115618
|
}
|
|
@@ -115343,10 +115698,10 @@ import {
|
|
|
115343
115698
|
copyFileSync as copyFileSync2,
|
|
115344
115699
|
mkdirSync as mkdirSync27,
|
|
115345
115700
|
readFileSync as readFileSync42,
|
|
115346
|
-
statSync as
|
|
115701
|
+
statSync as statSync22,
|
|
115347
115702
|
writeFileSync as writeFileSync26
|
|
115348
115703
|
} from "fs";
|
|
115349
|
-
import { dirname as dirname36, isAbsolute as
|
|
115704
|
+
import { dirname as dirname36, isAbsolute as isAbsolute33, relative as relative11, resolve as resolve30, sep as sep14 } from "path";
|
|
115350
115705
|
function validateStationId(stationId) {
|
|
115351
115706
|
if (!/^[a-z0-9-]+$/.test(stationId)) {
|
|
115352
115707
|
throw new StationSnapshotError("INVALID_STATION", `station id must be a slug, got: ${stationId}`);
|
|
@@ -115383,7 +115738,7 @@ function scanHome(definition, homesRoot) {
|
|
|
115383
115738
|
skipped.push({ relativePath: entry.relativePath, reason: "not-regular-file" });
|
|
115384
115739
|
continue;
|
|
115385
115740
|
}
|
|
115386
|
-
const info =
|
|
115741
|
+
const info = statSync22(entry.fullPath);
|
|
115387
115742
|
portable.push({
|
|
115388
115743
|
relativePath: entry.relativePath,
|
|
115389
115744
|
fullPath: entry.fullPath,
|
|
@@ -115452,7 +115807,7 @@ function writeStationSnapshot(options) {
|
|
|
115452
115807
|
for (const plan of plans) {
|
|
115453
115808
|
const destination = resolve30(repoRoot, plan.destination);
|
|
115454
115809
|
const destinationRelative = relative11(repoRoot, destination);
|
|
115455
|
-
if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep14) ||
|
|
115810
|
+
if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep14) || isAbsolute33(destinationRelative)) {
|
|
115456
115811
|
throw new StationSnapshotError("DESTINATION_ESCAPE", `destination escapes repo root: ${plan.destination}`);
|
|
115457
115812
|
}
|
|
115458
115813
|
let existingDigest = null;
|
|
@@ -115924,6 +116279,50 @@ var init_create_sync_config = __esm(() => {
|
|
|
115924
116279
|
init_station_snapshot();
|
|
115925
116280
|
});
|
|
115926
116281
|
|
|
116282
|
+
// src/lib/agent-install-selection.ts
|
|
116283
|
+
import { lstatSync as lstatSync36 } from "fs";
|
|
116284
|
+
import { dirname as dirname37, join as join65, resolve as resolve31 } from "path";
|
|
116285
|
+
import { homedir as homedir12 } from "os";
|
|
116286
|
+
function detectedIntegrationAgents(options = {}) {
|
|
116287
|
+
const home = options.home ?? homedir12(), env3 = options.env ?? process.env;
|
|
116288
|
+
const policy = readManagedSkillPolicySnapshot(options.dataDir ?? getDataDirReadOnly())?.value;
|
|
116289
|
+
const bridge = policy?.bridge;
|
|
116290
|
+
if (bridge !== undefined && (!bridge || typeof bridge !== "object" || Array.isArray(bridge)))
|
|
116291
|
+
throw new Error("Invalid existing Skills bridge policy");
|
|
116292
|
+
const configured = bridge === undefined ? [] : bridge.agents;
|
|
116293
|
+
if (!Array.isArray(configured) || configured.some((agent) => !INTEGRATION_AGENTS.includes(agent)))
|
|
116294
|
+
throw new Error("Invalid existing bridge agent inventory");
|
|
116295
|
+
const present = (path) => {
|
|
116296
|
+
try {
|
|
116297
|
+
return lstatSync36(path, { throwIfNoEntry: false }) !== undefined;
|
|
116298
|
+
} catch {
|
|
116299
|
+
throw new Error("Agent presence cannot be inspected; review native configuration before hook installation");
|
|
116300
|
+
}
|
|
116301
|
+
};
|
|
116302
|
+
const selected = INTEGRATION_AGENTS.filter((agent) => {
|
|
116303
|
+
if (configured.includes(agent) || Bun.which(agent, { PATH: env3.PATH ?? "" }))
|
|
116304
|
+
return true;
|
|
116305
|
+
if (agent === "sumi") {
|
|
116306
|
+
const xdg = env3.XDG_CONFIG_HOME;
|
|
116307
|
+
const xdgSumi = xdg?.trim() ? resolve31(options.cwd ?? process.cwd(), xdg === "~" ? home : xdg.startsWith("~/") || xdg.startsWith("~\\") ? resolve31(home, xdg.slice(2)) : xdg, "sumi") : null;
|
|
116308
|
+
return ["SUMI_HOME", "SUMI_CONFIG_DIR", "SUMI_CONFIG", "SUMI_CONFIG_CONTENT"].some((key) => env3[key] !== undefined) || Bun.which("sumi-paths", { PATH: env3.PATH ?? "" }) !== null || NATIVE_SKILL_ROOTS.some(([provider, root2]) => provider === "sumi" && present(join65(home, dirname37(root2)))) || present(join65(home, ".config", "sumi")) || xdgSumi !== null && present(xdgSumi);
|
|
116309
|
+
}
|
|
116310
|
+
if (agent === "hermes" && env3.HERMES_HOME !== undefined)
|
|
116311
|
+
return true;
|
|
116312
|
+
const adapter = AGENT_ADAPTERS[agent];
|
|
116313
|
+
return present(join65(home, dirname37(adapter.config))) || NATIVE_SKILL_ROOTS.some(([provider, root2]) => provider === agent && dirname37(root2) === `.${agent}` && present(join65(home, dirname37(root2))));
|
|
116314
|
+
});
|
|
116315
|
+
if (!selected.length && !options.allowEmpty)
|
|
116316
|
+
throw new Error(`No configured or detected agents; select --agent <agent> explicitly (${INTEGRATION_AGENTS.join(", ")}).`);
|
|
116317
|
+
return selected;
|
|
116318
|
+
}
|
|
116319
|
+
var init_agent_install_selection = __esm(() => {
|
|
116320
|
+
init_agent_adapters();
|
|
116321
|
+
init_native_discovery_roots();
|
|
116322
|
+
init_managed_policy();
|
|
116323
|
+
init_config();
|
|
116324
|
+
});
|
|
116325
|
+
|
|
115927
116326
|
// src/lib/codex-native-config.ts
|
|
115928
116327
|
import { isDeepStrictEqual as isDeepStrictEqual14 } from "util";
|
|
115929
116328
|
function isRecord8(value) {
|
|
@@ -115971,11 +116370,11 @@ var NUMBER_TAG = "$serde_json::private::Number";
|
|
|
115971
116370
|
var init_codex_native_config = () => {};
|
|
115972
116371
|
|
|
115973
116372
|
// src/lib/codex-hook-trust-identity.ts
|
|
115974
|
-
import { lstatSync as
|
|
115975
|
-
import { dirname as
|
|
116373
|
+
import { lstatSync as lstatSync37, realpathSync as realpathSync19 } from "fs";
|
|
116374
|
+
import { dirname as dirname38, isAbsolute as isAbsolute34, join as join66, resolve as resolve32 } from "path";
|
|
115976
116375
|
import { isDeepStrictEqual as isDeepStrictEqual15 } from "util";
|
|
115977
116376
|
function commandPhysical(command) {
|
|
115978
|
-
need6(typeof command === "string" &&
|
|
116377
|
+
need6(typeof command === "string" && isAbsolute34(command) && !command.includes("\x00") && resolve32(command) === command, COMMAND_NOT_CANONICAL);
|
|
115979
116378
|
const physical = realpathSync19(command);
|
|
115980
116379
|
let spelled;
|
|
115981
116380
|
try {
|
|
@@ -115986,7 +116385,7 @@ function commandPhysical(command) {
|
|
|
115986
116385
|
safeParents(spelled);
|
|
115987
116386
|
let direct = false;
|
|
115988
116387
|
try {
|
|
115989
|
-
const leaf =
|
|
116388
|
+
const leaf = lstatSync37(spelled);
|
|
115990
116389
|
direct = leaf.isSymbolicLink() ? trustedAncestorOwner(leaf.uid) && directAliasTarget(spelled) === physical : spelled === physical;
|
|
115991
116390
|
} catch {}
|
|
115992
116391
|
need6(direct, COMMAND_ALIAS_UNSAFE);
|
|
@@ -115998,7 +116397,7 @@ function assertPinnedRuntime(runtime) {
|
|
|
115998
116397
|
} catch {
|
|
115999
116398
|
need6(false, "SKILLS_LAUNCHER_UNVERIFIED");
|
|
116000
116399
|
}
|
|
116001
|
-
need6(
|
|
116400
|
+
need6(resolve32(runtime) === runtime, "SKILLS_LAUNCHER_UNVERIFIED");
|
|
116002
116401
|
safeParents(runtime);
|
|
116003
116402
|
}
|
|
116004
116403
|
function skillsCommandTarget(command) {
|
|
@@ -116030,12 +116429,12 @@ function targetUnchanged(command, target) {
|
|
|
116030
116429
|
assertPinnedRuntime(target.runtime);
|
|
116031
116430
|
}
|
|
116032
116431
|
function inspectRecordedSkillsCli(command, expected) {
|
|
116033
|
-
need6(
|
|
116432
|
+
need6(isAbsolute34(command) && !command.includes("\x00"), "RECONCILE_RECORDED_COMMAND_REQUIRED");
|
|
116034
116433
|
const target = skillsCommandTarget(command), resolved = target.entry;
|
|
116035
116434
|
const cli = snapshot(resolved, false, { readOnlyPackage: true });
|
|
116036
|
-
const manifest = snapshot(
|
|
116435
|
+
const manifest = snapshot(join66(dirname38(dirname38(resolved)), "package.json"), false, { readOnlyPackage: true });
|
|
116037
116436
|
const pkg = JSON.parse(manifest.text);
|
|
116038
|
-
need6(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved ===
|
|
116437
|
+
need6(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved === join66(dirname38(manifest.file), "bin/index.js"), "SKILLS_PACKAGE_MISMATCH");
|
|
116039
116438
|
need6((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
|
|
116040
116439
|
const receipt = { path: resolved, version: pkg.version, sha256: cli.sha256, manifestSha256: manifest.sha256 };
|
|
116041
116440
|
need6(isDeepStrictEqual15(receipt, expected), "RECONCILE_SKILLS_BINDING_CHANGED");
|
|
@@ -116049,16 +116448,16 @@ function bindSkillsCli(command, reviewed) {
|
|
|
116049
116448
|
const normal = Bun.which("skills", { PATH: process.env.PATH });
|
|
116050
116449
|
need6(normal, "SKILLS_COMMAND_UNAVAILABLE");
|
|
116051
116450
|
const normalTarget = skillsCommandTarget(normal), resolved = normalTarget.entry;
|
|
116052
|
-
const bound =
|
|
116451
|
+
const bound = isAbsolute34(command) ? command : command === "skills" ? normal : undefined;
|
|
116053
116452
|
need6(bound, "SKILLS_COMMAND_MISMATCH");
|
|
116054
116453
|
const boundTarget = skillsCommandTarget(bound);
|
|
116055
116454
|
need6(boundTarget.entry === resolved, "SKILLS_COMMAND_MISMATCH");
|
|
116056
116455
|
const entrypoint = reviewed?.path ?? process.argv[1];
|
|
116057
116456
|
need6(entrypoint && realpathSync19(entrypoint) === resolved, "SKILLS_ENTRYPOINT_MISMATCH");
|
|
116058
116457
|
const cli = snapshot(resolved, false, { readOnlyPackage: true });
|
|
116059
|
-
const manifest = snapshot(
|
|
116458
|
+
const manifest = snapshot(join66(dirname38(dirname38(resolved)), "package.json"), false, { readOnlyPackage: true });
|
|
116060
116459
|
const pkg = JSON.parse(manifest.text);
|
|
116061
|
-
need6(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved ===
|
|
116460
|
+
need6(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved === join66(dirname38(manifest.file), "bin/index.js"), "SKILLS_PACKAGE_MISMATCH");
|
|
116062
116461
|
if (reviewed)
|
|
116063
116462
|
need6(/^[a-f0-9]{64}$/.test(reviewed.sha256) && reviewed.sha256 === cli.sha256 && reviewed.version === pkg.version, "SKILLS_RELEASE_MISMATCH");
|
|
116064
116463
|
need6((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
|
|
@@ -116077,7 +116476,7 @@ function captureSkillsCliProducerIdentity(command) {
|
|
|
116077
116476
|
const bound = bindSkillsCli(command);
|
|
116078
116477
|
const target = skillsCommandTarget(command);
|
|
116079
116478
|
const cli = snapshot(target.entry, false, { readOnlyPackage: true });
|
|
116080
|
-
const manifest = snapshot(
|
|
116479
|
+
const manifest = snapshot(join66(dirname38(dirname38(target.entry)), "package.json"), false, { readOnlyPackage: true });
|
|
116081
116480
|
const pkg = JSON.parse(manifest.text);
|
|
116082
116481
|
need6(pkg.name === "@hasna/skills" && pkg.version === bound.receipt.version && target.entry === bound.receipt.path, "SKILLS_PACKAGE_MISMATCH");
|
|
116083
116482
|
const launcher = target.launcher ?? cli;
|
|
@@ -116131,20 +116530,20 @@ var init_codex_hook_policy_recovery = __esm(() => {
|
|
|
116131
116530
|
});
|
|
116132
116531
|
|
|
116133
116532
|
// src/lib/agent-codex-trust.ts
|
|
116134
|
-
import { lstatSync as
|
|
116533
|
+
import { lstatSync as lstatSync38, mkdirSync as mkdirSync28, readdirSync as readdirSync23, readFileSync as readFileSync43, realpathSync as realpathSync20, statSync as statSync23 } from "fs";
|
|
116135
116534
|
import { createHash as createHash39, randomUUID as randomUUID12 } from "crypto";
|
|
116136
116535
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
116137
|
-
import { dirname as
|
|
116138
|
-
import { homedir as
|
|
116536
|
+
import { dirname as dirname39, isAbsolute as isAbsolute35, join as join67, resolve as resolve33 } from "path";
|
|
116537
|
+
import { homedir as homedir13 } from "os";
|
|
116139
116538
|
import { isDeepStrictEqual as isDeepStrictEqual17 } from "util";
|
|
116140
116539
|
function verifyReleaseArtifact(proof, skillsCli) {
|
|
116141
|
-
need6(
|
|
116540
|
+
need6(isAbsolute35(proof.packageTarPath) && !proof.packageTarPath.includes("\x00"), "RECONCILE_RELEASE_PROVENANCE_PATH");
|
|
116142
116541
|
const tarPath = realpathSync20(proof.packageTarPath);
|
|
116143
|
-
need6(
|
|
116542
|
+
need6(statSync23(tarPath).isFile(), "RECONCILE_RELEASE_PROVENANCE_PATH");
|
|
116144
116543
|
const tarBytes = readFileSync43(tarPath);
|
|
116145
116544
|
need6(tarBytes.byteLength === proof.packageTarBytes && createHash39("sha256").update(tarBytes).digest("hex") === proof.packageTarSha256, "RECONCILE_RELEASE_ARTIFACT_CHANGED");
|
|
116146
|
-
const packageRoot =
|
|
116147
|
-
const manifest = readFileSync43(
|
|
116545
|
+
const packageRoot = dirname39(dirname39(realpathSync20(skillsCli.receipt.path)));
|
|
116546
|
+
const manifest = readFileSync43(join67(packageRoot, "package.json"));
|
|
116148
116547
|
need6(createHash39("sha256").update(manifest).digest("hex") === skillsCli.receipt.manifestSha256 && skillsCli.receipt.manifestSha256 === proof.manifestSha256, "RECONCILE_RELEASE_MANIFEST_CHANGED");
|
|
116149
116548
|
need6(createHash39("sha256").update(readFileSync43(skillsCli.receipt.path)).digest("hex") === proof.executableSha256 && skillsCli.receipt.sha256 === proof.executableSha256, "RECONCILE_RELEASE_EXECUTABLE_CHANGED");
|
|
116150
116549
|
const members2 = [["package/package.json", manifest], ["package/bin/index.js", readFileSync43(skillsCli.receipt.path)]];
|
|
@@ -116161,26 +116560,26 @@ function verifyReleaseArtifact(proof, skillsCli) {
|
|
|
116161
116560
|
async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc) {
|
|
116162
116561
|
let rpc;
|
|
116163
116562
|
try {
|
|
116164
|
-
const home =
|
|
116165
|
-
const parent =
|
|
116563
|
+
const home = resolve33(options.home ?? homedir13()), dataDir3 = resolve33(options.dataDir ?? getDataDirReadOnly());
|
|
116564
|
+
const parent = resolve33(join67(dataDir3, "native-hook-trust")), journal = resolve33(options.journal);
|
|
116166
116565
|
need6(journal.startsWith(parent + "/") && /^[a-f0-9-]{36}$/.test(journal.slice(parent.length + 1)), "RECONCILE_JOURNAL_PATH");
|
|
116167
|
-
const dir =
|
|
116566
|
+
const dir = lstatSync38(journal, { throwIfNoEntry: false });
|
|
116168
116567
|
need6(!!dir && dir.isDirectory() && !dir.isSymbolicLink() && dir.uid === process.getuid() && (dir.mode & 511) === 448, "UNSAFE_JOURNAL");
|
|
116169
|
-
need6(!
|
|
116170
|
-
need6(
|
|
116171
|
-
const stoppedFile = snapshot(
|
|
116172
|
-
const intentFile = snapshot(
|
|
116173
|
-
const configBefore = snapshot(
|
|
116568
|
+
need6(!lstatSync38(join67(journal, "receipt.json"), { throwIfNoEntry: false }), "RECONCILE_ALREADY_COMPLETE");
|
|
116569
|
+
need6(lstatSync38(join67(journal, "stopped.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_JOURNAL_INCOMPLETE");
|
|
116570
|
+
const stoppedFile = snapshot(join67(journal, "stopped.json"), true);
|
|
116571
|
+
const intentFile = snapshot(join67(journal, "intent.json"), true), intent = JSON.parse(intentFile.text);
|
|
116572
|
+
const configBefore = snapshot(join67(journal, "config.before.toml"), true), hooksBefore = snapshot(join67(journal, "hooks.before.json"), true), policyBefore = snapshot(join67(journal, "policy.before.json"), true);
|
|
116174
116573
|
const legacyIntent = intent.home === undefined && intent.configSha256 === undefined && intent.configVersion === undefined && intent.declarations === undefined && intent.admitted === undefined && intent.nativeHooks === undefined;
|
|
116175
116574
|
need6(intent.version === 1 && /^[a-f0-9]{64}$/.test(intent.planDigest) && typeof intent.configPath === "string" && /^[a-f0-9]{64}$/.test(intent.policySha256) && /^[a-f0-9]{64}$/.test(intent.hooksSha256) && Array.isArray(intent.hooks) && intent.hooks.length > 0 && intent.hooks.length <= 100 && (legacyIntent || typeof intent.home === "string" && intent.home === home && /^[a-f0-9]{64}$/.test(intent.configSha256) && typeof intent.configVersion === "string" && Array.isArray(intent.declarations) && Array.isArray(intent.admitted) && Array.isArray(intent.nativeHooks)), "RECONCILE_INTENT_INVALID");
|
|
116176
|
-
const declarations = intent.declarations ?? intent.hooks.map((hook) => ({ event: hook.event, key: `${
|
|
116575
|
+
const declarations = intent.declarations ?? intent.hooks.map((hook) => ({ event: hook.event, key: `${join67(home, ".codex/hooks.json")}${hook.key.slice(hook.key.indexOf(".codex/hooks.json") + ".codex/hooks.json".length)}`, command: hook.command }));
|
|
116177
116576
|
const admitted = intent.admitted ?? intent.hooks;
|
|
116178
116577
|
const configSha256 = intent.configSha256 ?? configBefore.sha256, configVersion = intent.configVersion ?? intent.expectedVersion;
|
|
116179
116578
|
const digestInput = { version: 1, home: intent.home ?? home, configPath: intent.configPath, ...intent.nativeConfigPath !== undefined ? { nativeConfigPath: intent.nativeConfigPath } : {}, configSha256, configVersion, policySha256: intent.policySha256, hooksSha256: intent.hooksSha256, skillsCli: intent.skillsCli, nativeVersion: intent.nativeVersion, declarations, admitted };
|
|
116180
116579
|
need6(makePlanDigest(digestInput) === intent.planDigest, "RECONCILE_PLAN_CHANGED");
|
|
116181
116580
|
need6(isDeepStrictEqual17(intent.hooks, admitted.filter((hook) => !hook.enabled || hook.trustStatus !== "trusted")), "RECONCILE_INTENT_HOOKS_CHANGED");
|
|
116182
116581
|
need6(configBefore.sha256 === (intent.beforeSha256 ?? intent.configSha256) && hooksBefore.sha256 === intent.hooksSha256 && policyBefore.sha256 === intent.policySha256, "RECONCILE_JOURNAL_CHANGED");
|
|
116183
|
-
const policyCurrent = snapshot(
|
|
116582
|
+
const policyCurrent = snapshot(join67(dataDir3, "agent-policy.json"), true);
|
|
116184
116583
|
const { claudeDiscoveryRecovery: claudeRecovery, nativeHookAdditionsRecovery: additionsRecovery } = options;
|
|
116185
116584
|
const recovery = claudeRecovery ?? additionsRecovery;
|
|
116186
116585
|
need6(!recovery || !options.supersedeBinding, "RECONCILE_RECOVERY_MODE_CONFLICT");
|
|
@@ -116197,17 +116596,17 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
116197
116596
|
if (supersededBinding || recovery) {
|
|
116198
116597
|
need6(Array.isArray(intent.nativeHooks) && intent.nativeHooks.length > 0, "RECONCILE_NATIVE_INVENTORY_REQUIRED");
|
|
116199
116598
|
const proof = options.releaseProof;
|
|
116200
|
-
need6(!!proof &&
|
|
116599
|
+
need6(!!proof && isAbsolute35(proof.packageTarPath) && /^[a-f0-9]{64}$/.test(proof.packageTarSha256) && Number.isInteger(proof.packageTarBytes) && proof.packageTarBytes > 0 && /^[a-f0-9]{64}$/.test(proof.manifestSha256) && /^[a-f0-9]{64}$/.test(proof.executableSha256), "RECONCILE_RELEASE_PROVENANCE_REQUIRED");
|
|
116201
116600
|
}
|
|
116202
116601
|
const currentConfig = snapshot(intent.configPath, true);
|
|
116203
116602
|
const policy = parseManagedSkillPolicy(policyCurrent.text), binding = policy.bridge;
|
|
116204
|
-
const alias = binding.rootAliases?.find((item) => item.agent === "codex"), physicalRoot = alias?.target ??
|
|
116205
|
-
need6(
|
|
116603
|
+
const alias = binding.rootAliases?.find((item) => item.agent === "codex"), physicalRoot = alias?.target ?? join67(home, ".codex"), hooksPath = join67(physicalRoot, "hooks.json");
|
|
116604
|
+
need6(resolve33(intent.configPath) === resolve33(join67(physicalRoot, "config.toml")), "RECONCILE_CONFIG_PATH_CHANGED");
|
|
116206
116605
|
const nativeConfigPath = intent.nativeConfigPath ?? intent.configPath;
|
|
116207
|
-
need6([
|
|
116208
|
-
const codexHome = nativeConfigPath !== intent.configPath ? undefined :
|
|
116606
|
+
need6([join67(home, ".codex/config.toml"), join67(physicalRoot, "config.toml")].includes(nativeConfigPath), "RECONCILE_NATIVE_CONFIG_PATH_CHANGED");
|
|
116607
|
+
const codexHome = nativeConfigPath !== intent.configPath ? undefined : dirname39(nativeConfigPath);
|
|
116209
116608
|
const hooksCurrent = snapshot(hooksPath);
|
|
116210
|
-
const additions = additionsRecovery ? reviewNativeHookAdditions({ path: additionsRecovery.path, intent: intentFile, policy: policyCurrent, configBefore, configCurrent: currentConfig, hooksBefore, hooksCurrent, nativeHooksPath:
|
|
116609
|
+
const additions = additionsRecovery ? reviewNativeHookAdditions({ path: additionsRecovery.path, intent: intentFile, policy: policyCurrent, configBefore, configCurrent: currentConfig, hooksBefore, hooksCurrent, nativeHooksPath: join67(dirname39(nativeConfigPath), "hooks.json"), journalHooks: intent.hooks, recordedNativeHooks: intent.nativeHooks }) : undefined;
|
|
116211
116610
|
const managedHooks = [...intent.hooks, ...additions?.hooks ?? []];
|
|
116212
116611
|
const managedKeys = managedHooks.map((h) => h.key);
|
|
116213
116612
|
const witnessSame = codexTrustReconcileWitness(configBefore.text, managedKeys) === codexTrustReconcileWitness(currentConfig.text, managedKeys);
|
|
@@ -116271,7 +116670,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
116271
116670
|
need6(isDeepStrictEqual17(actual, expected), "RECONCILE_UNRELATED_HOOK_CHANGED");
|
|
116272
116671
|
}
|
|
116273
116672
|
for (const wanted of intent.hooks) {
|
|
116274
|
-
const matches2 = nativeHooks.filter((h2) => h2.key === wanted.key || h2.key === wanted.key.replace(
|
|
116673
|
+
const matches2 = nativeHooks.filter((h2) => h2.key === wanted.key || h2.key === wanted.key.replace(join67(home, ".codex/hooks.json"), hooksPath));
|
|
116275
116674
|
need6(matches2.length === 1, "RECONCILE_NATIVE_IDENTITY_CHANGED");
|
|
116276
116675
|
const h = matches2[0];
|
|
116277
116676
|
const trusted = h.trustStatus === "trusted";
|
|
@@ -116320,7 +116719,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
116320
116719
|
const receipt = { version: 1, status: preview2 ? "recovery-review-required" : supersededBinding ? "superseded" : "reconciled", reconciled: !preview2, supersededBinding, automaticRollback: false, journal, planDigest: intent.planDigest, nativeVersion: rpc.version, nativeStateVerified: !nativeTrustPending, nativeTrustPending, bindingRefreshRequired: !!configDiscoveryRecovery, nativeExecutionVerified: false, configSha256: currentConfig.sha256, hooksSha256: hooksCurrent.sha256, policySha256: policyBefore.sha256, policyBeforeSha256: policyBefore.sha256, policyCurrentSha256: policyCurrent.sha256, previousSkillsCli: intent.skillsCli, skillsCli: skillsCli.receipt, releaseProof: options.releaseProof, nativeInventoryScope: recordedNativeHooks ? "complete" : "declared-managed-hooks-only", unrelatedNativeHooksPreserved: !!recordedNativeHooks, unrelatedSettingsAndCommentsPreserved: true, ...recoveryPlan ? { recoveryPlan, recoveryPlanDigest } : {} };
|
|
116321
116720
|
if (preview2)
|
|
116322
116721
|
return receipt;
|
|
116323
|
-
save(
|
|
116722
|
+
save(join67(journal, "receipt.json"), json2(receipt));
|
|
116324
116723
|
return receipt;
|
|
116325
116724
|
} catch (error61) {
|
|
116326
116725
|
const message = error61 instanceof Error && error61.message.startsWith("CODEX_HOOK_TRUST_") ? error61.message : "CODEX_HOOK_TRUST_RECONCILE_REFUSED";
|
|
@@ -116330,21 +116729,21 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
116330
116729
|
}
|
|
116331
116730
|
}
|
|
116332
116731
|
async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRpc) {
|
|
116333
|
-
const home =
|
|
116334
|
-
return withCodexCorpusWriteAsync([
|
|
116732
|
+
const home = resolve33(options.home ?? homedir13());
|
|
116733
|
+
return withCodexCorpusWriteAsync([join67(home, ".codex")], () => enrollCodexNativeHooksUnlocked(options, connect), options);
|
|
116335
116734
|
}
|
|
116336
116735
|
async function enrollCodexNativeHooksUnlocked(options, connect) {
|
|
116337
116736
|
let rpc, journal;
|
|
116338
116737
|
try {
|
|
116339
|
-
const home =
|
|
116738
|
+
const home = resolve33(options.home ?? homedir13()), dataDir3 = resolve33(options.dataDir ?? getDataDirReadOnly());
|
|
116340
116739
|
assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home });
|
|
116341
|
-
const policyFile = snapshot(
|
|
116740
|
+
const policyFile = snapshot(join67(dataDir3, "agent-policy.json"), true), policy = parseManagedSkillPolicy(policyFile.text);
|
|
116342
116741
|
const binding = policy.bridge, alias = binding.rootAliases?.find((item) => item.agent === "codex");
|
|
116343
116742
|
const skillsCli = bindSkillsCli(binding.commands.codex, options.reviewedSkillsCli);
|
|
116344
|
-
const physicalRoot = alias?.target ??
|
|
116345
|
-
need6(options.codexHome === undefined ||
|
|
116743
|
+
const physicalRoot = alias?.target ?? join67(home, ".codex"), hooksPath = join67(physicalRoot, "hooks.json"), configPath = join67(physicalRoot, "config.toml");
|
|
116744
|
+
need6(options.codexHome === undefined || isAbsolute35(options.codexHome) && [join67(home, ".codex"), physicalRoot].includes(options.codexHome), "NATIVE_HOME_NOT_ADMITTED");
|
|
116346
116745
|
const codexHome = options.codexHome === undefined ? undefined : physicalRoot;
|
|
116347
|
-
const nativeConfigPath =
|
|
116746
|
+
const nativeConfigPath = join67(codexHome ?? join67(home, ".codex"), "config.toml");
|
|
116348
116747
|
const hooksFile = snapshot(hooksPath), configFile = snapshot(configPath, true), original = structure3(configFile.text);
|
|
116349
116748
|
const declarations = JSON.parse(hooksFile.text).hooks, expected = [];
|
|
116350
116749
|
for (const [event, [nativeEvent, label]] of Object.entries(eventNames)) {
|
|
@@ -116353,25 +116752,25 @@ async function enrollCodexNativeHooksUnlocked(options, connect) {
|
|
|
116353
116752
|
need6(Array.isArray(groups), "DECLARATION_CHANGED");
|
|
116354
116753
|
const matches2 = groups.flatMap((group, gi) => (group.hooks ?? []).flatMap((entry, hi) => entry.command === command ? [{ group, entry, gi, hi }] : []));
|
|
116355
116754
|
need6(matches2.length === 1 && isDeepStrictEqual17(matches2[0].group, { hooks: [{ type: "command", command, timeout: 15 }] }), "DECLARATION_CHANGED");
|
|
116356
|
-
expected.push({ event: nativeEvent, key: `${
|
|
116755
|
+
expected.push({ event: nativeEvent, key: `${join67(home, ".codex/hooks.json")}:${label}:${matches2[0].gi}:${matches2[0].hi}`, command });
|
|
116357
116756
|
}
|
|
116358
116757
|
codexTrustTextWitness(configFile.text, expected.map((h) => h.key));
|
|
116359
116758
|
rpc = await connect({ command: options.codexCommand ?? "codex", home, codexHome });
|
|
116360
116759
|
need6(SUPPORTED_CODEX_HOOK_VERSIONS.includes(rpc.version), "NATIVE_UNSUPPORTED_VERSION");
|
|
116361
116760
|
const list2 = async () => {
|
|
116362
116761
|
const response = await rpc.request("hooks/list", { cwds: [home] });
|
|
116363
|
-
const nativeRoots = [...new Set([physicalRoot,
|
|
116364
|
-
const coexistenceWarnings = nativeRoots.flatMap((hooksRoot) => nativeRoots.map((configRoot) => `loading hooks from both ${
|
|
116762
|
+
const nativeRoots = [...new Set([physicalRoot, join67(home, ".codex")])];
|
|
116763
|
+
const coexistenceWarnings = nativeRoots.flatMap((hooksRoot) => nativeRoots.map((configRoot) => `loading hooks from both ${join67(hooksRoot, "hooks.json")} and ${join67(configRoot, "config.toml")}; prefer a single representation for this layer`));
|
|
116365
116764
|
const entry = response?.data?.[0];
|
|
116366
116765
|
need6(Array.isArray(response?.data) && response.data.length === 1 && entry.cwd === home && Array.isArray(entry.hooks) && entry.hooks.length <= 1e4 && Array.isArray(entry.errors) && entry.errors.length === 0 && Array.isArray(entry.warnings) && entry.warnings.length <= 1 && entry.warnings.every((warning) => typeof warning === "string" && coexistenceWarnings.includes(warning)), "NATIVE_DISCOVERY_REFUSED");
|
|
116367
116766
|
return response.data[0].hooks;
|
|
116368
116767
|
};
|
|
116369
116768
|
const admit = (hooks) => expected.map((wanted) => {
|
|
116370
|
-
const canonicalKey = wanted.key.replace(
|
|
116769
|
+
const canonicalKey = wanted.key.replace(join67(home, ".codex/hooks.json"), hooksPath);
|
|
116371
116770
|
const matches2 = hooks.filter((h2) => h2.key === wanted.key || h2.key === canonicalKey);
|
|
116372
116771
|
need6(matches2.length === 1, "AMBIGUOUS_IDENTITY");
|
|
116373
116772
|
const h = matches2[0];
|
|
116374
|
-
need6(h.eventName === wanted.event && h.handlerType === "command" && h.command === wanted.command && h.matcher === null && h.timeoutSec === 15 && h.async === false && h.statusMessage === null && h.additionalContextLimit === null && [hooksPath,
|
|
116773
|
+
need6(h.eventName === wanted.event && h.handlerType === "command" && h.command === wanted.command && h.matcher === null && h.timeoutSec === 15 && h.async === false && h.statusMessage === null && h.additionalContextLimit === null && [hooksPath, join67(home, ".codex/hooks.json")].includes(h.sourcePath) && h.source === "user" && h.pluginId === null && h.isManaged === false && /^sha256:[a-f0-9]{64}$/.test(h.currentHash) && typeof h.enabled === "boolean", "NATIVE_IDENTITY_CHANGED");
|
|
116375
116774
|
need6(hooks.filter((other) => other.command === wanted.command).length === 1, "AMBIGUOUS_IDENTITY");
|
|
116376
116775
|
need6(["trusted", "untrusted", "modified"].includes(h.trustStatus), "UNKNOWN_TRUST_STATUS");
|
|
116377
116776
|
return { key: h.key, event: wanted.event, command: wanted.command, handlerType: h.handlerType, timeoutSec: h.timeoutSec, sourcePath: h.sourcePath, currentHash: h.currentHash, enabled: h.enabled, trustStatus: h.trustStatus };
|
|
@@ -116397,27 +116796,27 @@ async function enrollCodexNativeHooksUnlocked(options, connect) {
|
|
|
116397
116796
|
const baseReceipt = { planDigest, skillsCli: skillsCli.receipt, nativeVersion: rpc.version, nativeConfigPath, ownedNativeProcessId: rpc.processId, agent: "codex", applied: false, planned, nativeEligible: planned.length === 0, bindingRefreshRequired: false, transport: "owned-stdio-process", existingSessionsReloaded: false, nativeExecutionVerified: false };
|
|
116398
116797
|
if (options.apply)
|
|
116399
116798
|
need6(options.reviewedPlanDigest === planDigest, "PLAN_CHANGED: run the dry-run again and pass its reviewed --plan-digest with --apply");
|
|
116400
|
-
const parent =
|
|
116401
|
-
const st =
|
|
116799
|
+
const parent = join67(dataDir3, "native-hook-trust");
|
|
116800
|
+
const st = lstatSync38(parent, { throwIfNoEntry: false });
|
|
116402
116801
|
if (st) {
|
|
116403
116802
|
need6(st.isDirectory() && !st.isSymbolicLink() && st.uid === process.getuid() && (st.mode & 511) === 448, "UNSAFE_JOURNAL");
|
|
116404
116803
|
const priorJournals = readdirSync23(parent);
|
|
116405
116804
|
need6(priorJournals.length < 1000, "JOURNAL_BOUND");
|
|
116406
116805
|
for (const name of priorJournals) {
|
|
116407
116806
|
need6(/^[a-f0-9-]{36}$/.test(name), "UNSAFE_JOURNAL");
|
|
116408
|
-
need6(
|
|
116807
|
+
need6(lstatSync38(join67(parent, name, "receipt.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_REQUIRED: inspect the incomplete private journal before applying again");
|
|
116409
116808
|
}
|
|
116410
116809
|
}
|
|
116411
116810
|
if (!options.apply || !planned.length)
|
|
116412
116811
|
return baseReceipt;
|
|
116413
116812
|
if (!st)
|
|
116414
116813
|
mkdirSync28(parent, { mode: 448 });
|
|
116415
|
-
journal =
|
|
116814
|
+
journal = join67(parent, randomUUID12());
|
|
116416
116815
|
mkdirSync28(journal, { mode: 448 });
|
|
116417
|
-
save(
|
|
116418
|
-
save(
|
|
116419
|
-
save(
|
|
116420
|
-
save(
|
|
116816
|
+
save(join67(journal, "config.before.toml"), configFile.bytes);
|
|
116817
|
+
save(join67(journal, "hooks.before.json"), hooksFile.bytes);
|
|
116818
|
+
save(join67(journal, "policy.before.json"), policyFile.bytes);
|
|
116819
|
+
save(join67(journal, "intent.json"), json2({ ...digestInput, planDigest, hooks: planned, nativeHooks: discovered.map(safeNativeHook) }));
|
|
116421
116820
|
need6(isDeepStrictEqual17(admit(await list2()), admitted), "NATIVE_DISCOVERY_CHANGED");
|
|
116422
116821
|
checkInputs();
|
|
116423
116822
|
let result2;
|
|
@@ -116433,7 +116832,7 @@ async function enrollCodexNativeHooksUnlocked(options, connect) {
|
|
|
116433
116832
|
for (const h of planned)
|
|
116434
116833
|
expectedConfig.hooks.state[h.key] = { ...expectedConfig.hooks.state[h.key], enabled: true, trusted_hash: h.currentHash };
|
|
116435
116834
|
need6(isDeepStrictEqual17(structure3(after2.text), expectedConfig) && codexTrustTextWitness(after2.text, keys3) === preservationText, "PRESERVATION_FAILED");
|
|
116436
|
-
const savedConfig = snapshot(
|
|
116835
|
+
const savedConfig = snapshot(join67(journal, "config.before.toml"), true);
|
|
116437
116836
|
need6(savedConfig.sha256 === configFile.sha256, "JOURNAL_CHANGED");
|
|
116438
116837
|
const discoveryTransition = binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, savedConfig, after2, planned) : undefined;
|
|
116439
116838
|
unchanged2(policyFile);
|
|
@@ -116449,13 +116848,13 @@ async function enrollCodexNativeHooksUnlocked(options, connect) {
|
|
|
116449
116848
|
skillsCli.recheck();
|
|
116450
116849
|
assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: discoveryTransition });
|
|
116451
116850
|
const receipt = { ...baseReceipt, applied: true, nativeEligible: true, bindingRefreshRequired: !!discoveryTransition, ...discoveryTransition ? { discoveryTransition } : {}, nativeConfigVersion: result2.version, journal, beforeSha256: configFile.sha256, afterSha256: after2.sha256, unrelatedSettingsAndCommentsPreserved: true };
|
|
116452
|
-
save(
|
|
116851
|
+
save(join67(journal, "receipt.json"), json2(receipt));
|
|
116453
116852
|
return receipt;
|
|
116454
116853
|
} catch (error61) {
|
|
116455
116854
|
const message = error61 instanceof Error && error61.message.startsWith("CODEX_HOOK_TRUST_") ? error61.message : "CODEX_HOOK_TRUST_REFUSED: verify managed bridge installation and native Codex support";
|
|
116456
116855
|
if (journal) {
|
|
116457
116856
|
try {
|
|
116458
|
-
save(
|
|
116857
|
+
save(join67(journal, "stopped.json"), json2({ error: message.split(":")[0], automaticRollback: false, reconcileBeforeRetry: true }));
|
|
116459
116858
|
} catch {}
|
|
116460
116859
|
}
|
|
116461
116860
|
throw new Error(message);
|
|
@@ -116490,7 +116889,7 @@ var init_agent_codex_trust = __esm(() => {
|
|
|
116490
116889
|
// src/lib/codex-native-trust.ts
|
|
116491
116890
|
import { createHash as createHash40 } from "crypto";
|
|
116492
116891
|
import { readFileSync as readFileSync44 } from "fs";
|
|
116493
|
-
import { join as
|
|
116892
|
+
import { join as join68, resolve as resolve34 } from "path";
|
|
116494
116893
|
function refuse5(detail) {
|
|
116495
116894
|
throw new Error(`NATIVE_SKILL_POLICY_TRUST_REFUSED: ${detail}`);
|
|
116496
116895
|
}
|
|
@@ -116509,7 +116908,7 @@ function planCodexNativeTrust(options) {
|
|
|
116509
116908
|
refuse5("digests must be unique");
|
|
116510
116909
|
if (typeof expectedPolicySha256 !== "string" || !HEX_DIGEST2.test(expectedPolicySha256))
|
|
116511
116910
|
refuse5("--expected-policy-sha256 must be lowercase SHA-256 hex");
|
|
116512
|
-
const dataDir3 =
|
|
116911
|
+
const dataDir3 = resolve34(options.dataDir ?? getDataDirReadOnly()), policyPath = join68(dataDir3, "agent-policy.json");
|
|
116513
116912
|
assertOperatorTrustRoot(dataDir3);
|
|
116514
116913
|
const snapshot2 = readManagedSkillPolicySnapshot(dataDir3);
|
|
116515
116914
|
if (!snapshot2)
|
|
@@ -116692,8 +117091,8 @@ var init_hook_diagnostics = __esm(() => {
|
|
|
116692
117091
|
|
|
116693
117092
|
// src/lib/claude-prospective-review.ts
|
|
116694
117093
|
import { createHash as createHash41 } from "crypto";
|
|
116695
|
-
import { lstatSync as
|
|
116696
|
-
import { basename as basename19, dirname as
|
|
117094
|
+
import { lstatSync as lstatSync39, readFileSync as readFileSync45, readdirSync as readdirSync24, realpathSync as realpathSync21 } from "fs";
|
|
117095
|
+
import { basename as basename19, dirname as dirname40, isAbsolute as isAbsolute36, join as join69, relative as relative12, resolve as resolve35, sep as sep15 } from "path";
|
|
116697
117096
|
import { isDeepStrictEqual as isDeepStrictEqual18 } from "util";
|
|
116698
117097
|
function hashClaudeDiscoveryBinding(binding) {
|
|
116699
117098
|
return sha7(JSON.stringify(binding));
|
|
@@ -116744,7 +117143,7 @@ function keys3(value, expected, name) {
|
|
|
116744
117143
|
refuse6(`${name} has an unsupported shape`);
|
|
116745
117144
|
}
|
|
116746
117145
|
function abs(path, name) {
|
|
116747
|
-
if (typeof path !== "string" || !path || path.length > 4096 || /[\x00-\x1f\x7f]/.test(path) || !
|
|
117146
|
+
if (typeof path !== "string" || !path || path.length > 4096 || /[\x00-\x1f\x7f]/.test(path) || !isAbsolute36(path) || resolve35(path) !== path)
|
|
116748
117147
|
refuse6(`${name} must be a normalized absolute path`);
|
|
116749
117148
|
}
|
|
116750
117149
|
function validUtcTimestamp(value) {
|
|
@@ -116752,27 +117151,27 @@ function validUtcTimestamp(value) {
|
|
|
116752
117151
|
}
|
|
116753
117152
|
function safeFile(path, name) {
|
|
116754
117153
|
abs(path, name);
|
|
116755
|
-
for (let at2 =
|
|
116756
|
-
const stat4 =
|
|
117154
|
+
for (let at2 = dirname40(path);; at2 = dirname40(at2)) {
|
|
117155
|
+
const stat4 = lstatSync39(at2, { throwIfNoEntry: false });
|
|
116757
117156
|
if (!stat4?.isDirectory() || stat4.isSymbolicLink())
|
|
116758
117157
|
refuse6(`${name} traverses a symlink or non-directory`);
|
|
116759
|
-
if (at2 ===
|
|
117158
|
+
if (at2 === dirname40(at2))
|
|
116760
117159
|
break;
|
|
116761
117160
|
}
|
|
116762
|
-
const stat3 =
|
|
117161
|
+
const stat3 = lstatSync39(path, { throwIfNoEntry: false });
|
|
116763
117162
|
if (!stat3?.isFile() || stat3.isSymbolicLink() || stat3.size > MAX_CANDIDATE_BYTES)
|
|
116764
117163
|
refuse6(`${name} is not a bounded regular file`);
|
|
116765
117164
|
return readFileSync45(path);
|
|
116766
117165
|
}
|
|
116767
117166
|
function canonicalDir(path, name) {
|
|
116768
117167
|
abs(path, name);
|
|
116769
|
-
if (realpathSync21(path) !== path || !
|
|
117168
|
+
if (realpathSync21(path) !== path || !lstatSync39(path).isDirectory())
|
|
116770
117169
|
refuse6(`${name} is not a canonical directory`);
|
|
116771
|
-
for (let at2 = path;; at2 =
|
|
116772
|
-
const stat3 =
|
|
117170
|
+
for (let at2 = path;; at2 = dirname40(at2)) {
|
|
117171
|
+
const stat3 = lstatSync39(at2);
|
|
116773
117172
|
if (!stat3.isDirectory() || stat3.isSymbolicLink())
|
|
116774
117173
|
refuse6(`${name} traverses a symlink`);
|
|
116775
|
-
if (at2 ===
|
|
117174
|
+
if (at2 === dirname40(at2))
|
|
116776
117175
|
break;
|
|
116777
117176
|
}
|
|
116778
117177
|
}
|
|
@@ -116781,17 +117180,17 @@ function captureClaudeProspectiveCandidateClosure(root2) {
|
|
|
116781
117180
|
const entries = [];
|
|
116782
117181
|
let bytes = 0;
|
|
116783
117182
|
const walk2 = (directory2) => {
|
|
116784
|
-
const beforeDirectory =
|
|
117183
|
+
const beforeDirectory = lstatSync39(directory2);
|
|
116785
117184
|
const names = readdirSync24(directory2).sort();
|
|
116786
117185
|
if (new Set(names).size !== names.length)
|
|
116787
117186
|
refuse6("candidate contains ambiguous directory entries");
|
|
116788
117187
|
for (const name of names) {
|
|
116789
117188
|
if (!name || name === "." || name === ".." || name.includes("/") || name.includes("\\") || /[\x00-\x1f\x7f]/.test(name))
|
|
116790
117189
|
refuse6("candidate contains an unsupported path member");
|
|
116791
|
-
const path =
|
|
117190
|
+
const path = join69(directory2, name), rel = relative12(root2, path).split(sep15).join("/");
|
|
116792
117191
|
if (entries.length >= MAX_CANDIDATE_FILES)
|
|
116793
117192
|
refuse6("candidate closure exceeds its member limit");
|
|
116794
|
-
const stat3 =
|
|
117193
|
+
const stat3 = lstatSync39(path);
|
|
116795
117194
|
if (stat3.isSymbolicLink())
|
|
116796
117195
|
refuse6("candidate closure contains a symlink");
|
|
116797
117196
|
if (stat3.isDirectory()) {
|
|
@@ -116801,14 +117200,14 @@ function captureClaudeProspectiveCandidateClosure(root2) {
|
|
|
116801
117200
|
bytes += stat3.size;
|
|
116802
117201
|
if (bytes > MAX_CANDIDATE_BYTES)
|
|
116803
117202
|
refuse6("candidate closure exceeds its byte limit");
|
|
116804
|
-
const content = safeFile(path, "candidate member"), after2 =
|
|
117203
|
+
const content = safeFile(path, "candidate member"), after2 = lstatSync39(path);
|
|
116805
117204
|
if (!after2.isFile() || after2.dev !== stat3.dev || after2.ino !== stat3.ino || after2.size !== stat3.size || after2.mtimeMs !== stat3.mtimeMs || after2.ctimeMs !== stat3.ctimeMs)
|
|
116806
117205
|
refuse6("candidate member changed while being read");
|
|
116807
117206
|
entries.push([rel, "file", sha7(content)]);
|
|
116808
117207
|
} else
|
|
116809
117208
|
refuse6("candidate closure contains a special file");
|
|
116810
117209
|
}
|
|
116811
|
-
const afterDirectory =
|
|
117210
|
+
const afterDirectory = lstatSync39(directory2);
|
|
116812
117211
|
if (!afterDirectory.isDirectory() || afterDirectory.dev !== beforeDirectory.dev || afterDirectory.ino !== beforeDirectory.ino || afterDirectory.mtimeMs !== beforeDirectory.mtimeMs || afterDirectory.ctimeMs !== beforeDirectory.ctimeMs)
|
|
116813
117212
|
refuse6("candidate directory changed while being read");
|
|
116814
117213
|
};
|
|
@@ -116819,9 +117218,9 @@ function captureClaudeProspectiveCandidateClosure(root2) {
|
|
|
116819
117218
|
function captureClaudeInstallerCandidate(root2, policyPath) {
|
|
116820
117219
|
const closureSha256 = captureClaudeProspectiveCandidateClosure(root2);
|
|
116821
117220
|
const dataDir3 = getDataDirReadOnly();
|
|
116822
|
-
if (policyPath !==
|
|
117221
|
+
if (policyPath !== join69(dataDir3, "agent-policy.json"))
|
|
116823
117222
|
refuse6("Skills policy path differs from the package-owned resolver");
|
|
116824
|
-
const catalogPath =
|
|
117223
|
+
const catalogPath = join69(root2, ".claude-plugin/marketplace.json");
|
|
116825
117224
|
const catalog = jsonFile(catalogPath, "candidate catalog");
|
|
116826
117225
|
if (!catalog || !Array.isArray(catalog.plugins))
|
|
116827
117226
|
refuse6("candidate catalog is invalid");
|
|
@@ -116832,13 +117231,13 @@ function captureClaudeInstallerCandidate(root2, policyPath) {
|
|
|
116832
117231
|
if (names.has(row2.name))
|
|
116833
117232
|
refuse6("candidate catalog repeats a plugin name");
|
|
116834
117233
|
names.add(row2.name);
|
|
116835
|
-
if (typeof row2.source !== "string" ||
|
|
117234
|
+
if (typeof row2.source !== "string" || isAbsolute36(row2.source) || /[\\\x00-\x1f\x7f]/.test(row2.source))
|
|
116836
117235
|
refuse6("candidate catalog plugin source is invalid");
|
|
116837
|
-
const pluginRoot =
|
|
117236
|
+
const pluginRoot = resolve35(root2, row2.source);
|
|
116838
117237
|
const relativeRoot = relative12(root2, pluginRoot);
|
|
116839
|
-
if (!relativeRoot || relativeRoot === "." || relativeRoot === ".." || relativeRoot.startsWith(`..${sep15}`) ||
|
|
117238
|
+
if (!relativeRoot || relativeRoot === "." || relativeRoot === ".." || relativeRoot.startsWith(`..${sep15}`) || isAbsolute36(relativeRoot))
|
|
116840
117239
|
refuse6("candidate plugin source escapes the candidate root");
|
|
116841
|
-
const path =
|
|
117240
|
+
const path = join69(pluginRoot, ".claude-plugin/plugin.json");
|
|
116842
117241
|
return { plugin: row2.name, ...captureClaudePluginManifestFile(path) };
|
|
116843
117242
|
});
|
|
116844
117243
|
const policy = readManagedSkillPolicySnapshot(dataDir3);
|
|
@@ -116855,7 +117254,7 @@ function captureClaudeInstallerCandidate(root2, policyPath) {
|
|
|
116855
117254
|
}
|
|
116856
117255
|
function readWitness(path, expected, name) {
|
|
116857
117256
|
abs(path, `${name} path`);
|
|
116858
|
-
const stat3 =
|
|
117257
|
+
const stat3 = lstatSync39(path, { throwIfNoEntry: false });
|
|
116859
117258
|
if (expected === null) {
|
|
116860
117259
|
if (stat3)
|
|
116861
117260
|
refuse6(`${name} was absent at review but is now present`);
|
|
@@ -116867,7 +117266,7 @@ function readWitness(path, expected, name) {
|
|
|
116867
117266
|
refuse6(`${name} preimage changed`);
|
|
116868
117267
|
}
|
|
116869
117268
|
function jsonFile(path, name) {
|
|
116870
|
-
const stat3 =
|
|
117269
|
+
const stat3 = lstatSync39(path, { throwIfNoEntry: false });
|
|
116871
117270
|
if (!stat3)
|
|
116872
117271
|
return null;
|
|
116873
117272
|
let value;
|
|
@@ -116898,8 +117297,8 @@ function assertNoUnprojectedSkillPayload(root2, catalogPath, marketplace, plugin
|
|
|
116898
117297
|
refuse6("candidate marketplace entry declares native skill or command payloads");
|
|
116899
117298
|
const walk2 = (directory2) => {
|
|
116900
117299
|
for (const name of readdirSync24(directory2).sort()) {
|
|
116901
|
-
const path =
|
|
116902
|
-
const stat3 =
|
|
117300
|
+
const path = join69(directory2, name), rel = relative12(root2, path).split(sep15).join("/");
|
|
117301
|
+
const stat3 = lstatSync39(path);
|
|
116903
117302
|
if (stat3.isDirectory())
|
|
116904
117303
|
walk2(path);
|
|
116905
117304
|
else if (stat3.isFile()) {
|
|
@@ -116956,16 +117355,16 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
116956
117355
|
refuse6("Skills policy root alias changed or is invalid");
|
|
116957
117356
|
}
|
|
116958
117357
|
const canonical8 = (path) => canonicalAgentPath(path, aliases);
|
|
116959
|
-
const configRoot = canonical8(
|
|
117358
|
+
const configRoot = canonical8(join69(request2.native.home, ".claude"));
|
|
116960
117359
|
canonicalDir(configRoot, "Claude config root");
|
|
116961
117360
|
if (request2.native.configRoot !== configRoot)
|
|
116962
117361
|
refuse6("Claude config root differs from the current resolver and reviewed root alias");
|
|
116963
|
-
const pluginRoot =
|
|
117362
|
+
const pluginRoot = join69(configRoot, "plugins");
|
|
116964
117363
|
if (process.env.CLAUDE_CODE_PLUGIN_CACHE_DIR)
|
|
116965
117364
|
refuse6("CLAUDE_CODE_PLUGIN_CACHE_DIR overrides are unsupported by this prospective schema; bind and review the actual cache root first");
|
|
116966
117365
|
if (request2.native.pluginRoot !== pluginRoot)
|
|
116967
117366
|
refuse6("Claude plugin root differs from the supported standard plugins directory; Cowork and custom cache roots require a separately bound schema");
|
|
116968
|
-
const pluginRootStat =
|
|
117367
|
+
const pluginRootStat = lstatSync39(pluginRoot, { throwIfNoEntry: false });
|
|
116969
117368
|
if (pluginRootStat && (!pluginRootStat.isDirectory() || pluginRootStat.isSymbolicLink()))
|
|
116970
117369
|
refuse6("Claude plugin root is not a regular directory");
|
|
116971
117370
|
keys3(request2.candidate, ["marketplace", "root", "catalogPath", "catalogSha256", "closureSha256", "plugins", ...hasOwn2(request2.candidate, "releaseManifest") ? ["releaseManifest"] : [], ...hasOwn2(request2.candidate, "functionHooksEnv") ? ["functionHooksEnv"] : [], ...hasOwn2(request2.candidate, "settingsMarketplaceSource") ? ["settingsMarketplaceSource"] : []], "candidate");
|
|
@@ -116982,7 +117381,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
116982
117381
|
abs(candidate2.catalogPath, "catalog path");
|
|
116983
117382
|
if (!candidate2.catalogPath.startsWith(candidate2.root + sep15))
|
|
116984
117383
|
refuse6("catalog must be inside the frozen candidate root");
|
|
116985
|
-
if (candidate2.catalogPath !==
|
|
117384
|
+
if (candidate2.catalogPath !== join69(candidate2.root, ".claude-plugin", "marketplace.json"))
|
|
116986
117385
|
refuse6("marketplace catalog must be at the frozen root's .claude-plugin/marketplace.json path");
|
|
116987
117386
|
if (!SHA256.test(candidate2.catalogSha256) || !SHA256.test(candidate2.closureSha256))
|
|
116988
117387
|
refuse6("candidate digests must be lowercase SHA-256");
|
|
@@ -117024,11 +117423,11 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
117024
117423
|
if (Buffer.byteLength(canonicalJson3(selected.optionsPatch), "utf8") > 16 * 1024)
|
|
117025
117424
|
refuse6("selected plugin optionsPatch exceeds its byte bound");
|
|
117026
117425
|
abs(selected.manifestPath, "manifest path");
|
|
117027
|
-
if (!selected.manifestPath.startsWith(candidate2.root + sep15) || basename19(
|
|
117426
|
+
if (!selected.manifestPath.startsWith(candidate2.root + sep15) || basename19(dirname40(selected.manifestPath)) !== ".claude-plugin" || selected.manifestPath !== join69(dirname40(dirname40(selected.manifestPath)), ".claude-plugin", "plugin.json"))
|
|
117028
117427
|
refuse6("plugin manifest must be under a plugin root inside the frozen marketplace closure");
|
|
117029
|
-
const pluginRoot2 =
|
|
117428
|
+
const pluginRoot2 = dirname40(dirname40(selected.manifestPath));
|
|
117030
117429
|
const relativePluginRoot = relative12(candidate2.root, pluginRoot2);
|
|
117031
|
-
if (!relativePluginRoot || relativePluginRoot === "." || relativePluginRoot === ".." || relativePluginRoot.startsWith(`..${sep15}`) ||
|
|
117430
|
+
if (!relativePluginRoot || relativePluginRoot === "." || relativePluginRoot === ".." || relativePluginRoot.startsWith(`..${sep15}`) || isAbsolute36(relativePluginRoot))
|
|
117032
117431
|
refuse6("plugin root must be a child of the frozen marketplace root");
|
|
117033
117432
|
canonicalDir(pluginRoot2, "candidate plugin root");
|
|
117034
117433
|
if (!SHA256.test(selected.manifestSha256))
|
|
@@ -117062,7 +117461,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
117062
117461
|
const sourcePath = selectedEntry.source;
|
|
117063
117462
|
const sourceRelativePath = relative12(candidate2.root, pluginRoot2).split(sep15).join("/");
|
|
117064
117463
|
const expectedSourcePath = sourceRelativePath === "." ? "./" : `./${sourceRelativePath}`;
|
|
117065
|
-
if (typeof sourcePath !== "string" ||
|
|
117464
|
+
if (typeof sourcePath !== "string" || isAbsolute36(sourcePath) || sourcePath !== expectedSourcePath || resolve35(dirname40(dirname40(candidate2.catalogPath)), sourcePath) !== pluginRoot2)
|
|
117066
117465
|
refuse6("marketplace source does not resolve to the frozen plugin closure; external source mapping is not supported by this schema");
|
|
117067
117466
|
const entry = captureClaudeMarketplaceEntry(candidate2.catalogPath, candidate2.marketplace, selected.plugin);
|
|
117068
117467
|
if (entry.sha256.length !== 64)
|
|
@@ -117082,12 +117481,12 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
117082
117481
|
for (const name of ["settings", "projectSettings", "projectSettingsLocal", "marketplaces", "installedPlugins"])
|
|
117083
117482
|
keys3(request2.preimages[name], ["path", "sha256"], `${name} preimage`);
|
|
117084
117483
|
const expectedPaths = {
|
|
117085
|
-
settings: request2.scope.kind === "project" ? canonical8(
|
|
117086
|
-
userSettings: canonical8(
|
|
117087
|
-
projectSettings: canonical8(
|
|
117088
|
-
projectSettingsLocal: canonical8(
|
|
117089
|
-
marketplaces: canonical8(
|
|
117090
|
-
installedPlugins: canonical8(
|
|
117484
|
+
settings: request2.scope.kind === "project" ? canonical8(join69(request2.scope.projectPath, ".claude/settings.json")) : canonical8(join69(request2.native.home, ".claude/settings.json")),
|
|
117485
|
+
userSettings: canonical8(join69(request2.native.home, ".claude/settings.json")),
|
|
117486
|
+
projectSettings: canonical8(join69(request2.scope.projectPath, ".claude/settings.json")),
|
|
117487
|
+
projectSettingsLocal: canonical8(join69(request2.scope.projectPath, ".claude/settings.local.json")),
|
|
117488
|
+
marketplaces: canonical8(join69(request2.native.home, ".claude/plugins/known_marketplaces.json")),
|
|
117489
|
+
installedPlugins: canonical8(join69(request2.native.home, ".claude/plugins/installed_plugins.json"))
|
|
117091
117490
|
};
|
|
117092
117491
|
for (const name of Object.keys(expectedPaths)) {
|
|
117093
117492
|
const witness = request2.preimages[name];
|
|
@@ -117205,7 +117604,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
117205
117604
|
const manifestVersion = manifest.version;
|
|
117206
117605
|
const sanitizeComponent = (value) => value.replace(/[^A-Za-z0-9_-]/g, "-");
|
|
117207
117606
|
const sanitizedVersion = manifestVersion === "." || manifestVersion === ".." ? "-" : manifestVersion.replace(/[^A-Za-z0-9._-]/g, "-");
|
|
117208
|
-
const expectedInstallPath =
|
|
117607
|
+
const expectedInstallPath = join69(pluginRoot, "cache", sanitizeComponent(candidate2.marketplace), sanitizeComponent(plugin), sanitizedVersion);
|
|
117209
117608
|
if (expectedInstallPath.length > 4096)
|
|
117210
117609
|
refuse6("candidate native cache path exceeds its bound");
|
|
117211
117610
|
const targetRegistration = {
|
|
@@ -117343,7 +117742,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
117343
117742
|
{ name: "project-settings-local", path: expectedPaths.projectSettingsLocal, sha256: request2.preimages.projectSettingsLocal.sha256 },
|
|
117344
117743
|
{ name: "known-marketplaces", path: expectedPaths.marketplaces, sha256: request2.preimages.marketplaces.sha256 },
|
|
117345
117744
|
{ name: "installed-plugins", path: expectedPaths.installedPlugins, sha256: request2.preimages.installedPlugins.sha256 },
|
|
117346
|
-
{ name: "skills-policy", path:
|
|
117745
|
+
{ name: "skills-policy", path: join69(request2.skills.dataDir, "agent-policy.json"), sha256: request2.skills.policySha256 }
|
|
117347
117746
|
],
|
|
117348
117747
|
ownedDelta: { settingsEnabledPlugins: selectedPluginIds, selectedPluginOptions: selectedOptionPaths, functionHooksEnv: candidate2.functionHooksEnv ?? null, knownMarketplace: candidate2.marketplace, installedPlugins: selectedPluginIds, unrelatedGraph: "preserved-by-complete-semantic-documents" },
|
|
117349
117748
|
identityPrecondition: "Harnesses must resolve the installed Claude home/config/plugin roots and executable path/version/hash plus the installed Skills data directory through their package-owned consumers, then compare every value before trusting this receipt; this validator checks supplied paths and current bytes only and does not establish actual consumer identity",
|
|
@@ -117369,10 +117768,10 @@ var init_claude_prospective_review = __esm(() => {
|
|
|
117369
117768
|
|
|
117370
117769
|
// src/lib/self-spawn.ts
|
|
117371
117770
|
import { realpathSync as realpathSync22 } from "fs";
|
|
117372
|
-
import { dirname as
|
|
117771
|
+
import { dirname as dirname41, isAbsolute as isAbsolute37, sep as sep16 } from "path";
|
|
117373
117772
|
function selfSpawnRoot(entry) {
|
|
117374
117773
|
const index = entry.indexOf(INSTALLED_PACKAGE);
|
|
117375
|
-
const root2 = index > 0 ? entry.slice(0, index) :
|
|
117774
|
+
const root2 = index > 0 ? entry.slice(0, index) : dirname41(entry);
|
|
117376
117775
|
try {
|
|
117377
117776
|
return realpathSync22(root2);
|
|
117378
117777
|
} catch {
|
|
@@ -117382,12 +117781,12 @@ function selfSpawnRoot(entry) {
|
|
|
117382
117781
|
function selfSpawnCommand(args2, options = {}) {
|
|
117383
117782
|
const runtime = options.runtime ?? process.execPath;
|
|
117384
117783
|
const entry = options.entry ?? process.argv[1];
|
|
117385
|
-
if (!runtime || !
|
|
117784
|
+
if (!runtime || !isAbsolute37(runtime) || !entry || !isAbsolute37(entry))
|
|
117386
117785
|
throw new Error("SKILLS_SELF_SPAWN_ENTRY_UNRESOLVED");
|
|
117387
117786
|
const root2 = selfSpawnRoot(entry);
|
|
117388
117787
|
const env3 = pinnedLauncherEnvironment(options.env ?? process.env);
|
|
117389
117788
|
env3[LAUNCH_CWD_VARIABLE] = options.callerCwd ?? process.cwd();
|
|
117390
|
-
return { command: [runtime, ...
|
|
117789
|
+
return { command: [runtime, ...PINNED_LAUNCHER_BUN_FLAGS2, `--cwd=${root2}`, entry, ...args2], cwd: root2, env: env3 };
|
|
117391
117790
|
}
|
|
117392
117791
|
var INSTALLED_PACKAGE;
|
|
117393
117792
|
var init_self_spawn = __esm(() => {
|
|
@@ -117396,8 +117795,8 @@ var init_self_spawn = __esm(() => {
|
|
|
117396
117795
|
});
|
|
117397
117796
|
|
|
117398
117797
|
// src/cli/commands/claude-installer-capture.ts
|
|
117399
|
-
import { closeSync as closeSync26, constants as
|
|
117400
|
-
import { isAbsolute as
|
|
117798
|
+
import { closeSync as closeSync26, constants as constants25, fstatSync as fstatSync26, lstatSync as lstatSync40, openSync as openSync26, readSync as readSync19 } from "fs";
|
|
117799
|
+
import { isAbsolute as isAbsolute38, resolve as resolve36 } from "path";
|
|
117401
117800
|
function need8(condition, code2) {
|
|
117402
117801
|
if (!condition)
|
|
117403
117802
|
throw new CaptureRefusal(code2);
|
|
@@ -117411,14 +117810,14 @@ function exactKeys4(value, expected, operation) {
|
|
|
117411
117810
|
}
|
|
117412
117811
|
}
|
|
117413
117812
|
function canonicalPath2(value) {
|
|
117414
|
-
need8(typeof value === "string" &&
|
|
117813
|
+
need8(typeof value === "string" && isAbsolute38(value) && resolve36(value) === value && !/[\x00-\x1f\x7f]/.test(value), "INVALID_PATH: path fields must be normalized absolute paths without control characters");
|
|
117415
117814
|
}
|
|
117416
117815
|
function readRequest2(path) {
|
|
117417
117816
|
canonicalPath2(path);
|
|
117418
|
-
const before2 =
|
|
117817
|
+
const before2 = lstatSync40(path, { throwIfNoEntry: false });
|
|
117419
117818
|
if (!before2?.isFile() || before2.isSymbolicLink() || before2.size > MAX_REQUEST_BYTES)
|
|
117420
117819
|
throw new CaptureRefusal("INVALID_REQUEST_FILE: --request must name a regular non-symlink JSON file no larger than 64 KiB");
|
|
117421
|
-
const fd = openSync26(path,
|
|
117820
|
+
const fd = openSync26(path, constants25.O_RDONLY | (constants25.O_NOFOLLOW ?? 0) | constants25.O_NONBLOCK);
|
|
117422
117821
|
try {
|
|
117423
117822
|
const opened = fstatSync26(fd);
|
|
117424
117823
|
need8(opened.isFile() && opened.dev === before2.dev && opened.ino === before2.ino && opened.size === before2.size, "INVALID_REQUEST_FILE: --request must remain the same regular file while read");
|
|
@@ -117430,7 +117829,7 @@ function readRequest2(path) {
|
|
|
117430
117829
|
break;
|
|
117431
117830
|
length += count;
|
|
117432
117831
|
}
|
|
117433
|
-
const after2 = fstatSync26(fd), current =
|
|
117832
|
+
const after2 = fstatSync26(fd), current = lstatSync40(path);
|
|
117434
117833
|
need8(length <= MAX_REQUEST_BYTES && length === opened.size && after2.size === opened.size && after2.mtimeMs === opened.mtimeMs && after2.ctimeMs === opened.ctimeMs && current.dev === opened.dev && current.ino === opened.ino && current.mtimeMs === opened.mtimeMs && current.ctimeMs === opened.ctimeMs, "INVALID_REQUEST_FILE: --request must remain unchanged while read");
|
|
117435
117834
|
try {
|
|
117436
117835
|
return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, length)));
|
|
@@ -117562,10 +117961,10 @@ var exports_agent_integration = {};
|
|
|
117562
117961
|
__export(exports_agent_integration, {
|
|
117563
117962
|
registerAgentIntegration: () => registerAgentIntegration
|
|
117564
117963
|
});
|
|
117565
|
-
import { existsSync as existsSync36, lstatSync as
|
|
117964
|
+
import { existsSync as existsSync36, lstatSync as lstatSync41, readFileSync as readFileSync46, readSync as readSync20, writeFileSync as writeFileSync27 } from "fs";
|
|
117566
117965
|
import { createHash as createHash42 } from "crypto";
|
|
117567
|
-
import { homedir as
|
|
117568
|
-
import { isAbsolute as
|
|
117966
|
+
import { homedir as homedir14 } from "os";
|
|
117967
|
+
import { isAbsolute as isAbsolute39 } from "path";
|
|
117569
117968
|
function pinnedHookProfile(input3, configuredProfile) {
|
|
117570
117969
|
try {
|
|
117571
117970
|
const parsed = parseSkillContextInput(JSON.stringify(input3));
|
|
@@ -117661,13 +118060,13 @@ function registerAgentIntegration(parent) {
|
|
|
117661
118060
|
});
|
|
117662
118061
|
hook.command("native-catalog").requiredOption("--cwd <path>", "Absolute project directory observed by native Codex skills/list").requiredOption("--output <file>", "New private file for the projected native catalog").option("--codex-command <path>", "Installed Codex executable used by the native client", "codex").option("--json", "Output bounded capture metadata as JSON", false).description("Capture a reviewed Codex native skill catalog for exact hook enrollment").action(async (options) => {
|
|
117663
118062
|
try {
|
|
117664
|
-
if (!
|
|
118063
|
+
if (!isAbsolute39(options.cwd) || !isAbsolute39(options.output))
|
|
117665
118064
|
throw new Error("CODEX_NATIVE_SKILL_CATALOG_ABSOLUTE_PATH_REQUIRED");
|
|
117666
118065
|
if (existsSync36(options.output))
|
|
117667
118066
|
throw new Error("CODEX_NATIVE_SKILL_CATALOG_OUTPUT_EXISTS");
|
|
117668
118067
|
const catalog = await captureCodexNativeSkillCatalog({
|
|
117669
118068
|
command: options.codexCommand,
|
|
117670
|
-
home:
|
|
118069
|
+
home: homedir14(),
|
|
117671
118070
|
...process.env.CODEX_HOME === undefined ? {} : { codexHome: process.env.CODEX_HOME },
|
|
117672
118071
|
cwd: options.cwd
|
|
117673
118072
|
});
|
|
@@ -117680,7 +118079,7 @@ function registerAgentIntegration(parent) {
|
|
|
117680
118079
|
throw new Error("CODEX_NATIVE_SKILL_CATALOG_OUTPUT_EXISTS");
|
|
117681
118080
|
throw error61;
|
|
117682
118081
|
}
|
|
117683
|
-
const written =
|
|
118082
|
+
const written = lstatSync41(options.output);
|
|
117684
118083
|
if (!written.isFile() || written.isSymbolicLink() || (written.mode & 63) !== 0 || readFileSync46(options.output, "utf8") !== bytes)
|
|
117685
118084
|
throw new Error("CODEX_NATIVE_SKILL_CATALOG_READBACK_FAILED");
|
|
117686
118085
|
const receipt = {
|
|
@@ -117728,9 +118127,9 @@ function registerAgentIntegration(parent) {
|
|
|
117728
118127
|
});
|
|
117729
118128
|
hook.command("review-claude-candidate").requiredOption("--request <file>", "Frozen skills.claude-plugin-prospective-review/v1 JSON request").option("--json", "Return the validation-only receipt as JSON", false).description("Validate a prospective Claude plugin candidate and current preimages without changing native state; Harnesses must compare native and Skills paths against installed package-owned resolvers before trusting the receipt").action(async (options) => {
|
|
117730
118129
|
try {
|
|
117731
|
-
if (!
|
|
118130
|
+
if (!isAbsolute39(options.request))
|
|
117732
118131
|
throw new Error("CLAUDE_CANDIDATE_REVIEW_REFUSED: --request must be an absolute path");
|
|
117733
|
-
const stat3 =
|
|
118132
|
+
const stat3 = lstatSync41(options.request);
|
|
117734
118133
|
if (!stat3.isFile() || stat3.isSymbolicLink() || stat3.size > 1024 * 1024)
|
|
117735
118134
|
throw new Error("CLAUDE_CANDIDATE_REVIEW_REFUSED: request must be a regular file no larger than 1 MiB");
|
|
117736
118135
|
const requestBytes = readFileSync46(options.request);
|
|
@@ -117775,10 +118174,10 @@ function registerAgentIntegration(parent) {
|
|
|
117775
118174
|
hook.command("agents").option("--json", "Output the adapter capability inventory", false).description("Show maintained native adapters and explicit coverage limits").action(async () => {
|
|
117776
118175
|
await writeCliOutput(JSON.stringify({ agents: INTEGRATION_AGENTS.map((agent) => ({ agent, bridge: true, ...AGENT_ADAPTERS[agent] })), inventoryOnly: ["codewith", "windsurf", "pi", "amp", "cline", "roo", "copilot"], limitations: ["Cursor prompt hooks gate submission; selected context is injected at session start only.", "Native discovery checks cover known home roots and current project ancestors. External plugin hook injection and arbitrary added directories require separate review.", "Hermes injects selected prompt context, but native pre_llm_call fails open. Exact native hook trust, bundled reseeding opt-out, native payload retirement and a supervised pre-tool guard are required. Child failures block explicitly; native host/supervisor death is not a universal fail-closed guarantee.", "Restart agents and use their normal hook trust controls after installation."] }, null, 2));
|
|
117777
118176
|
});
|
|
117778
|
-
hook.command("install").option("--agent <agent>", `Agent to configure: ${INTEGRATION_AGENTS.join(", ")}, all
|
|
118177
|
+
hook.command("install").option("--agent <agent>", `Agent to configure: ${INTEGRATION_AGENTS.join(", ")}, all (default: configured or detected agents; explicit all requires every adapter)`).option("--command <path>", "Skills executable used by the hook (preserves existing binding; new agents use skills)").option("--selection-profile <id>", "Selection profile (preserves existing binding; new agents use default)").option("--include-vendor", "Retained for compatibility; vendor system skills are always inventoried and disabled", false).option("--discovery-inputs <file>", "Advanced reviewed active plugin roots and source hashes for unsupported registrations").option("--codex-skill-denials <file>", "Explicit reviewed remote skill denials: array of exact name, path and document sha256; requires fresh catalog and discovery inputs").option("--codex-native-catalog <file>", "Reviewed supported Codex skill and installed-plugin receipt for exact qualified-name disables").option("--reviewed-cache-alias <path>", "Exact skill-containing vendor cache alias reviewed for this hook plan").option("--allow-root-aliases", "Allow home .claude/.codex aliases to existing directories within this home", false).option("--apply", "Apply the plan, preserving prior configuration in private backups", false).option("--json", "Output a receipt as JSON", false).description("Plan or install one Skills CLI bridge plus native prompt hooks").action(async (options) => {
|
|
117779
118178
|
try {
|
|
117780
118179
|
const discoveryInputs = options.discoveryInputs ? JSON.parse(readFileSync46(options.discoveryInputs, "utf8")) : undefined;
|
|
117781
|
-
const plan = planAgentIntegration({ projectDir: process.cwd(), agents: agents(options.agent), command: options.command, profileId: options.selectionProfile, includeVendor: options.includeVendor, discoveryInputs, allowRootAliases: options.allowRootAliases, reviewedCacheAlias: options.reviewedCacheAlias, codexSkillDenials: options.codexSkillDenials ? JSON.parse(readFileSync46(options.codexSkillDenials, "utf8")) : undefined, codexNativeCatalog: options.codexNativeCatalog ? JSON.parse(readFileSync46(options.codexNativeCatalog, "utf8")) : undefined });
|
|
118180
|
+
const plan = planAgentIntegration({ projectDir: process.cwd(), agents: options.agent === undefined ? detectedIntegrationAgents() : agents(options.agent), command: options.command, profileId: options.selectionProfile, includeVendor: options.includeVendor, discoveryInputs, allowRootAliases: options.allowRootAliases, reviewedCacheAlias: options.reviewedCacheAlias, codexSkillDenials: options.codexSkillDenials ? JSON.parse(readFileSync46(options.codexSkillDenials, "utf8")) : undefined, codexNativeCatalog: options.codexNativeCatalog ? JSON.parse(readFileSync46(options.codexNativeCatalog, "utf8")) : undefined });
|
|
117782
118181
|
const result2 = options.apply ? applyAgentIntegration(plan) : { changed: [], backups: [] };
|
|
117783
118182
|
const receipt = { codexPluginSkillReview: plan.codexPluginSkillReview, codexPluginSkills: plan.changes.filter((change) => change.path.endsWith("agent-policy.json")).map((change) => JSON.parse(change.after).bridge?.codexPluginSkills ?? []).flat(), applied: options.apply, planned: plan.changes.map((change) => change.path), ...result2, rootAliases: plan.rootAliases ?? [], discovery: plan.discoveryAfter, nativeSkills: plan.nativeSkills.map((entry) => ({ agent: entry.agent, path: entry.path, managed: entry.managed, vendor: entry.vendor, system: entry.system === true, bridge: entry.bridge === true })), requiresNativeRetirement: plan.nativeSkills.some((entry) => !entry.bridge && !entry.system) };
|
|
117784
118183
|
if (options.json)
|
|
@@ -117850,12 +118249,12 @@ function registerAgentIntegration(parent) {
|
|
|
117850
118249
|
input3.hook_event_name = event;
|
|
117851
118250
|
const projects = [process.cwd()];
|
|
117852
118251
|
if (input3.cwd !== undefined) {
|
|
117853
|
-
if (typeof input3.cwd !== "string" || !
|
|
118252
|
+
if (typeof input3.cwd !== "string" || !isAbsolute39(input3.cwd) || input3.cwd.includes("\x00"))
|
|
117854
118253
|
throw new Error("Invalid native hook working directory");
|
|
117855
118254
|
projects.push(input3.cwd);
|
|
117856
118255
|
}
|
|
117857
118256
|
if (options.agent === "cursor") {
|
|
117858
|
-
if (!Array.isArray(input3.workspace_roots) || input3.workspace_roots.length > 32 || input3.workspace_roots.some((path) => typeof path !== "string" || !
|
|
118257
|
+
if (!Array.isArray(input3.workspace_roots) || input3.workspace_roots.length > 32 || input3.workspace_roots.some((path) => typeof path !== "string" || !isAbsolute39(path) || path.includes("\x00")))
|
|
117859
118258
|
throw new Error("Invalid Cursor workspace roots");
|
|
117860
118259
|
projects.push(...input3.workspace_roots);
|
|
117861
118260
|
input3.cwd ??= input3.workspace_roots[0] ?? process.cwd();
|
|
@@ -117981,6 +118380,7 @@ var init_agent_integration2 = __esm(() => {
|
|
|
117981
118380
|
init_agent_hermes();
|
|
117982
118381
|
init_context();
|
|
117983
118382
|
init_agent_adapters();
|
|
118383
|
+
init_agent_install_selection();
|
|
117984
118384
|
init_agent_integration();
|
|
117985
118385
|
init_agent_codex_trust();
|
|
117986
118386
|
init_codex_native_skill_policy();
|
|
@@ -118133,9 +118533,9 @@ var exports_profiles = {};
|
|
|
118133
118533
|
__export(exports_profiles, {
|
|
118134
118534
|
registerProfiles: () => registerProfiles
|
|
118135
118535
|
});
|
|
118136
|
-
import { closeSync as closeSync27, constants as
|
|
118536
|
+
import { closeSync as closeSync27, constants as constants26, fstatSync as fstatSync27, openSync as openSync27, readSync as readSync21, writeFileSync as writeFileSync28 } from "fs";
|
|
118137
118537
|
function readProfileInput(path) {
|
|
118138
|
-
const fd = openSync27(path,
|
|
118538
|
+
const fd = openSync27(path, constants26.O_RDONLY | constants26.O_NONBLOCK);
|
|
118139
118539
|
try {
|
|
118140
118540
|
const stat3 = fstatSync27(fd);
|
|
118141
118541
|
if (!stat3.isFile() || stat3.size > MAX_PROFILE_DOCUMENT_BYTES)
|
|
@@ -118203,7 +118603,7 @@ __export(exports_grants, {
|
|
|
118203
118603
|
registerGrants: () => registerGrants
|
|
118204
118604
|
});
|
|
118205
118605
|
import {
|
|
118206
|
-
constants as
|
|
118606
|
+
constants as constants27,
|
|
118207
118607
|
closeSync as closeSync28,
|
|
118208
118608
|
fstatSync as fstatSync28,
|
|
118209
118609
|
openSync as openSync28,
|
|
@@ -118211,7 +118611,7 @@ import {
|
|
|
118211
118611
|
writeFileSync as writeFileSync29
|
|
118212
118612
|
} from "fs";
|
|
118213
118613
|
function readInput(path) {
|
|
118214
|
-
const fd = openSync28(path,
|
|
118614
|
+
const fd = openSync28(path, constants27.O_RDONLY | constants27.O_NONBLOCK);
|
|
118215
118615
|
try {
|
|
118216
118616
|
const stat3 = fstatSync28(fd);
|
|
118217
118617
|
if (!stat3.isFile() || stat3.size > MAX_EXECUTION_GRANT_BYTES)
|
|
@@ -118274,19 +118674,19 @@ import {
|
|
|
118274
118674
|
mkdirSync as mkdirSync29,
|
|
118275
118675
|
readdirSync as readdirSync25,
|
|
118276
118676
|
readFileSync as readFileSync47,
|
|
118277
|
-
statSync as
|
|
118677
|
+
statSync as statSync24,
|
|
118278
118678
|
writeFileSync as writeFileSync30
|
|
118279
118679
|
} from "fs";
|
|
118280
|
-
import { dirname as
|
|
118680
|
+
import { dirname as dirname42, join as join70, resolve as resolve37, sep as sep17 } from "path";
|
|
118281
118681
|
function fail6(code2, message, detail = []) {
|
|
118282
118682
|
throw new StationSnapshotError(code2, message, detail);
|
|
118283
118683
|
}
|
|
118284
118684
|
function snapshotRootFor(repoRoot, stationId) {
|
|
118285
|
-
return
|
|
118685
|
+
return join70(repoRoot, "resources", stationId, "skills");
|
|
118286
118686
|
}
|
|
118287
118687
|
function readSnapshotManifest(repoRoot, stationId) {
|
|
118288
118688
|
const snapshotRoot = snapshotRootFor(repoRoot, stationId);
|
|
118289
|
-
const manifestPath =
|
|
118689
|
+
const manifestPath = join70(snapshotRoot, "sync-manifest.json");
|
|
118290
118690
|
let manifest;
|
|
118291
118691
|
try {
|
|
118292
118692
|
manifest = JSON.parse(readFileSync47(manifestPath, "utf8"));
|
|
@@ -118313,7 +118713,7 @@ function planStationHydration(stationId, repoRoot) {
|
|
|
118313
118713
|
const hashMismatches = [];
|
|
118314
118714
|
const skippedByRule = [];
|
|
118315
118715
|
for (const agent of SYNC_AGENTS) {
|
|
118316
|
-
const agentRoot =
|
|
118716
|
+
const agentRoot = join70(snapshotRoot, "agent-homes", agent);
|
|
118317
118717
|
let identEntries;
|
|
118318
118718
|
try {
|
|
118319
118719
|
identEntries = readdirSync25(agentRoot, { withFileTypes: true });
|
|
@@ -118324,7 +118724,7 @@ function planStationHydration(stationId, repoRoot) {
|
|
|
118324
118724
|
if (!identEntry.isDirectory() || identEntry.name.startsWith(".")) {
|
|
118325
118725
|
continue;
|
|
118326
118726
|
}
|
|
118327
|
-
const identRoot =
|
|
118727
|
+
const identRoot = join70(agentRoot, identEntry.name);
|
|
118328
118728
|
const entries = walkEntries(identRoot);
|
|
118329
118729
|
for (const entry of entries) {
|
|
118330
118730
|
const relativeParts = [identEntry.name, ...entry.relativePath.split(sep17)];
|
|
@@ -118371,7 +118771,7 @@ function planStationHydration(stationId, repoRoot) {
|
|
|
118371
118771
|
});
|
|
118372
118772
|
continue;
|
|
118373
118773
|
}
|
|
118374
|
-
const info =
|
|
118774
|
+
const info = statSync24(entry.fullPath);
|
|
118375
118775
|
const manifestHash = manifestHashes.get(`${agent}${MANIFEST_HASH_KEY_SEP}${homeRelative}`) ?? null;
|
|
118376
118776
|
let verified = false;
|
|
118377
118777
|
if (manifestHash !== null) {
|
|
@@ -118475,8 +118875,8 @@ function skillSha256(skill) {
|
|
|
118475
118875
|
`)).digest("hex");
|
|
118476
118876
|
}
|
|
118477
118877
|
function writeStationHydration(options) {
|
|
118478
|
-
const repoRoot =
|
|
118479
|
-
const cacheRoot =
|
|
118878
|
+
const repoRoot = resolve37(options.repoRoot ?? process.cwd());
|
|
118879
|
+
const cacheRoot = resolve37(options.cacheRoot ?? resolveCorpusRoot());
|
|
118480
118880
|
const plan = planStationHydration(options.stationId, repoRoot);
|
|
118481
118881
|
const resultSkills = plan.winners.map((skill) => ({
|
|
118482
118882
|
ident: skill.ident,
|
|
@@ -118509,7 +118909,7 @@ function writeStationHydration(options) {
|
|
|
118509
118909
|
const toWrite = [];
|
|
118510
118910
|
for (const skill of plan.winners) {
|
|
118511
118911
|
for (const file2 of skill.files) {
|
|
118512
|
-
const destination =
|
|
118912
|
+
const destination = join70(cacheRoot, skill.ident, file2.withinIdent);
|
|
118513
118913
|
const digest4 = sha256File(file2.winner.fullPath);
|
|
118514
118914
|
let existingDigest = null;
|
|
118515
118915
|
try {
|
|
@@ -118530,7 +118930,7 @@ function writeStationHydration(options) {
|
|
|
118530
118930
|
}
|
|
118531
118931
|
let written = 0;
|
|
118532
118932
|
for (const entry of toWrite) {
|
|
118533
|
-
mkdirSync29(
|
|
118933
|
+
mkdirSync29(dirname42(entry.destination), { recursive: true });
|
|
118534
118934
|
copyFileSync3(entry.fullPath, entry.destination);
|
|
118535
118935
|
written += 1;
|
|
118536
118936
|
}
|
|
@@ -118551,8 +118951,8 @@ function writeStationHydration(options) {
|
|
|
118551
118951
|
},
|
|
118552
118952
|
skills: resultSkills
|
|
118553
118953
|
};
|
|
118554
|
-
const hydrationManifestPath =
|
|
118555
|
-
mkdirSync29(
|
|
118954
|
+
const hydrationManifestPath = join70(dirname42(cacheRoot), `hydration-${options.stationId}.json`);
|
|
118955
|
+
mkdirSync29(dirname42(hydrationManifestPath), { recursive: true });
|
|
118556
118956
|
writeFileSync30(hydrationManifestPath, `${JSON.stringify(hydration, null, 2)}
|
|
118557
118957
|
`);
|
|
118558
118958
|
return {
|
|
@@ -118629,14 +119029,14 @@ var init_hydrate = __esm(() => {
|
|
|
118629
119029
|
|
|
118630
119030
|
// src/lib/prepare-skill.ts
|
|
118631
119031
|
import { createHash as createHash44, randomUUID as randomUUID13 } from "crypto";
|
|
118632
|
-
import { chmodSync as chmodSync5, existsSync as existsSync37, lstatSync as
|
|
119032
|
+
import { chmodSync as chmodSync5, existsSync as existsSync37, lstatSync as lstatSync42, mkdirSync as mkdirSync30, mkdtempSync as mkdtempSync6, readFileSync as readFileSync48, readdirSync as readdirSync26, renameSync as renameSync15, rmSync as rmSync9, writeFileSync as writeFileSync31 } from "fs";
|
|
118633
119033
|
import { tmpdir as tmpdir2 } from "os";
|
|
118634
|
-
import { dirname as
|
|
119034
|
+
import { dirname as dirname43, isAbsolute as isAbsolute40, join as join71, relative as relative13, resolve as resolve38, sep as sep18 } from "path";
|
|
118635
119035
|
function prepareSkill(name, options) {
|
|
118636
119036
|
const normalized = normalizePortableSkillName(name);
|
|
118637
119037
|
if (!new RegExp(SEMVER_PATTERN).test(options.version))
|
|
118638
119038
|
throw new Error("--version must be a semantic version, for example 0.2.0.");
|
|
118639
|
-
const path =
|
|
119039
|
+
const path = join71(getPortableSkillsRootReadOnly(options), normalized);
|
|
118640
119040
|
assertPortableAuthoringPath(path, options);
|
|
118641
119041
|
const before2 = snapshot2(path);
|
|
118642
119042
|
const manifestFile = before2.files.find((file2) => file2.path === "skill.json");
|
|
@@ -118671,16 +119071,16 @@ function prepareSkill(name, options) {
|
|
|
118671
119071
|
throw new Error("skill.json provenance must be an object.");
|
|
118672
119072
|
const provenance = manifest.provenance;
|
|
118673
119073
|
const candidate2 = { ...manifest, version: options.version, kind, provenance: { ...provenance } };
|
|
118674
|
-
const staging = mkdtempSync6(
|
|
119074
|
+
const staging = mkdtempSync6(join71(tmpdir2(), "skills-prepare-"));
|
|
118675
119075
|
try {
|
|
118676
119076
|
for (const directory2 of before2.directories)
|
|
118677
|
-
mkdirSync30(
|
|
119077
|
+
mkdirSync30(join71(staging, directory2), { recursive: true });
|
|
118678
119078
|
for (const file2 of before2.files) {
|
|
118679
|
-
const destination =
|
|
118680
|
-
mkdirSync30(
|
|
119079
|
+
const destination = join71(staging, file2.path);
|
|
119080
|
+
mkdirSync30(dirname43(destination), { recursive: true });
|
|
118681
119081
|
writeFileSync31(destination, file2.bytes, { mode: file2.mode });
|
|
118682
119082
|
}
|
|
118683
|
-
const stagedManifest =
|
|
119083
|
+
const stagedManifest = join71(staging, "skill.json");
|
|
118684
119084
|
writeFileSync31(stagedManifest, `${JSON.stringify(candidate2, null, 2)}
|
|
118685
119085
|
`);
|
|
118686
119086
|
const contentHash = computeContentHash(staging);
|
|
@@ -118703,11 +119103,11 @@ ${validation.issues.map((issue2) => `${issue2.code}: ${issue2.message}`).join(`
|
|
|
118703
119103
|
if (snapshot2(path).identity !== before2.identity)
|
|
118704
119104
|
throw new Error("Skill changed during preparation; review the draft and run prepare again.");
|
|
118705
119105
|
if (changed3 && !options.dryRun) {
|
|
118706
|
-
const temporary =
|
|
119106
|
+
const temporary = join71(path, `.skill-prepare-${randomUUID13()}.tmp`);
|
|
118707
119107
|
try {
|
|
118708
119108
|
writeFileSync31(temporary, candidateBytes, { flag: "wx", mode: manifestFile.mode });
|
|
118709
119109
|
chmodSync5(temporary, manifestFile.mode);
|
|
118710
|
-
renameSync15(temporary,
|
|
119110
|
+
renameSync15(temporary, join71(path, "skill.json"));
|
|
118711
119111
|
} finally {
|
|
118712
119112
|
rmSync9(temporary, { force: true });
|
|
118713
119113
|
}
|
|
@@ -118737,8 +119137,8 @@ function validateRuntimeEntrypoint(candidate2, root2) {
|
|
|
118737
119137
|
const entry = candidate2.runtime.entrypoint;
|
|
118738
119138
|
if (typeof entry !== "string")
|
|
118739
119139
|
return;
|
|
118740
|
-
const target =
|
|
118741
|
-
if (
|
|
119140
|
+
const target = resolve38(root2, entry), rel = relative13(root2, target);
|
|
119141
|
+
if (isAbsolute40(entry) || /^[a-zA-Z]:/.test(entry) || entry.includes("\\") || !rel || rel === ".." || rel.startsWith(`..${sep18}`) || isAbsolute40(rel) || !existsSync37(target) || !lstatSync42(target).isFile()) {
|
|
118742
119142
|
throw new Error("Executable runtime.entrypoint must name an existing regular file inside the skill directory.");
|
|
118743
119143
|
}
|
|
118744
119144
|
}
|
|
@@ -118823,20 +119223,20 @@ function compareVersions(left, right) {
|
|
|
118823
119223
|
return 0;
|
|
118824
119224
|
}
|
|
118825
119225
|
function snapshot2(root2) {
|
|
118826
|
-
const rootStat =
|
|
119226
|
+
const rootStat = lstatSync42(root2);
|
|
118827
119227
|
if (rootStat.isSymbolicLink() || !rootStat.isDirectory())
|
|
118828
119228
|
throw new Error("Skill root must be a real directory, not a symlink.");
|
|
118829
119229
|
const files = [], directories = [];
|
|
118830
119230
|
const hash6 = createHash44("sha256").update(`${rootStat.dev}:${rootStat.ino}\x00`);
|
|
118831
119231
|
let count = 0, bytes = 0;
|
|
118832
119232
|
const walk2 = (relative14) => {
|
|
118833
|
-
for (const name of readdirSync26(
|
|
119233
|
+
for (const name of readdirSync26(join71(root2, relative14)).sort()) {
|
|
118834
119234
|
if (IGNORED.has(name.toLowerCase()) || !relative14 && ROOT_IGNORED.has(name.toLowerCase()))
|
|
118835
119235
|
continue;
|
|
118836
119236
|
const path = relative14 ? `${relative14}/${name}` : name;
|
|
118837
119237
|
if (++count > 20000)
|
|
118838
119238
|
throw new Error("Skill exceeds the preparation entry limit (20000).");
|
|
118839
|
-
const absolute =
|
|
119239
|
+
const absolute = join71(root2, path), stat3 = lstatSync42(absolute);
|
|
118840
119240
|
if (stat3.isSymbolicLink())
|
|
118841
119241
|
throw new Error(`Skill contains a symlink: ${path}. No files were changed.`);
|
|
118842
119242
|
if (stat3.isDirectory() && name === "node_modules")
|
|
@@ -119252,7 +119652,7 @@ var init_schedule = __esm(() => {
|
|
|
119252
119652
|
|
|
119253
119653
|
// src/lib/registry-sync.ts
|
|
119254
119654
|
import { mkdirSync as mkdirSync31, writeFileSync as writeFileSync32 } from "fs";
|
|
119255
|
-
import { dirname as
|
|
119655
|
+
import { dirname as dirname44, relative as relative14 } from "path";
|
|
119256
119656
|
function createRegistrySyncArtifact(options = {}) {
|
|
119257
119657
|
const profile = options.profile ?? "all";
|
|
119258
119658
|
const includeDocs = options.includeDocs ?? true;
|
|
@@ -119309,7 +119709,7 @@ function createRegistrySyncArtifact(options = {}) {
|
|
|
119309
119709
|
};
|
|
119310
119710
|
}
|
|
119311
119711
|
function writeRegistrySyncArtifact(path, artifact) {
|
|
119312
|
-
mkdirSync31(
|
|
119712
|
+
mkdirSync31(dirname44(path), { recursive: true });
|
|
119313
119713
|
writeFileSync32(path, `${JSON.stringify(artifact, null, 2)}
|
|
119314
119714
|
`);
|
|
119315
119715
|
}
|
|
@@ -119329,8 +119729,8 @@ var init_registry_sync = __esm(() => {
|
|
|
119329
119729
|
});
|
|
119330
119730
|
|
|
119331
119731
|
// src/lib/review-export.ts
|
|
119332
|
-
import { constants as
|
|
119333
|
-
import { basename as basename20, dirname as
|
|
119732
|
+
import { constants as constants28, closeSync as closeSync29, existsSync as existsSync38, fstatSync as fstatSync29, fsyncSync as fsyncSync9, lstatSync as lstatSync43, openSync as openSync29, realpathSync as realpathSync23, statSync as statSync25, writeFileSync as writeFileSync33 } from "fs";
|
|
119733
|
+
import { basename as basename20, dirname as dirname45, isAbsolute as isAbsolute41, join as join72, parse as parse13, resolve as resolve39, sep as sep19 } from "path";
|
|
119334
119734
|
function exactVersion(spec) {
|
|
119335
119735
|
const at2 = spec.indexOf("@");
|
|
119336
119736
|
const slug2 = spec.slice(0, at2);
|
|
@@ -119341,14 +119741,14 @@ function exactVersion(spec) {
|
|
|
119341
119741
|
return { slug: slug2, version: version2 };
|
|
119342
119742
|
}
|
|
119343
119743
|
function assertPrivateDestination(output2) {
|
|
119344
|
-
if (!
|
|
119744
|
+
if (!isAbsolute41(output2) || resolve39(output2) !== output2 || !basename20(output2).endsWith(".tar.gz")) {
|
|
119345
119745
|
throw new Error("Review output must be an absolute, normalized .tar.gz path.");
|
|
119346
119746
|
}
|
|
119347
|
-
const parent =
|
|
119348
|
-
if (realpathSync23(parent) !== parent ||
|
|
119747
|
+
const parent = dirname45(output2);
|
|
119748
|
+
if (realpathSync23(parent) !== parent || lstatSync43(parent).isSymbolicLink()) {
|
|
119349
119749
|
throw new Error("Review output parent must be a real directory, not a symlink.");
|
|
119350
119750
|
}
|
|
119351
|
-
const parentStat =
|
|
119751
|
+
const parentStat = statSync25(parent);
|
|
119352
119752
|
if (!parentStat.isDirectory() || (parentStat.mode & 63) !== 0 || process.getuid && parentStat.uid !== process.getuid()) {
|
|
119353
119753
|
throw new Error("Review output parent must be an owner-only directory (mode 0700).");
|
|
119354
119754
|
}
|
|
@@ -119356,8 +119756,8 @@ function assertPrivateDestination(output2) {
|
|
|
119356
119756
|
if (segments.some((segment) => NATIVE_CONTAINERS.has(segment)) || segments.some((segment, index) => segment === ".config" && segments[index + 1] === "opencode") || segments.some((segment, index) => segment === ".hasna" && segments[index + 1] === "skills")) {
|
|
119357
119757
|
throw new Error("Review output cannot be placed in agent-native discovery or Skills installation paths.");
|
|
119358
119758
|
}
|
|
119359
|
-
for (let current = parent;; current =
|
|
119360
|
-
if (existsSync38(
|
|
119759
|
+
for (let current = parent;; current = dirname45(current)) {
|
|
119760
|
+
if (existsSync38(join72(current, ".git"))) {
|
|
119361
119761
|
throw new Error("Review output cannot be placed inside a Git worktree.");
|
|
119362
119762
|
}
|
|
119363
119763
|
if (current === parse13(current).root)
|
|
@@ -119393,7 +119793,7 @@ async function exportSkillVersionForReview(spec, output2, client2) {
|
|
|
119393
119793
|
if (bytes.byteLength !== metadata2.bundleByteSize || sha256Hex(bytes) !== metadata2.bundleSha256.toLowerCase()) {
|
|
119394
119794
|
throw new Error("Published bundle bytes do not match the exact version metadata.");
|
|
119395
119795
|
}
|
|
119396
|
-
const fd = openSync29(target,
|
|
119796
|
+
const fd = openSync29(target, constants28.O_WRONLY | constants28.O_CREAT | constants28.O_EXCL | constants28.O_NOFOLLOW, 384);
|
|
119397
119797
|
try {
|
|
119398
119798
|
writeFileSync33(fd, bytes);
|
|
119399
119799
|
fsyncSync9(fd);
|
|
@@ -119433,12 +119833,12 @@ function registerRegistry(parent) {
|
|
|
119433
119833
|
async function writeJson2(value, space) {
|
|
119434
119834
|
const text4 = `${JSON.stringify(value, null, space)}
|
|
119435
119835
|
`;
|
|
119436
|
-
await new Promise((
|
|
119836
|
+
await new Promise((resolve40, reject2) => {
|
|
119437
119837
|
process.stdout.write(text4, (error61) => {
|
|
119438
119838
|
if (error61)
|
|
119439
119839
|
reject2(error61);
|
|
119440
119840
|
else
|
|
119441
|
-
|
|
119841
|
+
resolve40();
|
|
119442
119842
|
});
|
|
119443
119843
|
});
|
|
119444
119844
|
}
|
|
@@ -119644,7 +120044,7 @@ __export(exports_publish, {
|
|
|
119644
120044
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
119645
120045
|
import { existsSync as existsSync39, readFileSync as readFileSync49 } from "fs";
|
|
119646
120046
|
import { hostname as hostname5 } from "os";
|
|
119647
|
-
import { join as
|
|
120047
|
+
import { join as join73 } from "path";
|
|
119648
120048
|
function registerPublish(parent) {
|
|
119649
120049
|
parent.command("push").argument("<name>", "Name of a skill in the local corpus (~/.hasna/skills/installed or the migrated ~/.hasna/skills/skills)").option("--version <version>", "Override the version recorded on the instance").option("--force-new-version", "If name@version already exists with different content, publish as the next patch version", false).option("--dry-run", "Pack and validate without uploading", false).option("--json", "Output result as JSON", false).description("Publish a local skill to the configured skills instance").action(async (name, options) => {
|
|
119650
120050
|
try {
|
|
@@ -119696,7 +120096,7 @@ async function pushSkill(name, options = {}) {
|
|
|
119696
120096
|
const packed = packSkillBundle(skill.path, { maxUnpackedBytes: MAX_UNPACKED_BYTES });
|
|
119697
120097
|
await verifyPackedCanonicalHash(skill.name, packed);
|
|
119698
120098
|
const versionManifest = buildVersionManifest(skill.path, packed);
|
|
119699
|
-
const skillMdPath =
|
|
120099
|
+
const skillMdPath = join73(skill.path, "SKILL.md");
|
|
119700
120100
|
const skillMd = existsSync39(skillMdPath) ? readFileSync49(skillMdPath, "utf-8") : undefined;
|
|
119701
120101
|
const base3 = {
|
|
119702
120102
|
slug: skill.name,
|
|
@@ -119935,7 +120335,7 @@ var exports_private_publications = {};
|
|
|
119935
120335
|
__export(exports_private_publications, {
|
|
119936
120336
|
registerPrivatePublications: () => registerPrivatePublications
|
|
119937
120337
|
});
|
|
119938
|
-
import { resolve as
|
|
120338
|
+
import { resolve as resolve40 } from "path";
|
|
119939
120339
|
function verifyOptions(options, action) {
|
|
119940
120340
|
if (options.userId === undefined !== (options.membershipId === undefined) || options.userId !== undefined && (!publicationUuid(options.userId) || !publicationUuid(options.membershipId)))
|
|
119941
120341
|
throw new PrivatePublicationError("PUBLICATION_CONTEXT_REQUIRED", "Provide both observed --user-id and --membership-id UUIDs.");
|
|
@@ -119980,9 +120380,9 @@ function registerPrivatePublications(parent) {
|
|
|
119980
120380
|
if (code2 === null)
|
|
119981
120381
|
return;
|
|
119982
120382
|
const context2 = options.userId ? { userId: options.userId, membershipId: options.membershipId } : undefined;
|
|
119983
|
-
const client2 = await privatePublicationSession(options.email, code2, context2), directory2 =
|
|
120383
|
+
const client2 = await privatePublicationSession(options.email, code2, context2), directory2 = resolve40(options.recoveryDir);
|
|
119984
120384
|
if (action === "publish")
|
|
119985
|
-
await preparePrivatePublication(client2,
|
|
120385
|
+
await preparePrivatePublication(client2, resolve40(args2[0]), directory2, { skillId: options.skillId, expectedCurrentVersionId: options.expectedCurrentVersion ?? null, idempotencyKey: options.idempotencyKey });
|
|
119986
120386
|
const result2 = action === "publish" || action === "resume" ? await continuePrivatePublication(client2, directory2, { confirm: true, waitMs: Number(options.waitSeconds) * 1000 }) : await inspectPrivatePublication(client2, directory2, action === "cancel");
|
|
119987
120387
|
print2(result2, options.json);
|
|
119988
120388
|
} catch (error61) {
|
|
@@ -120084,7 +120484,7 @@ __export(exports_auth, {
|
|
|
120084
120484
|
import { createInterface as createInterface3 } from "readline";
|
|
120085
120485
|
function prompt(question) {
|
|
120086
120486
|
const rl = createInterface3({ input: process.stdin, output: process.stdout });
|
|
120087
|
-
return new Promise((
|
|
120487
|
+
return new Promise((resolve41) => {
|
|
120088
120488
|
let settled = false;
|
|
120089
120489
|
const finish = (answer) => {
|
|
120090
120490
|
if (settled)
|
|
@@ -120093,7 +120493,7 @@ function prompt(question) {
|
|
|
120093
120493
|
rl.close();
|
|
120094
120494
|
if (answer === null)
|
|
120095
120495
|
process.exitCode = 130;
|
|
120096
|
-
|
|
120496
|
+
resolve41(answer);
|
|
120097
120497
|
};
|
|
120098
120498
|
rl.once("SIGINT", () => finish(null));
|
|
120099
120499
|
rl.once("close", () => finish(null));
|
|
@@ -120271,7 +120671,7 @@ Skipped. Run it any time: skills setup agents`));
|
|
|
120271
120671
|
function promptHidden(question) {
|
|
120272
120672
|
const stdin = process.stdin;
|
|
120273
120673
|
process.stdout.write(question);
|
|
120274
|
-
return new Promise((
|
|
120674
|
+
return new Promise((resolve41) => {
|
|
120275
120675
|
let value = "";
|
|
120276
120676
|
const done = (answer) => {
|
|
120277
120677
|
stdin.off("data", onData);
|
|
@@ -120281,7 +120681,7 @@ function promptHidden(question) {
|
|
|
120281
120681
|
`);
|
|
120282
120682
|
if (answer === null)
|
|
120283
120683
|
process.exitCode = 130;
|
|
120284
|
-
|
|
120684
|
+
resolve41(answer);
|
|
120285
120685
|
};
|
|
120286
120686
|
const onData = (chunk2) => {
|
|
120287
120687
|
for (const character of chunk2.toString()) {
|
|
@@ -120837,7 +121237,7 @@ function promptInvitationProof(kind) {
|
|
|
120837
121237
|
const label = kind === "token" ? "invitation token" : "recovery code";
|
|
120838
121238
|
const character = kind === "token" ? /^[A-Za-z0-9_-]$/ : /^\d$/;
|
|
120839
121239
|
const { stdin, stderr: output2 } = process, wasRaw = stdin.isRaw, wasFlowing = stdin.readableFlowing;
|
|
120840
|
-
return new Promise((
|
|
121240
|
+
return new Promise((resolve41) => {
|
|
120841
121241
|
let value = "", settled = false, overflow = false;
|
|
120842
121242
|
const finish = (answer) => {
|
|
120843
121243
|
if (settled)
|
|
@@ -120854,7 +121254,7 @@ function promptInvitationProof(kind) {
|
|
|
120854
121254
|
`);
|
|
120855
121255
|
if (answer === null)
|
|
120856
121256
|
process.exitCode = 130;
|
|
120857
|
-
|
|
121257
|
+
resolve41(answer);
|
|
120858
121258
|
};
|
|
120859
121259
|
const cancel = () => finish(null);
|
|
120860
121260
|
const keypress = (text4, key) => {
|
|
@@ -121426,11 +121826,11 @@ var init_storage2 = __esm(() => {
|
|
|
121426
121826
|
});
|
|
121427
121827
|
|
|
121428
121828
|
// src/lib/registry-reconcile.ts
|
|
121429
|
-
import { existsSync as existsSync40, readFileSync as readFileSync50, statSync as
|
|
121430
|
-
import { join as
|
|
121829
|
+
import { existsSync as existsSync40, readFileSync as readFileSync50, statSync as statSync26, writeFileSync as writeFileSync34 } from "fs";
|
|
121830
|
+
import { join as join74 } from "path";
|
|
121431
121831
|
function isDirectory2(path) {
|
|
121432
121832
|
try {
|
|
121433
|
-
return
|
|
121833
|
+
return statSync26(path).isDirectory();
|
|
121434
121834
|
} catch {
|
|
121435
121835
|
return false;
|
|
121436
121836
|
}
|
|
@@ -121438,11 +121838,11 @@ function isDirectory2(path) {
|
|
|
121438
121838
|
function migrationNeeded(options) {
|
|
121439
121839
|
if (options.rootDir)
|
|
121440
121840
|
return false;
|
|
121441
|
-
const appDir = options.homeDir ?
|
|
121442
|
-
return !(isOwnerLayoutMigrated(appDir) && isDirectory2(
|
|
121841
|
+
const appDir = options.homeDir ? join74(options.homeDir, ".hasna", "skills") : getDataDir();
|
|
121842
|
+
return !(isOwnerLayoutMigrated(appDir) && isDirectory2(join74(appDir, SKILLS_CACHE_DIRNAME)));
|
|
121443
121843
|
}
|
|
121444
121844
|
function readBaseline(skillDir) {
|
|
121445
|
-
const markerPath =
|
|
121845
|
+
const markerPath = join74(skillDir, PULL_MARKER_FILE);
|
|
121446
121846
|
if (!existsSync40(markerPath))
|
|
121447
121847
|
return;
|
|
121448
121848
|
try {
|
|
@@ -121458,7 +121858,7 @@ function readBaseline(skillDir) {
|
|
|
121458
121858
|
}
|
|
121459
121859
|
}
|
|
121460
121860
|
function readCursor(root2) {
|
|
121461
|
-
const path =
|
|
121861
|
+
const path = join74(root2, SYNC_CURSOR_FILE);
|
|
121462
121862
|
if (!existsSync40(path))
|
|
121463
121863
|
return { runCount: 0 };
|
|
121464
121864
|
try {
|
|
@@ -121471,12 +121871,12 @@ function readCursor(root2) {
|
|
|
121471
121871
|
function resolveCorpusRootReadOnly(options) {
|
|
121472
121872
|
if (options.rootDir)
|
|
121473
121873
|
return { root: options.rootDir, migrationPending: false };
|
|
121474
|
-
const appDir = options.homeDir ?
|
|
121475
|
-
const cache3 =
|
|
121874
|
+
const appDir = options.homeDir ? join74(options.homeDir, ".hasna", "skills") : getDataDirReadOnly();
|
|
121875
|
+
const cache3 = join74(appDir, SKILLS_CACHE_DIRNAME);
|
|
121476
121876
|
if (isOwnerLayoutMigrated(appDir) && isDirectory2(cache3)) {
|
|
121477
121877
|
return { root: cache3, migrationPending: false };
|
|
121478
121878
|
}
|
|
121479
|
-
return { root:
|
|
121879
|
+
return { root: join74(appDir, INSTALLED_SKILLS_DIRNAME), migrationPending: true };
|
|
121480
121880
|
}
|
|
121481
121881
|
function remoteRowToSkill(record12) {
|
|
121482
121882
|
const slug2 = typeof record12.slug === "string" ? record12.slug : typeof record12.name === "string" ? record12.name : undefined;
|
|
@@ -121610,7 +122010,7 @@ async function reconcileRegistry(options = {}) {
|
|
|
121610
122010
|
for (const slug2 of allSlugs) {
|
|
121611
122011
|
const local = locals.get(slug2);
|
|
121612
122012
|
const remote = remotes.get(slug2);
|
|
121613
|
-
const baseline = local ? readBaseline(
|
|
122013
|
+
const baseline = local ? readBaseline(join74(root2, slug2)) : undefined;
|
|
121614
122014
|
const { state, reason: reason2 } = classifySkill(local, remote, baseline);
|
|
121615
122015
|
let { action, reason: actionReason } = resolveAction(state, direction, conflict);
|
|
121616
122016
|
if (state === "remote-only" && isDigestless(remote)) {
|
|
@@ -121669,7 +122069,7 @@ async function reconcileRegistry(options = {}) {
|
|
|
121669
122069
|
try {
|
|
121670
122070
|
await pushSkill(slug2, { rootDir: root2, client: client2 });
|
|
121671
122071
|
const pushed = locals.get(slug2);
|
|
121672
|
-
writePullMarker(
|
|
122072
|
+
writePullMarker(join74(root2, slug2), {
|
|
121673
122073
|
skill: slug2,
|
|
121674
122074
|
...pushed?.version ? { version: pushed.version } : {},
|
|
121675
122075
|
...pushed?.sha256 ? { contentHash: pushed.sha256 } : {},
|
|
@@ -121741,7 +122141,7 @@ async function reconcileRegistry(options = {}) {
|
|
|
121741
122141
|
runCount: readCursor(root2).runCount + 1,
|
|
121742
122142
|
summary
|
|
121743
122143
|
};
|
|
121744
|
-
writeFileSync34(
|
|
122144
|
+
writeFileSync34(join74(root2, SYNC_CURSOR_FILE), `${JSON.stringify(cursor2, null, 2)}
|
|
121745
122145
|
`);
|
|
121746
122146
|
return {
|
|
121747
122147
|
corpusRoot: root2,
|