@hasna/skills 0.10.60 → 0.10.61
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 +781 -454
- package/bin/mcp.js +18193 -35730
- package/bin/migrate.js +5 -4
- package/bin/server.js +5 -4
- package/bin/worker.js +5 -4
- package/dist/cli/commands/runtime-launcher.d.ts +19 -11
- package/dist/index.js +1577 -999
- package/dist/lib/agent-adapters.d.ts +2 -2
- package/dist/lib/agent-install-selection.d.ts +10 -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/sdk/index.js +1837 -1259
- package/dist/server/launcher-environment-policy.d.ts +11 -0
- package/native/kernel-lock-acl-darwin +0 -0
- package/package.json +4 -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.61",
|
|
36892
36892
|
description: "Skills library for AI coding agents",
|
|
36893
36893
|
type: "module",
|
|
36894
36894
|
bin: {
|
|
@@ -36925,6 +36925,7 @@ 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",
|
|
@@ -36938,8 +36939,8 @@ var init_package = __esm(() => {
|
|
|
36938
36939
|
types: "./dist/index.d.ts",
|
|
36939
36940
|
scripts: {
|
|
36940
36941
|
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
|
|
36942
|
+
build: "bun run clean && bun build --external @hasna/contracts/kernel-lock ./src/cli/index.tsx --outdir ./bin --target bun && bun build --external @modelcontextprotocol/sdk ./src/mcp/index.ts --outfile ./bin/mcp.js --target bun && bun build --external @hasna/contracts/kernel-lock ./src/server/index.ts --outfile ./bin/server.js --target bun && bun build --external @hasna/contracts/kernel-lock ./src/server/worker.ts --outfile ./bin/worker.js --target bun && bun build --external @hasna/contracts/kernel-lock ./src/server/migrate.ts --outfile ./bin/migrate.js --target bun && bun build --external @hasna/contracts/kernel-lock ./src/server/maintenance.ts --outfile ./bin/maintenance.js --target bun && bun build ./src/index.ts ./src/storage.ts ./src/sdk/index.ts ./src/admin-contract.ts --outdir ./dist --target bun && tsc --emitDeclarationOnly --declaration --outDir dist && bun scripts/stage-kernel-lock-assets.ts",
|
|
36943
|
+
"build:js": "rm -rf dist && bun build ./src/index.ts ./src/storage.ts ./src/sdk/index.ts ./src/admin-contract.ts --outdir ./dist --target bun && tsc --emitDeclarationOnly --declaration --outDir dist && bun scripts/stage-kernel-lock-assets.ts",
|
|
36943
36944
|
test: "bun test --timeout 30000",
|
|
36944
36945
|
dev: "bun run ./src/cli/index.tsx",
|
|
36945
36946
|
"dev:watch": "bun --watch run ./src/cli/index.tsx",
|
|
@@ -39899,7 +39900,7 @@ var init_agent_adapters = __esm(() => {
|
|
|
39899
39900
|
codex: { root: ".codex/skills", config: ".codex/hooks.json", events: ["UserPromptSubmit", "SessionStart", "SubagentStart"], promptContext: true },
|
|
39900
39901
|
gemini: { root: ".gemini/skills", config: ".gemini/settings.json", events: ["BeforeAgent", "SessionStart"], promptContext: true },
|
|
39901
39902
|
opencode: { root: ".config/opencode/skills", config: ".config/opencode/opencode.json", events: ["chat.message"], promptContext: true },
|
|
39902
|
-
sumi: { root:
|
|
39903
|
+
sumi: { root: null, config: null, events: ["prompt", "context"], promptContext: true },
|
|
39903
39904
|
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
39905
|
cursor: { root: ".cursor/skills", config: ".cursor/hooks.json", events: ["beforeSubmitPrompt", "sessionStart"], promptContext: false }
|
|
39905
39906
|
};
|
|
@@ -54091,37 +54092,136 @@ var init_agent_codex = __esm(() => {
|
|
|
54091
54092
|
});
|
|
54092
54093
|
|
|
54093
54094
|
// src/lib/agent-sumi.ts
|
|
54094
|
-
import {
|
|
54095
|
-
import {
|
|
54096
|
-
|
|
54095
|
+
import { spawnSync as spawnSync3 } from "child_process";
|
|
54096
|
+
import { accessSync as accessSync2, constants as constants11, existsSync as existsSync12, lstatSync as lstatSync18, realpathSync as realpathSync8, statSync as statSync9 } from "fs";
|
|
54097
|
+
import { delimiter as delimiter2, isAbsolute as isAbsolute15, join as join27, resolve as resolve15 } from "path";
|
|
54098
|
+
function recordWithKeys(value, keys2) {
|
|
54099
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === keys2.length && keys2.every((key) => Object.hasOwn(value, key));
|
|
54100
|
+
}
|
|
54101
|
+
function absolutePath3(value) {
|
|
54102
|
+
return typeof value === "string" && value.length > 0 && value.length <= 32768 && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute15(value) && resolve15(value) === value;
|
|
54103
|
+
}
|
|
54104
|
+
function absoluteInput(value) {
|
|
54105
|
+
return value.length > 0 && value.length <= 32768 && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute15(value);
|
|
54106
|
+
}
|
|
54107
|
+
function resolveSumiPathsCommand(pathValue) {
|
|
54108
|
+
if (!pathValue)
|
|
54109
|
+
return null;
|
|
54110
|
+
for (const directory of pathValue.split(delimiter2)) {
|
|
54111
|
+
if (!directory || /[\x00-\x1f\x7f]/.test(directory))
|
|
54112
|
+
continue;
|
|
54113
|
+
const candidate = resolve15(directory, "sumi-paths");
|
|
54114
|
+
try {
|
|
54115
|
+
accessSync2(candidate, constants11.X_OK);
|
|
54116
|
+
if (statSync9(candidate).isFile())
|
|
54117
|
+
return candidate;
|
|
54118
|
+
} catch {}
|
|
54119
|
+
}
|
|
54120
|
+
return null;
|
|
54121
|
+
}
|
|
54122
|
+
function validPathPlan(value, home, cwd2) {
|
|
54123
|
+
if (!recordWithKeys(value, ["schemaVersion", "kind", "home", "cwd", "roots", "legacyRoots", "configFiles", "skillRoots"]))
|
|
54124
|
+
return false;
|
|
54125
|
+
if (value.schemaVersion !== 1 || value.kind !== "sumi-paths" || value.home !== resolve15(home) || value.cwd !== resolve15(cwd2))
|
|
54126
|
+
return false;
|
|
54127
|
+
if (!recordWithKeys(value.roots, SUMI_PATH_KEYS) || !recordWithKeys(value.legacyRoots, SUMI_PATH_KEYS))
|
|
54128
|
+
return false;
|
|
54129
|
+
for (const key of SUMI_PATH_KEYS) {
|
|
54130
|
+
if (!absolutePath3(value.roots[key]))
|
|
54131
|
+
return false;
|
|
54132
|
+
if (value.legacyRoots[key] !== null && !absolutePath3(value.legacyRoots[key]))
|
|
54133
|
+
return false;
|
|
54134
|
+
}
|
|
54135
|
+
if (!recordWithKeys(value.configFiles, ["canonical", "legacy"]) || !recordWithKeys(value.skillRoots, ["canonical", "legacy"]))
|
|
54136
|
+
return false;
|
|
54137
|
+
if (!absolutePath3(value.configFiles.canonical) || !absolutePath3(value.skillRoots.canonical))
|
|
54138
|
+
return false;
|
|
54139
|
+
if (value.configFiles.legacy !== null && !absolutePath3(value.configFiles.legacy))
|
|
54140
|
+
return false;
|
|
54141
|
+
if (value.skillRoots.legacy !== null && !absolutePath3(value.skillRoots.legacy))
|
|
54142
|
+
return false;
|
|
54143
|
+
const configRoot = value.roots.config;
|
|
54144
|
+
const legacyConfigRoot = value.legacyRoots.config;
|
|
54145
|
+
if (typeof configRoot !== "string" || legacyConfigRoot !== null && typeof legacyConfigRoot !== "string")
|
|
54146
|
+
return false;
|
|
54147
|
+
if (value.configFiles.canonical !== join27(configRoot, "sumi.json") || value.skillRoots.canonical !== join27(configRoot, "skills"))
|
|
54148
|
+
return false;
|
|
54149
|
+
if (legacyConfigRoot === null)
|
|
54150
|
+
return value.configFiles.legacy === null && value.skillRoots.legacy === null;
|
|
54151
|
+
return value.configFiles.legacy === join27(legacyConfigRoot, "sumi.json") && value.skillRoots.legacy === join27(legacyConfigRoot, "skills");
|
|
54152
|
+
}
|
|
54153
|
+
function sumiPathPlan(home, cwd2 = process.cwd(), env3 = process.env) {
|
|
54097
54154
|
for (const key of ["SUMI_CONFIG", "SUMI_CONFIG_CONTENT"])
|
|
54098
54155
|
if (env3[key] !== undefined)
|
|
54099
|
-
throw new
|
|
54100
|
-
|
|
54101
|
-
|
|
54102
|
-
const
|
|
54103
|
-
const
|
|
54104
|
-
|
|
54105
|
-
|
|
54106
|
-
|
|
54107
|
-
|
|
54108
|
-
|
|
54109
|
-
|
|
54110
|
-
|
|
54156
|
+
throw new SumiPathResolverError("SUMI_PATH_CONFIG_UNSUPPORTED");
|
|
54157
|
+
if (!absoluteInput(home) || !absoluteInput(cwd2))
|
|
54158
|
+
throw new SumiPathResolverError("SUMI_PATH_INPUT_REFUSED");
|
|
54159
|
+
const runtimePath = process.env.PATH ?? "";
|
|
54160
|
+
const executable2 = resolveSumiPathsCommand(runtimePath);
|
|
54161
|
+
if (!executable2 || !isAbsolute15(executable2))
|
|
54162
|
+
throw new SumiPathResolverError("SUMI_PATH_RESOLVER_UNAVAILABLE");
|
|
54163
|
+
const childEnv = { PATH: runtimePath };
|
|
54164
|
+
for (const key of SUMI_PATH_SELECTORS)
|
|
54165
|
+
if (env3[key] !== undefined)
|
|
54166
|
+
childEnv[key] = env3[key];
|
|
54167
|
+
let child2;
|
|
54168
|
+
try {
|
|
54169
|
+
child2 = spawnSync3(executable2, ["--json", "--home", resolve15(home), "--cwd", resolve15(cwd2)], {
|
|
54170
|
+
cwd: resolve15(cwd2),
|
|
54171
|
+
env: childEnv,
|
|
54172
|
+
encoding: "buffer",
|
|
54173
|
+
timeout: 3000,
|
|
54174
|
+
maxBuffer: SUMI_PATH_OUTPUT_LIMIT,
|
|
54175
|
+
shell: false
|
|
54176
|
+
});
|
|
54177
|
+
} catch {
|
|
54178
|
+
throw new SumiPathResolverError("SUMI_PATH_RESOLVER_UNAVAILABLE");
|
|
54179
|
+
}
|
|
54180
|
+
const stdoutBytes = child2.stdout === null ? 0 : Buffer.byteLength(child2.stdout);
|
|
54181
|
+
const stderrBytes = child2.stderr === null ? 0 : Buffer.byteLength(child2.stderr);
|
|
54182
|
+
if (child2.error || child2.signal || !child2.stdout || stdoutBytes > SUMI_PATH_OUTPUT_LIMIT || stderrBytes > 0) {
|
|
54183
|
+
throw new SumiPathResolverError("SUMI_PATH_RESOLVER_UNAVAILABLE");
|
|
54184
|
+
}
|
|
54185
|
+
let result2;
|
|
54186
|
+
try {
|
|
54187
|
+
result2 = JSON.parse(child2.stdout.toString("utf8"));
|
|
54188
|
+
} catch {
|
|
54189
|
+
throw new SumiPathResolverError("SUMI_PATH_RESOLVER_INVALID_RESPONSE");
|
|
54190
|
+
}
|
|
54191
|
+
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) {
|
|
54192
|
+
throw new SumiPathResolverError(result2.code);
|
|
54193
|
+
}
|
|
54194
|
+
if (child2.status !== 0 || !validPathPlan(result2, home, cwd2))
|
|
54195
|
+
throw new SumiPathResolverError("SUMI_PATH_RESOLVER_INVALID_RESPONSE");
|
|
54196
|
+
return result2;
|
|
54197
|
+
}
|
|
54198
|
+
function selectedConfigDirectory(plan) {
|
|
54199
|
+
const canonical7 = plan.roots.config, legacy = plan.legacyRoots.config;
|
|
54200
|
+
if (legacy === null)
|
|
54201
|
+
return existsSync12(canonical7) ? realpathSync8(canonical7) : canonical7;
|
|
54202
|
+
const canonicalStat = lstatSync18(canonical7, { throwIfNoEntry: false }), legacyStat = lstatSync18(legacy, { throwIfNoEntry: false });
|
|
54203
|
+
if (canonicalStat && legacyStat && realpathSync8(canonical7) !== realpathSync8(legacy))
|
|
54111
54204
|
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 ((
|
|
54205
|
+
const selected = canonicalStat ? canonical7 : legacyStat ? legacy : canonical7;
|
|
54206
|
+
if (!existsSync12(selected))
|
|
54207
|
+
return selected;
|
|
54208
|
+
const physical = realpathSync8(selected);
|
|
54209
|
+
if ((canonicalStat?.isSymbolicLink() || legacyStat?.isSymbolicLink()) && ![canonical7, legacy].includes(physical))
|
|
54117
54210
|
throw new Error("Sumi config alias must resolve to its canonical or legacy root");
|
|
54118
54211
|
return physical;
|
|
54119
54212
|
}
|
|
54120
|
-
function
|
|
54121
|
-
return
|
|
54213
|
+
function sumiConfigDirectory(home, env3 = process.env, cwd2 = process.cwd()) {
|
|
54214
|
+
return selectedConfigDirectory(sumiPathPlan(home, cwd2, env3));
|
|
54215
|
+
}
|
|
54216
|
+
function sumiSkillRoots(home, cwd2 = process.cwd(), env3 = process.env) {
|
|
54217
|
+
const plan = sumiPathPlan(home, cwd2, env3);
|
|
54218
|
+
return [join27(selectedConfigDirectory(plan), "skills")];
|
|
54122
54219
|
}
|
|
54123
|
-
function
|
|
54124
|
-
return
|
|
54220
|
+
function sumiBridgeRoot(home, cwd2 = process.cwd(), env3 = process.env) {
|
|
54221
|
+
return sumiSkillRoots(home, cwd2, env3)[0];
|
|
54222
|
+
}
|
|
54223
|
+
function sumiConfigPath(home, cwd2 = process.cwd(), env3 = process.env) {
|
|
54224
|
+
return join27(sumiConfigDirectory(home, env3, cwd2), "sumi.json");
|
|
54125
54225
|
}
|
|
54126
54226
|
function renderSumiPlugin(command, profile) {
|
|
54127
54227
|
return renderSumiPluginVersion(command, profile, false);
|
|
@@ -54207,8 +54307,19 @@ export default {
|
|
|
54207
54307
|
};
|
|
54208
54308
|
`;
|
|
54209
54309
|
}
|
|
54210
|
-
var SUMI_SKILL_PERMISSIONS;
|
|
54310
|
+
var SUMI_PATH_SELECTORS, SUMI_PATH_KEYS, SUMI_PATH_OUTPUT_LIMIT, SumiPathResolverError, SUMI_SKILL_PERMISSIONS;
|
|
54211
54311
|
var init_agent_sumi = __esm(() => {
|
|
54312
|
+
SUMI_PATH_SELECTORS = ["SUMI_HOME", "SUMI_CONFIG_DIR", "XDG_DATA_HOME", "XDG_CACHE_HOME", "XDG_CONFIG_HOME", "XDG_STATE_HOME"];
|
|
54313
|
+
SUMI_PATH_KEYS = ["data", "cache", "config", "state"];
|
|
54314
|
+
SUMI_PATH_OUTPUT_LIMIT = 128 * 1024;
|
|
54315
|
+
SumiPathResolverError = class SumiPathResolverError extends Error {
|
|
54316
|
+
code;
|
|
54317
|
+
constructor(code) {
|
|
54318
|
+
super(`Sumi path discovery refused (${code})`);
|
|
54319
|
+
this.code = code;
|
|
54320
|
+
this.name = "SumiPathResolverError";
|
|
54321
|
+
}
|
|
54322
|
+
};
|
|
54212
54323
|
SUMI_SKILL_PERMISSIONS = [
|
|
54213
54324
|
{ action: "skill", resource: "*", effect: "deny" },
|
|
54214
54325
|
{ action: "skill", resource: "skills-cli", effect: "allow" }
|
|
@@ -54216,9 +54327,9 @@ var init_agent_sumi = __esm(() => {
|
|
|
54216
54327
|
});
|
|
54217
54328
|
|
|
54218
54329
|
// src/lib/codex-hook-trust-files.ts
|
|
54219
|
-
import { closeSync as closeSync10, constants as
|
|
54330
|
+
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
54331
|
import { createHash as createHash18 } from "crypto";
|
|
54221
|
-
import { dirname as dirname15, isAbsolute as
|
|
54332
|
+
import { dirname as dirname15, isAbsolute as isAbsolute16, resolve as resolve16 } from "path";
|
|
54222
54333
|
function need6(value, code) {
|
|
54223
54334
|
if (!value)
|
|
54224
54335
|
throw new Error(`CODEX_HOOK_TRUST_${code}`);
|
|
@@ -54238,7 +54349,7 @@ function safeParents(file) {
|
|
|
54238
54349
|
function directAliasTarget(link2) {
|
|
54239
54350
|
const text2 = readlinkSync5(link2), parts = text2.split("/");
|
|
54240
54351
|
let first = 0;
|
|
54241
|
-
if (
|
|
54352
|
+
if (isAbsolute16(text2))
|
|
54242
54353
|
first = 1;
|
|
54243
54354
|
else
|
|
54244
54355
|
while (parts[first] === "..")
|
|
@@ -54254,7 +54365,7 @@ function snapshot(file, privateFile = false, options = {}) {
|
|
|
54254
54365
|
const initial2 = lstatSync19(file, { bigint: true });
|
|
54255
54366
|
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
54367
|
need6(initial2.size <= 8n * 1024n * 1024n, "FILE_BOUND");
|
|
54257
|
-
const fd = openSync10(file,
|
|
54368
|
+
const fd = openSync10(file, constants12.O_RDONLY | constants12.O_NOFOLLOW | constants12.O_NONBLOCK);
|
|
54258
54369
|
try {
|
|
54259
54370
|
const before2 = fstatSync10(fd, { bigint: true });
|
|
54260
54371
|
need6(sameStat(initial2, before2), "INPUT_CHANGED");
|
|
@@ -54279,7 +54390,7 @@ function unchanged2(before2) {
|
|
|
54279
54390
|
}
|
|
54280
54391
|
function save(file, content) {
|
|
54281
54392
|
safeParents(file);
|
|
54282
|
-
const fd = openSync10(file,
|
|
54393
|
+
const fd = openSync10(file, constants12.O_WRONLY | constants12.O_CREAT | constants12.O_EXCL | constants12.O_NOFOLLOW, 384);
|
|
54283
54394
|
try {
|
|
54284
54395
|
writeFileSync5(fd, content);
|
|
54285
54396
|
fsyncSync3(fd);
|
|
@@ -54290,35 +54401,152 @@ function save(file, content) {
|
|
|
54290
54401
|
var sameStat = (a, b) => ["dev", "ino", "uid", "nlink", "mode", "size", "mtimeNs", "ctimeNs"].every((key) => a[key] === b[key]);
|
|
54291
54402
|
var init_codex_hook_trust_files = () => {};
|
|
54292
54403
|
|
|
54404
|
+
// src/server/launcher-environment-policy.ts
|
|
54405
|
+
function renderLegacyPinnedLauncher(binding) {
|
|
54406
|
+
const names = LEGACY_ENV_NAMES.join(" ");
|
|
54407
|
+
const prefixes = LEGACY_ENV_PREFIXES.join("|");
|
|
54408
|
+
return [
|
|
54409
|
+
"#!/bin/sh -p",
|
|
54410
|
+
`# ${LEGACY_PINNED_LAUNCHER_SCHEMA}`,
|
|
54411
|
+
"# Written by `skills self-update`; rewrite it with `skills self-update`, do not edit by hand.",
|
|
54412
|
+
"# Runs the exact Skills entry below under one exact Bun from one trusted directory with",
|
|
54413
|
+
"# no working-directory configuration (no bunfig.toml, no .env, no macros, no auto-install)",
|
|
54414
|
+
"# and only the environment names allowed here. Everything else, BUN_* and NODE_OPTIONS",
|
|
54415
|
+
"# included, never reaches the runtime. The CLI returns to the caller's directory itself.",
|
|
54416
|
+
"# `-p` keeps the caller's exported functions and shell options out of this shell.",
|
|
54417
|
+
"set -eu",
|
|
54418
|
+
`${LAUNCH_CWD_VARIABLE2}=$(pwd -P 2>/dev/null || :)`,
|
|
54419
|
+
`export ${LAUNCH_CWD_VARIABLE2}`,
|
|
54420
|
+
`set -- '${binding.runtime}' ${PINNED_LAUNCHER_BUN_FLAGS.join(" ")} '--cwd=${binding.cwd}' '${binding.entry}' "$@"`,
|
|
54421
|
+
"hasna_skills_env=$(LC_ALL=C /usr/bin/awk 'BEGIN {",
|
|
54422
|
+
` n = split("${names}", exact, " ")`,
|
|
54423
|
+
" for (i = 1; i <= n; i++) allow[exact[i]] = 1",
|
|
54424
|
+
" for (name in ENVIRON) {",
|
|
54425
|
+
" if (name !~ /^[A-Za-z_][A-Za-z0-9_]*$/) continue",
|
|
54426
|
+
` if (name == "LC_ALL" || (!(name in allow) && name !~ /^(${prefixes})_/)) continue`,
|
|
54427
|
+
' value = ENVIRON[name]; quoted = ""',
|
|
54428
|
+
' while ((k = index(value, "\\047")) > 0) { quoted = quoted substr(value, 1, k - 1) "\\047\\\\\\047\\047"; value = substr(value, k + 1) }',
|
|
54429
|
+
' printf "\\047%s=%s\\047 ", name, quoted value',
|
|
54430
|
+
" }",
|
|
54431
|
+
"}')",
|
|
54432
|
+
'eval "set -- $hasna_skills_env \\"\\$@\\""',
|
|
54433
|
+
'if [ "${LC_ALL+x}" = x ]; then set -- "LC_ALL=$LC_ALL" "$@"; fi',
|
|
54434
|
+
'exec /usr/bin/env -i "$@"',
|
|
54435
|
+
""
|
|
54436
|
+
].join(`
|
|
54437
|
+
`);
|
|
54438
|
+
}
|
|
54439
|
+
function isStorageLocatorEnvironmentName(name) {
|
|
54440
|
+
return storageLocators.has(name);
|
|
54441
|
+
}
|
|
54442
|
+
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`;
|
|
54443
|
+
var init_launcher_environment_policy = __esm(() => {
|
|
54444
|
+
PINNED_LAUNCHER_BUN_FLAGS = ["--config=/dev/null", "--no-env-file", "--no-macros", "--no-install"];
|
|
54445
|
+
LEGACY_ENV_NAMES = [
|
|
54446
|
+
"HOME",
|
|
54447
|
+
"PATH",
|
|
54448
|
+
"TMPDIR",
|
|
54449
|
+
"TERM",
|
|
54450
|
+
"TERM_PROGRAM",
|
|
54451
|
+
"TERM_PROGRAM_VERSION",
|
|
54452
|
+
"COLORTERM",
|
|
54453
|
+
"LANG",
|
|
54454
|
+
"USER",
|
|
54455
|
+
"LOGNAME",
|
|
54456
|
+
"SHELL",
|
|
54457
|
+
"TZ",
|
|
54458
|
+
"NO_COLOR",
|
|
54459
|
+
"FORCE_COLOR",
|
|
54460
|
+
"CI",
|
|
54461
|
+
"COLUMNS",
|
|
54462
|
+
"LINES",
|
|
54463
|
+
"EDITOR",
|
|
54464
|
+
"VISUAL",
|
|
54465
|
+
"PAGER",
|
|
54466
|
+
"SSH_AUTH_SOCK",
|
|
54467
|
+
"DATABASE_URL",
|
|
54468
|
+
"TERMINAL_CWD",
|
|
54469
|
+
"CODEX_HOME",
|
|
54470
|
+
"HERMES_HOME",
|
|
54471
|
+
"HERMES_ENABLE_PROJECT_PLUGINS",
|
|
54472
|
+
"HOST",
|
|
54473
|
+
"PORT",
|
|
54474
|
+
"NODE_ENV",
|
|
54475
|
+
"AGENT_ID",
|
|
54476
|
+
"ECS_CONTAINER_METADATA_URI_V4"
|
|
54477
|
+
];
|
|
54478
|
+
LEGACY_ENV_PREFIXES = ["HASNA", "SKILLS", "SKILL", "MCP", "XDG", "LC", "AWS"];
|
|
54479
|
+
SERVER_LAUNCHER_ENV_NAMES = ["DATABASE_URL"];
|
|
54480
|
+
STORAGE_LOCATOR_ENV_NAMES = ["DATABASE_URL", "HASNA_SKILLS_DATABASE_URL", "SKILLS_DATABASE_URL"];
|
|
54481
|
+
storageLocators = new Set(STORAGE_LOCATOR_ENV_NAMES);
|
|
54482
|
+
});
|
|
54483
|
+
|
|
54293
54484
|
// src/cli/commands/runtime-launcher.ts
|
|
54294
54485
|
import { createHash as createHash19 } from "crypto";
|
|
54295
|
-
import { closeSync as closeSync11, constants as
|
|
54296
|
-
import { isAbsolute as
|
|
54297
|
-
function pinnedLauncherEnvironment(env3) {
|
|
54486
|
+
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";
|
|
54487
|
+
import { isAbsolute as isAbsolute17 } from "path";
|
|
54488
|
+
function pinnedLauncherEnvironment(env3, profile = "client") {
|
|
54489
|
+
assertLauncherProfile(profile);
|
|
54298
54490
|
const result2 = {};
|
|
54299
|
-
for (const
|
|
54300
|
-
if (
|
|
54491
|
+
for (const name of Object.keys(env3)) {
|
|
54492
|
+
if (!ENV_NAME.test(name))
|
|
54493
|
+
continue;
|
|
54494
|
+
const storageLocator = isStorageLocatorEnvironmentName(name);
|
|
54495
|
+
if (storageLocator && profile === "client")
|
|
54301
54496
|
continue;
|
|
54302
|
-
|
|
54497
|
+
if (!storageLocator && !ENV_EXACT.has(name) && !ENV_PREFIX.test(name))
|
|
54498
|
+
continue;
|
|
54499
|
+
const value = env3[name];
|
|
54500
|
+
if (value !== undefined)
|
|
54501
|
+
result2[name] = value;
|
|
54303
54502
|
}
|
|
54304
54503
|
return result2;
|
|
54305
54504
|
}
|
|
54505
|
+
function assertLauncherProfile(profile) {
|
|
54506
|
+
if (profile !== "client" && profile !== "server")
|
|
54507
|
+
throw new Error("LAUNCHER_PROFILE_INVALID");
|
|
54508
|
+
}
|
|
54509
|
+
function launcherProfileForBin(name, entry) {
|
|
54510
|
+
const bins = {
|
|
54511
|
+
skills: ["bin/index.js", "client"],
|
|
54512
|
+
"skills-mcp": ["bin/mcp.js", "client"],
|
|
54513
|
+
"skills-serve": ["bin/server.js", "server"],
|
|
54514
|
+
"skills-server": ["bin/server.js", "server"],
|
|
54515
|
+
"skills-worker": ["bin/worker.js", "server"],
|
|
54516
|
+
"skills-maintenance": ["bin/maintenance.js", "server"],
|
|
54517
|
+
"skills-migrate": ["bin/migrate.js", "server"]
|
|
54518
|
+
};
|
|
54519
|
+
const contract = bins[name];
|
|
54520
|
+
if (!contract || entry !== contract[0])
|
|
54521
|
+
throw new Error("LAUNCHER_BIN_CONTRACT_INVALID");
|
|
54522
|
+
return contract[1];
|
|
54523
|
+
}
|
|
54306
54524
|
function sha2562(bytes) {
|
|
54307
54525
|
return createHash19("sha256").update(bytes).digest("hex");
|
|
54308
54526
|
}
|
|
54309
54527
|
function assertLauncherPath(value, code) {
|
|
54310
|
-
if (typeof value !== "string" || !
|
|
54528
|
+
if (typeof value !== "string" || !isAbsolute17(value) || /['\x00-\x1f\x7f]/.test(value))
|
|
54311
54529
|
throw new Error(code);
|
|
54312
54530
|
}
|
|
54313
54531
|
function renderPinnedLauncher(binding) {
|
|
54314
54532
|
assertLauncherPath(binding.runtime, "LAUNCHER_RUNTIME_PATH_INVALID");
|
|
54315
54533
|
assertLauncherPath(binding.cwd, "LAUNCHER_CWD_PATH_INVALID");
|
|
54316
54534
|
assertLauncherPath(binding.entry, "LAUNCHER_ENTRY_PATH_INVALID");
|
|
54317
|
-
|
|
54535
|
+
if (binding.format === "v1") {
|
|
54536
|
+
if (binding.profile !== undefined)
|
|
54537
|
+
throw new Error("LAUNCHER_PROFILE_INVALID");
|
|
54538
|
+
return renderLegacyPinnedLauncher(binding);
|
|
54539
|
+
}
|
|
54540
|
+
if (binding.format !== undefined && binding.format !== "v2")
|
|
54541
|
+
throw new Error("LAUNCHER_FORMAT_INVALID");
|
|
54542
|
+
const profile = binding.profile === undefined ? "client" : binding.profile;
|
|
54543
|
+
assertLauncherProfile(profile);
|
|
54544
|
+
const names = [...PINNED_LAUNCHER_ENV_NAMES, ...profile === "server" ? SERVER_LAUNCHER_ENV_NAMES : []].join(" ");
|
|
54318
54545
|
const prefixes = PINNED_LAUNCHER_ENV_PREFIXES.join("|");
|
|
54319
54546
|
return [
|
|
54320
54547
|
"#!/bin/sh -p",
|
|
54321
54548
|
`# ${PINNED_LAUNCHER_SCHEMA}`,
|
|
54549
|
+
`# environment-profile: ${profile}`,
|
|
54322
54550
|
"# Written by `skills self-update`; rewrite it with `skills self-update`, do not edit by hand.",
|
|
54323
54551
|
"# Runs the exact Skills entry below under one exact Bun from one trusted directory with",
|
|
54324
54552
|
"# no working-directory configuration (no bunfig.toml, no .env, no macros, no auto-install)",
|
|
@@ -54326,15 +54554,16 @@ function renderPinnedLauncher(binding) {
|
|
|
54326
54554
|
"# included, never reaches the runtime. The CLI returns to the caller's directory itself.",
|
|
54327
54555
|
"# `-p` keeps the caller's exported functions and shell options out of this shell.",
|
|
54328
54556
|
"set -eu",
|
|
54329
|
-
`${
|
|
54330
|
-
`export ${
|
|
54331
|
-
`set -- '${binding.runtime}' ${
|
|
54557
|
+
`${LAUNCH_CWD_VARIABLE3}=$(pwd -P 2>/dev/null || :)`,
|
|
54558
|
+
`export ${LAUNCH_CWD_VARIABLE3}`,
|
|
54559
|
+
`set -- '${binding.runtime}' ${PINNED_LAUNCHER_BUN_FLAGS2.join(" ")} '--cwd=${binding.cwd}' '${binding.entry}' "$@"`,
|
|
54332
54560
|
"hasna_skills_env=$(LC_ALL=C /usr/bin/awk 'BEGIN {",
|
|
54333
54561
|
` n = split("${names}", exact, " ")`,
|
|
54334
54562
|
" for (i = 1; i <= n; i++) allow[exact[i]] = 1",
|
|
54335
54563
|
" for (name in ENVIRON) {",
|
|
54336
54564
|
" if (name !~ /^[A-Za-z_][A-Za-z0-9_]*$/) continue",
|
|
54337
54565
|
` if (name == "LC_ALL" || (!(name in allow) && name !~ /^(${prefixes})_/)) continue`,
|
|
54566
|
+
...profile === "client" ? [CLIENT_LAUNCHER_STORAGE_DENY_AWK] : [],
|
|
54338
54567
|
' value = ENVIRON[name]; quoted = ""',
|
|
54339
54568
|
' while ((k = index(value, "\\047")) > 0) { quoted = quoted substr(value, 1, k - 1) "\\047\\\\\\047\\047"; value = substr(value, k + 1) }',
|
|
54340
54569
|
' printf "\\047%s=%s\\047 ", name, quoted value',
|
|
@@ -54351,7 +54580,19 @@ function parsePinnedLauncher(text2) {
|
|
|
54351
54580
|
const match = COMMAND_LINE.exec(text2);
|
|
54352
54581
|
if (!match)
|
|
54353
54582
|
return null;
|
|
54354
|
-
|
|
54583
|
+
let metadata;
|
|
54584
|
+
if (text2.split(`
|
|
54585
|
+
`)[1] === `# ${LEGACY_PINNED_LAUNCHER_SCHEMA}`)
|
|
54586
|
+
metadata = { format: "v1" };
|
|
54587
|
+
else if (text2.split(`
|
|
54588
|
+
`)[1] === `# ${PINNED_LAUNCHER_SCHEMA}`) {
|
|
54589
|
+
const profile = /^# environment-profile: (client|server)$/m.exec(text2)?.[1];
|
|
54590
|
+
if (!profile)
|
|
54591
|
+
return null;
|
|
54592
|
+
metadata = { format: "v2", profile };
|
|
54593
|
+
} else
|
|
54594
|
+
return null;
|
|
54595
|
+
const binding = { runtime: match[1], cwd: match[2], entry: match[3], ...metadata };
|
|
54355
54596
|
try {
|
|
54356
54597
|
if (renderPinnedLauncher(binding) !== text2)
|
|
54357
54598
|
return null;
|
|
@@ -54398,7 +54639,7 @@ function inspectLauncher(path) {
|
|
|
54398
54639
|
const binding = parsePinnedLauncher(text2);
|
|
54399
54640
|
if (!binding)
|
|
54400
54641
|
return { kind: "foreign" };
|
|
54401
|
-
return { kind: "pinned", runtime: binding.runtime, cwd: binding.cwd, target: binding.entry, sha256: sha2562(text2), text: text2 };
|
|
54642
|
+
return { kind: "pinned", format: binding.format, profile: binding.profile, runtime: binding.runtime, cwd: binding.cwd, target: binding.entry, sha256: sha2562(text2), text: text2 };
|
|
54402
54643
|
}
|
|
54403
54644
|
function launcherTarget(path) {
|
|
54404
54645
|
const inspected = inspectLauncher(path);
|
|
@@ -54415,17 +54656,22 @@ function launcherIs(path, state) {
|
|
|
54415
54656
|
}
|
|
54416
54657
|
if (state.shape === "symlink")
|
|
54417
54658
|
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;
|
|
54659
|
+
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
54660
|
}
|
|
54420
54661
|
function pinnedLauncherText(state) {
|
|
54421
|
-
|
|
54662
|
+
if (state.format === "v2")
|
|
54663
|
+
assertLauncherProfile(state.profile);
|
|
54664
|
+
const text2 = renderPinnedLauncher({ runtime: state.runtime, cwd: state.cwd, entry: state.target, format: state.format === undefined ? "v1" : state.format, profile: state.profile });
|
|
54422
54665
|
if (sha2562(text2) !== state.sha256)
|
|
54423
54666
|
throw new Error("LAUNCHER_TEXT_DIGEST_MISMATCH");
|
|
54424
54667
|
return text2;
|
|
54425
54668
|
}
|
|
54426
|
-
function pinnedLauncherState(runtime, cwd2, target) {
|
|
54427
|
-
const
|
|
54428
|
-
|
|
54669
|
+
function pinnedLauncherState(runtime, cwd2, target, metadata = { format: "v2", profile: "client" }) {
|
|
54670
|
+
const format = metadata.format === undefined ? "v1" : metadata.format, profile = metadata.profile;
|
|
54671
|
+
if (format === "v2")
|
|
54672
|
+
assertLauncherProfile(profile);
|
|
54673
|
+
const text2 = renderPinnedLauncher({ runtime, cwd: cwd2, entry: target, format, profile });
|
|
54674
|
+
return { shape: "pinned", runtime, cwd: cwd2, target, sha256: sha2562(text2), format, ...profile ? { profile } : {} };
|
|
54429
54675
|
}
|
|
54430
54676
|
function materializeLauncher(path, state) {
|
|
54431
54677
|
if (state.shape === "symlink") {
|
|
@@ -54435,7 +54681,7 @@ function materializeLauncher(path, state) {
|
|
|
54435
54681
|
return;
|
|
54436
54682
|
}
|
|
54437
54683
|
const text2 = pinnedLauncherText(state);
|
|
54438
|
-
const fd = openSync11(path,
|
|
54684
|
+
const fd = openSync11(path, constants13.O_WRONLY | constants13.O_CREAT | constants13.O_EXCL | constants13.O_NOFOLLOW, 493);
|
|
54439
54685
|
try {
|
|
54440
54686
|
const bytes = Buffer.from(text2, "utf8");
|
|
54441
54687
|
let written = 0;
|
|
@@ -54491,9 +54737,10 @@ function assertPinnedLauncherShell() {
|
|
|
54491
54737
|
if (probe.exitCode !== 0)
|
|
54492
54738
|
throw new Error("LAUNCHER_SHELL_UNSUPPORTED");
|
|
54493
54739
|
}
|
|
54494
|
-
var PINNED_LAUNCHER_SCHEMA = "hasna-skills-pinned-launcher-
|
|
54740
|
+
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
54741
|
var init_runtime_launcher = __esm(() => {
|
|
54496
|
-
|
|
54742
|
+
init_launcher_environment_policy();
|
|
54743
|
+
PINNED_LAUNCHER_BUN_FLAGS2 = ["--config=/dev/null", "--no-env-file", "--no-macros", "--no-install"];
|
|
54497
54744
|
PINNED_LAUNCHER_ENV_NAMES = [
|
|
54498
54745
|
"HOME",
|
|
54499
54746
|
"PATH",
|
|
@@ -54516,7 +54763,6 @@ var init_runtime_launcher = __esm(() => {
|
|
|
54516
54763
|
"VISUAL",
|
|
54517
54764
|
"PAGER",
|
|
54518
54765
|
"SSH_AUTH_SOCK",
|
|
54519
|
-
"DATABASE_URL",
|
|
54520
54766
|
"TERMINAL_CWD",
|
|
54521
54767
|
"CODEX_HOME",
|
|
54522
54768
|
"HERMES_HOME",
|
|
@@ -54531,16 +54777,32 @@ var init_runtime_launcher = __esm(() => {
|
|
|
54531
54777
|
ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
54532
54778
|
ENV_PREFIX = new RegExp(`^(${PINNED_LAUNCHER_ENV_PREFIXES.join("|")})_`);
|
|
54533
54779
|
ENV_EXACT = new Set(PINNED_LAUNCHER_ENV_NAMES);
|
|
54534
|
-
COMMAND_LINE = new RegExp(`^set -- '([^']+)' ${
|
|
54780
|
+
COMMAND_LINE = new RegExp(`^set -- '([^']+)' ${PINNED_LAUNCHER_BUN_FLAGS2.join(" ")} '--cwd=([^']+)' '([^']+)' "\\$@"$`, "m");
|
|
54535
54781
|
PINNED_LAUNCHER_MAX_BYTES = 16 * 1024;
|
|
54536
54782
|
});
|
|
54537
54783
|
|
|
54538
54784
|
// src/lib/agent-integration.ts
|
|
54539
54785
|
import { createHash as createHash20, randomUUID as randomUUID6 } from "crypto";
|
|
54540
54786
|
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
|
|
54787
|
+
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";
|
|
54788
|
+
import { dirname as dirname16, join as join28, resolve as resolve17, relative as relative6, isAbsolute as isAbsolute18, sep as sep7 } from "path";
|
|
54543
54789
|
import { homedir as homedir3 } from "os";
|
|
54790
|
+
function nativeAgentRoot(home, agent, cwd2 = process.cwd()) {
|
|
54791
|
+
if (agent === "sumi")
|
|
54792
|
+
return sumiBridgeRoot(home, cwd2);
|
|
54793
|
+
const root = AGENT_ADAPTERS[agent].root;
|
|
54794
|
+
if (typeof root !== "string")
|
|
54795
|
+
throw new Error(`Native skill root is unavailable for ${agent}`);
|
|
54796
|
+
return join28(home, root);
|
|
54797
|
+
}
|
|
54798
|
+
function nativeAgentConfig(home, agent, cwd2 = process.cwd()) {
|
|
54799
|
+
if (agent === "sumi")
|
|
54800
|
+
return sumiConfigPath(home, cwd2);
|
|
54801
|
+
const config = AGENT_ADAPTERS[agent].config;
|
|
54802
|
+
if (typeof config !== "string")
|
|
54803
|
+
throw new Error(`Native configuration path is unavailable for ${agent}`);
|
|
54804
|
+
return join28(home, config);
|
|
54805
|
+
}
|
|
54544
54806
|
function hasTrustedDarwinAcl(fd, allowDenyOnly = false) {
|
|
54545
54807
|
try {
|
|
54546
54808
|
const { dlopen, read: read2, ptr } = __require("bun:ffi");
|
|
@@ -54603,7 +54865,7 @@ function isSystemRootAlias(path) {
|
|
|
54603
54865
|
throw new Error("Writable system alias directory");
|
|
54604
54866
|
} else if ((stat.mode & 0o1000n) === 0n)
|
|
54605
54867
|
throw new Error("Unprotected system temporary directory");
|
|
54606
|
-
const fd = openSync12(directory,
|
|
54868
|
+
const fd = openSync12(directory, constants14.O_RDONLY | constants14.O_DIRECTORY | constants14.O_NOFOLLOW);
|
|
54607
54869
|
try {
|
|
54608
54870
|
if (directoryIdentity(fstatSync12(fd, { bigint: true })) !== directoryIdentity(stat) || !hasTrustedDarwinAcl(fd) || directoryIdentity(fstatSync12(fd, { bigint: true })) !== directoryIdentity(stat))
|
|
54609
54871
|
throw new Error("Unverified system alias directory ACL");
|
|
@@ -54648,7 +54910,7 @@ function readRootAlias(home, agent) {
|
|
|
54648
54910
|
if (!targetStat?.isDirectory())
|
|
54649
54911
|
throw new Error(`Agent root alias must target an existing directory: ${alias}`);
|
|
54650
54912
|
const target = realpathSync10(targetPath), inside = relative6(realHome, target);
|
|
54651
|
-
if (!inside || inside === ".." || inside.startsWith(`..${sep7}`) ||
|
|
54913
|
+
if (!inside || inside === ".." || inside.startsWith(`..${sep7}`) || isAbsolute18(inside))
|
|
54652
54914
|
throw new Error(`Agent root alias target must be inside the real home: ${alias}`);
|
|
54653
54915
|
return { agent, home: realHome, alias, target, link: link2, aliasIdentity: `${stat.dev}:${stat.ino}:${stat.ctimeNs}`, targetIdentity: `${targetStat.dev}:${targetStat.ino}` };
|
|
54654
54916
|
}
|
|
@@ -54674,13 +54936,13 @@ function disabledCodexSkillPaths(config, aliases) {
|
|
|
54674
54936
|
const rows = skills.config;
|
|
54675
54937
|
if (!Array.isArray(rows))
|
|
54676
54938
|
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" || !
|
|
54939
|
+
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
54940
|
return [];
|
|
54679
54941
|
if (rows.some((entry) => entry.name !== undefined && entry.enabled !== false))
|
|
54680
54942
|
return [];
|
|
54681
54943
|
const settings = new Map;
|
|
54682
54944
|
for (const entry of rows) {
|
|
54683
|
-
if (typeof entry.path !== "string" || !
|
|
54945
|
+
if (typeof entry.path !== "string" || !isAbsolute18(entry.path))
|
|
54684
54946
|
continue;
|
|
54685
54947
|
let document3;
|
|
54686
54948
|
try {
|
|
@@ -54712,7 +54974,7 @@ function readNativeBytes(path, maximum = 64 * 1024 * 1024) {
|
|
|
54712
54974
|
const before2 = lstatSync21(path);
|
|
54713
54975
|
if (!before2.isFile() || before2.size > maximum)
|
|
54714
54976
|
throw new Error("Unsupported or oversized native skill file");
|
|
54715
|
-
const descriptor = openSync12(path,
|
|
54977
|
+
const descriptor = openSync12(path, constants14.O_RDONLY | constants14.O_NOFOLLOW | constants14.O_NONBLOCK);
|
|
54716
54978
|
try {
|
|
54717
54979
|
const opened = fstatSync12(descriptor);
|
|
54718
54980
|
if (!opened.isFile() || opened.dev !== before2.dev || opened.ino !== before2.ino || opened.size !== before2.size)
|
|
@@ -54785,16 +55047,16 @@ function parseNativeMigrationTargetManifest(input) {
|
|
|
54785
55047
|
throw new Error("Invalid native migration target fields");
|
|
54786
55048
|
if (!ROOTS.some(([agent]) => agent === item.agent))
|
|
54787
55049
|
throw new Error(`Unsupported native migration target agent: ${item.agent}`);
|
|
54788
|
-
if (!
|
|
55050
|
+
if (!isAbsolute18(item.projectRoot) || resolve17(item.projectRoot) !== item.projectRoot)
|
|
54789
55051
|
throw new Error(`Native migration target project root must be an existing absolute directory: ${item.projectRoot}`);
|
|
54790
55052
|
const projectRoot = canonicalSystemPath(item.projectRoot);
|
|
54791
55053
|
if (!existsSync13(projectRoot) || !lstatSync21(projectRoot).isDirectory())
|
|
54792
55054
|
throw new Error(`Native migration target project root must be an existing absolute directory: ${item.projectRoot}`);
|
|
54793
55055
|
assertSafePath(projectRoot);
|
|
54794
|
-
if (
|
|
55056
|
+
if (isAbsolute18(item.path) || item.path.includes("\\") || item.path.length === 0 || item.path.includes("\x00"))
|
|
54795
55057
|
throw new Error(`Native migration target path must be normalized and project-relative: ${item.path}`);
|
|
54796
55058
|
const resolved = resolve17(projectRoot, item.path), normalized = relative6(projectRoot, resolved);
|
|
54797
|
-
if (!normalized || normalized === ".." || normalized.startsWith(`..${sep7}`) ||
|
|
55059
|
+
if (!normalized || normalized === ".." || normalized.startsWith(`..${sep7}`) || isAbsolute18(normalized) || normalized !== item.path)
|
|
54798
55060
|
throw new Error(`Native migration target path escapes or is not normalized: ${item.path}`);
|
|
54799
55061
|
if (!/^[0-9a-f]{64}$/.test(item.treeSha256))
|
|
54800
55062
|
throw new Error(`Invalid native migration tree digest for ${item.path}`);
|
|
@@ -54815,13 +55077,13 @@ function selectNativeMigrationTargets(inventory, manifest) {
|
|
|
54815
55077
|
const identities = new Set;
|
|
54816
55078
|
const selected = [];
|
|
54817
55079
|
for (const target of manifest.targets) {
|
|
54818
|
-
if (!
|
|
55080
|
+
if (!isAbsolute18(target.projectRoot) || resolve17(target.projectRoot) !== target.projectRoot)
|
|
54819
55081
|
throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
|
|
54820
55082
|
const projectRoot = canonicalSystemPath(target.projectRoot), normalized = relative6(projectRoot, resolve17(projectRoot, target.path));
|
|
54821
55083
|
if (!existsSync13(projectRoot) || !lstatSync21(projectRoot).isDirectory())
|
|
54822
55084
|
throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
|
|
54823
55085
|
assertSafePath(projectRoot);
|
|
54824
|
-
if (
|
|
55086
|
+
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
55087
|
throw new Error(`Invalid native migration target: ${target.path}`);
|
|
54826
55088
|
const identity6 = `${target.agent}\x00${canonicalSystemPath(projectRoot)}\x00${normalized}`;
|
|
54827
55089
|
if (identities.has(identity6))
|
|
@@ -54864,25 +55126,32 @@ function isCodexSkillDiscoveryInput(path) {
|
|
|
54864
55126
|
}
|
|
54865
55127
|
function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
54866
55128
|
home = canonicalSystemPath(home);
|
|
54867
|
-
if (options.reviewedCacheAlias !== undefined && (!options.includeVendor || !
|
|
55129
|
+
if (options.reviewedCacheAlias !== undefined && (!options.includeVendor || !isAbsolute18(options.reviewedCacheAlias) || resolve17(options.reviewedCacheAlias) !== options.reviewedCacheAlias))
|
|
54868
55130
|
throw new Error("A reviewed cache alias requires vendor inventory and an exact absolute path");
|
|
54869
|
-
if (options.disabledVendorPaths?.some((path) => !
|
|
55131
|
+
if (options.disabledVendorPaths?.some((path) => !isAbsolute18(path) || resolve17(path) !== path))
|
|
54870
55132
|
throw new Error("Disabled vendor paths must be exact absolute paths");
|
|
54871
55133
|
const reviewedCacheAlias = options.reviewedCacheAlias === undefined ? undefined : canonicalSystemPath(options.reviewedCacheAlias);
|
|
54872
55134
|
const disabledVendorPaths = new Set((options.disabledVendorPaths ?? []).map(canonicalSystemPath));
|
|
54873
55135
|
const aliases = rootAliases(home, options.allowRootAliases);
|
|
54874
55136
|
const selectedAgents = options.agents ? new Set(options.agents) : undefined;
|
|
54875
55137
|
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;
|
|
55138
|
+
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
55139
|
const roots = rootDefinitions.map(([agent, path]) => [agent, canonicalAgentPath(join28(home, path), aliases)]);
|
|
54878
|
-
const
|
|
55140
|
+
const includesSumi = !selectedAgents || selectedAgents.has("sumi");
|
|
55141
|
+
if (includesSumi)
|
|
55142
|
+
for (const path of sumiSkillRoots(home))
|
|
55143
|
+
roots.push(["sumi", canonicalAgentPath(path, aliases)]);
|
|
55144
|
+
const bridgePaths = Object.entries(AGENT_ADAPTERS).filter(([agent]) => agent !== "sumi" || includesSumi).map(([agent]) => canonicalAgentPath(join28(nativeAgentRoot(home, agent), CLI_BRIDGE_NAME), aliases));
|
|
54879
55145
|
for (const project of projectAncestorDirectories([...options.projectDirs ?? [], ...options.projectDir ? [options.projectDir] : []])) {
|
|
54880
55146
|
for (const [agent, path] of rootDefinitions)
|
|
54881
55147
|
roots.push([agent, canonicalAgentPath(join28(project, path), aliases)]);
|
|
54882
|
-
if (selectedAgents?.has("sumi"))
|
|
55148
|
+
if (selectedAgents?.has("sumi")) {
|
|
55149
|
+
for (const path of sumiSkillRoots(home, project))
|
|
55150
|
+
roots.push(["sumi", canonicalAgentPath(path, aliases)]);
|
|
54883
55151
|
for (const directory of [".claude", ".agents"])
|
|
54884
55152
|
for (const name of ["skill", "skills"])
|
|
54885
55153
|
roots.push(["sumi", canonicalAgentPath(join28(project, directory, name), aliases)]);
|
|
55154
|
+
}
|
|
54886
55155
|
}
|
|
54887
55156
|
const installationInputs = options.codexInstallationInputRoots ?? [];
|
|
54888
55157
|
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 +55169,7 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
54900
55169
|
let reviewedCacheAliasFound = false;
|
|
54901
55170
|
function verifiedSiblingCacheAlias(agent, path, parent) {
|
|
54902
55171
|
const link2 = readlinkSync7(path), lexicalTarget = resolve17(parent, link2);
|
|
54903
|
-
if (
|
|
55172
|
+
if (isAbsolute18(link2) ? link2 !== lexicalTarget : dirname16(link2) !== ".")
|
|
54904
55173
|
return false;
|
|
54905
55174
|
const target = canonicalSystemPath(lexicalTarget);
|
|
54906
55175
|
if (dirname16(target) !== parent)
|
|
@@ -54980,7 +55249,7 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
54980
55249
|
continue;
|
|
54981
55250
|
const child2 = join28(path, name);
|
|
54982
55251
|
if (isVendor && lstatSync21(child2, { throwIfNoEntry: false })?.isSymbolicLink()) {
|
|
54983
|
-
const target =
|
|
55252
|
+
const target = statSync10(child2, { throwIfNoEntry: false });
|
|
54984
55253
|
if (target?.isFile() || pluginCache && target?.isDirectory() && verifiedSiblingCacheAlias(agent, child2, path)) {
|
|
54985
55254
|
scan.entries++;
|
|
54986
55255
|
continue;
|
|
@@ -55244,8 +55513,7 @@ function planAgentIntegration(options) {
|
|
|
55244
55513
|
if (!INTEGRATION_AGENTS.includes(agent))
|
|
55245
55514
|
throw new Error(`Unsupported agent: ${agent}`);
|
|
55246
55515
|
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);
|
|
55516
|
+
const bridgePath = canonicalAgentPath(join28(nativeAgentRoot(home, agent, options.projectDir ?? process.cwd()), CLI_BRIDGE_NAME), aliases);
|
|
55249
55517
|
assertSafePath(bridgePath);
|
|
55250
55518
|
if (existsSync13(bridgePath) && !isOwnedCliBridge(bridgePath, [bridgePath]))
|
|
55251
55519
|
throw new Error(`Refusing to overwrite an unrecognized or modified Skills bridge: ${bridgePath}`);
|
|
@@ -55254,7 +55522,7 @@ function planAgentIntegration(options) {
|
|
|
55254
55522
|
if (before3 !== after3)
|
|
55255
55523
|
changes.push({ path: path2, before: before3, after: after3 });
|
|
55256
55524
|
}
|
|
55257
|
-
const path = canonicalAgentPath(
|
|
55525
|
+
const path = canonicalAgentPath(nativeAgentConfig(home, agent, options.projectDir ?? process.cwd()), aliases);
|
|
55258
55526
|
const before2 = readOptional(path);
|
|
55259
55527
|
if (agent === "hermes") {
|
|
55260
55528
|
const supervisorPath = join28(dataDir3, "agent-hooks", "hermes.js"), supervisorBefore = readOptional(supervisorPath), supervisorAfter = renderHermesSupervisor(command, profileId2);
|
|
@@ -55279,7 +55547,7 @@ function planAgentIntegration(options) {
|
|
|
55279
55547
|
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
55548
|
throw new Error("Expected Sumi native permission rules");
|
|
55281
55549
|
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);
|
|
55550
|
+
const pluginPath = join28(sumiConfigDirectory(home, process.env, options.projectDir ?? process.cwd()), "plugins", "skills-cli.js"), pluginBefore = readOptional(pluginPath);
|
|
55283
55551
|
const pluginAfter = renderSumiPlugin(command, profileId2);
|
|
55284
55552
|
const priorCommand = policy.bridge?.commands?.sumi, priorProfile = policy.bridge?.profiles?.sumi ?? policy.profileId;
|
|
55285
55553
|
if (pluginBefore !== null && pluginBefore !== pluginAfter && !(typeof priorCommand === "string" && typeof priorProfile === "string" && isManagedSumiPlugin(pluginBefore, priorCommand, priorProfile)))
|
|
@@ -55370,7 +55638,7 @@ function projectedHookAcl(path, observed) {
|
|
|
55370
55638
|
if (process.platform !== "darwin")
|
|
55371
55639
|
return;
|
|
55372
55640
|
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,
|
|
55641
|
+
const fd = openSync12(path, constants14.O_RDONLY | constants14.O_NOFOLLOW | constants14.O_NONBLOCK | (observed.isDirectory() ? constants14.O_DIRECTORY : 0));
|
|
55374
55642
|
try {
|
|
55375
55643
|
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
55644
|
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
@@ -55380,7 +55648,7 @@ function projectedHookAcl(path, observed) {
|
|
|
55380
55648
|
}
|
|
55381
55649
|
function projectedHookExecutable(command, expectedResolved) {
|
|
55382
55650
|
try {
|
|
55383
|
-
if (!
|
|
55651
|
+
if (!isAbsolute18(command) || /[\0\r\n]/.test(command) || resolve17(command) !== command)
|
|
55384
55652
|
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
55385
55653
|
command = canonicalSystemPath(command);
|
|
55386
55654
|
const parents2 = (file = command) => {
|
|
@@ -55600,7 +55868,7 @@ function planAgentSettingsWitnessUpgrade(options) {
|
|
|
55600
55868
|
const binding = policy.bridge?.discovery?.[options.agent];
|
|
55601
55869
|
if (!binding || binding.agent !== options.agent || binding.method !== "reviewed")
|
|
55602
55870
|
throw new Error("Settings witness upgrade requires an existing reviewed native binding");
|
|
55603
|
-
const configPath = canonicalAgentPath(options.agent === "sumi" ?
|
|
55871
|
+
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
55872
|
const settings = readOptional(configPath);
|
|
55605
55873
|
if (settings === null || sha3(settings) !== options.expectedSettingsSha256)
|
|
55606
55874
|
throw new Error("Native settings preimage changed");
|
|
@@ -55778,7 +56046,7 @@ function applyAgentIntegrationUnlocked(plan, options = {}, assertCurrent) {
|
|
|
55778
56046
|
}
|
|
55779
56047
|
function syncArchiveDirectory(path) {
|
|
55780
56048
|
assertSafePath(path);
|
|
55781
|
-
const descriptor = openSync12(path,
|
|
56049
|
+
const descriptor = openSync12(path, constants14.O_RDONLY | constants14.O_DIRECTORY | constants14.O_NOFOLLOW | constants14.O_NONBLOCK);
|
|
55782
56050
|
try {
|
|
55783
56051
|
fsyncSync5(descriptor);
|
|
55784
56052
|
} finally {
|
|
@@ -55790,7 +56058,7 @@ function writeArchiveJournal(path, value) {
|
|
|
55790
56058
|
const temporary = `${path}.skills-${randomUUID6()}`;
|
|
55791
56059
|
let descriptor;
|
|
55792
56060
|
try {
|
|
55793
|
-
descriptor = openSync12(temporary,
|
|
56061
|
+
descriptor = openSync12(temporary, constants14.O_WRONLY | constants14.O_CREAT | constants14.O_EXCL | constants14.O_NOFOLLOW, 384);
|
|
55794
56062
|
writeFileSync6(descriptor, `${JSON.stringify(value)}
|
|
55795
56063
|
`);
|
|
55796
56064
|
fsyncSync5(descriptor);
|
|
@@ -55824,7 +56092,7 @@ function archiveNativeSkillsUnlocked(inventory, options, assertCurrent) {
|
|
|
55824
56092
|
recheckRootAliases(aliases);
|
|
55825
56093
|
for (const entry of inventory.filter((entry2) => entry2.bridge)) {
|
|
55826
56094
|
const adapter = AGENT_ADAPTERS[entry.agent];
|
|
55827
|
-
const expected = adapter && entry.bridgeHome ? canonicalAgentPath(join28(
|
|
56095
|
+
const expected = adapter && entry.bridgeHome ? canonicalAgentPath(join28(nativeAgentRoot(entry.bridgeHome, entry.agent), CLI_BRIDGE_NAME), aliases) : undefined;
|
|
55828
56096
|
if (!expected || treeHash(entry.path) !== entry.hash || !isOwnedCliBridge(entry.path, [expected]))
|
|
55829
56097
|
throw new Error(`Skills bridge changed after planning: ${entry.path}`);
|
|
55830
56098
|
}
|
|
@@ -55948,7 +56216,7 @@ function isInertCodexPluginCacheCopy(entry, cache3, allowedHostPaths, read2) {
|
|
|
55948
56216
|
return false;
|
|
55949
56217
|
const document3 = join28(entry.path, "SKILL.md");
|
|
55950
56218
|
const inside = relative6(cache3, entry.path);
|
|
55951
|
-
if (!inside ||
|
|
56219
|
+
if (!inside || isAbsolute18(inside) || inside.split(sep7).some((segment) => segment === ".."))
|
|
55952
56220
|
return false;
|
|
55953
56221
|
assertSafePath(entry.path);
|
|
55954
56222
|
if (!lstatSync21(cache3).isDirectory() || !lstatSync21(entry.path).isDirectory() || !lstatSync21(document3).isFile())
|
|
@@ -55980,14 +56248,14 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
|
|
|
55980
56248
|
if (!Array.isArray(aliases))
|
|
55981
56249
|
throw new Error("NATIVE_SKILL_DRIFT: invalid root alias binding");
|
|
55982
56250
|
recheckRootAliases(aliases);
|
|
55983
|
-
const expected = canonicalAgentPath(join28(
|
|
56251
|
+
const expected = canonicalAgentPath(join28(nativeAgentRoot(home, agent, options.projectDir ?? process.cwd()), CLI_BRIDGE_NAME), aliases);
|
|
55984
56252
|
if (!isOwnedCliBridge(expected, [expected]))
|
|
55985
56253
|
throw new Error("NATIVE_SKILL_DRIFT: the native Skills bridge is missing or modified; repair it before continuing");
|
|
55986
56254
|
const roots = projectAncestorDirectories([options.projectDir ?? process.cwd(), ...options.projectDirs ?? [], ...agent === "hermes" && process.env.TERMINAL_CWD ? [process.cwd()] : []]);
|
|
55987
56255
|
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
56256
|
const discovery = provenDiscovery ?? binding.discovery?.[agent];
|
|
55989
56257
|
assertProjectDiscovery(agent, [...roots], home, (path) => canonicalAgentPath(path, aliases), discovery);
|
|
55990
|
-
const configPath = canonicalAgentPath(
|
|
56258
|
+
const configPath = canonicalAgentPath(nativeAgentConfig(home, agent, options.projectDir ?? process.cwd()), aliases), config = agent === "hermes" ? parseHermesConfig(readOptional(configPath)) : jsonObject(readOptional(configPath), configPath);
|
|
55991
56259
|
const command = binding.commands?.[agent], profile = binding.profiles?.[agent];
|
|
55992
56260
|
if (typeof command !== "string" || typeof profile !== "string")
|
|
55993
56261
|
throw new Error("NATIVE_SKILL_DRIFT: the native hook command/profile binding is missing");
|
|
@@ -55999,7 +56267,7 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
|
|
|
55999
56267
|
throw new Error("NATIVE_SKILL_DRIFT: Hermes supervisor binding changed; run skills hook install");
|
|
56000
56268
|
assertHermesProtection(home, config, command, profile, supervisor);
|
|
56001
56269
|
} 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))
|
|
56270
|
+
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
56271
|
throw new Error("NATIVE_SKILL_DRIFT: Sumi bridge protection changed; run skills hook install");
|
|
56004
56272
|
} else if (agent === "opencode") {
|
|
56005
56273
|
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 +56373,7 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
|
|
|
56105
56373
|
return escaped.length > 768 ? `${escaped.slice(0, 384)}...${escaped.slice(-381)}` : escaped;
|
|
56106
56374
|
});
|
|
56107
56375
|
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}` : ""}`);
|
|
56376
|
+
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
56377
|
}
|
|
56110
56378
|
recheckRootAliases(aliases);
|
|
56111
56379
|
}
|
|
@@ -56170,7 +56438,7 @@ var init_agent_integration = __esm(() => {
|
|
|
56170
56438
|
});
|
|
56171
56439
|
|
|
56172
56440
|
// src/lib/home-migration.ts
|
|
56173
|
-
import { existsSync as existsSync14, mkdirSync as mkdirSync7, readdirSync as readdirSync9, renameSync as renameSync4, rmSync, statSync as
|
|
56441
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync7, readdirSync as readdirSync9, renameSync as renameSync4, rmSync, statSync as statSync11, writeFileSync as writeFileSync7 } from "fs";
|
|
56174
56442
|
import { join as join29 } from "path";
|
|
56175
56443
|
function layoutMigrationRecordPath(appDir) {
|
|
56176
56444
|
return join29(appDir, SKILLS_CACHE_DIRNAME, LAYOUT_MIGRATION_RECORD);
|
|
@@ -56183,7 +56451,7 @@ function migrationAppDir(homeDir2) {
|
|
|
56183
56451
|
}
|
|
56184
56452
|
function looksLikeSkillDirectory(path) {
|
|
56185
56453
|
try {
|
|
56186
|
-
if (!
|
|
56454
|
+
if (!statSync11(path).isDirectory())
|
|
56187
56455
|
return false;
|
|
56188
56456
|
} catch {
|
|
56189
56457
|
return false;
|
|
@@ -56315,7 +56583,7 @@ import {
|
|
|
56315
56583
|
readdirSync as readdirSync10,
|
|
56316
56584
|
renameSync as renameSync5,
|
|
56317
56585
|
rmSync as rmSync2,
|
|
56318
|
-
statSync as
|
|
56586
|
+
statSync as statSync12,
|
|
56319
56587
|
writeFileSync as writeFileSync8
|
|
56320
56588
|
} from "fs";
|
|
56321
56589
|
import { homedir as homedir4 } from "os";
|
|
@@ -56432,7 +56700,7 @@ function containsSkillDirectories(path) {
|
|
|
56432
56700
|
}
|
|
56433
56701
|
function isDirectory(path) {
|
|
56434
56702
|
try {
|
|
56435
|
-
return
|
|
56703
|
+
return statSync12(path).isDirectory();
|
|
56436
56704
|
} catch {
|
|
56437
56705
|
return false;
|
|
56438
56706
|
}
|
|
@@ -57962,8 +58230,8 @@ var init_plugin_projection = __esm(() => {
|
|
|
57962
58230
|
|
|
57963
58231
|
// src/lib/plugin-projection-store.ts
|
|
57964
58232
|
import { createHash as createHash22, randomUUID as randomUUID7 } from "crypto";
|
|
57965
|
-
import { constants as
|
|
57966
|
-
import { dirname as dirname18, isAbsolute as
|
|
58233
|
+
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";
|
|
58234
|
+
import { dirname as dirname18, isAbsolute as isAbsolute19, join as join34, parse as parse6, resolve as resolve18 } from "path";
|
|
57967
58235
|
function stat(path) {
|
|
57968
58236
|
try {
|
|
57969
58237
|
return lstatSync23(path, { bigint: true });
|
|
@@ -57974,7 +58242,7 @@ function stat(path) {
|
|
|
57974
58242
|
}
|
|
57975
58243
|
}
|
|
57976
58244
|
function canonical7(path) {
|
|
57977
|
-
pluginNeed(typeof path === "string" && path.length <= 8192 &&
|
|
58245
|
+
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
58246
|
}
|
|
57979
58247
|
function owner(stats, system = false) {
|
|
57980
58248
|
const current = uid();
|
|
@@ -58324,8 +58592,8 @@ function pluginExecutableDigest(path) {
|
|
|
58324
58592
|
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
58593
|
var init_plugin_projection_store = __esm(() => {
|
|
58326
58594
|
init_plugin_projection();
|
|
58327
|
-
READ_FLAGS =
|
|
58328
|
-
WRITE_FLAGS =
|
|
58595
|
+
READ_FLAGS = constants15.O_RDONLY | constants15.O_NOFOLLOW | constants15.O_NONBLOCK;
|
|
58596
|
+
WRITE_FLAGS = constants15.O_WRONLY | constants15.O_CREAT | constants15.O_EXCL | constants15.O_NOFOLLOW | constants15.O_NONBLOCK;
|
|
58329
58597
|
});
|
|
58330
58598
|
|
|
58331
58599
|
// src/lib/selected-manifest.ts
|
|
@@ -58356,7 +58624,7 @@ var init_selected_manifest = __esm(() => {
|
|
|
58356
58624
|
|
|
58357
58625
|
// src/lib/plugin-admission.ts
|
|
58358
58626
|
import { homedir as homedir6 } from "os";
|
|
58359
|
-
import { isAbsolute as
|
|
58627
|
+
import { isAbsolute as isAbsolute20, join as join35, resolve as resolve19 } from "path";
|
|
58360
58628
|
function pluginAdmissionRoot() {
|
|
58361
58629
|
return join35(homedir6(), ".hasna", "skills", "plugin-admission");
|
|
58362
58630
|
}
|
|
@@ -58369,7 +58637,7 @@ function validatePluginTarget(value) {
|
|
|
58369
58637
|
for (const registration of value.registrations) {
|
|
58370
58638
|
pluginKeys(registration, ["scope", "projectPath"]);
|
|
58371
58639
|
pluginNeed(registration.scope === "user" || registration.scope === "project", "Unsupported plugin registration scope");
|
|
58372
|
-
pluginNeed(registration.scope === "user" ? registration.projectPath === null : typeof registration.projectPath === "string" &&
|
|
58640
|
+
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
58641
|
const key = JSON.stringify([registration.scope, registration.projectPath]);
|
|
58374
58642
|
pluginNeed(!scopes.has(key), "Duplicate plugin registration scope");
|
|
58375
58643
|
scopes.add(key);
|
|
@@ -58377,7 +58645,7 @@ function validatePluginTarget(value) {
|
|
|
58377
58645
|
for (const key of ["native", "resolver"]) {
|
|
58378
58646
|
pluginKeys(value[key], key === "native" ? ["version", "executable", "digest"] : ["executable", "digest"]);
|
|
58379
58647
|
pluginText(value[key].executable);
|
|
58380
|
-
pluginNeed(
|
|
58648
|
+
pluginNeed(isAbsolute20(value[key].executable) && resolve19(value[key].executable) === value[key].executable, "Plugin executable must have a canonical absolute path");
|
|
58381
58649
|
pluginDigest(value[key].digest);
|
|
58382
58650
|
}
|
|
58383
58651
|
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 +58795,7 @@ function pluginResolverCommand(binding) {
|
|
|
58527
58795
|
}
|
|
58528
58796
|
function root(options) {
|
|
58529
58797
|
const path = options.storeRoot ?? pluginAdmissionRoot();
|
|
58530
|
-
pluginNeed(
|
|
58798
|
+
pluginNeed(isAbsolute20(path) && resolve19(path) === path, "Invalid plugin admission store root");
|
|
58531
58799
|
return path;
|
|
58532
58800
|
}
|
|
58533
58801
|
function pluginBindingPath(storeRoot, id) {
|
|
@@ -58734,8 +59002,8 @@ var init_plugin_admission = __esm(() => {
|
|
|
58734
59002
|
});
|
|
58735
59003
|
|
|
58736
59004
|
// src/lib/plugin-discovery.ts
|
|
58737
|
-
import { closeSync as closeSync14, constants as
|
|
58738
|
-
import { basename as basename10, dirname as dirname19, isAbsolute as
|
|
59005
|
+
import { closeSync as closeSync14, constants as constants16, fstatSync as fstatSync14, lstatSync as lstatSync24, openSync as openSync14, opendirSync as opendirSync5, readSync as readSync11 } from "fs";
|
|
59006
|
+
import { basename as basename10, dirname as dirname19, isAbsolute as isAbsolute21, join as join36, resolve as resolve20 } from "path";
|
|
58739
59007
|
function validateManagedPluginWitnesses(value) {
|
|
58740
59008
|
pluginNeed(Array.isArray(value) && value.length > 0 && value.length <= PLUGIN_PROJECTION_LIMITS.registrations, "Invalid managed plugin witness collection");
|
|
58741
59009
|
const seen = new Set;
|
|
@@ -58744,12 +59012,12 @@ function validateManagedPluginWitnesses(value) {
|
|
|
58744
59012
|
pluginNeed(typeof item.bindingId === "string" && /^[a-f0-9]{64}$/.test(item.bindingId) && !seen.has(item.bindingId), "Invalid or duplicate managed plugin witness");
|
|
58745
59013
|
seen.add(item.bindingId);
|
|
58746
59014
|
pluginText(item.storeRoot);
|
|
58747
|
-
pluginNeed(
|
|
59015
|
+
pluginNeed(isAbsolute21(item.storeRoot) && resolve20(item.storeRoot) === item.storeRoot, "Invalid plugin receipt store path");
|
|
58748
59016
|
}
|
|
58749
59017
|
}
|
|
58750
59018
|
function safe3(path) {
|
|
58751
59019
|
pluginText(path);
|
|
58752
|
-
pluginNeed(
|
|
59020
|
+
pluginNeed(isAbsolute21(path) && resolve20(path) === path, "Invalid plugin registry path");
|
|
58753
59021
|
for (let at2 = path;; at2 = dirname19(at2)) {
|
|
58754
59022
|
pluginNeed(!lstatSync24(at2, { throwIfNoEntry: false })?.isSymbolicLink(), "Plugin registry path traverses a symlink");
|
|
58755
59023
|
if (at2 === dirname19(at2))
|
|
@@ -58760,7 +59028,7 @@ function readRegistry(path) {
|
|
|
58760
59028
|
safe3(path);
|
|
58761
59029
|
const initial2 = lstatSync24(path);
|
|
58762
59030
|
pluginNeed(initial2.isFile() && initial2.size <= 1024 * 1024, "Plugin registry is not a bounded regular file");
|
|
58763
|
-
const fd = openSync14(path,
|
|
59031
|
+
const fd = openSync14(path, constants16.O_RDONLY | constants16.O_NOFOLLOW | constants16.O_NONBLOCK);
|
|
58764
59032
|
try {
|
|
58765
59033
|
const opened = fstatSync14(fd);
|
|
58766
59034
|
pluginNeed(opened.isFile() && opened.ino === initial2.ino && opened.dev === initial2.dev, "Plugin registry changed during open");
|
|
@@ -58886,14 +59154,14 @@ var init_plugin_discovery = __esm(() => {
|
|
|
58886
59154
|
|
|
58887
59155
|
// src/lib/claude-marketplace-registry.ts
|
|
58888
59156
|
import { createHash as createHash23 } from "crypto";
|
|
58889
|
-
import { closeSync as closeSync15, constants as
|
|
58890
|
-
import { basename as basename11, dirname as dirname20, isAbsolute as
|
|
59157
|
+
import { closeSync as closeSync15, constants as constants17, fstatSync as fstatSync15, lstatSync as lstatSync25, openSync as openSync15, readSync as readSync12 } from "fs";
|
|
59158
|
+
import { basename as basename11, dirname as dirname20, isAbsolute as isAbsolute22, resolve as resolve21 } from "path";
|
|
58891
59159
|
function need7(value, reason2) {
|
|
58892
59160
|
if (!value)
|
|
58893
59161
|
throw new Error(`Claude marketplace registry ${reason2}`);
|
|
58894
59162
|
}
|
|
58895
|
-
function
|
|
58896
|
-
need7(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) &&
|
|
59163
|
+
function absolutePath4(value) {
|
|
59164
|
+
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
59165
|
}
|
|
58898
59166
|
function parents2(path) {
|
|
58899
59167
|
const result2 = [];
|
|
@@ -58906,13 +59174,13 @@ function parents2(path) {
|
|
|
58906
59174
|
}
|
|
58907
59175
|
}
|
|
58908
59176
|
function readRegistry2(path, budget2) {
|
|
58909
|
-
|
|
59177
|
+
absolutePath4(path);
|
|
58910
59178
|
need7(basename11(path) === "known_marketplaces.json", "requires known_marketplaces.json");
|
|
58911
59179
|
need7(Number.isSafeInteger(budget2.remaining) && budget2.remaining >= 0, "has an invalid byte budget");
|
|
58912
59180
|
const ancestors2 = parents2(path), initial2 = lstatSync25(path, { bigint: true });
|
|
58913
59181
|
need7(initial2.isFile() && !initial2.isSymbolicLink() && initial2.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
|
|
58914
59182
|
need7(initial2.size <= BigInt(budget2.remaining), "exceeds its aggregate byte limit");
|
|
58915
|
-
const fd = openSync15(path,
|
|
59183
|
+
const fd = openSync15(path, constants17.O_RDONLY | constants17.O_NOFOLLOW | constants17.O_NONBLOCK);
|
|
58916
59184
|
try {
|
|
58917
59185
|
const opened = fstatSync15(fd, { bigint: true });
|
|
58918
59186
|
need7(opened.isFile() && sameFile2(initial2, opened), "changed during open");
|
|
@@ -59039,8 +59307,8 @@ function normalizeRow(row, version = 1) {
|
|
|
59039
59307
|
return;
|
|
59040
59308
|
const sourceLocation = textField(field2(source, location));
|
|
59041
59309
|
if (type.value === "directory")
|
|
59042
|
-
|
|
59043
|
-
|
|
59310
|
+
absolutePath4(sourceLocation);
|
|
59311
|
+
absolutePath4(textField(field2(row, "installLocation")));
|
|
59044
59312
|
const updated = textField(field2(row, "lastUpdated"));
|
|
59045
59313
|
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
59314
|
const millis = Date.parse(updated);
|
|
@@ -59201,7 +59469,7 @@ var fail3 = () => new Error('CODEX_HOOK_TRUST_UNSUPPORTED_LAYOUT: preserve and c
|
|
|
59201
59469
|
var init_codex_hook_trust_layout = () => {};
|
|
59202
59470
|
|
|
59203
59471
|
// src/lib/codex-hook-additions-review.ts
|
|
59204
|
-
import { isAbsolute as
|
|
59472
|
+
import { isAbsolute as isAbsolute23 } from "path";
|
|
59205
59473
|
import { isDeepStrictEqual as isDeepStrictEqual9 } from "util";
|
|
59206
59474
|
function exactKeys2(value, keys2) {
|
|
59207
59475
|
need6(value && typeof value === "object" && !Array.isArray(value) && isDeepStrictEqual9(Object.keys(value).sort(), [...keys2].sort()), "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
|
|
@@ -59215,7 +59483,7 @@ function readReviewedAdditionTrustStates(proof, before2, current, journalHooks)
|
|
|
59215
59483
|
return captured.states;
|
|
59216
59484
|
}
|
|
59217
59485
|
function reviewNativeHookAdditions(options) {
|
|
59218
|
-
need6(
|
|
59486
|
+
need6(isAbsolute23(options.path), "RECONCILE_ADDITIONS_REVIEW_PATH");
|
|
59219
59487
|
const reviewFile = snapshot(options.path, true), review = JSON.parse(reviewFile.text);
|
|
59220
59488
|
exactKeys2(review, ["version", "kind", "reason", "producerEvidence", "journalIntentSha256", "policySha256", "configCurrentSha256", "hooksCurrentSha256", "producerBefore", "additions"]);
|
|
59221
59489
|
need6((review.version === 1 || review.version === 2) && review.kind === "native-hook-additions" && text2(review.reason) && text2(review.producerEvidence), "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
|
|
@@ -59223,7 +59491,7 @@ function reviewNativeHookAdditions(options) {
|
|
|
59223
59491
|
need6(hash2(review[name]) && review[name] === expected, "RECONCILE_ADDITIONS_REVIEW_CHANGED");
|
|
59224
59492
|
exactKeys2(review.producerBefore, ["configPath", "configSha256", "hooksPath", "hooksSha256"]);
|
|
59225
59493
|
const before2 = review.producerBefore;
|
|
59226
|
-
need6(
|
|
59494
|
+
need6(isAbsolute23(before2.configPath) && isAbsolute23(before2.hooksPath) && hash2(before2.configSha256) && hash2(before2.hooksSha256), "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
|
|
59227
59495
|
const producerConfig = snapshot(before2.configPath, true), producerHooks = snapshot(before2.hooksPath, true);
|
|
59228
59496
|
need6(producerConfig.sha256 === before2.configSha256 && producerHooks.sha256 === before2.hooksSha256 && producerHooks.sha256 === options.hooksBefore.sha256, "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
|
|
59229
59497
|
const original = structure(options.configBefore.text), producer = structure(producerConfig.text), expectedProducer = structuredClone(original), originalKeys = options.journalHooks.map((hook) => hook.key);
|
|
@@ -59316,13 +59584,13 @@ function createCodexHookDiscoveryRecovery(binding, before2, current, hooks, addi
|
|
|
59316
59584
|
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
59585
|
unchanged2(before2);
|
|
59318
59586
|
unchanged2(current);
|
|
59319
|
-
const witness = Object.freeze({ configPath: current.file, beforeSha256: before2.sha256, currentSha256: current.sha256, discoverySha256:
|
|
59587
|
+
const witness = Object.freeze({ configPath: current.file, beforeSha256: before2.sha256, currentSha256: current.sha256, discoverySha256: discoveryDigest(binding), typedProjectionSha256: projection });
|
|
59320
59588
|
proofs2.set(witness, { before: before2, current, recheckAdditions });
|
|
59321
59589
|
return witness;
|
|
59322
59590
|
}
|
|
59323
59591
|
function assertCodexHookDiscoveryRecovery(binding, witness) {
|
|
59324
59592
|
const proof = proofs2.get(witness);
|
|
59325
|
-
need6(!!proof && binding.agent === "codex" && witness.discoverySha256 ===
|
|
59593
|
+
need6(!!proof && binding.agent === "codex" && witness.discoverySha256 === discoveryDigest(binding), "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
|
|
59326
59594
|
unchanged2(proof.before);
|
|
59327
59595
|
unchanged2(proof.current);
|
|
59328
59596
|
proof.recheckAdditions();
|
|
@@ -59334,7 +59602,14 @@ function verifiesCodexHookDiscoverySource(binding, source, currentDigest, witnes
|
|
|
59334
59602
|
need6(source.sha256 === witness.beforeSha256 && currentDigest === witness.currentSha256, "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
|
|
59335
59603
|
return true;
|
|
59336
59604
|
}
|
|
59337
|
-
var sha4 = (text3) => createHash24("sha256").update(text3).digest("hex"), fields, structure2 = (text3) => JSON.parse(JSON.stringify(Bun.TOML.parse(text3))),
|
|
59605
|
+
var sha4 = (text3) => createHash24("sha256").update(text3).digest("hex"), fields, structure2 = (text3) => JSON.parse(JSON.stringify(Bun.TOML.parse(text3))), discoveryDigest = (binding) => {
|
|
59606
|
+
const controls = binding.codexDisabledPluginSkills;
|
|
59607
|
+
if (!Object.hasOwn(binding, "codexDisabledPluginSkills") || Array.isArray(controls) && controls.length === 0) {
|
|
59608
|
+
const { codexDisabledPluginSkills: _controls, ...withoutControls } = binding;
|
|
59609
|
+
return sha4(JSON.stringify({ ...withoutControls, codexDisabledPluginSkills: [] }));
|
|
59610
|
+
}
|
|
59611
|
+
return sha4(JSON.stringify(binding));
|
|
59612
|
+
}, proofs2;
|
|
59338
59613
|
var init_codex_hook_discovery_recovery = __esm(() => {
|
|
59339
59614
|
init_codex_hook_trust_files();
|
|
59340
59615
|
init_codex_hook_trust_layout();
|
|
@@ -59347,7 +59622,7 @@ var init_codex_hook_discovery_recovery = __esm(() => {
|
|
|
59347
59622
|
// src/lib/agent-discovery.ts
|
|
59348
59623
|
import { createHash as createHash25 } from "crypto";
|
|
59349
59624
|
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
|
|
59625
|
+
import { basename as basename12, dirname as dirname21, isAbsolute as isAbsolute24, join as join37, resolve as resolve22, sep as sep8 } from "path";
|
|
59351
59626
|
import { isDeepStrictEqual as isDeepStrictEqual11 } from "util";
|
|
59352
59627
|
function discoveryRootUnresolved(agent, command, detail) {
|
|
59353
59628
|
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 +59656,7 @@ function parseConfig(text3, path, toml = false) {
|
|
|
59381
59656
|
}
|
|
59382
59657
|
}
|
|
59383
59658
|
function safe4(path) {
|
|
59384
|
-
if (!
|
|
59659
|
+
if (!isAbsolute24(path) || path.includes("\x00"))
|
|
59385
59660
|
throw new Error("Expected an absolute native discovery path");
|
|
59386
59661
|
for (let cursor = path;; cursor = dirname21(cursor)) {
|
|
59387
59662
|
if (lstatSync26(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
@@ -59401,19 +59676,20 @@ function read2(path, changes) {
|
|
|
59401
59676
|
throw new Error(`Unsupported or oversized native discovery input: ${path}`);
|
|
59402
59677
|
return readFileSync21(path, "utf8");
|
|
59403
59678
|
}
|
|
59404
|
-
function assertReviewedClaudeCacheClosures(home, config, review) {
|
|
59679
|
+
function assertReviewedClaudeCacheClosures(home, config, review, canonical8) {
|
|
59405
59680
|
const enabledIds = Object.entries(config.enabledPlugins ?? {}).filter(([, enabled]) => enabled === true).map(([id]) => id);
|
|
59406
59681
|
if (enabledIds.length === 0)
|
|
59407
59682
|
return;
|
|
59408
|
-
const registryPath = join37(home, ".claude/plugins/installed_plugins.json");
|
|
59409
|
-
const
|
|
59683
|
+
const registryPath = canonical8(join37(home, ".claude/plugins/installed_plugins.json"));
|
|
59684
|
+
const cacheAliasRoot = join37(home, ".claude/plugins/cache");
|
|
59685
|
+
const cacheRoot = canonical8(cacheAliasRoot);
|
|
59410
59686
|
const registryText = read2(registryPath);
|
|
59411
59687
|
if (registryText === null)
|
|
59412
59688
|
return;
|
|
59413
59689
|
const registry = parseConfig(registryText, registryPath);
|
|
59414
59690
|
if (registry.version !== 2 || !registry.plugins || typeof registry.plugins !== "object" || Array.isArray(registry.plugins))
|
|
59415
59691
|
throw new Error("Reviewed Claude installed plugin registrations are invalid");
|
|
59416
|
-
const cachePath = (path) => typeof path === "string" &&
|
|
59692
|
+
const cachePath = (path) => typeof path === "string" && isAbsolute24(path) && resolve22(path) === path && [cacheAliasRoot, cacheRoot].some((root2) => path === root2 || path.startsWith(root2 + sep8));
|
|
59417
59693
|
const activeRoots = new Set;
|
|
59418
59694
|
for (const id of enabledIds) {
|
|
59419
59695
|
const rows = registry.plugins[id];
|
|
@@ -59425,13 +59701,13 @@ function assertReviewedClaudeCacheClosures(home, config, review) {
|
|
|
59425
59701
|
if (!row || typeof row !== "object" || Array.isArray(row) || typeof row.installPath !== "string") {
|
|
59426
59702
|
throw new Error("Reviewed Claude enabled plugin registration requires an object with an installPath string");
|
|
59427
59703
|
}
|
|
59428
|
-
if (
|
|
59704
|
+
if ([cacheAliasRoot, cacheRoot].some((root2) => row.installPath === root2 || row.installPath.startsWith(root2 + sep8))) {
|
|
59429
59705
|
if (!cachePath(row.installPath) || row.installPath.length > AGENT_POLICY_LIMITS.pathCharacters || row.version !== undefined && (typeof row.version !== "string" || basename12(row.installPath) !== row.version)) {
|
|
59430
59706
|
throw new Error("Reviewed Claude discovery has a malformed active cache registration");
|
|
59431
59707
|
}
|
|
59432
|
-
if (row.scope === "user" && (row.projectPath === undefined || row.projectPath === null)) {} else if (row.scope === "project" && typeof row.projectPath === "string" &&
|
|
59708
|
+
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
59709
|
throw new Error("Reviewed Claude discovery has an unsupported active cache registration scope");
|
|
59434
|
-
activeRoots.add(row.installPath);
|
|
59710
|
+
activeRoots.add(canonical8(row.installPath));
|
|
59435
59711
|
}
|
|
59436
59712
|
}
|
|
59437
59713
|
}
|
|
@@ -59676,12 +59952,12 @@ function absentRetiredClaudeRoots(binding) {
|
|
|
59676
59952
|
if (!row || typeof row !== "object" || Array.isArray(row))
|
|
59677
59953
|
return null;
|
|
59678
59954
|
const value = row;
|
|
59679
|
-
if (typeof value.installPath !== "string" || /[\x00-\x1f\x7f]/.test(value.installPath) || !
|
|
59955
|
+
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
59956
|
return null;
|
|
59681
59957
|
if (value.scope === "user")
|
|
59682
59958
|
return value.projectPath === undefined || value.projectPath === null ? "user\x00" : null;
|
|
59683
59959
|
if (value.scope === "project")
|
|
59684
|
-
return typeof value.projectPath === "string" && !/[\x00-\x1f\x7f]/.test(value.projectPath) && value.projectPath.length <= AGENT_POLICY_LIMITS.pathCharacters &&
|
|
59960
|
+
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
59961
|
return null;
|
|
59686
59962
|
};
|
|
59687
59963
|
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 +60221,7 @@ function resolveAgentDiscovery(options) {
|
|
|
59945
60221
|
if (config.skills !== undefined && (!Array.isArray(config.skills) || config.skills.some((path) => typeof path !== "string")))
|
|
59946
60222
|
unresolved("skills must be a string array");
|
|
59947
60223
|
for (const value of config.skills ?? []) {
|
|
59948
|
-
if (typeof value !== "string" || /[\0$]/.test(value) || !value || !(
|
|
60224
|
+
if (typeof value !== "string" || /[\0$]/.test(value) || !value || !(isAbsolute24(value) || value.startsWith("~/")))
|
|
59949
60225
|
unresolved("remote or relative skill sources need a dedicated discovery adapter");
|
|
59950
60226
|
roots.add(canonical8(value.startsWith("~/") ? join37(home, value.slice(2)) : value));
|
|
59951
60227
|
}
|
|
@@ -60075,7 +60351,7 @@ function resolveAgentDiscovery(options) {
|
|
|
60075
60351
|
return { path: source.path, sha256: manifestSha256, hashMode: "claude-plugin-manifest-v1" };
|
|
60076
60352
|
});
|
|
60077
60353
|
if (agent === "claude")
|
|
60078
|
-
assertReviewedClaudeCacheClosures(home, config, review);
|
|
60354
|
+
assertReviewedClaudeCacheClosures(home, config, review, canonical8);
|
|
60079
60355
|
const combined = [...reviewedSources, ...reviewedSourcesWithManifestProjection];
|
|
60080
60356
|
const unique = combined.filter((source, index) => combined.findIndex((candidate2) => isDeepStrictEqual11(candidate2, source)) === index);
|
|
60081
60357
|
return { ...supplied, roots: [...new Set([...roots, ...supplied.roots])].sort(), sources: unique, ...agent === "gemini" ? { builtinNames } : {} };
|
|
@@ -60135,7 +60411,7 @@ function resolveAgentDiscovery(options) {
|
|
|
60135
60411
|
unresolved("unsupported plugin enablement");
|
|
60136
60412
|
const split2 = id.lastIndexOf("@"), name = id.slice(0, split2), marketplace = id.slice(split2 + 1);
|
|
60137
60413
|
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" || !
|
|
60414
|
+
if (split2 < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !isAbsolute24(market.source))
|
|
60139
60415
|
unresolved("enabled plugin marketplace is not an explicit local source");
|
|
60140
60416
|
const catalogText = witness(join37(market.source, ".agents/plugins/marketplace.json"));
|
|
60141
60417
|
if (catalogText === null)
|
|
@@ -60151,7 +60427,7 @@ function resolveAgentDiscovery(options) {
|
|
|
60151
60427
|
if ((config.plugin?.length ?? 0) > 0 || config.skills?.urls?.length)
|
|
60152
60428
|
unresolved("external plugin or remote skill source");
|
|
60153
60429
|
for (const path of config.skills?.paths ?? []) {
|
|
60154
|
-
if (typeof path !== "string" || !
|
|
60430
|
+
if (typeof path !== "string" || !isAbsolute24(path))
|
|
60155
60431
|
unresolved("relative or malformed added skill root");
|
|
60156
60432
|
roots.add(path);
|
|
60157
60433
|
}
|
|
@@ -60336,10 +60612,10 @@ import {
|
|
|
60336
60612
|
realpathSync as realpathSync13,
|
|
60337
60613
|
renameSync as renameSync7,
|
|
60338
60614
|
rmSync as rmSync5,
|
|
60339
|
-
statSync as
|
|
60615
|
+
statSync as statSync13,
|
|
60340
60616
|
writeFileSync as writeFileSync10
|
|
60341
60617
|
} from "fs";
|
|
60342
|
-
import { basename as basename14, dirname as dirname23, isAbsolute as
|
|
60618
|
+
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
60619
|
function getPortableSkillsRoot(options = {}) {
|
|
60344
60620
|
return resolvePortableSkillsRoot(options, true);
|
|
60345
60621
|
}
|
|
@@ -60367,7 +60643,7 @@ function findPortableSkill(name, options = {}) {
|
|
|
60367
60643
|
return null;
|
|
60368
60644
|
}
|
|
60369
60645
|
const path = getPortableSkillPath(normalized, options);
|
|
60370
|
-
if (!existsSync19(path) || !
|
|
60646
|
+
if (!existsSync19(path) || !statSync13(path).isDirectory())
|
|
60371
60647
|
return null;
|
|
60372
60648
|
try {
|
|
60373
60649
|
return summarizePortableSkill(path, normalized);
|
|
@@ -60438,7 +60714,7 @@ function scaffoldPortableSkill(name, options = {}) {
|
|
|
60438
60714
|
}
|
|
60439
60715
|
function portPortableSkillDirectory(sourceDir, options = {}) {
|
|
60440
60716
|
const absoluteSource = normalize4(sourceDir);
|
|
60441
|
-
if (!existsSync19(absoluteSource) || !
|
|
60717
|
+
if (!existsSync19(absoluteSource) || !statSync13(absoluteSource).isDirectory()) {
|
|
60442
60718
|
throw new Error(`Import directory not found: ${sourceDir}`);
|
|
60443
60719
|
}
|
|
60444
60720
|
const continueOnError = options.continueOnError ?? true;
|
|
@@ -60497,7 +60773,7 @@ function assertDisjointImportPaths(source, destination) {
|
|
|
60497
60773
|
const destinationPath = physicalImportPath(destination);
|
|
60498
60774
|
const contains2 = (parent, child2) => {
|
|
60499
60775
|
const path = relative7(parent, child2);
|
|
60500
|
-
return path === "" || !
|
|
60776
|
+
return path === "" || !isAbsolute25(path) && path !== ".." && !path.startsWith(`..${sep10}`);
|
|
60501
60777
|
};
|
|
60502
60778
|
if (contains2(sourcePath, destinationPath) || contains2(destinationPath, sourcePath)) {
|
|
60503
60779
|
throw new Error("Source and destination skill directories must not overlap");
|
|
@@ -60505,7 +60781,7 @@ function assertDisjointImportPaths(source, destination) {
|
|
|
60505
60781
|
}
|
|
60506
60782
|
function portPortableSkill(sourcePath, options = {}) {
|
|
60507
60783
|
const absoluteSource = normalize4(sourcePath);
|
|
60508
|
-
if (!existsSync19(absoluteSource) || !
|
|
60784
|
+
if (!existsSync19(absoluteSource) || !statSync13(absoluteSource).isDirectory()) {
|
|
60509
60785
|
throw new Error(`Skill source directory not found: ${sourcePath}`);
|
|
60510
60786
|
}
|
|
60511
60787
|
const inferred = readPortableSkillManifestForImport(absoluteSource);
|
|
@@ -60668,7 +60944,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
60668
60944
|
const entryPath = join39(skillPath, command.entry);
|
|
60669
60945
|
if (!existsSync19(entryPath))
|
|
60670
60946
|
add4(issues, "portable.command_entry_missing", `Command '${command.name}' entry '${command.entry}' is missing`);
|
|
60671
|
-
else if (
|
|
60947
|
+
else if (statSync13(entryPath).isDirectory())
|
|
60672
60948
|
add4(issues, "portable.command_entry_directory", `Command '${command.name}' entry '${command.entry}' must be a file`);
|
|
60673
60949
|
}
|
|
60674
60950
|
}
|
|
@@ -60708,13 +60984,13 @@ function summarizePortableSkill(skillPath, fallbackName) {
|
|
|
60708
60984
|
}
|
|
60709
60985
|
function safeIsDirectory(path) {
|
|
60710
60986
|
try {
|
|
60711
|
-
return
|
|
60987
|
+
return statSync13(path).isDirectory();
|
|
60712
60988
|
} catch {
|
|
60713
60989
|
return false;
|
|
60714
60990
|
}
|
|
60715
60991
|
}
|
|
60716
60992
|
function isSafeRelativePath2(value) {
|
|
60717
|
-
if (!value.trim() ||
|
|
60993
|
+
if (!value.trim() || isAbsolute25(value))
|
|
60718
60994
|
return false;
|
|
60719
60995
|
const normalized = normalize4(value).replace(/\\/g, "/");
|
|
60720
60996
|
return normalized !== ".." && !normalized.startsWith("../") && !normalized.includes("/../");
|
|
@@ -62721,7 +62997,7 @@ var require_cli_spinners = __commonJS((exports, module) => {
|
|
|
62721
62997
|
});
|
|
62722
62998
|
|
|
62723
62999
|
// src/lib/auth-store.ts
|
|
62724
|
-
import { chmodSync as chmodSync2, existsSync as existsSync21, mkdirSync as mkdirSync12, readFileSync as readFileSync25, renameSync as renameSync8, statSync as
|
|
63000
|
+
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
63001
|
import { basename as basename15, dirname as dirname24, join as join41 } from "path";
|
|
62726
63002
|
function getAuthFilePath(env3 = process.env) {
|
|
62727
63003
|
return skillsCredentialFilePath(env3);
|
|
@@ -62935,7 +63211,7 @@ function getApiUrl(action, env3 = process.env, options = {}) {
|
|
|
62935
63211
|
}
|
|
62936
63212
|
function credentialFileMode(env3 = process.env) {
|
|
62937
63213
|
try {
|
|
62938
|
-
return
|
|
63214
|
+
return statSync14(skillsCredentialFilePath(env3)).mode & 511;
|
|
62939
63215
|
} catch {
|
|
62940
63216
|
return null;
|
|
62941
63217
|
}
|
|
@@ -65168,8 +65444,8 @@ var cuid, cuid2, ulid, xid, ksuid, nanoid, duration, extendedDuration, guid, uui
|
|
|
65168
65444
|
if (!version)
|
|
65169
65445
|
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
65446
|
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(
|
|
65447
|
+
}, uuid42, uuid6, uuid7, email2, html5Email, rfc5322Email, unicodeEmail, idnEmail, browserEmail, _emoji = `^[\\p{Extended_Pictographic}\\p{Emoji_Component}]+$`, ipv4, ipv6, mac = (delimiter3) => {
|
|
65448
|
+
const escapedDelim = escapeRegex(delimiter3 ?? ":");
|
|
65173
65449
|
return new RegExp(`^(?:[0-9A-F]{2}${escapedDelim}){5}[0-9A-F]{2}$|^(?:[0-9a-f]{2}${escapedDelim}){5}[0-9a-f]{2}$`);
|
|
65174
65450
|
}, 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
65451
|
const regex2 = params ? `[\\s\\S]{${params?.minimum ?? 0},${params?.maximum ?? ""}}` : `[\\s\\S]*`;
|
|
@@ -88469,7 +88745,7 @@ var init_init = __esm(() => {
|
|
|
88469
88745
|
});
|
|
88470
88746
|
|
|
88471
88747
|
// src/lib/home-adoption.ts
|
|
88472
|
-
import { constants as
|
|
88748
|
+
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
88749
|
import { homedir as homedir8 } from "os";
|
|
88474
88750
|
import { join as join47 } from "path";
|
|
88475
88751
|
function indexCanonicalCorpus(corpusRoot) {
|
|
@@ -88505,7 +88781,7 @@ function selectedHomeNames(options, index, homeDir2, agents) {
|
|
|
88505
88781
|
continue;
|
|
88506
88782
|
const present = agents.some((agent) => {
|
|
88507
88783
|
try {
|
|
88508
|
-
return
|
|
88784
|
+
return statSync15(join47(agentGlobalSkillsDir(agent, homeDir2), name)).isDirectory();
|
|
88509
88785
|
} catch {
|
|
88510
88786
|
return false;
|
|
88511
88787
|
}
|
|
@@ -88539,7 +88815,7 @@ function scanUnmarkedHomes(options = {}) {
|
|
|
88539
88815
|
continue;
|
|
88540
88816
|
const dir = join47(home, skill);
|
|
88541
88817
|
try {
|
|
88542
|
-
if (!
|
|
88818
|
+
if (!statSync15(dir).isDirectory())
|
|
88543
88819
|
continue;
|
|
88544
88820
|
} catch {
|
|
88545
88821
|
continue;
|
|
@@ -88552,7 +88828,7 @@ function scanUnmarkedHomes(options = {}) {
|
|
|
88552
88828
|
if (!existsSync25(skillMdPath))
|
|
88553
88829
|
continue;
|
|
88554
88830
|
const hash5 = hashSkillMarkdownFile(skillMdPath);
|
|
88555
|
-
const mtime =
|
|
88831
|
+
const mtime = statSync15(skillMdPath).mtime.toISOString();
|
|
88556
88832
|
const entry = { agent, skill, home, path: dir, hash: hash5, mtime };
|
|
88557
88833
|
const canonicalHash = index.get(skill);
|
|
88558
88834
|
if (canonicalHash === undefined) {
|
|
@@ -88647,7 +88923,7 @@ function pruneOwnership(dir) {
|
|
|
88647
88923
|
const markerPath = join47(dir, SYNC_MARKER_FILE), markerPathBefore = lstatSync28(markerPath);
|
|
88648
88924
|
if (!markerPathBefore.isFile())
|
|
88649
88925
|
return;
|
|
88650
|
-
descriptor = openSync16(markerPath,
|
|
88926
|
+
descriptor = openSync16(markerPath, constants18.O_RDONLY | constants18.O_NOFOLLOW | constants18.O_NONBLOCK);
|
|
88651
88927
|
const before2 = fstatSync16(descriptor);
|
|
88652
88928
|
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
88929
|
return;
|
|
@@ -88698,7 +88974,7 @@ function pruneStrayHomes(options = {}) {
|
|
|
88698
88974
|
continue;
|
|
88699
88975
|
const dir = join47(home, skill);
|
|
88700
88976
|
try {
|
|
88701
|
-
if (!
|
|
88977
|
+
if (!statSync15(dir).isDirectory())
|
|
88702
88978
|
continue;
|
|
88703
88979
|
} catch {
|
|
88704
88980
|
continue;
|
|
@@ -88756,7 +89032,7 @@ var init_home_adoption = __esm(() => {
|
|
|
88756
89032
|
});
|
|
88757
89033
|
|
|
88758
89034
|
// src/lib/home-census.ts
|
|
88759
|
-
import { existsSync as existsSync26, readFileSync as readFileSync31, readdirSync as readdirSync16, statSync as
|
|
89035
|
+
import { existsSync as existsSync26, readFileSync as readFileSync31, readdirSync as readdirSync16, statSync as statSync16 } from "fs";
|
|
88760
89036
|
import { homedir as homedir9 } from "os";
|
|
88761
89037
|
import { join as join48 } from "path";
|
|
88762
89038
|
function sortEntries(entries) {
|
|
@@ -88801,7 +89077,7 @@ function censusHomeDrift(options = {}) {
|
|
|
88801
89077
|
continue;
|
|
88802
89078
|
const dir = join48(home, skill);
|
|
88803
89079
|
try {
|
|
88804
|
-
if (!
|
|
89080
|
+
if (!statSync16(dir).isDirectory())
|
|
88805
89081
|
continue;
|
|
88806
89082
|
} catch {
|
|
88807
89083
|
continue;
|
|
@@ -88872,13 +89148,13 @@ var init_home_census = __esm(() => {
|
|
|
88872
89148
|
});
|
|
88873
89149
|
|
|
88874
89150
|
// src/cli/env-assignment.ts
|
|
88875
|
-
import { closeSync as closeSync17, constants as
|
|
89151
|
+
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
89152
|
function serializeValue(value) {
|
|
88877
89153
|
if (controls.test(value))
|
|
88878
89154
|
throw new EnvAssignmentError("Environment values cannot contain control characters or newlines.");
|
|
88879
89155
|
if (/^[A-Za-z0-9_./:@+=,-]*$/.test(value))
|
|
88880
89156
|
return value;
|
|
88881
|
-
const quote3 = ["'", "`", '"'].find((
|
|
89157
|
+
const quote3 = ["'", "`", '"'].find((delimiter3) => !value.includes(delimiter3) && (delimiter3 !== '"' || !value.includes("\\")));
|
|
88882
89158
|
const trailingSlashes = value.match(/\\+$/)?.[0].length ?? 0;
|
|
88883
89159
|
if (!quote3 || trailingSlashes % 2 !== 0 || value.endsWith("\\$")) {
|
|
88884
89160
|
throw new EnvAssignmentError("Cannot safely encode this environment value; incompatible quote/backslash combinations require manual editing.");
|
|
@@ -88960,7 +89236,7 @@ function setEnvAssignment(path, assignment) {
|
|
|
88960
89236
|
})();
|
|
88961
89237
|
if (previous && !previous.isFile())
|
|
88962
89238
|
throw new EnvAssignmentError("The project .env must be a regular file, not a symlink or special file.");
|
|
88963
|
-
descriptor = openSync17(path, previous ?
|
|
89239
|
+
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
89240
|
const opened = fstatSync17(descriptor);
|
|
88965
89241
|
if (!opened.isFile() || previous && (opened.ino !== previous.ino || opened.dev !== previous.dev)) {
|
|
88966
89242
|
throw new EnvAssignmentError("The project .env changed while opening it; retry with a regular file.");
|
|
@@ -89054,7 +89330,7 @@ var exports_diagnostic = {};
|
|
|
89054
89330
|
__export(exports_diagnostic, {
|
|
89055
89331
|
registerDiagnostic: () => registerDiagnostic
|
|
89056
89332
|
});
|
|
89057
|
-
import { existsSync as existsSync27, readFileSync as readFileSync33, readdirSync as readdirSync17, statSync as
|
|
89333
|
+
import { existsSync as existsSync27, readFileSync as readFileSync33, readdirSync as readdirSync17, statSync as statSync17 } from "fs";
|
|
89058
89334
|
import { join as join49 } from "path";
|
|
89059
89335
|
import { execSync as execSync2 } from "child_process";
|
|
89060
89336
|
function registerDiagnostic(parent) {
|
|
@@ -89247,7 +89523,7 @@ function handleWhoami(options) {
|
|
|
89247
89523
|
let skillCount = 0;
|
|
89248
89524
|
if (exists)
|
|
89249
89525
|
try {
|
|
89250
|
-
skillCount = readdirSync17(agentSkillsPath).filter((f) => !f.startsWith(".") &&
|
|
89526
|
+
skillCount = readdirSync17(agentSkillsPath).filter((f) => !f.startsWith(".") && statSync17(join49(agentSkillsPath, f)).isDirectory()).length;
|
|
89251
89527
|
} catch {}
|
|
89252
89528
|
agentConfigs.push({ agent, label: AGENT_LABELS[agent], path: agentSkillsPath, exists, skillCount });
|
|
89253
89529
|
}
|
|
@@ -89505,12 +89781,12 @@ var init_cloud_executions = __esm(() => {
|
|
|
89505
89781
|
|
|
89506
89782
|
// node_modules/@hasna/secrets/dist/sdk.js
|
|
89507
89783
|
import { isIP as isIP3 } from "net";
|
|
89508
|
-
import { spawnSync as
|
|
89784
|
+
import { spawnSync as spawnSync4 } from "child_process";
|
|
89509
89785
|
import { closeSync as closeSync18, fstatSync as fstatSync18, openSync as openSync18, readFileSync as readFileSync34 } from "fs";
|
|
89510
89786
|
import { O_NOFOLLOW as O_NOFOLLOW3, O_NONBLOCK as O_NONBLOCK3, O_RDONLY as O_RDONLY3 } from "constants";
|
|
89511
89787
|
import { createRequire as createRequire2 } from "module";
|
|
89512
89788
|
import { hostname as osHostname2 } from "os";
|
|
89513
|
-
import { isAbsolute as
|
|
89789
|
+
import { isAbsolute as isAbsolute26, join as join50 } from "path";
|
|
89514
89790
|
import { createRequire as createRequire22 } from "module";
|
|
89515
89791
|
function envToken2(name) {
|
|
89516
89792
|
return name.toUpperCase().replace(/-/g, "_");
|
|
@@ -89534,7 +89810,7 @@ function homeDir2(env3) {
|
|
|
89534
89810
|
}
|
|
89535
89811
|
function absoluteOverride2(env3, key) {
|
|
89536
89812
|
const value = env3[key]?.trim();
|
|
89537
|
-
return value &&
|
|
89813
|
+
return value && isAbsolute26(value) ? value : null;
|
|
89538
89814
|
}
|
|
89539
89815
|
function hasnaHomeDir2(env3) {
|
|
89540
89816
|
const override = absoluteOverride2(env3, HASNA_HOME_ENV_KEY2);
|
|
@@ -89780,7 +90056,7 @@ function isAmbientEnvironment2(env3) {
|
|
|
89780
90056
|
return env3 === process.env || env3[AMBIENT_ENVIRONMENT2] === true;
|
|
89781
90057
|
}
|
|
89782
90058
|
function defaultKeychainRunner2(argv) {
|
|
89783
|
-
const result2 =
|
|
90059
|
+
const result2 = spawnSync4(KEYCHAIN_SECURITY_BIN2, [...argv], {
|
|
89784
90060
|
encoding: "utf8",
|
|
89785
90061
|
stdio: ["ignore", "pipe", "pipe"],
|
|
89786
90062
|
timeout: KEYCHAIN_SPAWN_TIMEOUT_MS2
|
|
@@ -90806,7 +91082,7 @@ var init_sdk = __esm(() => {
|
|
|
90806
91082
|
});
|
|
90807
91083
|
|
|
90808
91084
|
// src/lib/execution-secrets.ts
|
|
90809
|
-
import { constants as
|
|
91085
|
+
import { constants as constants20, closeSync as closeSync19, fstatSync as fstatSync19, openSync as openSync19, readSync as readSync15, realpathSync as realpathSync14 } from "fs";
|
|
90810
91086
|
import { hostname as stationHostname } from "os";
|
|
90811
91087
|
function selectedSecretBindingsTemplate(scope, names, createClient2 = createSecretsClientFromEnv) {
|
|
90812
91088
|
let secretsAuthority;
|
|
@@ -90850,7 +91126,7 @@ function declaredSecretNames(value) {
|
|
|
90850
91126
|
function readSelectedSecretBindings(path) {
|
|
90851
91127
|
let fd;
|
|
90852
91128
|
try {
|
|
90853
|
-
fd = openSync19(path,
|
|
91129
|
+
fd = openSync19(path, constants20.O_RDONLY | constants20.O_NOFOLLOW | constants20.O_NONBLOCK);
|
|
90854
91130
|
const stat2 = fstatSync19(fd);
|
|
90855
91131
|
if (!stat2.isFile() || stat2.size > 65536)
|
|
90856
91132
|
throw new Error;
|
|
@@ -95499,7 +95775,7 @@ var init_runs = __esm(() => {
|
|
|
95499
95775
|
|
|
95500
95776
|
// src/lib/run-state.ts
|
|
95501
95777
|
import { createHash as createHash33, randomBytes } from "crypto";
|
|
95502
|
-
import { existsSync as existsSync28, mkdirSync as mkdirSync17, readFileSync as readFileSync35, readdirSync as readdirSync18, statSync as
|
|
95778
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync17, readFileSync as readFileSync35, readdirSync as readdirSync18, statSync as statSync18, writeFileSync as writeFileSync17 } from "fs";
|
|
95503
95779
|
import { extname, join as join52, relative as relative8 } from "path";
|
|
95504
95780
|
function createSkillRun(params, targetDir = process.cwd()) {
|
|
95505
95781
|
const now3 = new Date;
|
|
@@ -95581,7 +95857,7 @@ function listSkillRuns(targetDir = process.cwd(), limit = 50) {
|
|
|
95581
95857
|
const records = [];
|
|
95582
95858
|
for (const day of readdirSync18(runsRoot).sort().reverse()) {
|
|
95583
95859
|
const dayDir = join52(runsRoot, day);
|
|
95584
|
-
if (!
|
|
95860
|
+
if (!statSync18(dayDir).isDirectory())
|
|
95585
95861
|
continue;
|
|
95586
95862
|
for (const runId2 of readdirSync18(dayDir).sort().reverse()) {
|
|
95587
95863
|
const record11 = readRunRecord(join52(dayDir, runId2));
|
|
@@ -95630,7 +95906,7 @@ function collectRunArtifacts(context) {
|
|
|
95630
95906
|
return [];
|
|
95631
95907
|
const artifacts = [];
|
|
95632
95908
|
for (const path of walkFiles(context.exportDir)) {
|
|
95633
|
-
const stat2 =
|
|
95909
|
+
const stat2 = statSync18(path);
|
|
95634
95910
|
const bytes = readFileSync35(path);
|
|
95635
95911
|
artifacts.push({
|
|
95636
95912
|
path: toProjectRelative(context.targetDir, path),
|
|
@@ -95655,7 +95931,7 @@ function walkFiles(dir) {
|
|
|
95655
95931
|
const files = [];
|
|
95656
95932
|
for (const entry of readdirSync18(dir)) {
|
|
95657
95933
|
const full = join52(dir, entry);
|
|
95658
|
-
if (
|
|
95934
|
+
if (statSync18(full).isDirectory())
|
|
95659
95935
|
files.push(...walkFiles(full));
|
|
95660
95936
|
else
|
|
95661
95937
|
files.push(full);
|
|
@@ -99592,11 +99868,11 @@ var require_codegen = __commonJS((exports) => {
|
|
|
99592
99868
|
const rhs = this.rhs === undefined ? "" : ` = ${this.rhs}`;
|
|
99593
99869
|
return `${varKind} ${this.name}${rhs};` + _n;
|
|
99594
99870
|
}
|
|
99595
|
-
optimizeNames(names,
|
|
99871
|
+
optimizeNames(names, constants21) {
|
|
99596
99872
|
if (!names[this.name.str])
|
|
99597
99873
|
return;
|
|
99598
99874
|
if (this.rhs)
|
|
99599
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
99875
|
+
this.rhs = optimizeExpr(this.rhs, names, constants21);
|
|
99600
99876
|
return this;
|
|
99601
99877
|
}
|
|
99602
99878
|
get names() {
|
|
@@ -99614,10 +99890,10 @@ var require_codegen = __commonJS((exports) => {
|
|
|
99614
99890
|
render({ _n }) {
|
|
99615
99891
|
return `${this.lhs} = ${this.rhs};` + _n;
|
|
99616
99892
|
}
|
|
99617
|
-
optimizeNames(names,
|
|
99893
|
+
optimizeNames(names, constants21) {
|
|
99618
99894
|
if (this.lhs instanceof code_1.Name && !names[this.lhs.str] && !this.sideEffects)
|
|
99619
99895
|
return;
|
|
99620
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
99896
|
+
this.rhs = optimizeExpr(this.rhs, names, constants21);
|
|
99621
99897
|
return this;
|
|
99622
99898
|
}
|
|
99623
99899
|
get names() {
|
|
@@ -99683,8 +99959,8 @@ var require_codegen = __commonJS((exports) => {
|
|
|
99683
99959
|
optimizeNodes() {
|
|
99684
99960
|
return `${this.code}` ? this : undefined;
|
|
99685
99961
|
}
|
|
99686
|
-
optimizeNames(names,
|
|
99687
|
-
this.code = optimizeExpr(this.code, names,
|
|
99962
|
+
optimizeNames(names, constants21) {
|
|
99963
|
+
this.code = optimizeExpr(this.code, names, constants21);
|
|
99688
99964
|
return this;
|
|
99689
99965
|
}
|
|
99690
99966
|
get names() {
|
|
@@ -99714,12 +99990,12 @@ var require_codegen = __commonJS((exports) => {
|
|
|
99714
99990
|
}
|
|
99715
99991
|
return nodes.length > 0 ? this : undefined;
|
|
99716
99992
|
}
|
|
99717
|
-
optimizeNames(names,
|
|
99993
|
+
optimizeNames(names, constants21) {
|
|
99718
99994
|
const { nodes } = this;
|
|
99719
99995
|
let i = nodes.length;
|
|
99720
99996
|
while (i--) {
|
|
99721
99997
|
const n2 = nodes[i];
|
|
99722
|
-
if (n2.optimizeNames(names,
|
|
99998
|
+
if (n2.optimizeNames(names, constants21))
|
|
99723
99999
|
continue;
|
|
99724
100000
|
subtractNames(names, n2.names);
|
|
99725
100001
|
nodes.splice(i, 1);
|
|
@@ -99776,12 +100052,12 @@ var require_codegen = __commonJS((exports) => {
|
|
|
99776
100052
|
return;
|
|
99777
100053
|
return this;
|
|
99778
100054
|
}
|
|
99779
|
-
optimizeNames(names,
|
|
100055
|
+
optimizeNames(names, constants21) {
|
|
99780
100056
|
var _a3;
|
|
99781
|
-
this.else = (_a3 = this.else) === null || _a3 === undefined ? undefined : _a3.optimizeNames(names,
|
|
99782
|
-
if (!(super.optimizeNames(names,
|
|
100057
|
+
this.else = (_a3 = this.else) === null || _a3 === undefined ? undefined : _a3.optimizeNames(names, constants21);
|
|
100058
|
+
if (!(super.optimizeNames(names, constants21) || this.else))
|
|
99783
100059
|
return;
|
|
99784
|
-
this.condition = optimizeExpr(this.condition, names,
|
|
100060
|
+
this.condition = optimizeExpr(this.condition, names, constants21);
|
|
99785
100061
|
return this;
|
|
99786
100062
|
}
|
|
99787
100063
|
get names() {
|
|
@@ -99806,10 +100082,10 @@ var require_codegen = __commonJS((exports) => {
|
|
|
99806
100082
|
render(opts) {
|
|
99807
100083
|
return `for(${this.iteration})` + super.render(opts);
|
|
99808
100084
|
}
|
|
99809
|
-
optimizeNames(names,
|
|
99810
|
-
if (!super.optimizeNames(names,
|
|
100085
|
+
optimizeNames(names, constants21) {
|
|
100086
|
+
if (!super.optimizeNames(names, constants21))
|
|
99811
100087
|
return;
|
|
99812
|
-
this.iteration = optimizeExpr(this.iteration, names,
|
|
100088
|
+
this.iteration = optimizeExpr(this.iteration, names, constants21);
|
|
99813
100089
|
return this;
|
|
99814
100090
|
}
|
|
99815
100091
|
get names() {
|
|
@@ -99847,10 +100123,10 @@ var require_codegen = __commonJS((exports) => {
|
|
|
99847
100123
|
render(opts) {
|
|
99848
100124
|
return `for(${this.varKind} ${this.name} ${this.loop} ${this.iterable})` + super.render(opts);
|
|
99849
100125
|
}
|
|
99850
|
-
optimizeNames(names,
|
|
99851
|
-
if (!super.optimizeNames(names,
|
|
100126
|
+
optimizeNames(names, constants21) {
|
|
100127
|
+
if (!super.optimizeNames(names, constants21))
|
|
99852
100128
|
return;
|
|
99853
|
-
this.iterable = optimizeExpr(this.iterable, names,
|
|
100129
|
+
this.iterable = optimizeExpr(this.iterable, names, constants21);
|
|
99854
100130
|
return this;
|
|
99855
100131
|
}
|
|
99856
100132
|
get names() {
|
|
@@ -99895,11 +100171,11 @@ var require_codegen = __commonJS((exports) => {
|
|
|
99895
100171
|
(_b = this.finally) === null || _b === undefined || _b.optimizeNodes();
|
|
99896
100172
|
return this;
|
|
99897
100173
|
}
|
|
99898
|
-
optimizeNames(names,
|
|
100174
|
+
optimizeNames(names, constants21) {
|
|
99899
100175
|
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,
|
|
100176
|
+
super.optimizeNames(names, constants21);
|
|
100177
|
+
(_a3 = this.catch) === null || _a3 === undefined || _a3.optimizeNames(names, constants21);
|
|
100178
|
+
(_b = this.finally) === null || _b === undefined || _b.optimizeNames(names, constants21);
|
|
99903
100179
|
return this;
|
|
99904
100180
|
}
|
|
99905
100181
|
get names() {
|
|
@@ -100173,7 +100449,7 @@ var require_codegen = __commonJS((exports) => {
|
|
|
100173
100449
|
function addExprNames(names, from) {
|
|
100174
100450
|
return from instanceof code_1._CodeOrName ? addNames(names, from.names) : names;
|
|
100175
100451
|
}
|
|
100176
|
-
function optimizeExpr(expr, names,
|
|
100452
|
+
function optimizeExpr(expr, names, constants21) {
|
|
100177
100453
|
if (expr instanceof code_1.Name)
|
|
100178
100454
|
return replaceName(expr);
|
|
100179
100455
|
if (!canOptimize(expr))
|
|
@@ -100188,14 +100464,14 @@ var require_codegen = __commonJS((exports) => {
|
|
|
100188
100464
|
return items;
|
|
100189
100465
|
}, []));
|
|
100190
100466
|
function replaceName(n2) {
|
|
100191
|
-
const c =
|
|
100467
|
+
const c = constants21[n2.str];
|
|
100192
100468
|
if (c === undefined || names[n2.str] !== 1)
|
|
100193
100469
|
return n2;
|
|
100194
100470
|
delete names[n2.str];
|
|
100195
100471
|
return c;
|
|
100196
100472
|
}
|
|
100197
100473
|
function canOptimize(e2) {
|
|
100198
|
-
return e2 instanceof code_1._Code && e2._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 &&
|
|
100474
|
+
return e2 instanceof code_1._Code && e2._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants21[c.str] !== undefined);
|
|
100199
100475
|
}
|
|
100200
100476
|
}
|
|
100201
100477
|
function subtractNames(names, from) {
|
|
@@ -107671,7 +107947,7 @@ var init_remote_customer_operations = __esm(() => {
|
|
|
107671
107947
|
});
|
|
107672
107948
|
|
|
107673
107949
|
// src/lib/workspace-profile.ts
|
|
107674
|
-
import { constants as
|
|
107950
|
+
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
107951
|
import { dirname as dirname28, join as join53 } from "path";
|
|
107676
107952
|
function stat2(path) {
|
|
107677
107953
|
try {
|
|
@@ -107685,7 +107961,7 @@ function stat2(path) {
|
|
|
107685
107961
|
function safeText(file2) {
|
|
107686
107962
|
if (stat2(file2) === null)
|
|
107687
107963
|
return null;
|
|
107688
|
-
const fd = openSync20(file2,
|
|
107964
|
+
const fd = openSync20(file2, constants21.O_RDONLY | constants21.O_NOFOLLOW | constants21.O_NONBLOCK);
|
|
107689
107965
|
try {
|
|
107690
107966
|
const s = fstatSync20(fd);
|
|
107691
107967
|
if (!s.isFile() || s.size > 65536 || ![256, 384].includes(s.mode & 4095) || process.getuid && s.uid !== process.getuid())
|
|
@@ -108039,8 +108315,8 @@ var init_recurring_customer = __esm(() => {
|
|
|
108039
108315
|
});
|
|
108040
108316
|
|
|
108041
108317
|
// src/lib/recurring-recovery.ts
|
|
108042
|
-
import { constants as
|
|
108043
|
-
import { dirname as dirname29, isAbsolute as
|
|
108318
|
+
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";
|
|
108319
|
+
import { dirname as dirname29, isAbsolute as isAbsolute27, join as join54, resolve as resolve27 } from "path";
|
|
108044
108320
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
108045
108321
|
|
|
108046
108322
|
class RecoveryOwner {
|
|
@@ -108048,7 +108324,7 @@ class RecoveryOwner {
|
|
|
108048
108324
|
parents = [];
|
|
108049
108325
|
constructor(directory) {
|
|
108050
108326
|
this.directory = directory;
|
|
108051
|
-
if (!
|
|
108327
|
+
if (!isAbsolute27(directory) || resolve27(directory) !== directory || realpathSync16(directory) !== directory)
|
|
108052
108328
|
invalid6();
|
|
108053
108329
|
for (let path = directory;; path = dirname29(path)) {
|
|
108054
108330
|
const stat3 = lstatSync31(path);
|
|
@@ -108074,7 +108350,7 @@ class RecoveryOwner {
|
|
|
108074
108350
|
}
|
|
108075
108351
|
read(name) {
|
|
108076
108352
|
this.assert();
|
|
108077
|
-
const fd = openSync21(join54(this.directory, name),
|
|
108353
|
+
const fd = openSync21(join54(this.directory, name), constants22.O_RDONLY | constants22.O_NOFOLLOW | constants22.O_NONBLOCK);
|
|
108078
108354
|
try {
|
|
108079
108355
|
const before2 = fstatSync21(fd);
|
|
108080
108356
|
if (!before2.isFile() || before2.nlink !== 1 || (before2.mode & 4095) !== 384 || before2.size < 1 || before2.size > 8192 || process.getuid && before2.uid !== process.getuid())
|
|
@@ -108100,7 +108376,7 @@ class RecoveryOwner {
|
|
|
108100
108376
|
this.assert();
|
|
108101
108377
|
const bytes = canonicalJson2(value, 8192) + `
|
|
108102
108378
|
`;
|
|
108103
|
-
const fd = openSync21(join54(this.directory, name),
|
|
108379
|
+
const fd = openSync21(join54(this.directory, name), constants22.O_WRONLY | constants22.O_CREAT | constants22.O_EXCL | constants22.O_NOFOLLOW, 384);
|
|
108104
108380
|
try {
|
|
108105
108381
|
writeFileSync19(fd, bytes);
|
|
108106
108382
|
fsyncSync7(fd);
|
|
@@ -108112,7 +108388,7 @@ class RecoveryOwner {
|
|
|
108112
108388
|
}
|
|
108113
108389
|
sync() {
|
|
108114
108390
|
this.assert();
|
|
108115
|
-
const fd = openSync21(this.directory,
|
|
108391
|
+
const fd = openSync21(this.directory, constants22.O_RDONLY | constants22.O_NOFOLLOW);
|
|
108116
108392
|
try {
|
|
108117
108393
|
fsyncSync7(fd);
|
|
108118
108394
|
} finally {
|
|
@@ -108134,7 +108410,7 @@ class RecoveryOwner {
|
|
|
108134
108410
|
this.assert();
|
|
108135
108411
|
let fd;
|
|
108136
108412
|
try {
|
|
108137
|
-
fd = openSync21(join54(this.directory, "operation.lock"),
|
|
108413
|
+
fd = openSync21(join54(this.directory, "operation.lock"), constants22.O_WRONLY | constants22.O_CREAT | constants22.O_EXCL | constants22.O_NOFOLLOW, 384);
|
|
108138
108414
|
} catch {
|
|
108139
108415
|
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
108416
|
}
|
|
@@ -108183,7 +108459,7 @@ function base2(customer, organizationId) {
|
|
|
108183
108459
|
};
|
|
108184
108460
|
}
|
|
108185
108461
|
function create3(directory, intent) {
|
|
108186
|
-
if (!
|
|
108462
|
+
if (!isAbsolute27(directory) || resolve27(directory) !== directory || realpathSync16(dirname29(directory)) !== dirname29(directory))
|
|
108187
108463
|
invalid6();
|
|
108188
108464
|
mkdirSync19(directory, { mode: 448 });
|
|
108189
108465
|
const owner2 = new RecoveryOwner(directory), checked = intentSchema.parse(intent), intentSha256 = canonicalJsonSha256(checked);
|
|
@@ -108346,7 +108622,7 @@ var init_recurring_recovery = __esm(() => {
|
|
|
108346
108622
|
});
|
|
108347
108623
|
|
|
108348
108624
|
// src/lib/recurring-surface.ts
|
|
108349
|
-
import { isAbsolute as
|
|
108625
|
+
import { isAbsolute as isAbsolute28 } from "path";
|
|
108350
108626
|
function recurringMcpSchema(action) {
|
|
108351
108627
|
return action === "activate" ? recurringSurfaceSchemas.activate.extend({ code, confirm: exports_external.literal(true) }) : recurringSurfaceSchemas[action];
|
|
108352
108628
|
}
|
|
@@ -108451,7 +108727,7 @@ var init_recurring_surface = __esm(() => {
|
|
|
108451
108727
|
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
108728
|
context = { userId: uuid12.optional(), membershipId: uuid12.optional() };
|
|
108453
108729
|
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(
|
|
108730
|
+
directory = exports_external.string().max(4096).refine(isAbsolute28, "Use an absolute recovery directory");
|
|
108455
108731
|
email4 = exports_external.string().trim().toLowerCase().email().max(254);
|
|
108456
108732
|
code = exports_external.string().regex(/^\d{6}$/);
|
|
108457
108733
|
recurringSurfaceSchemas = {
|
|
@@ -109823,7 +110099,7 @@ var init_run_routing = __esm(() => {
|
|
|
109823
110099
|
});
|
|
109824
110100
|
|
|
109825
110101
|
// src/mcp/operation-tools.ts
|
|
109826
|
-
import { existsSync as existsSync29, readdirSync as readdirSync19, statSync as
|
|
110102
|
+
import { existsSync as existsSync29, readdirSync as readdirSync19, statSync as statSync19 } from "fs";
|
|
109827
110103
|
import { join as join55 } from "path";
|
|
109828
110104
|
function registerOperationTools(server) {
|
|
109829
110105
|
server.registerTool("cloud_skill_eligibility", {
|
|
@@ -110302,7 +110578,7 @@ function registerOperationTools(server) {
|
|
|
110302
110578
|
try {
|
|
110303
110579
|
skillCount = readdirSync19(agentSkillsPath).filter((f) => {
|
|
110304
110580
|
const full = join55(agentSkillsPath, f);
|
|
110305
|
-
return !f.startsWith(".") &&
|
|
110581
|
+
return !f.startsWith(".") && statSync19(full).isDirectory();
|
|
110306
110582
|
}).length;
|
|
110307
110583
|
} catch {}
|
|
110308
110584
|
}
|
|
@@ -110889,7 +111165,7 @@ import {
|
|
|
110889
111165
|
mkdirSync as mkdirSync22,
|
|
110890
111166
|
readFileSync as readFileSync38,
|
|
110891
111167
|
readdirSync as readdirSync20,
|
|
110892
|
-
statSync as
|
|
111168
|
+
statSync as statSync20,
|
|
110893
111169
|
writeFileSync as writeFileSync21
|
|
110894
111170
|
} from "fs";
|
|
110895
111171
|
import { dirname as dirname31, join as join58, normalize as normalize5, relative as relative9, sep as sep11 } from "path";
|
|
@@ -111015,7 +111291,7 @@ function walkFiles2(dir) {
|
|
|
111015
111291
|
const files = [];
|
|
111016
111292
|
for (const entry of readdirSync20(dir)) {
|
|
111017
111293
|
const full = join58(dir, entry);
|
|
111018
|
-
const stats =
|
|
111294
|
+
const stats = statSync20(full);
|
|
111019
111295
|
if (stats.isDirectory())
|
|
111020
111296
|
files.push(...walkFiles2(full));
|
|
111021
111297
|
else
|
|
@@ -111252,11 +111528,11 @@ var init_private_publication_customer = __esm(() => {
|
|
|
111252
111528
|
});
|
|
111253
111529
|
|
|
111254
111530
|
// src/lib/private-publication-recovery.ts
|
|
111255
|
-
import { constants as
|
|
111256
|
-
import { dirname as dirname32, isAbsolute as
|
|
111531
|
+
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";
|
|
111532
|
+
import { dirname as dirname32, isAbsolute as isAbsolute29, join as join59, resolve as resolve28 } from "path";
|
|
111257
111533
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
111258
111534
|
function safeDirectory(directory2) {
|
|
111259
|
-
if (!
|
|
111535
|
+
if (!isAbsolute29(directory2) || directory2 !== resolve28(directory2) || realpathSync17(directory2) !== directory2)
|
|
111260
111536
|
return fail5();
|
|
111261
111537
|
for (let path = directory2;; path = dirname32(path)) {
|
|
111262
111538
|
const stat3 = lstatSync32(path);
|
|
@@ -111277,7 +111553,7 @@ function unchangedDirectory(directory2, identity6) {
|
|
|
111277
111553
|
}
|
|
111278
111554
|
function readOwned(directory2, name, max2) {
|
|
111279
111555
|
const identity6 = safeDirectory(directory2), file2 = join59(directory2, name);
|
|
111280
|
-
const fd = openSync23(file2,
|
|
111556
|
+
const fd = openSync23(file2, constants23.O_RDONLY | constants23.O_NOFOLLOW);
|
|
111281
111557
|
try {
|
|
111282
111558
|
const stat3 = fstatSync23(fd);
|
|
111283
111559
|
if (!stat3.isFile() || stat3.nlink !== 1 || stat3.size > max2 || stat3.size < 1 || (stat3.mode & 63) !== 0 || process.getuid && stat3.uid !== process.getuid())
|
|
@@ -111300,7 +111576,7 @@ function readOwned(directory2, name, max2) {
|
|
|
111300
111576
|
}
|
|
111301
111577
|
}
|
|
111302
111578
|
function writeOwned(directory2, name, bytes) {
|
|
111303
|
-
const fd = openSync23(join59(directory2, name),
|
|
111579
|
+
const fd = openSync23(join59(directory2, name), constants23.O_WRONLY | constants23.O_CREAT | constants23.O_EXCL | constants23.O_NOFOLLOW, 384);
|
|
111304
111580
|
try {
|
|
111305
111581
|
writeFileSync22(fd, bytes);
|
|
111306
111582
|
fsyncSync8(fd);
|
|
@@ -111314,7 +111590,7 @@ function save2(directory2, value) {
|
|
|
111314
111590
|
`);
|
|
111315
111591
|
unchangedDirectory(directory2, identity6);
|
|
111316
111592
|
renameSync13(join59(directory2, temporary), join59(directory2, "receipt.json"));
|
|
111317
|
-
const fd = openSync23(directory2,
|
|
111593
|
+
const fd = openSync23(directory2, constants23.O_RDONLY | constants23.O_NOFOLLOW);
|
|
111318
111594
|
try {
|
|
111319
111595
|
fsyncSync8(fd);
|
|
111320
111596
|
} finally {
|
|
@@ -111329,7 +111605,7 @@ async function locked(directory2, action) {
|
|
|
111329
111605
|
const identity6 = safeDirectory(directory2), file2 = join59(directory2, "operation.lock");
|
|
111330
111606
|
let fd;
|
|
111331
111607
|
try {
|
|
111332
|
-
fd = openSync23(file2,
|
|
111608
|
+
fd = openSync23(file2, constants23.O_WRONLY | constants23.O_CREAT | constants23.O_EXCL | constants23.O_NOFOLLOW, 384);
|
|
111333
111609
|
} catch {
|
|
111334
111610
|
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
111611
|
}
|
|
@@ -111394,11 +111670,11 @@ async function preparePrivatePublication(client2, sourceDirectory, recoveryDirec
|
|
|
111394
111670
|
phase: "prepared",
|
|
111395
111671
|
intent: null
|
|
111396
111672
|
};
|
|
111397
|
-
if (!
|
|
111673
|
+
if (!isAbsolute29(recoveryDirectory) || resolve28(recoveryDirectory) !== recoveryDirectory || realpathSync17(dirname32(recoveryDirectory)) !== dirname32(recoveryDirectory))
|
|
111398
111674
|
return fail5();
|
|
111399
111675
|
mkdirSync23(recoveryDirectory, { mode: 448 });
|
|
111400
111676
|
safeDirectory(recoveryDirectory);
|
|
111401
|
-
const parent = openSync23(dirname32(recoveryDirectory),
|
|
111677
|
+
const parent = openSync23(dirname32(recoveryDirectory), constants23.O_RDONLY | constants23.O_NOFOLLOW);
|
|
111402
111678
|
try {
|
|
111403
111679
|
fsyncSync8(parent);
|
|
111404
111680
|
} finally {
|
|
@@ -111495,10 +111771,10 @@ var init_private_publication_recovery = __esm(() => {
|
|
|
111495
111771
|
});
|
|
111496
111772
|
|
|
111497
111773
|
// src/mcp/private-publication-tools.ts
|
|
111498
|
-
import { isAbsolute as
|
|
111774
|
+
import { isAbsolute as isAbsolute30 } from "path";
|
|
111499
111775
|
function registerPrivatePublicationTools(server) {
|
|
111500
111776
|
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(
|
|
111777
|
+
const directory2 = exports_external.string().max(4096).refine(isAbsolute30, "Use an absolute local directory");
|
|
111502
111778
|
const verification2 = { email: exports_external.string().email().max(254), code: exports_external.string().regex(/^\d{6}$/), userId: uuid9, membershipId: uuid9, recoveryDirectory: directory2 };
|
|
111503
111779
|
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
111780
|
const handler = (action) => async (value) => {
|
|
@@ -112290,44 +112566,50 @@ import {
|
|
|
112290
112566
|
renameSync as renameSync14,
|
|
112291
112567
|
writeFileSync as writeFileSync24
|
|
112292
112568
|
} from "fs";
|
|
112293
|
-
import { basename as basename17, delimiter as
|
|
112569
|
+
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
112570
|
function oldLauncherState(item) {
|
|
112295
112571
|
if (item.oldShape === "pinned")
|
|
112296
|
-
return { shape: "pinned", runtime: item.oldRuntime, cwd: item.oldCwd, target: item.oldTarget, sha256: item.oldSha256 };
|
|
112572
|
+
return { shape: "pinned", runtime: item.oldRuntime, cwd: item.oldCwd, target: item.oldTarget, sha256: item.oldSha256, format: item.oldFormat, profile: item.oldProfile };
|
|
112297
112573
|
return { shape: "symlink", linkTarget: item.oldLinkTarget, target: item.oldTarget };
|
|
112298
112574
|
}
|
|
112299
112575
|
function newLauncherState(item) {
|
|
112300
112576
|
if (item.newShape === "pinned")
|
|
112301
|
-
return { shape: "pinned", runtime: item.newRuntime, cwd: item.newCwd, target: item.newTarget, sha256: item.newSha256 };
|
|
112577
|
+
return { shape: "pinned", runtime: item.newRuntime, cwd: item.newCwd, target: item.newTarget, sha256: item.newSha256, format: item.newFormat, profile: item.newProfile };
|
|
112302
112578
|
return { shape: "symlink", linkTarget: item.newTarget, target: item.newTarget };
|
|
112303
112579
|
}
|
|
112304
|
-
function assertLauncherRecordShapes(item) {
|
|
112580
|
+
function assertLauncherRecordShapes(item, expectedProfile) {
|
|
112305
112581
|
const hex3 = /^[a-f0-9]{64}$/;
|
|
112306
112582
|
for (const side of ["old", "new"]) {
|
|
112307
112583
|
const shape = item[`${side}Shape`], runtime = item[`${side}Runtime`], cwd2 = item[`${side}Cwd`], sha6 = item[`${side}Sha256`];
|
|
112584
|
+
const format = item[`${side}Format`], profile = item[`${side}Profile`];
|
|
112308
112585
|
if (shape === undefined) {
|
|
112309
|
-
if (runtime !== undefined || cwd2 !== undefined || sha6 !== undefined)
|
|
112586
|
+
if (runtime !== undefined || cwd2 !== undefined || sha6 !== undefined || format !== undefined || profile !== undefined)
|
|
112310
112587
|
throw new Error("RECEIPT_LAUNCHER_SHAPE_INVALID");
|
|
112311
112588
|
continue;
|
|
112312
112589
|
}
|
|
112313
112590
|
if (shape === "symlink") {
|
|
112314
|
-
if (runtime !== undefined || cwd2 !== undefined || sha6 !== undefined)
|
|
112591
|
+
if (runtime !== undefined || cwd2 !== undefined || sha6 !== undefined || format !== undefined || profile !== undefined)
|
|
112315
112592
|
throw new Error("RECEIPT_LAUNCHER_SHAPE_INVALID");
|
|
112316
112593
|
continue;
|
|
112317
112594
|
}
|
|
112318
|
-
if (shape !== "pinned" || typeof runtime !== "string" || !
|
|
112595
|
+
if (shape !== "pinned" || typeof runtime !== "string" || !isAbsolute31(runtime) || typeof cwd2 !== "string" || !isAbsolute31(cwd2) || typeof sha6 !== "string" || !hex3.test(sha6)) {
|
|
112319
112596
|
throw new Error("RECEIPT_LAUNCHER_SHAPE_INVALID");
|
|
112320
112597
|
}
|
|
112321
112598
|
const target = side === "old" ? item.oldTarget : item.newTarget;
|
|
112322
112599
|
if (side === "old" && item.oldLinkTarget !== item.oldTarget)
|
|
112323
112600
|
throw new Error("RECEIPT_LAUNCHER_SHAPE_INVALID");
|
|
112324
|
-
if (
|
|
112601
|
+
if (format === "v2" && profile !== expectedProfile)
|
|
112325
112602
|
throw new Error("RECEIPT_LAUNCHER_SHAPE_INVALID");
|
|
112603
|
+
try {
|
|
112604
|
+
pinnedLauncherText({ runtime, cwd: cwd2, target, sha256: sha6, format, profile });
|
|
112605
|
+
} catch {
|
|
112606
|
+
throw new Error("RECEIPT_LAUNCHER_SHAPE_INVALID");
|
|
112607
|
+
}
|
|
112326
112608
|
}
|
|
112327
112609
|
}
|
|
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 };
|
|
112610
|
+
function pinnedRecordFields(runtime, cwd2, target, profile) {
|
|
112611
|
+
const state = pinnedLauncherState(runtime, cwd2, target, { format: "v2", profile });
|
|
112612
|
+
return { newShape: "pinned", newRuntime: state.runtime, newCwd: state.cwd, newSha256: state.sha256, newFormat: state.format, newProfile: state.profile };
|
|
112331
112613
|
}
|
|
112332
112614
|
function object10(value, code2) {
|
|
112333
112615
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
@@ -112339,7 +112621,7 @@ function hash5(bytes) {
|
|
|
112339
112621
|
}
|
|
112340
112622
|
function isWithin(parent, child2) {
|
|
112341
112623
|
const rel = relative10(parent, child2);
|
|
112342
|
-
return rel === "" || !rel.startsWith(`..${sep12}`) && rel !== ".." && !
|
|
112624
|
+
return rel === "" || !rel.startsWith(`..${sep12}`) && rel !== ".." && !isAbsolute31(rel);
|
|
112343
112625
|
}
|
|
112344
112626
|
function entryExists(path) {
|
|
112345
112627
|
try {
|
|
@@ -112388,7 +112670,7 @@ function packageBins(pkg) {
|
|
|
112388
112670
|
const entries = typeof raw === "string" ? [[PACKAGE_NAME.slice(PACKAGE_NAME.lastIndexOf("/") + 1), raw]] : raw && typeof raw === "object" && !Array.isArray(raw) ? Object.entries(raw) : [];
|
|
112389
112671
|
const output2 = {};
|
|
112390
112672
|
for (const [name, value] of entries) {
|
|
112391
|
-
if (!/^[a-zA-Z0-9._-]+$/.test(name) || typeof value !== "string" || !value ||
|
|
112673
|
+
if (!/^[a-zA-Z0-9._-]+$/.test(name) || typeof value !== "string" || !value || isAbsolute31(value)) {
|
|
112392
112674
|
throw new Error("PACKAGE_BIN_INVALID");
|
|
112393
112675
|
}
|
|
112394
112676
|
const normalized = value.replaceAll("\\", "/");
|
|
@@ -112451,7 +112733,7 @@ function resolveRuntimeLayout(homeInput, pathInput) {
|
|
|
112451
112733
|
}
|
|
112452
112734
|
const launchers = [];
|
|
112453
112735
|
const seenDirectories = new Set;
|
|
112454
|
-
for (const rawDir of pathInput.split(
|
|
112736
|
+
for (const rawDir of pathInput.split(delimiter3).filter(Boolean)) {
|
|
112455
112737
|
const dir = resolve29(rawDir);
|
|
112456
112738
|
if (seenDirectories.has(dir))
|
|
112457
112739
|
continue;
|
|
@@ -112481,7 +112763,7 @@ function resolveRuntimeLayout(homeInput, pathInput) {
|
|
|
112481
112763
|
throw new Error("LAUNCHER_SYMLINK_CHAIN_UNSUPPORTED");
|
|
112482
112764
|
launchers.push({ path, oldTarget: actual, oldLinkTarget: launcher.linkTarget, newTarget, backupPath, oldShape: "symlink" });
|
|
112483
112765
|
} else {
|
|
112484
|
-
launchers.push({ path, oldTarget: actual, oldLinkTarget: actual, newTarget, backupPath, oldShape: "pinned", oldRuntime: launcher.runtime, oldCwd: launcher.cwd, oldSha256: launcher.sha256 });
|
|
112766
|
+
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
112767
|
}
|
|
112486
112768
|
}
|
|
112487
112769
|
}
|
|
@@ -113110,14 +113392,14 @@ function adoptCopyfileAliases(options = {}) {
|
|
|
113110
113392
|
const actual = launcher.target;
|
|
113111
113393
|
const oldLinkTarget = launcher.kind === "symlink" ? launcher.linkTarget : actual;
|
|
113112
113394
|
const newTarget = join61(layout.currentPackageRoot, target);
|
|
113113
|
-
if (actual === newTarget && launcher.kind === "pinned")
|
|
113395
|
+
if (actual === newTarget && launcher.kind === "pinned" && launcher.format === "v2" && launcher.profile === launcherProfileForBin(name, target))
|
|
113114
113396
|
continue;
|
|
113115
113397
|
const chain = inspectAliasPackageChain(home, path, oldLinkTarget, actual, target);
|
|
113116
113398
|
const source = validateAliasSource(home, name, actual);
|
|
113117
113399
|
const backupPath = `${path}.skills-alias-prev-${id2}`;
|
|
113118
113400
|
if (entryExists(backupPath))
|
|
113119
113401
|
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 };
|
|
113402
|
+
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
113403
|
aliases.push({
|
|
113122
113404
|
path,
|
|
113123
113405
|
oldTarget: actual,
|
|
@@ -113127,7 +113409,7 @@ function adoptCopyfileAliases(options = {}) {
|
|
|
113127
113409
|
newTarget,
|
|
113128
113410
|
backupPath,
|
|
113129
113411
|
...oldFields,
|
|
113130
|
-
...pinnedRecordFields(launcherRuntime, currentRuntime, newTarget),
|
|
113412
|
+
...pinnedRecordFields(launcherRuntime, currentRuntime, newTarget, launcherProfileForBin(name, target)),
|
|
113131
113413
|
...chain ? { chain } : {}
|
|
113132
113414
|
});
|
|
113133
113415
|
}
|
|
@@ -113247,7 +113529,7 @@ function rollbackCopyfileAliases(receiptId, options = {}) {
|
|
|
113247
113529
|
throw new Error("ALIAS_RECEIPT_LAUNCHER_INVALID");
|
|
113248
113530
|
}
|
|
113249
113531
|
inspectAliasPackageChain(home, item.path, item.oldLinkTarget, item.oldTarget, target, item.chain, true);
|
|
113250
|
-
assertLauncherRecordShapes(item);
|
|
113532
|
+
assertLauncherRecordShapes(item, launcherProfileForBin(name, target));
|
|
113251
113533
|
seen.add(item.path);
|
|
113252
113534
|
assertOwnedSafePath(dirname34(item.path), home, true);
|
|
113253
113535
|
const source = validateAliasSource(home, name, item.oldTarget);
|
|
@@ -113319,7 +113601,7 @@ async function updateCopyfileRuntime(version2, options = {}) {
|
|
|
113319
113601
|
throw new Error("REVIEWED_LOCK_INPUT_PAIR_REQUIRED");
|
|
113320
113602
|
if (!policy)
|
|
113321
113603
|
throw new Error("REVIEWED_LOCK_RELEASE_AGE_REQUIRED");
|
|
113322
|
-
if (!
|
|
113604
|
+
if (!isAbsolute31(options.reviewedLock))
|
|
113323
113605
|
throw new Error("REVIEWED_LOCK_ABSOLUTE_PATH_REQUIRED");
|
|
113324
113606
|
assertNoSymlinkAncestors(dirname34(options.reviewedLock));
|
|
113325
113607
|
const stat3 = lstatSync33(options.reviewedLock);
|
|
@@ -113352,7 +113634,7 @@ async function updateCopyfileRuntime(version2, options = {}) {
|
|
|
113352
113634
|
const launcherRuntime = pinnedLauncherRuntime();
|
|
113353
113635
|
const launchers = layout.launchers.map((item) => {
|
|
113354
113636
|
const newTarget = join61(finalPath, "node_modules", "@hasna", "skills", layout.bin[basename17(item.path)]);
|
|
113355
|
-
return { ...item, newTarget, ...pinnedRecordFields(launcherRuntime, finalPath, newTarget) };
|
|
113637
|
+
return { ...item, newTarget, ...pinnedRecordFields(launcherRuntime, finalPath, newTarget, launcherProfileForBin(basename17(item.path), layout.bin[basename17(item.path)])) };
|
|
113356
113638
|
});
|
|
113357
113639
|
const releaseLock = acquireRuntimeLock(layout.runtimeRoot);
|
|
113358
113640
|
let switched = [];
|
|
@@ -113566,10 +113848,10 @@ function rollbackCopyfileRuntime(receiptId, options = {}) {
|
|
|
113566
113848
|
const seen = new Set;
|
|
113567
113849
|
for (const item of receipt.launchers) {
|
|
113568
113850
|
const bin = oldBins[basename17(item.path)];
|
|
113569
|
-
if (!bin || !
|
|
113851
|
+
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
113852
|
throw new Error("RECEIPT_LAUNCHER_BINDING_INVALID");
|
|
113571
113853
|
assertNoSymlinkAncestors(dirname34(item.path));
|
|
113572
|
-
assertLauncherRecordShapes(item);
|
|
113854
|
+
assertLauncherRecordShapes(item, launcherProfileForBin(basename17(item.path), bin));
|
|
113573
113855
|
seen.add(item.path);
|
|
113574
113856
|
const oldState = oldLauncherState(item), newState = newLauncherState(item);
|
|
113575
113857
|
let activeTarget;
|
|
@@ -113635,7 +113917,7 @@ __export(exports_runtime, {
|
|
|
113635
113917
|
});
|
|
113636
113918
|
import { createHash as createHash37, randomUUID as randomUUID11 } from "crypto";
|
|
113637
113919
|
import { lstatSync as lstatSync34, mkdirSync as mkdirSync26, readFileSync as readFileSync41, writeFileSync as writeFileSync25 } from "fs";
|
|
113638
|
-
import { basename as basename18, isAbsolute as
|
|
113920
|
+
import { basename as basename18, isAbsolute as isAbsolute32, join as join62 } from "path";
|
|
113639
113921
|
import { createInterface } from "readline";
|
|
113640
113922
|
function registerRuntime(parent) {
|
|
113641
113923
|
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 +114116,7 @@ Updating ${name}...
|
|
|
113834
114116
|
async function readUpdatedVersion(bunExecutable) {
|
|
113835
114117
|
const output2 = await readUpdateCommand([bunExecutable, "pm", "bin", "-g"]);
|
|
113836
114118
|
const globalBin = output2.replace(/\r?\n$/, "");
|
|
113837
|
-
if (!globalBin || !
|
|
114119
|
+
if (!globalBin || !isAbsolute32(globalBin) || /[\r\n\0]/.test(globalBin))
|
|
113838
114120
|
throw new Error("Update bin discovery failed");
|
|
113839
114121
|
const installed = Bun.which("skills", { PATH: globalBin, cwd: globalBin });
|
|
113840
114122
|
const selected = Bun.which("skills");
|
|
@@ -114889,10 +115171,10 @@ var exports_recurring = {};
|
|
|
114889
115171
|
__export(exports_recurring, {
|
|
114890
115172
|
registerRecurringCommands: () => registerRecurringCommands
|
|
114891
115173
|
});
|
|
114892
|
-
import { constants as
|
|
115174
|
+
import { constants as constants24, closeSync as closeSync25, fstatSync as fstatSync25, lstatSync as lstatSync35, openSync as openSync25, readSync as readSync18 } from "fs";
|
|
114893
115175
|
import { createInterface as createInterface2 } from "readline";
|
|
114894
115176
|
function readRequest(path) {
|
|
114895
|
-
const fd = openSync25(path,
|
|
115177
|
+
const fd = openSync25(path, constants24.O_RDONLY | constants24.O_NOFOLLOW | constants24.O_NONBLOCK);
|
|
114896
115178
|
try {
|
|
114897
115179
|
const before2 = fstatSync25(fd);
|
|
114898
115180
|
if (!before2.isFile() || before2.size > 1048576 || before2.size < 1)
|
|
@@ -115189,7 +115471,7 @@ var init_completion = __esm(() => {
|
|
|
115189
115471
|
});
|
|
115190
115472
|
|
|
115191
115473
|
// src/lib/portable-snapshot-filter.ts
|
|
115192
|
-
import { readdirSync as readdirSync22, statSync as
|
|
115474
|
+
import { readdirSync as readdirSync22, statSync as statSync21 } from "fs";
|
|
115193
115475
|
import { homedir as homedir11 } from "os";
|
|
115194
115476
|
import { join as join63, sep as sep13 } from "path";
|
|
115195
115477
|
function isExcludedSkillFileName(fileName) {
|
|
@@ -115257,7 +115539,7 @@ function walkEntries(absoluteRoot) {
|
|
|
115257
115539
|
}
|
|
115258
115540
|
function isRegularFile(filePath) {
|
|
115259
115541
|
try {
|
|
115260
|
-
return
|
|
115542
|
+
return statSync21(filePath).isFile();
|
|
115261
115543
|
} catch {
|
|
115262
115544
|
return false;
|
|
115263
115545
|
}
|
|
@@ -115343,10 +115625,10 @@ import {
|
|
|
115343
115625
|
copyFileSync as copyFileSync2,
|
|
115344
115626
|
mkdirSync as mkdirSync27,
|
|
115345
115627
|
readFileSync as readFileSync42,
|
|
115346
|
-
statSync as
|
|
115628
|
+
statSync as statSync22,
|
|
115347
115629
|
writeFileSync as writeFileSync26
|
|
115348
115630
|
} from "fs";
|
|
115349
|
-
import { dirname as dirname36, isAbsolute as
|
|
115631
|
+
import { dirname as dirname36, isAbsolute as isAbsolute33, relative as relative11, resolve as resolve30, sep as sep14 } from "path";
|
|
115350
115632
|
function validateStationId(stationId) {
|
|
115351
115633
|
if (!/^[a-z0-9-]+$/.test(stationId)) {
|
|
115352
115634
|
throw new StationSnapshotError("INVALID_STATION", `station id must be a slug, got: ${stationId}`);
|
|
@@ -115383,7 +115665,7 @@ function scanHome(definition, homesRoot) {
|
|
|
115383
115665
|
skipped.push({ relativePath: entry.relativePath, reason: "not-regular-file" });
|
|
115384
115666
|
continue;
|
|
115385
115667
|
}
|
|
115386
|
-
const info =
|
|
115668
|
+
const info = statSync22(entry.fullPath);
|
|
115387
115669
|
portable.push({
|
|
115388
115670
|
relativePath: entry.relativePath,
|
|
115389
115671
|
fullPath: entry.fullPath,
|
|
@@ -115452,7 +115734,7 @@ function writeStationSnapshot(options) {
|
|
|
115452
115734
|
for (const plan of plans) {
|
|
115453
115735
|
const destination = resolve30(repoRoot, plan.destination);
|
|
115454
115736
|
const destinationRelative = relative11(repoRoot, destination);
|
|
115455
|
-
if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep14) ||
|
|
115737
|
+
if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep14) || isAbsolute33(destinationRelative)) {
|
|
115456
115738
|
throw new StationSnapshotError("DESTINATION_ESCAPE", `destination escapes repo root: ${plan.destination}`);
|
|
115457
115739
|
}
|
|
115458
115740
|
let existingDigest = null;
|
|
@@ -115924,6 +116206,50 @@ var init_create_sync_config = __esm(() => {
|
|
|
115924
116206
|
init_station_snapshot();
|
|
115925
116207
|
});
|
|
115926
116208
|
|
|
116209
|
+
// src/lib/agent-install-selection.ts
|
|
116210
|
+
import { lstatSync as lstatSync36 } from "fs";
|
|
116211
|
+
import { dirname as dirname37, join as join65, resolve as resolve31 } from "path";
|
|
116212
|
+
import { homedir as homedir12 } from "os";
|
|
116213
|
+
function detectedIntegrationAgents(options = {}) {
|
|
116214
|
+
const home = options.home ?? homedir12(), env3 = options.env ?? process.env;
|
|
116215
|
+
const policy = readManagedSkillPolicySnapshot(options.dataDir ?? getDataDirReadOnly())?.value;
|
|
116216
|
+
const bridge = policy?.bridge;
|
|
116217
|
+
if (bridge !== undefined && (!bridge || typeof bridge !== "object" || Array.isArray(bridge)))
|
|
116218
|
+
throw new Error("Invalid existing Skills bridge policy");
|
|
116219
|
+
const configured = bridge === undefined ? [] : bridge.agents;
|
|
116220
|
+
if (!Array.isArray(configured) || configured.some((agent) => !INTEGRATION_AGENTS.includes(agent)))
|
|
116221
|
+
throw new Error("Invalid existing bridge agent inventory");
|
|
116222
|
+
const present = (path) => {
|
|
116223
|
+
try {
|
|
116224
|
+
return lstatSync36(path, { throwIfNoEntry: false }) !== undefined;
|
|
116225
|
+
} catch {
|
|
116226
|
+
throw new Error("Agent presence cannot be inspected; review native configuration before hook installation");
|
|
116227
|
+
}
|
|
116228
|
+
};
|
|
116229
|
+
const selected = INTEGRATION_AGENTS.filter((agent) => {
|
|
116230
|
+
if (configured.includes(agent) || Bun.which(agent, { PATH: env3.PATH ?? "" }))
|
|
116231
|
+
return true;
|
|
116232
|
+
if (agent === "sumi") {
|
|
116233
|
+
const xdg = env3.XDG_CONFIG_HOME;
|
|
116234
|
+
const xdgSumi = xdg?.trim() ? resolve31(options.cwd ?? process.cwd(), xdg === "~" ? home : xdg.startsWith("~/") || xdg.startsWith("~\\") ? resolve31(home, xdg.slice(2)) : xdg, "sumi") : null;
|
|
116235
|
+
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);
|
|
116236
|
+
}
|
|
116237
|
+
if (agent === "hermes" && env3.HERMES_HOME !== undefined)
|
|
116238
|
+
return true;
|
|
116239
|
+
const adapter = AGENT_ADAPTERS[agent];
|
|
116240
|
+
return present(join65(home, dirname37(adapter.config))) || NATIVE_SKILL_ROOTS.some(([provider, root2]) => provider === agent && dirname37(root2) === `.${agent}` && present(join65(home, dirname37(root2))));
|
|
116241
|
+
});
|
|
116242
|
+
if (!selected.length)
|
|
116243
|
+
throw new Error(`No configured or detected agents; select --agent <agent> explicitly (${INTEGRATION_AGENTS.join(", ")}).`);
|
|
116244
|
+
return selected;
|
|
116245
|
+
}
|
|
116246
|
+
var init_agent_install_selection = __esm(() => {
|
|
116247
|
+
init_agent_adapters();
|
|
116248
|
+
init_native_discovery_roots();
|
|
116249
|
+
init_managed_policy();
|
|
116250
|
+
init_config();
|
|
116251
|
+
});
|
|
116252
|
+
|
|
115927
116253
|
// src/lib/codex-native-config.ts
|
|
115928
116254
|
import { isDeepStrictEqual as isDeepStrictEqual14 } from "util";
|
|
115929
116255
|
function isRecord8(value) {
|
|
@@ -115971,11 +116297,11 @@ var NUMBER_TAG = "$serde_json::private::Number";
|
|
|
115971
116297
|
var init_codex_native_config = () => {};
|
|
115972
116298
|
|
|
115973
116299
|
// src/lib/codex-hook-trust-identity.ts
|
|
115974
|
-
import { lstatSync as
|
|
115975
|
-
import { dirname as
|
|
116300
|
+
import { lstatSync as lstatSync37, realpathSync as realpathSync19 } from "fs";
|
|
116301
|
+
import { dirname as dirname38, isAbsolute as isAbsolute34, join as join66, resolve as resolve32 } from "path";
|
|
115976
116302
|
import { isDeepStrictEqual as isDeepStrictEqual15 } from "util";
|
|
115977
116303
|
function commandPhysical(command) {
|
|
115978
|
-
need6(typeof command === "string" &&
|
|
116304
|
+
need6(typeof command === "string" && isAbsolute34(command) && !command.includes("\x00") && resolve32(command) === command, COMMAND_NOT_CANONICAL);
|
|
115979
116305
|
const physical = realpathSync19(command);
|
|
115980
116306
|
let spelled;
|
|
115981
116307
|
try {
|
|
@@ -115986,7 +116312,7 @@ function commandPhysical(command) {
|
|
|
115986
116312
|
safeParents(spelled);
|
|
115987
116313
|
let direct = false;
|
|
115988
116314
|
try {
|
|
115989
|
-
const leaf =
|
|
116315
|
+
const leaf = lstatSync37(spelled);
|
|
115990
116316
|
direct = leaf.isSymbolicLink() ? trustedAncestorOwner(leaf.uid) && directAliasTarget(spelled) === physical : spelled === physical;
|
|
115991
116317
|
} catch {}
|
|
115992
116318
|
need6(direct, COMMAND_ALIAS_UNSAFE);
|
|
@@ -115998,7 +116324,7 @@ function assertPinnedRuntime(runtime) {
|
|
|
115998
116324
|
} catch {
|
|
115999
116325
|
need6(false, "SKILLS_LAUNCHER_UNVERIFIED");
|
|
116000
116326
|
}
|
|
116001
|
-
need6(
|
|
116327
|
+
need6(resolve32(runtime) === runtime, "SKILLS_LAUNCHER_UNVERIFIED");
|
|
116002
116328
|
safeParents(runtime);
|
|
116003
116329
|
}
|
|
116004
116330
|
function skillsCommandTarget(command) {
|
|
@@ -116030,12 +116356,12 @@ function targetUnchanged(command, target) {
|
|
|
116030
116356
|
assertPinnedRuntime(target.runtime);
|
|
116031
116357
|
}
|
|
116032
116358
|
function inspectRecordedSkillsCli(command, expected) {
|
|
116033
|
-
need6(
|
|
116359
|
+
need6(isAbsolute34(command) && !command.includes("\x00"), "RECONCILE_RECORDED_COMMAND_REQUIRED");
|
|
116034
116360
|
const target = skillsCommandTarget(command), resolved = target.entry;
|
|
116035
116361
|
const cli = snapshot(resolved, false, { readOnlyPackage: true });
|
|
116036
|
-
const manifest = snapshot(
|
|
116362
|
+
const manifest = snapshot(join66(dirname38(dirname38(resolved)), "package.json"), false, { readOnlyPackage: true });
|
|
116037
116363
|
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 ===
|
|
116364
|
+
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
116365
|
need6((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
|
|
116040
116366
|
const receipt = { path: resolved, version: pkg.version, sha256: cli.sha256, manifestSha256: manifest.sha256 };
|
|
116041
116367
|
need6(isDeepStrictEqual15(receipt, expected), "RECONCILE_SKILLS_BINDING_CHANGED");
|
|
@@ -116049,16 +116375,16 @@ function bindSkillsCli(command, reviewed) {
|
|
|
116049
116375
|
const normal = Bun.which("skills", { PATH: process.env.PATH });
|
|
116050
116376
|
need6(normal, "SKILLS_COMMAND_UNAVAILABLE");
|
|
116051
116377
|
const normalTarget = skillsCommandTarget(normal), resolved = normalTarget.entry;
|
|
116052
|
-
const bound =
|
|
116378
|
+
const bound = isAbsolute34(command) ? command : command === "skills" ? normal : undefined;
|
|
116053
116379
|
need6(bound, "SKILLS_COMMAND_MISMATCH");
|
|
116054
116380
|
const boundTarget = skillsCommandTarget(bound);
|
|
116055
116381
|
need6(boundTarget.entry === resolved, "SKILLS_COMMAND_MISMATCH");
|
|
116056
116382
|
const entrypoint = reviewed?.path ?? process.argv[1];
|
|
116057
116383
|
need6(entrypoint && realpathSync19(entrypoint) === resolved, "SKILLS_ENTRYPOINT_MISMATCH");
|
|
116058
116384
|
const cli = snapshot(resolved, false, { readOnlyPackage: true });
|
|
116059
|
-
const manifest = snapshot(
|
|
116385
|
+
const manifest = snapshot(join66(dirname38(dirname38(resolved)), "package.json"), false, { readOnlyPackage: true });
|
|
116060
116386
|
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 ===
|
|
116387
|
+
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
116388
|
if (reviewed)
|
|
116063
116389
|
need6(/^[a-f0-9]{64}$/.test(reviewed.sha256) && reviewed.sha256 === cli.sha256 && reviewed.version === pkg.version, "SKILLS_RELEASE_MISMATCH");
|
|
116064
116390
|
need6((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
|
|
@@ -116077,7 +116403,7 @@ function captureSkillsCliProducerIdentity(command) {
|
|
|
116077
116403
|
const bound = bindSkillsCli(command);
|
|
116078
116404
|
const target = skillsCommandTarget(command);
|
|
116079
116405
|
const cli = snapshot(target.entry, false, { readOnlyPackage: true });
|
|
116080
|
-
const manifest = snapshot(
|
|
116406
|
+
const manifest = snapshot(join66(dirname38(dirname38(target.entry)), "package.json"), false, { readOnlyPackage: true });
|
|
116081
116407
|
const pkg = JSON.parse(manifest.text);
|
|
116082
116408
|
need6(pkg.name === "@hasna/skills" && pkg.version === bound.receipt.version && target.entry === bound.receipt.path, "SKILLS_PACKAGE_MISMATCH");
|
|
116083
116409
|
const launcher = target.launcher ?? cli;
|
|
@@ -116131,20 +116457,20 @@ var init_codex_hook_policy_recovery = __esm(() => {
|
|
|
116131
116457
|
});
|
|
116132
116458
|
|
|
116133
116459
|
// src/lib/agent-codex-trust.ts
|
|
116134
|
-
import { lstatSync as
|
|
116460
|
+
import { lstatSync as lstatSync38, mkdirSync as mkdirSync28, readdirSync as readdirSync23, readFileSync as readFileSync43, realpathSync as realpathSync20, statSync as statSync23 } from "fs";
|
|
116135
116461
|
import { createHash as createHash39, randomUUID as randomUUID12 } from "crypto";
|
|
116136
116462
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
116137
|
-
import { dirname as
|
|
116138
|
-
import { homedir as
|
|
116463
|
+
import { dirname as dirname39, isAbsolute as isAbsolute35, join as join67, resolve as resolve33 } from "path";
|
|
116464
|
+
import { homedir as homedir13 } from "os";
|
|
116139
116465
|
import { isDeepStrictEqual as isDeepStrictEqual17 } from "util";
|
|
116140
116466
|
function verifyReleaseArtifact(proof, skillsCli) {
|
|
116141
|
-
need6(
|
|
116467
|
+
need6(isAbsolute35(proof.packageTarPath) && !proof.packageTarPath.includes("\x00"), "RECONCILE_RELEASE_PROVENANCE_PATH");
|
|
116142
116468
|
const tarPath = realpathSync20(proof.packageTarPath);
|
|
116143
|
-
need6(
|
|
116469
|
+
need6(statSync23(tarPath).isFile(), "RECONCILE_RELEASE_PROVENANCE_PATH");
|
|
116144
116470
|
const tarBytes = readFileSync43(tarPath);
|
|
116145
116471
|
need6(tarBytes.byteLength === proof.packageTarBytes && createHash39("sha256").update(tarBytes).digest("hex") === proof.packageTarSha256, "RECONCILE_RELEASE_ARTIFACT_CHANGED");
|
|
116146
|
-
const packageRoot =
|
|
116147
|
-
const manifest = readFileSync43(
|
|
116472
|
+
const packageRoot = dirname39(dirname39(realpathSync20(skillsCli.receipt.path)));
|
|
116473
|
+
const manifest = readFileSync43(join67(packageRoot, "package.json"));
|
|
116148
116474
|
need6(createHash39("sha256").update(manifest).digest("hex") === skillsCli.receipt.manifestSha256 && skillsCli.receipt.manifestSha256 === proof.manifestSha256, "RECONCILE_RELEASE_MANIFEST_CHANGED");
|
|
116149
116475
|
need6(createHash39("sha256").update(readFileSync43(skillsCli.receipt.path)).digest("hex") === proof.executableSha256 && skillsCli.receipt.sha256 === proof.executableSha256, "RECONCILE_RELEASE_EXECUTABLE_CHANGED");
|
|
116150
116476
|
const members2 = [["package/package.json", manifest], ["package/bin/index.js", readFileSync43(skillsCli.receipt.path)]];
|
|
@@ -116161,26 +116487,26 @@ function verifyReleaseArtifact(proof, skillsCli) {
|
|
|
116161
116487
|
async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc) {
|
|
116162
116488
|
let rpc;
|
|
116163
116489
|
try {
|
|
116164
|
-
const home =
|
|
116165
|
-
const parent =
|
|
116490
|
+
const home = resolve33(options.home ?? homedir13()), dataDir3 = resolve33(options.dataDir ?? getDataDirReadOnly());
|
|
116491
|
+
const parent = resolve33(join67(dataDir3, "native-hook-trust")), journal = resolve33(options.journal);
|
|
116166
116492
|
need6(journal.startsWith(parent + "/") && /^[a-f0-9-]{36}$/.test(journal.slice(parent.length + 1)), "RECONCILE_JOURNAL_PATH");
|
|
116167
|
-
const dir =
|
|
116493
|
+
const dir = lstatSync38(journal, { throwIfNoEntry: false });
|
|
116168
116494
|
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(
|
|
116495
|
+
need6(!lstatSync38(join67(journal, "receipt.json"), { throwIfNoEntry: false }), "RECONCILE_ALREADY_COMPLETE");
|
|
116496
|
+
need6(lstatSync38(join67(journal, "stopped.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_JOURNAL_INCOMPLETE");
|
|
116497
|
+
const stoppedFile = snapshot(join67(journal, "stopped.json"), true);
|
|
116498
|
+
const intentFile = snapshot(join67(journal, "intent.json"), true), intent = JSON.parse(intentFile.text);
|
|
116499
|
+
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
116500
|
const legacyIntent = intent.home === undefined && intent.configSha256 === undefined && intent.configVersion === undefined && intent.declarations === undefined && intent.admitted === undefined && intent.nativeHooks === undefined;
|
|
116175
116501
|
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: `${
|
|
116502
|
+
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
116503
|
const admitted = intent.admitted ?? intent.hooks;
|
|
116178
116504
|
const configSha256 = intent.configSha256 ?? configBefore.sha256, configVersion = intent.configVersion ?? intent.expectedVersion;
|
|
116179
116505
|
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
116506
|
need6(makePlanDigest(digestInput) === intent.planDigest, "RECONCILE_PLAN_CHANGED");
|
|
116181
116507
|
need6(isDeepStrictEqual17(intent.hooks, admitted.filter((hook) => !hook.enabled || hook.trustStatus !== "trusted")), "RECONCILE_INTENT_HOOKS_CHANGED");
|
|
116182
116508
|
need6(configBefore.sha256 === (intent.beforeSha256 ?? intent.configSha256) && hooksBefore.sha256 === intent.hooksSha256 && policyBefore.sha256 === intent.policySha256, "RECONCILE_JOURNAL_CHANGED");
|
|
116183
|
-
const policyCurrent = snapshot(
|
|
116509
|
+
const policyCurrent = snapshot(join67(dataDir3, "agent-policy.json"), true);
|
|
116184
116510
|
const { claudeDiscoveryRecovery: claudeRecovery, nativeHookAdditionsRecovery: additionsRecovery } = options;
|
|
116185
116511
|
const recovery = claudeRecovery ?? additionsRecovery;
|
|
116186
116512
|
need6(!recovery || !options.supersedeBinding, "RECONCILE_RECOVERY_MODE_CONFLICT");
|
|
@@ -116197,17 +116523,17 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
116197
116523
|
if (supersededBinding || recovery) {
|
|
116198
116524
|
need6(Array.isArray(intent.nativeHooks) && intent.nativeHooks.length > 0, "RECONCILE_NATIVE_INVENTORY_REQUIRED");
|
|
116199
116525
|
const proof = options.releaseProof;
|
|
116200
|
-
need6(!!proof &&
|
|
116526
|
+
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
116527
|
}
|
|
116202
116528
|
const currentConfig = snapshot(intent.configPath, true);
|
|
116203
116529
|
const policy = parseManagedSkillPolicy(policyCurrent.text), binding = policy.bridge;
|
|
116204
|
-
const alias = binding.rootAliases?.find((item) => item.agent === "codex"), physicalRoot = alias?.target ??
|
|
116205
|
-
need6(
|
|
116530
|
+
const alias = binding.rootAliases?.find((item) => item.agent === "codex"), physicalRoot = alias?.target ?? join67(home, ".codex"), hooksPath = join67(physicalRoot, "hooks.json");
|
|
116531
|
+
need6(resolve33(intent.configPath) === resolve33(join67(physicalRoot, "config.toml")), "RECONCILE_CONFIG_PATH_CHANGED");
|
|
116206
116532
|
const nativeConfigPath = intent.nativeConfigPath ?? intent.configPath;
|
|
116207
|
-
need6([
|
|
116208
|
-
const codexHome = nativeConfigPath !== intent.configPath ? undefined :
|
|
116533
|
+
need6([join67(home, ".codex/config.toml"), join67(physicalRoot, "config.toml")].includes(nativeConfigPath), "RECONCILE_NATIVE_CONFIG_PATH_CHANGED");
|
|
116534
|
+
const codexHome = nativeConfigPath !== intent.configPath ? undefined : dirname39(nativeConfigPath);
|
|
116209
116535
|
const hooksCurrent = snapshot(hooksPath);
|
|
116210
|
-
const additions = additionsRecovery ? reviewNativeHookAdditions({ path: additionsRecovery.path, intent: intentFile, policy: policyCurrent, configBefore, configCurrent: currentConfig, hooksBefore, hooksCurrent, nativeHooksPath:
|
|
116536
|
+
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
116537
|
const managedHooks = [...intent.hooks, ...additions?.hooks ?? []];
|
|
116212
116538
|
const managedKeys = managedHooks.map((h) => h.key);
|
|
116213
116539
|
const witnessSame = codexTrustReconcileWitness(configBefore.text, managedKeys) === codexTrustReconcileWitness(currentConfig.text, managedKeys);
|
|
@@ -116271,7 +116597,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
116271
116597
|
need6(isDeepStrictEqual17(actual, expected), "RECONCILE_UNRELATED_HOOK_CHANGED");
|
|
116272
116598
|
}
|
|
116273
116599
|
for (const wanted of intent.hooks) {
|
|
116274
|
-
const matches2 = nativeHooks.filter((h2) => h2.key === wanted.key || h2.key === wanted.key.replace(
|
|
116600
|
+
const matches2 = nativeHooks.filter((h2) => h2.key === wanted.key || h2.key === wanted.key.replace(join67(home, ".codex/hooks.json"), hooksPath));
|
|
116275
116601
|
need6(matches2.length === 1, "RECONCILE_NATIVE_IDENTITY_CHANGED");
|
|
116276
116602
|
const h = matches2[0];
|
|
116277
116603
|
const trusted = h.trustStatus === "trusted";
|
|
@@ -116320,7 +116646,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
116320
116646
|
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
116647
|
if (preview2)
|
|
116322
116648
|
return receipt;
|
|
116323
|
-
save(
|
|
116649
|
+
save(join67(journal, "receipt.json"), json2(receipt));
|
|
116324
116650
|
return receipt;
|
|
116325
116651
|
} catch (error61) {
|
|
116326
116652
|
const message = error61 instanceof Error && error61.message.startsWith("CODEX_HOOK_TRUST_") ? error61.message : "CODEX_HOOK_TRUST_RECONCILE_REFUSED";
|
|
@@ -116330,21 +116656,21 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
116330
116656
|
}
|
|
116331
116657
|
}
|
|
116332
116658
|
async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRpc) {
|
|
116333
|
-
const home =
|
|
116334
|
-
return withCodexCorpusWriteAsync([
|
|
116659
|
+
const home = resolve33(options.home ?? homedir13());
|
|
116660
|
+
return withCodexCorpusWriteAsync([join67(home, ".codex")], () => enrollCodexNativeHooksUnlocked(options, connect), options);
|
|
116335
116661
|
}
|
|
116336
116662
|
async function enrollCodexNativeHooksUnlocked(options, connect) {
|
|
116337
116663
|
let rpc, journal;
|
|
116338
116664
|
try {
|
|
116339
|
-
const home =
|
|
116665
|
+
const home = resolve33(options.home ?? homedir13()), dataDir3 = resolve33(options.dataDir ?? getDataDirReadOnly());
|
|
116340
116666
|
assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home });
|
|
116341
|
-
const policyFile = snapshot(
|
|
116667
|
+
const policyFile = snapshot(join67(dataDir3, "agent-policy.json"), true), policy = parseManagedSkillPolicy(policyFile.text);
|
|
116342
116668
|
const binding = policy.bridge, alias = binding.rootAliases?.find((item) => item.agent === "codex");
|
|
116343
116669
|
const skillsCli = bindSkillsCli(binding.commands.codex, options.reviewedSkillsCli);
|
|
116344
|
-
const physicalRoot = alias?.target ??
|
|
116345
|
-
need6(options.codexHome === undefined ||
|
|
116670
|
+
const physicalRoot = alias?.target ?? join67(home, ".codex"), hooksPath = join67(physicalRoot, "hooks.json"), configPath = join67(physicalRoot, "config.toml");
|
|
116671
|
+
need6(options.codexHome === undefined || isAbsolute35(options.codexHome) && [join67(home, ".codex"), physicalRoot].includes(options.codexHome), "NATIVE_HOME_NOT_ADMITTED");
|
|
116346
116672
|
const codexHome = options.codexHome === undefined ? undefined : physicalRoot;
|
|
116347
|
-
const nativeConfigPath =
|
|
116673
|
+
const nativeConfigPath = join67(codexHome ?? join67(home, ".codex"), "config.toml");
|
|
116348
116674
|
const hooksFile = snapshot(hooksPath), configFile = snapshot(configPath, true), original = structure3(configFile.text);
|
|
116349
116675
|
const declarations = JSON.parse(hooksFile.text).hooks, expected = [];
|
|
116350
116676
|
for (const [event, [nativeEvent, label]] of Object.entries(eventNames)) {
|
|
@@ -116353,25 +116679,25 @@ async function enrollCodexNativeHooksUnlocked(options, connect) {
|
|
|
116353
116679
|
need6(Array.isArray(groups), "DECLARATION_CHANGED");
|
|
116354
116680
|
const matches2 = groups.flatMap((group, gi) => (group.hooks ?? []).flatMap((entry, hi) => entry.command === command ? [{ group, entry, gi, hi }] : []));
|
|
116355
116681
|
need6(matches2.length === 1 && isDeepStrictEqual17(matches2[0].group, { hooks: [{ type: "command", command, timeout: 15 }] }), "DECLARATION_CHANGED");
|
|
116356
|
-
expected.push({ event: nativeEvent, key: `${
|
|
116682
|
+
expected.push({ event: nativeEvent, key: `${join67(home, ".codex/hooks.json")}:${label}:${matches2[0].gi}:${matches2[0].hi}`, command });
|
|
116357
116683
|
}
|
|
116358
116684
|
codexTrustTextWitness(configFile.text, expected.map((h) => h.key));
|
|
116359
116685
|
rpc = await connect({ command: options.codexCommand ?? "codex", home, codexHome });
|
|
116360
116686
|
need6(SUPPORTED_CODEX_HOOK_VERSIONS.includes(rpc.version), "NATIVE_UNSUPPORTED_VERSION");
|
|
116361
116687
|
const list2 = async () => {
|
|
116362
116688
|
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 ${
|
|
116689
|
+
const nativeRoots = [...new Set([physicalRoot, join67(home, ".codex")])];
|
|
116690
|
+
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
116691
|
const entry = response?.data?.[0];
|
|
116366
116692
|
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
116693
|
return response.data[0].hooks;
|
|
116368
116694
|
};
|
|
116369
116695
|
const admit = (hooks) => expected.map((wanted) => {
|
|
116370
|
-
const canonicalKey = wanted.key.replace(
|
|
116696
|
+
const canonicalKey = wanted.key.replace(join67(home, ".codex/hooks.json"), hooksPath);
|
|
116371
116697
|
const matches2 = hooks.filter((h2) => h2.key === wanted.key || h2.key === canonicalKey);
|
|
116372
116698
|
need6(matches2.length === 1, "AMBIGUOUS_IDENTITY");
|
|
116373
116699
|
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,
|
|
116700
|
+
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
116701
|
need6(hooks.filter((other) => other.command === wanted.command).length === 1, "AMBIGUOUS_IDENTITY");
|
|
116376
116702
|
need6(["trusted", "untrusted", "modified"].includes(h.trustStatus), "UNKNOWN_TRUST_STATUS");
|
|
116377
116703
|
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 +116723,27 @@ async function enrollCodexNativeHooksUnlocked(options, connect) {
|
|
|
116397
116723
|
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
116724
|
if (options.apply)
|
|
116399
116725
|
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 =
|
|
116726
|
+
const parent = join67(dataDir3, "native-hook-trust");
|
|
116727
|
+
const st = lstatSync38(parent, { throwIfNoEntry: false });
|
|
116402
116728
|
if (st) {
|
|
116403
116729
|
need6(st.isDirectory() && !st.isSymbolicLink() && st.uid === process.getuid() && (st.mode & 511) === 448, "UNSAFE_JOURNAL");
|
|
116404
116730
|
const priorJournals = readdirSync23(parent);
|
|
116405
116731
|
need6(priorJournals.length < 1000, "JOURNAL_BOUND");
|
|
116406
116732
|
for (const name of priorJournals) {
|
|
116407
116733
|
need6(/^[a-f0-9-]{36}$/.test(name), "UNSAFE_JOURNAL");
|
|
116408
|
-
need6(
|
|
116734
|
+
need6(lstatSync38(join67(parent, name, "receipt.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_REQUIRED: inspect the incomplete private journal before applying again");
|
|
116409
116735
|
}
|
|
116410
116736
|
}
|
|
116411
116737
|
if (!options.apply || !planned.length)
|
|
116412
116738
|
return baseReceipt;
|
|
116413
116739
|
if (!st)
|
|
116414
116740
|
mkdirSync28(parent, { mode: 448 });
|
|
116415
|
-
journal =
|
|
116741
|
+
journal = join67(parent, randomUUID12());
|
|
116416
116742
|
mkdirSync28(journal, { mode: 448 });
|
|
116417
|
-
save(
|
|
116418
|
-
save(
|
|
116419
|
-
save(
|
|
116420
|
-
save(
|
|
116743
|
+
save(join67(journal, "config.before.toml"), configFile.bytes);
|
|
116744
|
+
save(join67(journal, "hooks.before.json"), hooksFile.bytes);
|
|
116745
|
+
save(join67(journal, "policy.before.json"), policyFile.bytes);
|
|
116746
|
+
save(join67(journal, "intent.json"), json2({ ...digestInput, planDigest, hooks: planned, nativeHooks: discovered.map(safeNativeHook) }));
|
|
116421
116747
|
need6(isDeepStrictEqual17(admit(await list2()), admitted), "NATIVE_DISCOVERY_CHANGED");
|
|
116422
116748
|
checkInputs();
|
|
116423
116749
|
let result2;
|
|
@@ -116433,7 +116759,7 @@ async function enrollCodexNativeHooksUnlocked(options, connect) {
|
|
|
116433
116759
|
for (const h of planned)
|
|
116434
116760
|
expectedConfig.hooks.state[h.key] = { ...expectedConfig.hooks.state[h.key], enabled: true, trusted_hash: h.currentHash };
|
|
116435
116761
|
need6(isDeepStrictEqual17(structure3(after2.text), expectedConfig) && codexTrustTextWitness(after2.text, keys3) === preservationText, "PRESERVATION_FAILED");
|
|
116436
|
-
const savedConfig = snapshot(
|
|
116762
|
+
const savedConfig = snapshot(join67(journal, "config.before.toml"), true);
|
|
116437
116763
|
need6(savedConfig.sha256 === configFile.sha256, "JOURNAL_CHANGED");
|
|
116438
116764
|
const discoveryTransition = binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, savedConfig, after2, planned) : undefined;
|
|
116439
116765
|
unchanged2(policyFile);
|
|
@@ -116449,13 +116775,13 @@ async function enrollCodexNativeHooksUnlocked(options, connect) {
|
|
|
116449
116775
|
skillsCli.recheck();
|
|
116450
116776
|
assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: discoveryTransition });
|
|
116451
116777
|
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(
|
|
116778
|
+
save(join67(journal, "receipt.json"), json2(receipt));
|
|
116453
116779
|
return receipt;
|
|
116454
116780
|
} catch (error61) {
|
|
116455
116781
|
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
116782
|
if (journal) {
|
|
116457
116783
|
try {
|
|
116458
|
-
save(
|
|
116784
|
+
save(join67(journal, "stopped.json"), json2({ error: message.split(":")[0], automaticRollback: false, reconcileBeforeRetry: true }));
|
|
116459
116785
|
} catch {}
|
|
116460
116786
|
}
|
|
116461
116787
|
throw new Error(message);
|
|
@@ -116490,7 +116816,7 @@ var init_agent_codex_trust = __esm(() => {
|
|
|
116490
116816
|
// src/lib/codex-native-trust.ts
|
|
116491
116817
|
import { createHash as createHash40 } from "crypto";
|
|
116492
116818
|
import { readFileSync as readFileSync44 } from "fs";
|
|
116493
|
-
import { join as
|
|
116819
|
+
import { join as join68, resolve as resolve34 } from "path";
|
|
116494
116820
|
function refuse5(detail) {
|
|
116495
116821
|
throw new Error(`NATIVE_SKILL_POLICY_TRUST_REFUSED: ${detail}`);
|
|
116496
116822
|
}
|
|
@@ -116509,7 +116835,7 @@ function planCodexNativeTrust(options) {
|
|
|
116509
116835
|
refuse5("digests must be unique");
|
|
116510
116836
|
if (typeof expectedPolicySha256 !== "string" || !HEX_DIGEST2.test(expectedPolicySha256))
|
|
116511
116837
|
refuse5("--expected-policy-sha256 must be lowercase SHA-256 hex");
|
|
116512
|
-
const dataDir3 =
|
|
116838
|
+
const dataDir3 = resolve34(options.dataDir ?? getDataDirReadOnly()), policyPath = join68(dataDir3, "agent-policy.json");
|
|
116513
116839
|
assertOperatorTrustRoot(dataDir3);
|
|
116514
116840
|
const snapshot2 = readManagedSkillPolicySnapshot(dataDir3);
|
|
116515
116841
|
if (!snapshot2)
|
|
@@ -116692,8 +117018,8 @@ var init_hook_diagnostics = __esm(() => {
|
|
|
116692
117018
|
|
|
116693
117019
|
// src/lib/claude-prospective-review.ts
|
|
116694
117020
|
import { createHash as createHash41 } from "crypto";
|
|
116695
|
-
import { lstatSync as
|
|
116696
|
-
import { basename as basename19, dirname as
|
|
117021
|
+
import { lstatSync as lstatSync39, readFileSync as readFileSync45, readdirSync as readdirSync24, realpathSync as realpathSync21 } from "fs";
|
|
117022
|
+
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
117023
|
import { isDeepStrictEqual as isDeepStrictEqual18 } from "util";
|
|
116698
117024
|
function hashClaudeDiscoveryBinding(binding) {
|
|
116699
117025
|
return sha7(JSON.stringify(binding));
|
|
@@ -116744,7 +117070,7 @@ function keys3(value, expected, name) {
|
|
|
116744
117070
|
refuse6(`${name} has an unsupported shape`);
|
|
116745
117071
|
}
|
|
116746
117072
|
function abs(path, name) {
|
|
116747
|
-
if (typeof path !== "string" || !path || path.length > 4096 || /[\x00-\x1f\x7f]/.test(path) || !
|
|
117073
|
+
if (typeof path !== "string" || !path || path.length > 4096 || /[\x00-\x1f\x7f]/.test(path) || !isAbsolute36(path) || resolve35(path) !== path)
|
|
116748
117074
|
refuse6(`${name} must be a normalized absolute path`);
|
|
116749
117075
|
}
|
|
116750
117076
|
function validUtcTimestamp(value) {
|
|
@@ -116752,27 +117078,27 @@ function validUtcTimestamp(value) {
|
|
|
116752
117078
|
}
|
|
116753
117079
|
function safeFile(path, name) {
|
|
116754
117080
|
abs(path, name);
|
|
116755
|
-
for (let at2 =
|
|
116756
|
-
const stat4 =
|
|
117081
|
+
for (let at2 = dirname40(path);; at2 = dirname40(at2)) {
|
|
117082
|
+
const stat4 = lstatSync39(at2, { throwIfNoEntry: false });
|
|
116757
117083
|
if (!stat4?.isDirectory() || stat4.isSymbolicLink())
|
|
116758
117084
|
refuse6(`${name} traverses a symlink or non-directory`);
|
|
116759
|
-
if (at2 ===
|
|
117085
|
+
if (at2 === dirname40(at2))
|
|
116760
117086
|
break;
|
|
116761
117087
|
}
|
|
116762
|
-
const stat3 =
|
|
117088
|
+
const stat3 = lstatSync39(path, { throwIfNoEntry: false });
|
|
116763
117089
|
if (!stat3?.isFile() || stat3.isSymbolicLink() || stat3.size > MAX_CANDIDATE_BYTES)
|
|
116764
117090
|
refuse6(`${name} is not a bounded regular file`);
|
|
116765
117091
|
return readFileSync45(path);
|
|
116766
117092
|
}
|
|
116767
117093
|
function canonicalDir(path, name) {
|
|
116768
117094
|
abs(path, name);
|
|
116769
|
-
if (realpathSync21(path) !== path || !
|
|
117095
|
+
if (realpathSync21(path) !== path || !lstatSync39(path).isDirectory())
|
|
116770
117096
|
refuse6(`${name} is not a canonical directory`);
|
|
116771
|
-
for (let at2 = path;; at2 =
|
|
116772
|
-
const stat3 =
|
|
117097
|
+
for (let at2 = path;; at2 = dirname40(at2)) {
|
|
117098
|
+
const stat3 = lstatSync39(at2);
|
|
116773
117099
|
if (!stat3.isDirectory() || stat3.isSymbolicLink())
|
|
116774
117100
|
refuse6(`${name} traverses a symlink`);
|
|
116775
|
-
if (at2 ===
|
|
117101
|
+
if (at2 === dirname40(at2))
|
|
116776
117102
|
break;
|
|
116777
117103
|
}
|
|
116778
117104
|
}
|
|
@@ -116781,17 +117107,17 @@ function captureClaudeProspectiveCandidateClosure(root2) {
|
|
|
116781
117107
|
const entries = [];
|
|
116782
117108
|
let bytes = 0;
|
|
116783
117109
|
const walk2 = (directory2) => {
|
|
116784
|
-
const beforeDirectory =
|
|
117110
|
+
const beforeDirectory = lstatSync39(directory2);
|
|
116785
117111
|
const names = readdirSync24(directory2).sort();
|
|
116786
117112
|
if (new Set(names).size !== names.length)
|
|
116787
117113
|
refuse6("candidate contains ambiguous directory entries");
|
|
116788
117114
|
for (const name of names) {
|
|
116789
117115
|
if (!name || name === "." || name === ".." || name.includes("/") || name.includes("\\") || /[\x00-\x1f\x7f]/.test(name))
|
|
116790
117116
|
refuse6("candidate contains an unsupported path member");
|
|
116791
|
-
const path =
|
|
117117
|
+
const path = join69(directory2, name), rel = relative12(root2, path).split(sep15).join("/");
|
|
116792
117118
|
if (entries.length >= MAX_CANDIDATE_FILES)
|
|
116793
117119
|
refuse6("candidate closure exceeds its member limit");
|
|
116794
|
-
const stat3 =
|
|
117120
|
+
const stat3 = lstatSync39(path);
|
|
116795
117121
|
if (stat3.isSymbolicLink())
|
|
116796
117122
|
refuse6("candidate closure contains a symlink");
|
|
116797
117123
|
if (stat3.isDirectory()) {
|
|
@@ -116801,14 +117127,14 @@ function captureClaudeProspectiveCandidateClosure(root2) {
|
|
|
116801
117127
|
bytes += stat3.size;
|
|
116802
117128
|
if (bytes > MAX_CANDIDATE_BYTES)
|
|
116803
117129
|
refuse6("candidate closure exceeds its byte limit");
|
|
116804
|
-
const content = safeFile(path, "candidate member"), after2 =
|
|
117130
|
+
const content = safeFile(path, "candidate member"), after2 = lstatSync39(path);
|
|
116805
117131
|
if (!after2.isFile() || after2.dev !== stat3.dev || after2.ino !== stat3.ino || after2.size !== stat3.size || after2.mtimeMs !== stat3.mtimeMs || after2.ctimeMs !== stat3.ctimeMs)
|
|
116806
117132
|
refuse6("candidate member changed while being read");
|
|
116807
117133
|
entries.push([rel, "file", sha7(content)]);
|
|
116808
117134
|
} else
|
|
116809
117135
|
refuse6("candidate closure contains a special file");
|
|
116810
117136
|
}
|
|
116811
|
-
const afterDirectory =
|
|
117137
|
+
const afterDirectory = lstatSync39(directory2);
|
|
116812
117138
|
if (!afterDirectory.isDirectory() || afterDirectory.dev !== beforeDirectory.dev || afterDirectory.ino !== beforeDirectory.ino || afterDirectory.mtimeMs !== beforeDirectory.mtimeMs || afterDirectory.ctimeMs !== beforeDirectory.ctimeMs)
|
|
116813
117139
|
refuse6("candidate directory changed while being read");
|
|
116814
117140
|
};
|
|
@@ -116819,9 +117145,9 @@ function captureClaudeProspectiveCandidateClosure(root2) {
|
|
|
116819
117145
|
function captureClaudeInstallerCandidate(root2, policyPath) {
|
|
116820
117146
|
const closureSha256 = captureClaudeProspectiveCandidateClosure(root2);
|
|
116821
117147
|
const dataDir3 = getDataDirReadOnly();
|
|
116822
|
-
if (policyPath !==
|
|
117148
|
+
if (policyPath !== join69(dataDir3, "agent-policy.json"))
|
|
116823
117149
|
refuse6("Skills policy path differs from the package-owned resolver");
|
|
116824
|
-
const catalogPath =
|
|
117150
|
+
const catalogPath = join69(root2, ".claude-plugin/marketplace.json");
|
|
116825
117151
|
const catalog = jsonFile(catalogPath, "candidate catalog");
|
|
116826
117152
|
if (!catalog || !Array.isArray(catalog.plugins))
|
|
116827
117153
|
refuse6("candidate catalog is invalid");
|
|
@@ -116832,13 +117158,13 @@ function captureClaudeInstallerCandidate(root2, policyPath) {
|
|
|
116832
117158
|
if (names.has(row2.name))
|
|
116833
117159
|
refuse6("candidate catalog repeats a plugin name");
|
|
116834
117160
|
names.add(row2.name);
|
|
116835
|
-
if (typeof row2.source !== "string" ||
|
|
117161
|
+
if (typeof row2.source !== "string" || isAbsolute36(row2.source) || /[\\\x00-\x1f\x7f]/.test(row2.source))
|
|
116836
117162
|
refuse6("candidate catalog plugin source is invalid");
|
|
116837
|
-
const pluginRoot =
|
|
117163
|
+
const pluginRoot = resolve35(root2, row2.source);
|
|
116838
117164
|
const relativeRoot = relative12(root2, pluginRoot);
|
|
116839
|
-
if (!relativeRoot || relativeRoot === "." || relativeRoot === ".." || relativeRoot.startsWith(`..${sep15}`) ||
|
|
117165
|
+
if (!relativeRoot || relativeRoot === "." || relativeRoot === ".." || relativeRoot.startsWith(`..${sep15}`) || isAbsolute36(relativeRoot))
|
|
116840
117166
|
refuse6("candidate plugin source escapes the candidate root");
|
|
116841
|
-
const path =
|
|
117167
|
+
const path = join69(pluginRoot, ".claude-plugin/plugin.json");
|
|
116842
117168
|
return { plugin: row2.name, ...captureClaudePluginManifestFile(path) };
|
|
116843
117169
|
});
|
|
116844
117170
|
const policy = readManagedSkillPolicySnapshot(dataDir3);
|
|
@@ -116855,7 +117181,7 @@ function captureClaudeInstallerCandidate(root2, policyPath) {
|
|
|
116855
117181
|
}
|
|
116856
117182
|
function readWitness(path, expected, name) {
|
|
116857
117183
|
abs(path, `${name} path`);
|
|
116858
|
-
const stat3 =
|
|
117184
|
+
const stat3 = lstatSync39(path, { throwIfNoEntry: false });
|
|
116859
117185
|
if (expected === null) {
|
|
116860
117186
|
if (stat3)
|
|
116861
117187
|
refuse6(`${name} was absent at review but is now present`);
|
|
@@ -116867,7 +117193,7 @@ function readWitness(path, expected, name) {
|
|
|
116867
117193
|
refuse6(`${name} preimage changed`);
|
|
116868
117194
|
}
|
|
116869
117195
|
function jsonFile(path, name) {
|
|
116870
|
-
const stat3 =
|
|
117196
|
+
const stat3 = lstatSync39(path, { throwIfNoEntry: false });
|
|
116871
117197
|
if (!stat3)
|
|
116872
117198
|
return null;
|
|
116873
117199
|
let value;
|
|
@@ -116898,8 +117224,8 @@ function assertNoUnprojectedSkillPayload(root2, catalogPath, marketplace, plugin
|
|
|
116898
117224
|
refuse6("candidate marketplace entry declares native skill or command payloads");
|
|
116899
117225
|
const walk2 = (directory2) => {
|
|
116900
117226
|
for (const name of readdirSync24(directory2).sort()) {
|
|
116901
|
-
const path =
|
|
116902
|
-
const stat3 =
|
|
117227
|
+
const path = join69(directory2, name), rel = relative12(root2, path).split(sep15).join("/");
|
|
117228
|
+
const stat3 = lstatSync39(path);
|
|
116903
117229
|
if (stat3.isDirectory())
|
|
116904
117230
|
walk2(path);
|
|
116905
117231
|
else if (stat3.isFile()) {
|
|
@@ -116956,16 +117282,16 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
116956
117282
|
refuse6("Skills policy root alias changed or is invalid");
|
|
116957
117283
|
}
|
|
116958
117284
|
const canonical8 = (path) => canonicalAgentPath(path, aliases);
|
|
116959
|
-
const configRoot = canonical8(
|
|
117285
|
+
const configRoot = canonical8(join69(request2.native.home, ".claude"));
|
|
116960
117286
|
canonicalDir(configRoot, "Claude config root");
|
|
116961
117287
|
if (request2.native.configRoot !== configRoot)
|
|
116962
117288
|
refuse6("Claude config root differs from the current resolver and reviewed root alias");
|
|
116963
|
-
const pluginRoot =
|
|
117289
|
+
const pluginRoot = join69(configRoot, "plugins");
|
|
116964
117290
|
if (process.env.CLAUDE_CODE_PLUGIN_CACHE_DIR)
|
|
116965
117291
|
refuse6("CLAUDE_CODE_PLUGIN_CACHE_DIR overrides are unsupported by this prospective schema; bind and review the actual cache root first");
|
|
116966
117292
|
if (request2.native.pluginRoot !== pluginRoot)
|
|
116967
117293
|
refuse6("Claude plugin root differs from the supported standard plugins directory; Cowork and custom cache roots require a separately bound schema");
|
|
116968
|
-
const pluginRootStat =
|
|
117294
|
+
const pluginRootStat = lstatSync39(pluginRoot, { throwIfNoEntry: false });
|
|
116969
117295
|
if (pluginRootStat && (!pluginRootStat.isDirectory() || pluginRootStat.isSymbolicLink()))
|
|
116970
117296
|
refuse6("Claude plugin root is not a regular directory");
|
|
116971
117297
|
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 +117308,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
116982
117308
|
abs(candidate2.catalogPath, "catalog path");
|
|
116983
117309
|
if (!candidate2.catalogPath.startsWith(candidate2.root + sep15))
|
|
116984
117310
|
refuse6("catalog must be inside the frozen candidate root");
|
|
116985
|
-
if (candidate2.catalogPath !==
|
|
117311
|
+
if (candidate2.catalogPath !== join69(candidate2.root, ".claude-plugin", "marketplace.json"))
|
|
116986
117312
|
refuse6("marketplace catalog must be at the frozen root's .claude-plugin/marketplace.json path");
|
|
116987
117313
|
if (!SHA256.test(candidate2.catalogSha256) || !SHA256.test(candidate2.closureSha256))
|
|
116988
117314
|
refuse6("candidate digests must be lowercase SHA-256");
|
|
@@ -117024,11 +117350,11 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
117024
117350
|
if (Buffer.byteLength(canonicalJson3(selected.optionsPatch), "utf8") > 16 * 1024)
|
|
117025
117351
|
refuse6("selected plugin optionsPatch exceeds its byte bound");
|
|
117026
117352
|
abs(selected.manifestPath, "manifest path");
|
|
117027
|
-
if (!selected.manifestPath.startsWith(candidate2.root + sep15) || basename19(
|
|
117353
|
+
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
117354
|
refuse6("plugin manifest must be under a plugin root inside the frozen marketplace closure");
|
|
117029
|
-
const pluginRoot2 =
|
|
117355
|
+
const pluginRoot2 = dirname40(dirname40(selected.manifestPath));
|
|
117030
117356
|
const relativePluginRoot = relative12(candidate2.root, pluginRoot2);
|
|
117031
|
-
if (!relativePluginRoot || relativePluginRoot === "." || relativePluginRoot === ".." || relativePluginRoot.startsWith(`..${sep15}`) ||
|
|
117357
|
+
if (!relativePluginRoot || relativePluginRoot === "." || relativePluginRoot === ".." || relativePluginRoot.startsWith(`..${sep15}`) || isAbsolute36(relativePluginRoot))
|
|
117032
117358
|
refuse6("plugin root must be a child of the frozen marketplace root");
|
|
117033
117359
|
canonicalDir(pluginRoot2, "candidate plugin root");
|
|
117034
117360
|
if (!SHA256.test(selected.manifestSha256))
|
|
@@ -117062,7 +117388,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
117062
117388
|
const sourcePath = selectedEntry.source;
|
|
117063
117389
|
const sourceRelativePath = relative12(candidate2.root, pluginRoot2).split(sep15).join("/");
|
|
117064
117390
|
const expectedSourcePath = sourceRelativePath === "." ? "./" : `./${sourceRelativePath}`;
|
|
117065
|
-
if (typeof sourcePath !== "string" ||
|
|
117391
|
+
if (typeof sourcePath !== "string" || isAbsolute36(sourcePath) || sourcePath !== expectedSourcePath || resolve35(dirname40(dirname40(candidate2.catalogPath)), sourcePath) !== pluginRoot2)
|
|
117066
117392
|
refuse6("marketplace source does not resolve to the frozen plugin closure; external source mapping is not supported by this schema");
|
|
117067
117393
|
const entry = captureClaudeMarketplaceEntry(candidate2.catalogPath, candidate2.marketplace, selected.plugin);
|
|
117068
117394
|
if (entry.sha256.length !== 64)
|
|
@@ -117082,12 +117408,12 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
117082
117408
|
for (const name of ["settings", "projectSettings", "projectSettingsLocal", "marketplaces", "installedPlugins"])
|
|
117083
117409
|
keys3(request2.preimages[name], ["path", "sha256"], `${name} preimage`);
|
|
117084
117410
|
const expectedPaths = {
|
|
117085
|
-
settings: request2.scope.kind === "project" ? canonical8(
|
|
117086
|
-
userSettings: canonical8(
|
|
117087
|
-
projectSettings: canonical8(
|
|
117088
|
-
projectSettingsLocal: canonical8(
|
|
117089
|
-
marketplaces: canonical8(
|
|
117090
|
-
installedPlugins: canonical8(
|
|
117411
|
+
settings: request2.scope.kind === "project" ? canonical8(join69(request2.scope.projectPath, ".claude/settings.json")) : canonical8(join69(request2.native.home, ".claude/settings.json")),
|
|
117412
|
+
userSettings: canonical8(join69(request2.native.home, ".claude/settings.json")),
|
|
117413
|
+
projectSettings: canonical8(join69(request2.scope.projectPath, ".claude/settings.json")),
|
|
117414
|
+
projectSettingsLocal: canonical8(join69(request2.scope.projectPath, ".claude/settings.local.json")),
|
|
117415
|
+
marketplaces: canonical8(join69(request2.native.home, ".claude/plugins/known_marketplaces.json")),
|
|
117416
|
+
installedPlugins: canonical8(join69(request2.native.home, ".claude/plugins/installed_plugins.json"))
|
|
117091
117417
|
};
|
|
117092
117418
|
for (const name of Object.keys(expectedPaths)) {
|
|
117093
117419
|
const witness = request2.preimages[name];
|
|
@@ -117205,7 +117531,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
117205
117531
|
const manifestVersion = manifest.version;
|
|
117206
117532
|
const sanitizeComponent = (value) => value.replace(/[^A-Za-z0-9_-]/g, "-");
|
|
117207
117533
|
const sanitizedVersion = manifestVersion === "." || manifestVersion === ".." ? "-" : manifestVersion.replace(/[^A-Za-z0-9._-]/g, "-");
|
|
117208
|
-
const expectedInstallPath =
|
|
117534
|
+
const expectedInstallPath = join69(pluginRoot, "cache", sanitizeComponent(candidate2.marketplace), sanitizeComponent(plugin), sanitizedVersion);
|
|
117209
117535
|
if (expectedInstallPath.length > 4096)
|
|
117210
117536
|
refuse6("candidate native cache path exceeds its bound");
|
|
117211
117537
|
const targetRegistration = {
|
|
@@ -117343,7 +117669,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
117343
117669
|
{ name: "project-settings-local", path: expectedPaths.projectSettingsLocal, sha256: request2.preimages.projectSettingsLocal.sha256 },
|
|
117344
117670
|
{ name: "known-marketplaces", path: expectedPaths.marketplaces, sha256: request2.preimages.marketplaces.sha256 },
|
|
117345
117671
|
{ name: "installed-plugins", path: expectedPaths.installedPlugins, sha256: request2.preimages.installedPlugins.sha256 },
|
|
117346
|
-
{ name: "skills-policy", path:
|
|
117672
|
+
{ name: "skills-policy", path: join69(request2.skills.dataDir, "agent-policy.json"), sha256: request2.skills.policySha256 }
|
|
117347
117673
|
],
|
|
117348
117674
|
ownedDelta: { settingsEnabledPlugins: selectedPluginIds, selectedPluginOptions: selectedOptionPaths, functionHooksEnv: candidate2.functionHooksEnv ?? null, knownMarketplace: candidate2.marketplace, installedPlugins: selectedPluginIds, unrelatedGraph: "preserved-by-complete-semantic-documents" },
|
|
117349
117675
|
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 +117695,10 @@ var init_claude_prospective_review = __esm(() => {
|
|
|
117369
117695
|
|
|
117370
117696
|
// src/lib/self-spawn.ts
|
|
117371
117697
|
import { realpathSync as realpathSync22 } from "fs";
|
|
117372
|
-
import { dirname as
|
|
117698
|
+
import { dirname as dirname41, isAbsolute as isAbsolute37, sep as sep16 } from "path";
|
|
117373
117699
|
function selfSpawnRoot(entry) {
|
|
117374
117700
|
const index = entry.indexOf(INSTALLED_PACKAGE);
|
|
117375
|
-
const root2 = index > 0 ? entry.slice(0, index) :
|
|
117701
|
+
const root2 = index > 0 ? entry.slice(0, index) : dirname41(entry);
|
|
117376
117702
|
try {
|
|
117377
117703
|
return realpathSync22(root2);
|
|
117378
117704
|
} catch {
|
|
@@ -117382,12 +117708,12 @@ function selfSpawnRoot(entry) {
|
|
|
117382
117708
|
function selfSpawnCommand(args2, options = {}) {
|
|
117383
117709
|
const runtime = options.runtime ?? process.execPath;
|
|
117384
117710
|
const entry = options.entry ?? process.argv[1];
|
|
117385
|
-
if (!runtime || !
|
|
117711
|
+
if (!runtime || !isAbsolute37(runtime) || !entry || !isAbsolute37(entry))
|
|
117386
117712
|
throw new Error("SKILLS_SELF_SPAWN_ENTRY_UNRESOLVED");
|
|
117387
117713
|
const root2 = selfSpawnRoot(entry);
|
|
117388
117714
|
const env3 = pinnedLauncherEnvironment(options.env ?? process.env);
|
|
117389
117715
|
env3[LAUNCH_CWD_VARIABLE] = options.callerCwd ?? process.cwd();
|
|
117390
|
-
return { command: [runtime, ...
|
|
117716
|
+
return { command: [runtime, ...PINNED_LAUNCHER_BUN_FLAGS2, `--cwd=${root2}`, entry, ...args2], cwd: root2, env: env3 };
|
|
117391
117717
|
}
|
|
117392
117718
|
var INSTALLED_PACKAGE;
|
|
117393
117719
|
var init_self_spawn = __esm(() => {
|
|
@@ -117396,8 +117722,8 @@ var init_self_spawn = __esm(() => {
|
|
|
117396
117722
|
});
|
|
117397
117723
|
|
|
117398
117724
|
// src/cli/commands/claude-installer-capture.ts
|
|
117399
|
-
import { closeSync as closeSync26, constants as
|
|
117400
|
-
import { isAbsolute as
|
|
117725
|
+
import { closeSync as closeSync26, constants as constants25, fstatSync as fstatSync26, lstatSync as lstatSync40, openSync as openSync26, readSync as readSync19 } from "fs";
|
|
117726
|
+
import { isAbsolute as isAbsolute38, resolve as resolve36 } from "path";
|
|
117401
117727
|
function need8(condition, code2) {
|
|
117402
117728
|
if (!condition)
|
|
117403
117729
|
throw new CaptureRefusal(code2);
|
|
@@ -117411,14 +117737,14 @@ function exactKeys4(value, expected, operation) {
|
|
|
117411
117737
|
}
|
|
117412
117738
|
}
|
|
117413
117739
|
function canonicalPath2(value) {
|
|
117414
|
-
need8(typeof value === "string" &&
|
|
117740
|
+
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
117741
|
}
|
|
117416
117742
|
function readRequest2(path) {
|
|
117417
117743
|
canonicalPath2(path);
|
|
117418
|
-
const before2 =
|
|
117744
|
+
const before2 = lstatSync40(path, { throwIfNoEntry: false });
|
|
117419
117745
|
if (!before2?.isFile() || before2.isSymbolicLink() || before2.size > MAX_REQUEST_BYTES)
|
|
117420
117746
|
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,
|
|
117747
|
+
const fd = openSync26(path, constants25.O_RDONLY | (constants25.O_NOFOLLOW ?? 0) | constants25.O_NONBLOCK);
|
|
117422
117748
|
try {
|
|
117423
117749
|
const opened = fstatSync26(fd);
|
|
117424
117750
|
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 +117756,7 @@ function readRequest2(path) {
|
|
|
117430
117756
|
break;
|
|
117431
117757
|
length += count;
|
|
117432
117758
|
}
|
|
117433
|
-
const after2 = fstatSync26(fd), current =
|
|
117759
|
+
const after2 = fstatSync26(fd), current = lstatSync40(path);
|
|
117434
117760
|
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
117761
|
try {
|
|
117436
117762
|
return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, length)));
|
|
@@ -117562,10 +117888,10 @@ var exports_agent_integration = {};
|
|
|
117562
117888
|
__export(exports_agent_integration, {
|
|
117563
117889
|
registerAgentIntegration: () => registerAgentIntegration
|
|
117564
117890
|
});
|
|
117565
|
-
import { existsSync as existsSync36, lstatSync as
|
|
117891
|
+
import { existsSync as existsSync36, lstatSync as lstatSync41, readFileSync as readFileSync46, readSync as readSync20, writeFileSync as writeFileSync27 } from "fs";
|
|
117566
117892
|
import { createHash as createHash42 } from "crypto";
|
|
117567
|
-
import { homedir as
|
|
117568
|
-
import { isAbsolute as
|
|
117893
|
+
import { homedir as homedir14 } from "os";
|
|
117894
|
+
import { isAbsolute as isAbsolute39 } from "path";
|
|
117569
117895
|
function pinnedHookProfile(input3, configuredProfile) {
|
|
117570
117896
|
try {
|
|
117571
117897
|
const parsed = parseSkillContextInput(JSON.stringify(input3));
|
|
@@ -117661,13 +117987,13 @@ function registerAgentIntegration(parent) {
|
|
|
117661
117987
|
});
|
|
117662
117988
|
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
117989
|
try {
|
|
117664
|
-
if (!
|
|
117990
|
+
if (!isAbsolute39(options.cwd) || !isAbsolute39(options.output))
|
|
117665
117991
|
throw new Error("CODEX_NATIVE_SKILL_CATALOG_ABSOLUTE_PATH_REQUIRED");
|
|
117666
117992
|
if (existsSync36(options.output))
|
|
117667
117993
|
throw new Error("CODEX_NATIVE_SKILL_CATALOG_OUTPUT_EXISTS");
|
|
117668
117994
|
const catalog = await captureCodexNativeSkillCatalog({
|
|
117669
117995
|
command: options.codexCommand,
|
|
117670
|
-
home:
|
|
117996
|
+
home: homedir14(),
|
|
117671
117997
|
...process.env.CODEX_HOME === undefined ? {} : { codexHome: process.env.CODEX_HOME },
|
|
117672
117998
|
cwd: options.cwd
|
|
117673
117999
|
});
|
|
@@ -117680,7 +118006,7 @@ function registerAgentIntegration(parent) {
|
|
|
117680
118006
|
throw new Error("CODEX_NATIVE_SKILL_CATALOG_OUTPUT_EXISTS");
|
|
117681
118007
|
throw error61;
|
|
117682
118008
|
}
|
|
117683
|
-
const written =
|
|
118009
|
+
const written = lstatSync41(options.output);
|
|
117684
118010
|
if (!written.isFile() || written.isSymbolicLink() || (written.mode & 63) !== 0 || readFileSync46(options.output, "utf8") !== bytes)
|
|
117685
118011
|
throw new Error("CODEX_NATIVE_SKILL_CATALOG_READBACK_FAILED");
|
|
117686
118012
|
const receipt = {
|
|
@@ -117728,9 +118054,9 @@ function registerAgentIntegration(parent) {
|
|
|
117728
118054
|
});
|
|
117729
118055
|
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
118056
|
try {
|
|
117731
|
-
if (!
|
|
118057
|
+
if (!isAbsolute39(options.request))
|
|
117732
118058
|
throw new Error("CLAUDE_CANDIDATE_REVIEW_REFUSED: --request must be an absolute path");
|
|
117733
|
-
const stat3 =
|
|
118059
|
+
const stat3 = lstatSync41(options.request);
|
|
117734
118060
|
if (!stat3.isFile() || stat3.isSymbolicLink() || stat3.size > 1024 * 1024)
|
|
117735
118061
|
throw new Error("CLAUDE_CANDIDATE_REVIEW_REFUSED: request must be a regular file no larger than 1 MiB");
|
|
117736
118062
|
const requestBytes = readFileSync46(options.request);
|
|
@@ -117775,10 +118101,10 @@ function registerAgentIntegration(parent) {
|
|
|
117775
118101
|
hook.command("agents").option("--json", "Output the adapter capability inventory", false).description("Show maintained native adapters and explicit coverage limits").action(async () => {
|
|
117776
118102
|
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
118103
|
});
|
|
117778
|
-
hook.command("install").option("--agent <agent>", `Agent to configure: ${INTEGRATION_AGENTS.join(", ")}, all
|
|
118104
|
+
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
118105
|
try {
|
|
117780
118106
|
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 });
|
|
118107
|
+
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
118108
|
const result2 = options.apply ? applyAgentIntegration(plan) : { changed: [], backups: [] };
|
|
117783
118109
|
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
118110
|
if (options.json)
|
|
@@ -117850,12 +118176,12 @@ function registerAgentIntegration(parent) {
|
|
|
117850
118176
|
input3.hook_event_name = event;
|
|
117851
118177
|
const projects = [process.cwd()];
|
|
117852
118178
|
if (input3.cwd !== undefined) {
|
|
117853
|
-
if (typeof input3.cwd !== "string" || !
|
|
118179
|
+
if (typeof input3.cwd !== "string" || !isAbsolute39(input3.cwd) || input3.cwd.includes("\x00"))
|
|
117854
118180
|
throw new Error("Invalid native hook working directory");
|
|
117855
118181
|
projects.push(input3.cwd);
|
|
117856
118182
|
}
|
|
117857
118183
|
if (options.agent === "cursor") {
|
|
117858
|
-
if (!Array.isArray(input3.workspace_roots) || input3.workspace_roots.length > 32 || input3.workspace_roots.some((path) => typeof path !== "string" || !
|
|
118184
|
+
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
118185
|
throw new Error("Invalid Cursor workspace roots");
|
|
117860
118186
|
projects.push(...input3.workspace_roots);
|
|
117861
118187
|
input3.cwd ??= input3.workspace_roots[0] ?? process.cwd();
|
|
@@ -117981,6 +118307,7 @@ var init_agent_integration2 = __esm(() => {
|
|
|
117981
118307
|
init_agent_hermes();
|
|
117982
118308
|
init_context();
|
|
117983
118309
|
init_agent_adapters();
|
|
118310
|
+
init_agent_install_selection();
|
|
117984
118311
|
init_agent_integration();
|
|
117985
118312
|
init_agent_codex_trust();
|
|
117986
118313
|
init_codex_native_skill_policy();
|
|
@@ -118133,9 +118460,9 @@ var exports_profiles = {};
|
|
|
118133
118460
|
__export(exports_profiles, {
|
|
118134
118461
|
registerProfiles: () => registerProfiles
|
|
118135
118462
|
});
|
|
118136
|
-
import { closeSync as closeSync27, constants as
|
|
118463
|
+
import { closeSync as closeSync27, constants as constants26, fstatSync as fstatSync27, openSync as openSync27, readSync as readSync21, writeFileSync as writeFileSync28 } from "fs";
|
|
118137
118464
|
function readProfileInput(path) {
|
|
118138
|
-
const fd = openSync27(path,
|
|
118465
|
+
const fd = openSync27(path, constants26.O_RDONLY | constants26.O_NONBLOCK);
|
|
118139
118466
|
try {
|
|
118140
118467
|
const stat3 = fstatSync27(fd);
|
|
118141
118468
|
if (!stat3.isFile() || stat3.size > MAX_PROFILE_DOCUMENT_BYTES)
|
|
@@ -118203,7 +118530,7 @@ __export(exports_grants, {
|
|
|
118203
118530
|
registerGrants: () => registerGrants
|
|
118204
118531
|
});
|
|
118205
118532
|
import {
|
|
118206
|
-
constants as
|
|
118533
|
+
constants as constants27,
|
|
118207
118534
|
closeSync as closeSync28,
|
|
118208
118535
|
fstatSync as fstatSync28,
|
|
118209
118536
|
openSync as openSync28,
|
|
@@ -118211,7 +118538,7 @@ import {
|
|
|
118211
118538
|
writeFileSync as writeFileSync29
|
|
118212
118539
|
} from "fs";
|
|
118213
118540
|
function readInput(path) {
|
|
118214
|
-
const fd = openSync28(path,
|
|
118541
|
+
const fd = openSync28(path, constants27.O_RDONLY | constants27.O_NONBLOCK);
|
|
118215
118542
|
try {
|
|
118216
118543
|
const stat3 = fstatSync28(fd);
|
|
118217
118544
|
if (!stat3.isFile() || stat3.size > MAX_EXECUTION_GRANT_BYTES)
|
|
@@ -118274,19 +118601,19 @@ import {
|
|
|
118274
118601
|
mkdirSync as mkdirSync29,
|
|
118275
118602
|
readdirSync as readdirSync25,
|
|
118276
118603
|
readFileSync as readFileSync47,
|
|
118277
|
-
statSync as
|
|
118604
|
+
statSync as statSync24,
|
|
118278
118605
|
writeFileSync as writeFileSync30
|
|
118279
118606
|
} from "fs";
|
|
118280
|
-
import { dirname as
|
|
118607
|
+
import { dirname as dirname42, join as join70, resolve as resolve37, sep as sep17 } from "path";
|
|
118281
118608
|
function fail6(code2, message, detail = []) {
|
|
118282
118609
|
throw new StationSnapshotError(code2, message, detail);
|
|
118283
118610
|
}
|
|
118284
118611
|
function snapshotRootFor(repoRoot, stationId) {
|
|
118285
|
-
return
|
|
118612
|
+
return join70(repoRoot, "resources", stationId, "skills");
|
|
118286
118613
|
}
|
|
118287
118614
|
function readSnapshotManifest(repoRoot, stationId) {
|
|
118288
118615
|
const snapshotRoot = snapshotRootFor(repoRoot, stationId);
|
|
118289
|
-
const manifestPath =
|
|
118616
|
+
const manifestPath = join70(snapshotRoot, "sync-manifest.json");
|
|
118290
118617
|
let manifest;
|
|
118291
118618
|
try {
|
|
118292
118619
|
manifest = JSON.parse(readFileSync47(manifestPath, "utf8"));
|
|
@@ -118313,7 +118640,7 @@ function planStationHydration(stationId, repoRoot) {
|
|
|
118313
118640
|
const hashMismatches = [];
|
|
118314
118641
|
const skippedByRule = [];
|
|
118315
118642
|
for (const agent of SYNC_AGENTS) {
|
|
118316
|
-
const agentRoot =
|
|
118643
|
+
const agentRoot = join70(snapshotRoot, "agent-homes", agent);
|
|
118317
118644
|
let identEntries;
|
|
118318
118645
|
try {
|
|
118319
118646
|
identEntries = readdirSync25(agentRoot, { withFileTypes: true });
|
|
@@ -118324,7 +118651,7 @@ function planStationHydration(stationId, repoRoot) {
|
|
|
118324
118651
|
if (!identEntry.isDirectory() || identEntry.name.startsWith(".")) {
|
|
118325
118652
|
continue;
|
|
118326
118653
|
}
|
|
118327
|
-
const identRoot =
|
|
118654
|
+
const identRoot = join70(agentRoot, identEntry.name);
|
|
118328
118655
|
const entries = walkEntries(identRoot);
|
|
118329
118656
|
for (const entry of entries) {
|
|
118330
118657
|
const relativeParts = [identEntry.name, ...entry.relativePath.split(sep17)];
|
|
@@ -118371,7 +118698,7 @@ function planStationHydration(stationId, repoRoot) {
|
|
|
118371
118698
|
});
|
|
118372
118699
|
continue;
|
|
118373
118700
|
}
|
|
118374
|
-
const info =
|
|
118701
|
+
const info = statSync24(entry.fullPath);
|
|
118375
118702
|
const manifestHash = manifestHashes.get(`${agent}${MANIFEST_HASH_KEY_SEP}${homeRelative}`) ?? null;
|
|
118376
118703
|
let verified = false;
|
|
118377
118704
|
if (manifestHash !== null) {
|
|
@@ -118475,8 +118802,8 @@ function skillSha256(skill) {
|
|
|
118475
118802
|
`)).digest("hex");
|
|
118476
118803
|
}
|
|
118477
118804
|
function writeStationHydration(options) {
|
|
118478
|
-
const repoRoot =
|
|
118479
|
-
const cacheRoot =
|
|
118805
|
+
const repoRoot = resolve37(options.repoRoot ?? process.cwd());
|
|
118806
|
+
const cacheRoot = resolve37(options.cacheRoot ?? resolveCorpusRoot());
|
|
118480
118807
|
const plan = planStationHydration(options.stationId, repoRoot);
|
|
118481
118808
|
const resultSkills = plan.winners.map((skill) => ({
|
|
118482
118809
|
ident: skill.ident,
|
|
@@ -118509,7 +118836,7 @@ function writeStationHydration(options) {
|
|
|
118509
118836
|
const toWrite = [];
|
|
118510
118837
|
for (const skill of plan.winners) {
|
|
118511
118838
|
for (const file2 of skill.files) {
|
|
118512
|
-
const destination =
|
|
118839
|
+
const destination = join70(cacheRoot, skill.ident, file2.withinIdent);
|
|
118513
118840
|
const digest4 = sha256File(file2.winner.fullPath);
|
|
118514
118841
|
let existingDigest = null;
|
|
118515
118842
|
try {
|
|
@@ -118530,7 +118857,7 @@ function writeStationHydration(options) {
|
|
|
118530
118857
|
}
|
|
118531
118858
|
let written = 0;
|
|
118532
118859
|
for (const entry of toWrite) {
|
|
118533
|
-
mkdirSync29(
|
|
118860
|
+
mkdirSync29(dirname42(entry.destination), { recursive: true });
|
|
118534
118861
|
copyFileSync3(entry.fullPath, entry.destination);
|
|
118535
118862
|
written += 1;
|
|
118536
118863
|
}
|
|
@@ -118551,8 +118878,8 @@ function writeStationHydration(options) {
|
|
|
118551
118878
|
},
|
|
118552
118879
|
skills: resultSkills
|
|
118553
118880
|
};
|
|
118554
|
-
const hydrationManifestPath =
|
|
118555
|
-
mkdirSync29(
|
|
118881
|
+
const hydrationManifestPath = join70(dirname42(cacheRoot), `hydration-${options.stationId}.json`);
|
|
118882
|
+
mkdirSync29(dirname42(hydrationManifestPath), { recursive: true });
|
|
118556
118883
|
writeFileSync30(hydrationManifestPath, `${JSON.stringify(hydration, null, 2)}
|
|
118557
118884
|
`);
|
|
118558
118885
|
return {
|
|
@@ -118629,14 +118956,14 @@ var init_hydrate = __esm(() => {
|
|
|
118629
118956
|
|
|
118630
118957
|
// src/lib/prepare-skill.ts
|
|
118631
118958
|
import { createHash as createHash44, randomUUID as randomUUID13 } from "crypto";
|
|
118632
|
-
import { chmodSync as chmodSync5, existsSync as existsSync37, lstatSync as
|
|
118959
|
+
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
118960
|
import { tmpdir as tmpdir2 } from "os";
|
|
118634
|
-
import { dirname as
|
|
118961
|
+
import { dirname as dirname43, isAbsolute as isAbsolute40, join as join71, relative as relative13, resolve as resolve38, sep as sep18 } from "path";
|
|
118635
118962
|
function prepareSkill(name, options) {
|
|
118636
118963
|
const normalized = normalizePortableSkillName(name);
|
|
118637
118964
|
if (!new RegExp(SEMVER_PATTERN).test(options.version))
|
|
118638
118965
|
throw new Error("--version must be a semantic version, for example 0.2.0.");
|
|
118639
|
-
const path =
|
|
118966
|
+
const path = join71(getPortableSkillsRootReadOnly(options), normalized);
|
|
118640
118967
|
assertPortableAuthoringPath(path, options);
|
|
118641
118968
|
const before2 = snapshot2(path);
|
|
118642
118969
|
const manifestFile = before2.files.find((file2) => file2.path === "skill.json");
|
|
@@ -118671,16 +118998,16 @@ function prepareSkill(name, options) {
|
|
|
118671
118998
|
throw new Error("skill.json provenance must be an object.");
|
|
118672
118999
|
const provenance = manifest.provenance;
|
|
118673
119000
|
const candidate2 = { ...manifest, version: options.version, kind, provenance: { ...provenance } };
|
|
118674
|
-
const staging = mkdtempSync6(
|
|
119001
|
+
const staging = mkdtempSync6(join71(tmpdir2(), "skills-prepare-"));
|
|
118675
119002
|
try {
|
|
118676
119003
|
for (const directory2 of before2.directories)
|
|
118677
|
-
mkdirSync30(
|
|
119004
|
+
mkdirSync30(join71(staging, directory2), { recursive: true });
|
|
118678
119005
|
for (const file2 of before2.files) {
|
|
118679
|
-
const destination =
|
|
118680
|
-
mkdirSync30(
|
|
119006
|
+
const destination = join71(staging, file2.path);
|
|
119007
|
+
mkdirSync30(dirname43(destination), { recursive: true });
|
|
118681
119008
|
writeFileSync31(destination, file2.bytes, { mode: file2.mode });
|
|
118682
119009
|
}
|
|
118683
|
-
const stagedManifest =
|
|
119010
|
+
const stagedManifest = join71(staging, "skill.json");
|
|
118684
119011
|
writeFileSync31(stagedManifest, `${JSON.stringify(candidate2, null, 2)}
|
|
118685
119012
|
`);
|
|
118686
119013
|
const contentHash = computeContentHash(staging);
|
|
@@ -118703,11 +119030,11 @@ ${validation.issues.map((issue2) => `${issue2.code}: ${issue2.message}`).join(`
|
|
|
118703
119030
|
if (snapshot2(path).identity !== before2.identity)
|
|
118704
119031
|
throw new Error("Skill changed during preparation; review the draft and run prepare again.");
|
|
118705
119032
|
if (changed3 && !options.dryRun) {
|
|
118706
|
-
const temporary =
|
|
119033
|
+
const temporary = join71(path, `.skill-prepare-${randomUUID13()}.tmp`);
|
|
118707
119034
|
try {
|
|
118708
119035
|
writeFileSync31(temporary, candidateBytes, { flag: "wx", mode: manifestFile.mode });
|
|
118709
119036
|
chmodSync5(temporary, manifestFile.mode);
|
|
118710
|
-
renameSync15(temporary,
|
|
119037
|
+
renameSync15(temporary, join71(path, "skill.json"));
|
|
118711
119038
|
} finally {
|
|
118712
119039
|
rmSync9(temporary, { force: true });
|
|
118713
119040
|
}
|
|
@@ -118737,8 +119064,8 @@ function validateRuntimeEntrypoint(candidate2, root2) {
|
|
|
118737
119064
|
const entry = candidate2.runtime.entrypoint;
|
|
118738
119065
|
if (typeof entry !== "string")
|
|
118739
119066
|
return;
|
|
118740
|
-
const target =
|
|
118741
|
-
if (
|
|
119067
|
+
const target = resolve38(root2, entry), rel = relative13(root2, target);
|
|
119068
|
+
if (isAbsolute40(entry) || /^[a-zA-Z]:/.test(entry) || entry.includes("\\") || !rel || rel === ".." || rel.startsWith(`..${sep18}`) || isAbsolute40(rel) || !existsSync37(target) || !lstatSync42(target).isFile()) {
|
|
118742
119069
|
throw new Error("Executable runtime.entrypoint must name an existing regular file inside the skill directory.");
|
|
118743
119070
|
}
|
|
118744
119071
|
}
|
|
@@ -118823,20 +119150,20 @@ function compareVersions(left, right) {
|
|
|
118823
119150
|
return 0;
|
|
118824
119151
|
}
|
|
118825
119152
|
function snapshot2(root2) {
|
|
118826
|
-
const rootStat =
|
|
119153
|
+
const rootStat = lstatSync42(root2);
|
|
118827
119154
|
if (rootStat.isSymbolicLink() || !rootStat.isDirectory())
|
|
118828
119155
|
throw new Error("Skill root must be a real directory, not a symlink.");
|
|
118829
119156
|
const files = [], directories = [];
|
|
118830
119157
|
const hash6 = createHash44("sha256").update(`${rootStat.dev}:${rootStat.ino}\x00`);
|
|
118831
119158
|
let count = 0, bytes = 0;
|
|
118832
119159
|
const walk2 = (relative14) => {
|
|
118833
|
-
for (const name of readdirSync26(
|
|
119160
|
+
for (const name of readdirSync26(join71(root2, relative14)).sort()) {
|
|
118834
119161
|
if (IGNORED.has(name.toLowerCase()) || !relative14 && ROOT_IGNORED.has(name.toLowerCase()))
|
|
118835
119162
|
continue;
|
|
118836
119163
|
const path = relative14 ? `${relative14}/${name}` : name;
|
|
118837
119164
|
if (++count > 20000)
|
|
118838
119165
|
throw new Error("Skill exceeds the preparation entry limit (20000).");
|
|
118839
|
-
const absolute =
|
|
119166
|
+
const absolute = join71(root2, path), stat3 = lstatSync42(absolute);
|
|
118840
119167
|
if (stat3.isSymbolicLink())
|
|
118841
119168
|
throw new Error(`Skill contains a symlink: ${path}. No files were changed.`);
|
|
118842
119169
|
if (stat3.isDirectory() && name === "node_modules")
|
|
@@ -119252,7 +119579,7 @@ var init_schedule = __esm(() => {
|
|
|
119252
119579
|
|
|
119253
119580
|
// src/lib/registry-sync.ts
|
|
119254
119581
|
import { mkdirSync as mkdirSync31, writeFileSync as writeFileSync32 } from "fs";
|
|
119255
|
-
import { dirname as
|
|
119582
|
+
import { dirname as dirname44, relative as relative14 } from "path";
|
|
119256
119583
|
function createRegistrySyncArtifact(options = {}) {
|
|
119257
119584
|
const profile = options.profile ?? "all";
|
|
119258
119585
|
const includeDocs = options.includeDocs ?? true;
|
|
@@ -119309,7 +119636,7 @@ function createRegistrySyncArtifact(options = {}) {
|
|
|
119309
119636
|
};
|
|
119310
119637
|
}
|
|
119311
119638
|
function writeRegistrySyncArtifact(path, artifact) {
|
|
119312
|
-
mkdirSync31(
|
|
119639
|
+
mkdirSync31(dirname44(path), { recursive: true });
|
|
119313
119640
|
writeFileSync32(path, `${JSON.stringify(artifact, null, 2)}
|
|
119314
119641
|
`);
|
|
119315
119642
|
}
|
|
@@ -119329,8 +119656,8 @@ var init_registry_sync = __esm(() => {
|
|
|
119329
119656
|
});
|
|
119330
119657
|
|
|
119331
119658
|
// src/lib/review-export.ts
|
|
119332
|
-
import { constants as
|
|
119333
|
-
import { basename as basename20, dirname as
|
|
119659
|
+
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";
|
|
119660
|
+
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
119661
|
function exactVersion(spec) {
|
|
119335
119662
|
const at2 = spec.indexOf("@");
|
|
119336
119663
|
const slug2 = spec.slice(0, at2);
|
|
@@ -119341,14 +119668,14 @@ function exactVersion(spec) {
|
|
|
119341
119668
|
return { slug: slug2, version: version2 };
|
|
119342
119669
|
}
|
|
119343
119670
|
function assertPrivateDestination(output2) {
|
|
119344
|
-
if (!
|
|
119671
|
+
if (!isAbsolute41(output2) || resolve39(output2) !== output2 || !basename20(output2).endsWith(".tar.gz")) {
|
|
119345
119672
|
throw new Error("Review output must be an absolute, normalized .tar.gz path.");
|
|
119346
119673
|
}
|
|
119347
|
-
const parent =
|
|
119348
|
-
if (realpathSync23(parent) !== parent ||
|
|
119674
|
+
const parent = dirname45(output2);
|
|
119675
|
+
if (realpathSync23(parent) !== parent || lstatSync43(parent).isSymbolicLink()) {
|
|
119349
119676
|
throw new Error("Review output parent must be a real directory, not a symlink.");
|
|
119350
119677
|
}
|
|
119351
|
-
const parentStat =
|
|
119678
|
+
const parentStat = statSync25(parent);
|
|
119352
119679
|
if (!parentStat.isDirectory() || (parentStat.mode & 63) !== 0 || process.getuid && parentStat.uid !== process.getuid()) {
|
|
119353
119680
|
throw new Error("Review output parent must be an owner-only directory (mode 0700).");
|
|
119354
119681
|
}
|
|
@@ -119356,8 +119683,8 @@ function assertPrivateDestination(output2) {
|
|
|
119356
119683
|
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
119684
|
throw new Error("Review output cannot be placed in agent-native discovery or Skills installation paths.");
|
|
119358
119685
|
}
|
|
119359
|
-
for (let current = parent;; current =
|
|
119360
|
-
if (existsSync38(
|
|
119686
|
+
for (let current = parent;; current = dirname45(current)) {
|
|
119687
|
+
if (existsSync38(join72(current, ".git"))) {
|
|
119361
119688
|
throw new Error("Review output cannot be placed inside a Git worktree.");
|
|
119362
119689
|
}
|
|
119363
119690
|
if (current === parse13(current).root)
|
|
@@ -119393,7 +119720,7 @@ async function exportSkillVersionForReview(spec, output2, client2) {
|
|
|
119393
119720
|
if (bytes.byteLength !== metadata2.bundleByteSize || sha256Hex(bytes) !== metadata2.bundleSha256.toLowerCase()) {
|
|
119394
119721
|
throw new Error("Published bundle bytes do not match the exact version metadata.");
|
|
119395
119722
|
}
|
|
119396
|
-
const fd = openSync29(target,
|
|
119723
|
+
const fd = openSync29(target, constants28.O_WRONLY | constants28.O_CREAT | constants28.O_EXCL | constants28.O_NOFOLLOW, 384);
|
|
119397
119724
|
try {
|
|
119398
119725
|
writeFileSync33(fd, bytes);
|
|
119399
119726
|
fsyncSync9(fd);
|
|
@@ -119433,12 +119760,12 @@ function registerRegistry(parent) {
|
|
|
119433
119760
|
async function writeJson2(value, space) {
|
|
119434
119761
|
const text4 = `${JSON.stringify(value, null, space)}
|
|
119435
119762
|
`;
|
|
119436
|
-
await new Promise((
|
|
119763
|
+
await new Promise((resolve40, reject2) => {
|
|
119437
119764
|
process.stdout.write(text4, (error61) => {
|
|
119438
119765
|
if (error61)
|
|
119439
119766
|
reject2(error61);
|
|
119440
119767
|
else
|
|
119441
|
-
|
|
119768
|
+
resolve40();
|
|
119442
119769
|
});
|
|
119443
119770
|
});
|
|
119444
119771
|
}
|
|
@@ -119644,7 +119971,7 @@ __export(exports_publish, {
|
|
|
119644
119971
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
119645
119972
|
import { existsSync as existsSync39, readFileSync as readFileSync49 } from "fs";
|
|
119646
119973
|
import { hostname as hostname5 } from "os";
|
|
119647
|
-
import { join as
|
|
119974
|
+
import { join as join73 } from "path";
|
|
119648
119975
|
function registerPublish(parent) {
|
|
119649
119976
|
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
119977
|
try {
|
|
@@ -119696,7 +120023,7 @@ async function pushSkill(name, options = {}) {
|
|
|
119696
120023
|
const packed = packSkillBundle(skill.path, { maxUnpackedBytes: MAX_UNPACKED_BYTES });
|
|
119697
120024
|
await verifyPackedCanonicalHash(skill.name, packed);
|
|
119698
120025
|
const versionManifest = buildVersionManifest(skill.path, packed);
|
|
119699
|
-
const skillMdPath =
|
|
120026
|
+
const skillMdPath = join73(skill.path, "SKILL.md");
|
|
119700
120027
|
const skillMd = existsSync39(skillMdPath) ? readFileSync49(skillMdPath, "utf-8") : undefined;
|
|
119701
120028
|
const base3 = {
|
|
119702
120029
|
slug: skill.name,
|
|
@@ -119935,7 +120262,7 @@ var exports_private_publications = {};
|
|
|
119935
120262
|
__export(exports_private_publications, {
|
|
119936
120263
|
registerPrivatePublications: () => registerPrivatePublications
|
|
119937
120264
|
});
|
|
119938
|
-
import { resolve as
|
|
120265
|
+
import { resolve as resolve40 } from "path";
|
|
119939
120266
|
function verifyOptions(options, action) {
|
|
119940
120267
|
if (options.userId === undefined !== (options.membershipId === undefined) || options.userId !== undefined && (!publicationUuid(options.userId) || !publicationUuid(options.membershipId)))
|
|
119941
120268
|
throw new PrivatePublicationError("PUBLICATION_CONTEXT_REQUIRED", "Provide both observed --user-id and --membership-id UUIDs.");
|
|
@@ -119980,9 +120307,9 @@ function registerPrivatePublications(parent) {
|
|
|
119980
120307
|
if (code2 === null)
|
|
119981
120308
|
return;
|
|
119982
120309
|
const context2 = options.userId ? { userId: options.userId, membershipId: options.membershipId } : undefined;
|
|
119983
|
-
const client2 = await privatePublicationSession(options.email, code2, context2), directory2 =
|
|
120310
|
+
const client2 = await privatePublicationSession(options.email, code2, context2), directory2 = resolve40(options.recoveryDir);
|
|
119984
120311
|
if (action === "publish")
|
|
119985
|
-
await preparePrivatePublication(client2,
|
|
120312
|
+
await preparePrivatePublication(client2, resolve40(args2[0]), directory2, { skillId: options.skillId, expectedCurrentVersionId: options.expectedCurrentVersion ?? null, idempotencyKey: options.idempotencyKey });
|
|
119986
120313
|
const result2 = action === "publish" || action === "resume" ? await continuePrivatePublication(client2, directory2, { confirm: true, waitMs: Number(options.waitSeconds) * 1000 }) : await inspectPrivatePublication(client2, directory2, action === "cancel");
|
|
119987
120314
|
print2(result2, options.json);
|
|
119988
120315
|
} catch (error61) {
|
|
@@ -120084,7 +120411,7 @@ __export(exports_auth, {
|
|
|
120084
120411
|
import { createInterface as createInterface3 } from "readline";
|
|
120085
120412
|
function prompt(question) {
|
|
120086
120413
|
const rl = createInterface3({ input: process.stdin, output: process.stdout });
|
|
120087
|
-
return new Promise((
|
|
120414
|
+
return new Promise((resolve41) => {
|
|
120088
120415
|
let settled = false;
|
|
120089
120416
|
const finish = (answer) => {
|
|
120090
120417
|
if (settled)
|
|
@@ -120093,7 +120420,7 @@ function prompt(question) {
|
|
|
120093
120420
|
rl.close();
|
|
120094
120421
|
if (answer === null)
|
|
120095
120422
|
process.exitCode = 130;
|
|
120096
|
-
|
|
120423
|
+
resolve41(answer);
|
|
120097
120424
|
};
|
|
120098
120425
|
rl.once("SIGINT", () => finish(null));
|
|
120099
120426
|
rl.once("close", () => finish(null));
|
|
@@ -120271,7 +120598,7 @@ Skipped. Run it any time: skills setup agents`));
|
|
|
120271
120598
|
function promptHidden(question) {
|
|
120272
120599
|
const stdin = process.stdin;
|
|
120273
120600
|
process.stdout.write(question);
|
|
120274
|
-
return new Promise((
|
|
120601
|
+
return new Promise((resolve41) => {
|
|
120275
120602
|
let value = "";
|
|
120276
120603
|
const done = (answer) => {
|
|
120277
120604
|
stdin.off("data", onData);
|
|
@@ -120281,7 +120608,7 @@ function promptHidden(question) {
|
|
|
120281
120608
|
`);
|
|
120282
120609
|
if (answer === null)
|
|
120283
120610
|
process.exitCode = 130;
|
|
120284
|
-
|
|
120611
|
+
resolve41(answer);
|
|
120285
120612
|
};
|
|
120286
120613
|
const onData = (chunk2) => {
|
|
120287
120614
|
for (const character of chunk2.toString()) {
|
|
@@ -120837,7 +121164,7 @@ function promptInvitationProof(kind) {
|
|
|
120837
121164
|
const label = kind === "token" ? "invitation token" : "recovery code";
|
|
120838
121165
|
const character = kind === "token" ? /^[A-Za-z0-9_-]$/ : /^\d$/;
|
|
120839
121166
|
const { stdin, stderr: output2 } = process, wasRaw = stdin.isRaw, wasFlowing = stdin.readableFlowing;
|
|
120840
|
-
return new Promise((
|
|
121167
|
+
return new Promise((resolve41) => {
|
|
120841
121168
|
let value = "", settled = false, overflow = false;
|
|
120842
121169
|
const finish = (answer) => {
|
|
120843
121170
|
if (settled)
|
|
@@ -120854,7 +121181,7 @@ function promptInvitationProof(kind) {
|
|
|
120854
121181
|
`);
|
|
120855
121182
|
if (answer === null)
|
|
120856
121183
|
process.exitCode = 130;
|
|
120857
|
-
|
|
121184
|
+
resolve41(answer);
|
|
120858
121185
|
};
|
|
120859
121186
|
const cancel = () => finish(null);
|
|
120860
121187
|
const keypress = (text4, key) => {
|
|
@@ -121426,11 +121753,11 @@ var init_storage2 = __esm(() => {
|
|
|
121426
121753
|
});
|
|
121427
121754
|
|
|
121428
121755
|
// src/lib/registry-reconcile.ts
|
|
121429
|
-
import { existsSync as existsSync40, readFileSync as readFileSync50, statSync as
|
|
121430
|
-
import { join as
|
|
121756
|
+
import { existsSync as existsSync40, readFileSync as readFileSync50, statSync as statSync26, writeFileSync as writeFileSync34 } from "fs";
|
|
121757
|
+
import { join as join74 } from "path";
|
|
121431
121758
|
function isDirectory2(path) {
|
|
121432
121759
|
try {
|
|
121433
|
-
return
|
|
121760
|
+
return statSync26(path).isDirectory();
|
|
121434
121761
|
} catch {
|
|
121435
121762
|
return false;
|
|
121436
121763
|
}
|
|
@@ -121438,11 +121765,11 @@ function isDirectory2(path) {
|
|
|
121438
121765
|
function migrationNeeded(options) {
|
|
121439
121766
|
if (options.rootDir)
|
|
121440
121767
|
return false;
|
|
121441
|
-
const appDir = options.homeDir ?
|
|
121442
|
-
return !(isOwnerLayoutMigrated(appDir) && isDirectory2(
|
|
121768
|
+
const appDir = options.homeDir ? join74(options.homeDir, ".hasna", "skills") : getDataDir();
|
|
121769
|
+
return !(isOwnerLayoutMigrated(appDir) && isDirectory2(join74(appDir, SKILLS_CACHE_DIRNAME)));
|
|
121443
121770
|
}
|
|
121444
121771
|
function readBaseline(skillDir) {
|
|
121445
|
-
const markerPath =
|
|
121772
|
+
const markerPath = join74(skillDir, PULL_MARKER_FILE);
|
|
121446
121773
|
if (!existsSync40(markerPath))
|
|
121447
121774
|
return;
|
|
121448
121775
|
try {
|
|
@@ -121458,7 +121785,7 @@ function readBaseline(skillDir) {
|
|
|
121458
121785
|
}
|
|
121459
121786
|
}
|
|
121460
121787
|
function readCursor(root2) {
|
|
121461
|
-
const path =
|
|
121788
|
+
const path = join74(root2, SYNC_CURSOR_FILE);
|
|
121462
121789
|
if (!existsSync40(path))
|
|
121463
121790
|
return { runCount: 0 };
|
|
121464
121791
|
try {
|
|
@@ -121471,12 +121798,12 @@ function readCursor(root2) {
|
|
|
121471
121798
|
function resolveCorpusRootReadOnly(options) {
|
|
121472
121799
|
if (options.rootDir)
|
|
121473
121800
|
return { root: options.rootDir, migrationPending: false };
|
|
121474
|
-
const appDir = options.homeDir ?
|
|
121475
|
-
const cache3 =
|
|
121801
|
+
const appDir = options.homeDir ? join74(options.homeDir, ".hasna", "skills") : getDataDirReadOnly();
|
|
121802
|
+
const cache3 = join74(appDir, SKILLS_CACHE_DIRNAME);
|
|
121476
121803
|
if (isOwnerLayoutMigrated(appDir) && isDirectory2(cache3)) {
|
|
121477
121804
|
return { root: cache3, migrationPending: false };
|
|
121478
121805
|
}
|
|
121479
|
-
return { root:
|
|
121806
|
+
return { root: join74(appDir, INSTALLED_SKILLS_DIRNAME), migrationPending: true };
|
|
121480
121807
|
}
|
|
121481
121808
|
function remoteRowToSkill(record12) {
|
|
121482
121809
|
const slug2 = typeof record12.slug === "string" ? record12.slug : typeof record12.name === "string" ? record12.name : undefined;
|
|
@@ -121610,7 +121937,7 @@ async function reconcileRegistry(options = {}) {
|
|
|
121610
121937
|
for (const slug2 of allSlugs) {
|
|
121611
121938
|
const local = locals.get(slug2);
|
|
121612
121939
|
const remote = remotes.get(slug2);
|
|
121613
|
-
const baseline = local ? readBaseline(
|
|
121940
|
+
const baseline = local ? readBaseline(join74(root2, slug2)) : undefined;
|
|
121614
121941
|
const { state, reason: reason2 } = classifySkill(local, remote, baseline);
|
|
121615
121942
|
let { action, reason: actionReason } = resolveAction(state, direction, conflict);
|
|
121616
121943
|
if (state === "remote-only" && isDigestless(remote)) {
|
|
@@ -121669,7 +121996,7 @@ async function reconcileRegistry(options = {}) {
|
|
|
121669
121996
|
try {
|
|
121670
121997
|
await pushSkill(slug2, { rootDir: root2, client: client2 });
|
|
121671
121998
|
const pushed = locals.get(slug2);
|
|
121672
|
-
writePullMarker(
|
|
121999
|
+
writePullMarker(join74(root2, slug2), {
|
|
121673
122000
|
skill: slug2,
|
|
121674
122001
|
...pushed?.version ? { version: pushed.version } : {},
|
|
121675
122002
|
...pushed?.sha256 ? { contentHash: pushed.sha256 } : {},
|
|
@@ -121741,7 +122068,7 @@ async function reconcileRegistry(options = {}) {
|
|
|
121741
122068
|
runCount: readCursor(root2).runCount + 1,
|
|
121742
122069
|
summary
|
|
121743
122070
|
};
|
|
121744
|
-
writeFileSync34(
|
|
122071
|
+
writeFileSync34(join74(root2, SYNC_CURSOR_FILE), `${JSON.stringify(cursor2, null, 2)}
|
|
121745
122072
|
`);
|
|
121746
122073
|
return {
|
|
121747
122074
|
corpusRoot: root2,
|