@hasna/skills 0.10.48 → 0.10.50
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 +66 -1
- package/bin/index.js +1137 -667
- package/bin/maintenance.js +18 -0
- package/bin/mcp.js +88 -11
- package/bin/migrate.js +19 -1
- package/bin/server.js +19 -1
- package/bin/worker.js +19 -1
- package/dist/cli/commands/runtime-launcher.d.ts +102 -0
- package/dist/cli/commands/runtime.d.ts +7 -0
- package/dist/cli/index.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +452 -272
- package/dist/lib/agent-discovery.d.ts +1 -1
- package/dist/lib/agent-integration.d.ts +1 -0
- package/dist/lib/claude-settings-witness.d.ts +19 -0
- package/dist/lib/launch-cwd-apply.d.ts +1 -0
- package/dist/lib/launch-cwd.d.ts +5 -0
- package/dist/lib/self-spawn.d.ts +21 -0
- package/dist/mcp/index.d.ts +1 -0
- package/dist/sdk/index.js +433 -255
- package/dist/server/index.d.ts +1 -1
- package/dist/server/maintenance.d.ts +1 -1
- package/dist/server/migrate.d.ts +17 -0
- package/dist/server/worker.d.ts +1 -0
- package/docs/plugin-admission.md +39 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6988,7 +6988,7 @@ var require_public_api = __commonJS((exports) => {
|
|
|
6988
6988
|
});
|
|
6989
6989
|
|
|
6990
6990
|
// src/lib/registry.ts
|
|
6991
|
-
import { existsSync as existsSync15, readFileSync as
|
|
6991
|
+
import { existsSync as existsSync15, readFileSync as readFileSync21, readdirSync as readdirSync12 } from "fs";
|
|
6992
6992
|
import { join as join35 } from "path";
|
|
6993
6993
|
|
|
6994
6994
|
// src/lib/config.ts
|
|
@@ -7256,13 +7256,13 @@ import {
|
|
|
7256
7256
|
mkdirSync as mkdirSync10,
|
|
7257
7257
|
mkdtempSync as mkdtempSync2,
|
|
7258
7258
|
readdirSync as readdirSync11,
|
|
7259
|
-
realpathSync as
|
|
7259
|
+
realpathSync as realpathSync13,
|
|
7260
7260
|
renameSync as renameSync6,
|
|
7261
7261
|
rmSync as rmSync4,
|
|
7262
7262
|
statSync as statSync11,
|
|
7263
7263
|
writeFileSync as writeFileSync9
|
|
7264
7264
|
} from "fs";
|
|
7265
|
-
import { basename as basename12, dirname as dirname21, isAbsolute as
|
|
7265
|
+
import { basename as basename12, dirname as dirname21, isAbsolute as isAbsolute20, join as join34, normalize as normalize4, relative as relative7, resolve as resolve20, sep as sep10 } from "path";
|
|
7266
7266
|
|
|
7267
7267
|
// src/lib/registry-data/index.ts
|
|
7268
7268
|
var SKILLS = [];
|
|
@@ -8920,7 +8920,7 @@ var NATIVE_SKILL_ROOTS = [
|
|
|
8920
8920
|
];
|
|
8921
8921
|
|
|
8922
8922
|
// src/lib/authoring-path.ts
|
|
8923
|
-
import { lstatSync as
|
|
8923
|
+
import { lstatSync as lstatSync26, realpathSync as realpathSync12 } from "fs";
|
|
8924
8924
|
import { homedir as homedir6 } from "os";
|
|
8925
8925
|
import { basename as basename11, dirname as dirname20, join as join33, resolve as resolve19, sep as sep9 } from "path";
|
|
8926
8926
|
|
|
@@ -9177,6 +9177,8 @@ var BUILTIN_MODEL_SELECTIONS = new Set([
|
|
|
9177
9177
|
"claude-opus-4-6[1m]",
|
|
9178
9178
|
"claude-sonnet-4-6[1m]"
|
|
9179
9179
|
]);
|
|
9180
|
+
var CLAUDE_BUILTIN_THEMES = Object.freeze(["auto", "dark", "light", "dark-daltonized", "light-daltonized", "dark-ansi", "light-ansi"]);
|
|
9181
|
+
var BUILTIN_THEMES = new Set(CLAUDE_BUILTIN_THEMES);
|
|
9180
9182
|
function canonical(value) {
|
|
9181
9183
|
if (value.kind === "object")
|
|
9182
9184
|
return { kind: "object", entries: value.entries.map(([key, child]) => [key, canonical(child)]).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0) };
|
|
@@ -9235,7 +9237,9 @@ function inferencePreference(key, child, version) {
|
|
|
9235
9237
|
function settingsDigest(text, version = 1) {
|
|
9236
9238
|
const value = parse(text);
|
|
9237
9239
|
value.entries = value.entries.filter(([key, child]) => {
|
|
9238
|
-
if (version
|
|
9240
|
+
if (version === 4 && key === "theme" && child.kind === "string" && BUILTIN_THEMES.has(child.value))
|
|
9241
|
+
return false;
|
|
9242
|
+
if (version !== 1 && inferencePreference(key, child, version === 4 ? 3 : version))
|
|
9239
9243
|
return false;
|
|
9240
9244
|
if (key === "model") {
|
|
9241
9245
|
need(child.kind === "string", "contains an invalid model selection");
|
|
@@ -9293,6 +9297,26 @@ function upgradeClaudeSettingsWitness(previous, reviewedSettingsPath) {
|
|
|
9293
9297
|
need(settingsDigest(before, 3) === sha256, "non-preference settings changed; explicit discovery review required");
|
|
9294
9298
|
return { path: previous.path, hashMode: "claude-settings-v3", sha256 };
|
|
9295
9299
|
}
|
|
9300
|
+
function captureClaudeSettingsV4(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
9301
|
+
return { path, hashMode: "claude-settings-v4", sha256: settingsDigest(readNativeSettingsWitnessFile(path, budget), 4) };
|
|
9302
|
+
}
|
|
9303
|
+
function hashClaudeSettingsReplacementV4(text, budget) {
|
|
9304
|
+
need(typeof text === "string", "requires settings text");
|
|
9305
|
+
const bytes = Buffer.byteLength(text);
|
|
9306
|
+
need(bytes <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes && Number.isSafeInteger(budget.remaining) && budget.remaining >= bytes, "exceeds its byte limit");
|
|
9307
|
+
budget.remaining -= bytes;
|
|
9308
|
+
return settingsDigest(text, 4);
|
|
9309
|
+
}
|
|
9310
|
+
function upgradeClaudeSettingsWitnessV4(previous, reviewedSettingsPath) {
|
|
9311
|
+
need(previous && Object.keys(previous).every((key) => ["path", "hashMode", "sha256"].includes(key)) && (previous.hashMode === undefined || previous.hashMode === "bytes" || previous.hashMode === "claude-settings-v1" || previous.hashMode === "claude-settings-v2" || previous.hashMode === "claude-settings-v3") && typeof previous.sha256 === "string" && /^[a-f0-9]{64}$/.test(previous.sha256), "requires an exact prior settings witness");
|
|
9312
|
+
const budget = { remaining: 2 * CLAUDE_SETTINGS_WITNESS_LIMITS.bytes };
|
|
9313
|
+
const before = readNativeSettingsWitnessFile(reviewedSettingsPath, budget), current = readNativeSettingsWitnessFile(previous.path, budget);
|
|
9314
|
+
const beforeDigest = previous.hashMode === undefined || previous.hashMode === "bytes" ? createHash2("sha256").update(before).digest("hex") : settingsDigest(before, previous.hashMode === "claude-settings-v1" ? 1 : previous.hashMode === "claude-settings-v2" ? 2 : 3);
|
|
9315
|
+
need(beforeDigest === previous.sha256, "reviewed preimage does not match the prior witness");
|
|
9316
|
+
const sha256 = settingsDigest(current, 4);
|
|
9317
|
+
need(settingsDigest(before, 4) === sha256, "non-preference settings changed; explicit discovery review required");
|
|
9318
|
+
return { path: previous.path, hashMode: "claude-settings-v4", sha256 };
|
|
9319
|
+
}
|
|
9296
9320
|
function hashNativeJsonControls(text, excludedMetadata) {
|
|
9297
9321
|
need(Buffer.byteLength(text) <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes, "exceeds its byte limit");
|
|
9298
9322
|
const value = parse(text);
|
|
@@ -9497,14 +9521,14 @@ function assertAgentPolicyCollections(policy) {
|
|
|
9497
9521
|
text(source.path);
|
|
9498
9522
|
requireBound(source.sha256 === null || typeof source.sha256 === "string" && /^[a-f0-9]{64}$/.test(source.sha256));
|
|
9499
9523
|
if (source.hashMode !== undefined)
|
|
9500
|
-
requireBound(["bytes", "path-bytes", "claude-plugin-manifest-v1", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1", "claude-settings-v2", "claude-settings-v3", "claude-marketplace-registry-v2", "codex-settings-v1", "codex-settings-v2", "codex-settings-v3", "codex-settings-v4", "sumi-settings-v1"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
|
|
9524
|
+
requireBound(["bytes", "path-bytes", "claude-plugin-manifest-v1", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1", "claude-settings-v2", "claude-settings-v3", "claude-settings-v4", "claude-marketplace-registry-v2", "codex-settings-v1", "codex-settings-v2", "codex-settings-v3", "codex-settings-v4", "sumi-settings-v1"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
|
|
9501
9525
|
if (source.hashMode === "claude-plugin-manifest-v1")
|
|
9502
9526
|
requireBound(agent === "claude" && value.agent === "claude" && ["automatic", "reviewed"].includes(value.method) && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute3(source.path) && resolve3(source.path) === source.path && source.path.endsWith(join7(sep2, ".claude-plugin", "plugin.json")) && source.managedPlugins === undefined);
|
|
9503
9527
|
if (source.hashMode === "sumi-settings-v1")
|
|
9504
9528
|
requireBound(agent === "sumi" && value.agent === "sumi" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute3(source.path) && resolve3(source.path) === source.path && basename3(source.path) === "sumi.json");
|
|
9505
9529
|
if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4"))
|
|
9506
9530
|
requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute3(source.path) && resolve3(source.path) === source.path && basename3(source.path) === "config.toml");
|
|
9507
|
-
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3")
|
|
9531
|
+
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4"))
|
|
9508
9532
|
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute3(source.path) && resolve3(source.path) === source.path && basename3(source.path) === "settings.json");
|
|
9509
9533
|
if (source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2")
|
|
9510
9534
|
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute3(source.path) && resolve3(source.path) === source.path && basename3(source.path) === "known_marketplaces.json");
|
|
@@ -9538,9 +9562,9 @@ function assertAgentPolicyCollections(policy) {
|
|
|
9538
9562
|
}
|
|
9539
9563
|
|
|
9540
9564
|
// src/lib/agent-discovery.ts
|
|
9541
|
-
import { createHash as
|
|
9542
|
-
import { lstatSync as
|
|
9543
|
-
import { basename as basename10, dirname as dirname19, isAbsolute as
|
|
9565
|
+
import { createHash as createHash24 } from "crypto";
|
|
9566
|
+
import { lstatSync as lstatSync25, readFileSync as readFileSync20, readdirSync as readdirSync10, realpathSync as realpathSync11 } from "fs";
|
|
9567
|
+
import { basename as basename10, dirname as dirname19, isAbsolute as isAbsolute19, join as join32, resolve as resolve18, sep as sep8 } from "path";
|
|
9544
9568
|
import { isDeepStrictEqual as isDeepStrictEqual7 } from "util";
|
|
9545
9569
|
|
|
9546
9570
|
// node_modules/yaml/dist/index.js
|
|
@@ -10230,12 +10254,12 @@ function projectReviewedClaudePluginManifest(text2, reviewedSha256) {
|
|
|
10230
10254
|
}
|
|
10231
10255
|
|
|
10232
10256
|
// src/lib/plugin-discovery.ts
|
|
10233
|
-
import { closeSync as
|
|
10234
|
-
import { basename as basename8, dirname as dirname17, isAbsolute as
|
|
10257
|
+
import { closeSync as closeSync13, constants as constants13, fstatSync as fstatSync13, lstatSync as lstatSync23, openSync as openSync13, opendirSync as opendirSync5, readSync as readSync10 } from "fs";
|
|
10258
|
+
import { basename as basename8, dirname as dirname17, isAbsolute as isAbsolute17, join as join31, resolve as resolve16 } from "path";
|
|
10235
10259
|
|
|
10236
10260
|
// src/lib/plugin-admission.ts
|
|
10237
10261
|
import { homedir as homedir5 } from "os";
|
|
10238
|
-
import { isAbsolute as
|
|
10262
|
+
import { isAbsolute as isAbsolute16, join as join30, resolve as resolve15 } from "path";
|
|
10239
10263
|
|
|
10240
10264
|
// src/lib/selection-cache.ts
|
|
10241
10265
|
import { createHash as createHash9, randomUUID } from "crypto";
|
|
@@ -11572,7 +11596,7 @@ function replaceSkillSession(expected, replacement, plan, options = {}, beforeCo
|
|
|
11572
11596
|
// package.json
|
|
11573
11597
|
var package_default = {
|
|
11574
11598
|
name: "@hasna/skills",
|
|
11575
|
-
version: "0.10.
|
|
11599
|
+
version: "0.10.50",
|
|
11576
11600
|
description: "Skills library for AI coding agents",
|
|
11577
11601
|
type: "module",
|
|
11578
11602
|
bin: {
|
|
@@ -13401,7 +13425,7 @@ async function prepareSkillDependencies(skillPath, env, timeoutMs = DEFAULT_PREP
|
|
|
13401
13425
|
}
|
|
13402
13426
|
|
|
13403
13427
|
// src/lib/skillinfo.ts
|
|
13404
|
-
import { existsSync as existsSync13, readFileSync as
|
|
13428
|
+
import { existsSync as existsSync13, readFileSync as readFileSync19 } from "fs";
|
|
13405
13429
|
import { join as join28 } from "path";
|
|
13406
13430
|
|
|
13407
13431
|
// src/lib/codex-corpus-write.ts
|
|
@@ -13566,7 +13590,7 @@ function withCodexCorpusWrite(roots, run, options = {}) {
|
|
|
13566
13590
|
}
|
|
13567
13591
|
|
|
13568
13592
|
// src/lib/installer.ts
|
|
13569
|
-
import { existsSync as existsSync12, readFileSync as
|
|
13593
|
+
import { existsSync as existsSync12, readFileSync as readFileSync18, rmSync as rmSync2 } from "fs";
|
|
13570
13594
|
import { join as join27 } from "path";
|
|
13571
13595
|
import { homedir as homedir4 } from "os";
|
|
13572
13596
|
|
|
@@ -13574,10 +13598,10 @@ import { homedir as homedir4 } from "os";
|
|
|
13574
13598
|
import {
|
|
13575
13599
|
cpSync as cpSync2,
|
|
13576
13600
|
existsSync as existsSync10,
|
|
13577
|
-
lstatSync as
|
|
13601
|
+
lstatSync as lstatSync21,
|
|
13578
13602
|
mkdirSync as mkdirSync7,
|
|
13579
13603
|
mkdtempSync,
|
|
13580
|
-
readFileSync as
|
|
13604
|
+
readFileSync as readFileSync16,
|
|
13581
13605
|
readdirSync as readdirSync9,
|
|
13582
13606
|
renameSync as renameSync4,
|
|
13583
13607
|
rmSync,
|
|
@@ -15501,10 +15525,10 @@ function upgradeCodexSettingsWitnessV4(previous, reviewedSettingsPath) {
|
|
|
15501
15525
|
}
|
|
15502
15526
|
|
|
15503
15527
|
// src/lib/agent-integration.ts
|
|
15504
|
-
import { createHash as
|
|
15528
|
+
import { createHash as createHash19, randomUUID as randomUUID3 } from "crypto";
|
|
15505
15529
|
import { isDeepStrictEqual as isDeepStrictEqual6 } from "util";
|
|
15506
|
-
import { existsSync as existsSync9, lstatSync as
|
|
15507
|
-
import { dirname as dirname14, join as join23, resolve as resolve13, relative as relative6, isAbsolute as
|
|
15530
|
+
import { existsSync as existsSync9, lstatSync as lstatSync20, statSync as statSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync15, readdirSync as readdirSync8, opendirSync as opendirSync3, readlinkSync as readlinkSync6, realpathSync as realpathSync10, renameSync as renameSync3, rmdirSync as rmdirSync2, writeFileSync as writeFileSync6, unlinkSync as unlinkSync4, chmodSync, openSync as openSync11, closeSync as closeSync11, fsyncSync as fsyncSync5, fstatSync as fstatSync11, readSync as readSync8, constants as constants11, linkSync as linkSync2 } from "fs";
|
|
15531
|
+
import { dirname as dirname14, join as join23, resolve as resolve13, relative as relative6, isAbsolute as isAbsolute14, sep as sep7 } from "path";
|
|
15508
15532
|
import { homedir as homedir2 } from "os";
|
|
15509
15533
|
|
|
15510
15534
|
// src/lib/managed-policy.ts
|
|
@@ -16068,8 +16092,144 @@ function unchanged2(before) {
|
|
|
16068
16092
|
need5(sameStat(before.stat, after.stat) && after.sha256 === before.sha256, "INPUT_CHANGED");
|
|
16069
16093
|
}
|
|
16070
16094
|
|
|
16095
|
+
// src/cli/commands/runtime-launcher.ts
|
|
16096
|
+
import { createHash as createHash18 } from "crypto";
|
|
16097
|
+
import { closeSync as closeSync10, constants as constants10, fchmodSync, fstatSync as fstatSync10, fsyncSync as fsyncSync4, lstatSync as lstatSync19, openSync as openSync10, readFileSync as readFileSync14, readlinkSync as readlinkSync5, realpathSync as realpathSync9, symlinkSync, writeSync as writeSync2 } from "fs";
|
|
16098
|
+
import { isAbsolute as isAbsolute13 } from "path";
|
|
16099
|
+
var PINNED_LAUNCHER_SCHEMA = "hasna-skills-pinned-launcher-v1";
|
|
16100
|
+
var LAUNCH_CWD_VARIABLE = "HASNA_SKILLS_LAUNCH_CWD";
|
|
16101
|
+
var PINNED_LAUNCHER_BUN_FLAGS = ["--config=/dev/null", "--no-env-file", "--no-macros", "--no-install"];
|
|
16102
|
+
var PINNED_LAUNCHER_ENV_NAMES = [
|
|
16103
|
+
"HOME",
|
|
16104
|
+
"PATH",
|
|
16105
|
+
"TMPDIR",
|
|
16106
|
+
"TERM",
|
|
16107
|
+
"TERM_PROGRAM",
|
|
16108
|
+
"TERM_PROGRAM_VERSION",
|
|
16109
|
+
"COLORTERM",
|
|
16110
|
+
"LANG",
|
|
16111
|
+
"USER",
|
|
16112
|
+
"LOGNAME",
|
|
16113
|
+
"SHELL",
|
|
16114
|
+
"TZ",
|
|
16115
|
+
"NO_COLOR",
|
|
16116
|
+
"FORCE_COLOR",
|
|
16117
|
+
"CI",
|
|
16118
|
+
"COLUMNS",
|
|
16119
|
+
"LINES",
|
|
16120
|
+
"EDITOR",
|
|
16121
|
+
"VISUAL",
|
|
16122
|
+
"PAGER",
|
|
16123
|
+
"SSH_AUTH_SOCK",
|
|
16124
|
+
"DATABASE_URL",
|
|
16125
|
+
"TERMINAL_CWD",
|
|
16126
|
+
"CODEX_HOME",
|
|
16127
|
+
"HERMES_HOME",
|
|
16128
|
+
"HERMES_ENABLE_PROJECT_PLUGINS",
|
|
16129
|
+
"HOST",
|
|
16130
|
+
"PORT",
|
|
16131
|
+
"NODE_ENV",
|
|
16132
|
+
"AGENT_ID",
|
|
16133
|
+
"ECS_CONTAINER_METADATA_URI_V4"
|
|
16134
|
+
];
|
|
16135
|
+
var PINNED_LAUNCHER_ENV_PREFIXES = ["HASNA", "SKILLS", "SKILL", "MCP", "XDG", "LC", "AWS"];
|
|
16136
|
+
var ENV_PREFIX = new RegExp(`^(${PINNED_LAUNCHER_ENV_PREFIXES.join("|")})_`);
|
|
16137
|
+
var ENV_EXACT = new Set(PINNED_LAUNCHER_ENV_NAMES);
|
|
16138
|
+
function sha2562(bytes) {
|
|
16139
|
+
return createHash18("sha256").update(bytes).digest("hex");
|
|
16140
|
+
}
|
|
16141
|
+
function assertLauncherPath(value, code) {
|
|
16142
|
+
if (typeof value !== "string" || !isAbsolute13(value) || /['\x00-\x1f\x7f]/.test(value))
|
|
16143
|
+
throw new Error(code);
|
|
16144
|
+
}
|
|
16145
|
+
function renderPinnedLauncher(binding) {
|
|
16146
|
+
assertLauncherPath(binding.runtime, "LAUNCHER_RUNTIME_PATH_INVALID");
|
|
16147
|
+
assertLauncherPath(binding.cwd, "LAUNCHER_CWD_PATH_INVALID");
|
|
16148
|
+
assertLauncherPath(binding.entry, "LAUNCHER_ENTRY_PATH_INVALID");
|
|
16149
|
+
const names = PINNED_LAUNCHER_ENV_NAMES.join(" ");
|
|
16150
|
+
const prefixes = PINNED_LAUNCHER_ENV_PREFIXES.join("|");
|
|
16151
|
+
return [
|
|
16152
|
+
"#!/bin/sh -p",
|
|
16153
|
+
`# ${PINNED_LAUNCHER_SCHEMA}`,
|
|
16154
|
+
"# Written by `skills self-update`; rewrite it with `skills self-update`, do not edit by hand.",
|
|
16155
|
+
"# Runs the exact Skills entry below under one exact Bun from one trusted directory with",
|
|
16156
|
+
"# no working-directory configuration (no bunfig.toml, no .env, no macros, no auto-install)",
|
|
16157
|
+
"# and only the environment names allowed here. Everything else, BUN_* and NODE_OPTIONS",
|
|
16158
|
+
"# included, never reaches the runtime. The CLI returns to the caller's directory itself.",
|
|
16159
|
+
"# `-p` keeps the caller's exported functions and shell options out of this shell.",
|
|
16160
|
+
"set -eu",
|
|
16161
|
+
`${LAUNCH_CWD_VARIABLE}=$(pwd -P 2>/dev/null || :)`,
|
|
16162
|
+
`export ${LAUNCH_CWD_VARIABLE}`,
|
|
16163
|
+
`set -- '${binding.runtime}' ${PINNED_LAUNCHER_BUN_FLAGS.join(" ")} '--cwd=${binding.cwd}' '${binding.entry}' "$@"`,
|
|
16164
|
+
"hasna_skills_env=$(LC_ALL=C /usr/bin/awk 'BEGIN {",
|
|
16165
|
+
` n = split("${names}", exact, " ")`,
|
|
16166
|
+
" for (i = 1; i <= n; i++) allow[exact[i]] = 1",
|
|
16167
|
+
" for (name in ENVIRON) {",
|
|
16168
|
+
" if (name !~ /^[A-Za-z_][A-Za-z0-9_]*$/) continue",
|
|
16169
|
+
` if (name == "LC_ALL" || (!(name in allow) && name !~ /^(${prefixes})_/)) continue`,
|
|
16170
|
+
' value = ENVIRON[name]; quoted = ""',
|
|
16171
|
+
' while ((k = index(value, "\\047")) > 0) { quoted = quoted substr(value, 1, k - 1) "\\047\\\\\\047\\047"; value = substr(value, k + 1) }',
|
|
16172
|
+
' printf "\\047%s=%s\\047 ", name, quoted value',
|
|
16173
|
+
" }",
|
|
16174
|
+
"}')",
|
|
16175
|
+
'eval "set -- $hasna_skills_env \\"\\$@\\""',
|
|
16176
|
+
'if [ "${LC_ALL+x}" = x ]; then set -- "LC_ALL=$LC_ALL" "$@"; fi',
|
|
16177
|
+
'exec /usr/bin/env -i "$@"',
|
|
16178
|
+
""
|
|
16179
|
+
].join(`
|
|
16180
|
+
`);
|
|
16181
|
+
}
|
|
16182
|
+
var COMMAND_LINE = new RegExp(`^set -- '([^']+)' ${PINNED_LAUNCHER_BUN_FLAGS.join(" ")} '--cwd=([^']+)' '([^']+)' "\\$@"$`, "m");
|
|
16183
|
+
function parsePinnedLauncher(text2) {
|
|
16184
|
+
const match = COMMAND_LINE.exec(text2);
|
|
16185
|
+
if (!match)
|
|
16186
|
+
return null;
|
|
16187
|
+
const binding = { runtime: match[1], cwd: match[2], entry: match[3] };
|
|
16188
|
+
try {
|
|
16189
|
+
if (renderPinnedLauncher(binding) !== text2)
|
|
16190
|
+
return null;
|
|
16191
|
+
} catch {
|
|
16192
|
+
return null;
|
|
16193
|
+
}
|
|
16194
|
+
return binding;
|
|
16195
|
+
}
|
|
16196
|
+
var PINNED_LAUNCHER_MAX_BYTES = 16 * 1024;
|
|
16197
|
+
function resolveLauncherCommand(path) {
|
|
16198
|
+
const physical = realpathSync9(path);
|
|
16199
|
+
const stat = lstatSync19(physical);
|
|
16200
|
+
if (stat.isFile() && stat.size <= PINNED_LAUNCHER_MAX_BYTES) {
|
|
16201
|
+
const text2 = readFileSync14(physical, "utf8");
|
|
16202
|
+
const binding = parsePinnedLauncher(text2);
|
|
16203
|
+
if (binding) {
|
|
16204
|
+
let entry;
|
|
16205
|
+
try {
|
|
16206
|
+
entry = realpathSync9(binding.entry);
|
|
16207
|
+
} catch {
|
|
16208
|
+
throw new Error("LAUNCHER_ENTRY_UNREADABLE");
|
|
16209
|
+
}
|
|
16210
|
+
if (entry !== binding.entry)
|
|
16211
|
+
throw new Error("LAUNCHER_ENTRY_NOT_PHYSICAL");
|
|
16212
|
+
return { physical, entry, pinned: { ...binding, sha256: sha2562(text2) } };
|
|
16213
|
+
}
|
|
16214
|
+
}
|
|
16215
|
+
return { physical, entry: physical, pinned: null };
|
|
16216
|
+
}
|
|
16217
|
+
function assertPinnedLauncherRuntimeSafe(runtime) {
|
|
16218
|
+
assertLauncherPath(runtime, "LAUNCHER_RUNTIME_PATH_INVALID");
|
|
16219
|
+
let stat;
|
|
16220
|
+
try {
|
|
16221
|
+
stat = lstatSync19(runtime);
|
|
16222
|
+
} catch {
|
|
16223
|
+
throw new Error("LAUNCHER_RUNTIME_UNSAFE");
|
|
16224
|
+
}
|
|
16225
|
+
const uid = process.getuid?.() ?? -1;
|
|
16226
|
+
if (!stat.isFile() || stat.isSymbolicLink() || ![0, uid].includes(stat.uid) || (stat.mode & 18) !== 0 || (stat.mode & 64) === 0) {
|
|
16227
|
+
throw new Error("LAUNCHER_RUNTIME_UNSAFE");
|
|
16228
|
+
}
|
|
16229
|
+
}
|
|
16230
|
+
|
|
16071
16231
|
// src/lib/agent-integration.ts
|
|
16072
|
-
var sha3 = (data) =>
|
|
16232
|
+
var sha3 = (data) => createHash19("sha256").update(data).digest("hex");
|
|
16073
16233
|
var ROOTS = NATIVE_SKILL_ROOTS;
|
|
16074
16234
|
function hasTrustedDarwinAcl(fd, allowDenyOnly = false) {
|
|
16075
16235
|
try {
|
|
@@ -16120,11 +16280,11 @@ function isSystemRootAlias(path) {
|
|
|
16120
16280
|
const target = `/private${path}`, link = `private${path}`;
|
|
16121
16281
|
const identity5 = (stat) => `${stat.dev}:${stat.ino}:${stat.ctimeNs}:${stat.uid}:${stat.mode}`;
|
|
16122
16282
|
try {
|
|
16123
|
-
const before =
|
|
16124
|
-
if (!before.isSymbolicLink() || before.uid !== 0n ||
|
|
16283
|
+
const before = lstatSync20(path, { bigint: true });
|
|
16284
|
+
if (!before.isSymbolicLink() || before.uid !== 0n || readlinkSync6(path) !== link)
|
|
16125
16285
|
return false;
|
|
16126
16286
|
const directories = ["/", "/private", target].map((directory) => {
|
|
16127
|
-
const stat =
|
|
16287
|
+
const stat = lstatSync20(directory, { bigint: true });
|
|
16128
16288
|
if (!stat.isDirectory() || stat.uid !== 0n)
|
|
16129
16289
|
throw new Error("Untrusted system alias directory");
|
|
16130
16290
|
if (directory !== "/private/tmp") {
|
|
@@ -16132,23 +16292,23 @@ function isSystemRootAlias(path) {
|
|
|
16132
16292
|
throw new Error("Writable system alias directory");
|
|
16133
16293
|
} else if ((stat.mode & 0o1000n) === 0n)
|
|
16134
16294
|
throw new Error("Unprotected system temporary directory");
|
|
16135
|
-
const fd =
|
|
16295
|
+
const fd = openSync11(directory, constants11.O_RDONLY | constants11.O_DIRECTORY | constants11.O_NOFOLLOW);
|
|
16136
16296
|
try {
|
|
16137
|
-
if (identity5(
|
|
16297
|
+
if (identity5(fstatSync11(fd, { bigint: true })) !== identity5(stat) || !hasTrustedDarwinAcl(fd) || identity5(fstatSync11(fd, { bigint: true })) !== identity5(stat))
|
|
16138
16298
|
throw new Error("Unverified system alias directory ACL");
|
|
16139
16299
|
} finally {
|
|
16140
|
-
|
|
16300
|
+
closeSync11(fd);
|
|
16141
16301
|
}
|
|
16142
16302
|
return { directory, identity: identity5(stat) };
|
|
16143
16303
|
});
|
|
16144
|
-
return
|
|
16304
|
+
return realpathSync10(path) === target && readlinkSync6(path) === link && identity5(lstatSync20(path, { bigint: true })) === identity5(before) && directories.every((item) => identity5(lstatSync20(item.directory, { bigint: true })) === item.identity);
|
|
16145
16305
|
} catch {
|
|
16146
16306
|
return false;
|
|
16147
16307
|
}
|
|
16148
16308
|
}
|
|
16149
16309
|
function canonicalSystemPath(path) {
|
|
16150
16310
|
const absolute = resolve13(path), root = `/${absolute.split(sep7)[1]}`;
|
|
16151
|
-
if (process.platform !== "darwin" || !["/var", "/tmp", "/etc"].includes(root) || !
|
|
16311
|
+
if (process.platform !== "darwin" || !["/var", "/tmp", "/etc"].includes(root) || !lstatSync20(root, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
16152
16312
|
return absolute;
|
|
16153
16313
|
if (!isSystemRootAlias(root))
|
|
16154
16314
|
throw new Error(`Refusing symlink path: ${root}`);
|
|
@@ -16157,7 +16317,7 @@ function canonicalSystemPath(path) {
|
|
|
16157
16317
|
function assertSafePath(path) {
|
|
16158
16318
|
let cursor = resolve13(path);
|
|
16159
16319
|
while (true) {
|
|
16160
|
-
if (
|
|
16320
|
+
if (lstatSync20(cursor, { throwIfNoEntry: false })?.isSymbolicLink() && !isSystemRootAlias(cursor))
|
|
16161
16321
|
throw new Error(`Refusing symlink path: ${cursor}`);
|
|
16162
16322
|
const parent = dirname14(cursor);
|
|
16163
16323
|
if (parent === cursor)
|
|
@@ -16167,17 +16327,17 @@ function assertSafePath(path) {
|
|
|
16167
16327
|
}
|
|
16168
16328
|
function readRootAlias(home, agent) {
|
|
16169
16329
|
assertSafePath(home);
|
|
16170
|
-
const realHome =
|
|
16171
|
-
const stat =
|
|
16330
|
+
const realHome = realpathSync10(home), alias = join23(realHome, `.${agent}`);
|
|
16331
|
+
const stat = lstatSync20(alias, { throwIfNoEntry: false, bigint: true });
|
|
16172
16332
|
if (!stat?.isSymbolicLink())
|
|
16173
16333
|
throw new Error(`Agent root alias changed after planning: ${alias}`);
|
|
16174
|
-
const link =
|
|
16334
|
+
const link = readlinkSync6(alias), targetPath = resolve13(dirname14(alias), link);
|
|
16175
16335
|
assertSafePath(targetPath);
|
|
16176
|
-
const targetStat =
|
|
16336
|
+
const targetStat = lstatSync20(targetPath, { throwIfNoEntry: false });
|
|
16177
16337
|
if (!targetStat?.isDirectory())
|
|
16178
16338
|
throw new Error(`Agent root alias must target an existing directory: ${alias}`);
|
|
16179
|
-
const target =
|
|
16180
|
-
if (!inside || inside === ".." || inside.startsWith(`..${sep7}`) ||
|
|
16339
|
+
const target = realpathSync10(targetPath), inside = relative6(realHome, target);
|
|
16340
|
+
if (!inside || inside === ".." || inside.startsWith(`..${sep7}`) || isAbsolute14(inside))
|
|
16181
16341
|
throw new Error(`Agent root alias target must be inside the real home: ${alias}`);
|
|
16182
16342
|
return { agent, home: realHome, alias, target, link, aliasIdentity: `${stat.dev}:${stat.ino}:${stat.ctimeNs}`, targetIdentity: `${targetStat.dev}:${targetStat.ino}` };
|
|
16183
16343
|
}
|
|
@@ -16186,7 +16346,7 @@ function rootAliases(home, allowed = false) {
|
|
|
16186
16346
|
return [];
|
|
16187
16347
|
const result = [];
|
|
16188
16348
|
for (const agent of ["claude", "codex"])
|
|
16189
|
-
if (
|
|
16349
|
+
if (lstatSync20(join23(home, `.${agent}`), { throwIfNoEntry: false })?.isSymbolicLink())
|
|
16190
16350
|
result.push(readRootAlias(home, agent));
|
|
16191
16351
|
if (result.some((item, index) => result.slice(index + 1).some((other) => item.target === other.target || item.target.startsWith(other.target + sep7) || other.target.startsWith(item.target + sep7))))
|
|
16192
16352
|
throw new Error("Agent root alias targets must not overlap");
|
|
@@ -16203,17 +16363,17 @@ function disabledCodexSkillPaths(config, aliases) {
|
|
|
16203
16363
|
const rows = skills.config;
|
|
16204
16364
|
if (!Array.isArray(rows))
|
|
16205
16365
|
return [];
|
|
16206
|
-
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" || !
|
|
16366
|
+
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" || !isAbsolute14(entry.path)) || entry.name !== undefined && (typeof entry.name !== "string" || !entry.name.trim())))
|
|
16207
16367
|
return [];
|
|
16208
16368
|
if (rows.some((entry) => entry.name !== undefined && entry.enabled !== false))
|
|
16209
16369
|
return [];
|
|
16210
16370
|
const settings = new Map;
|
|
16211
16371
|
for (const entry of rows) {
|
|
16212
|
-
if (typeof entry.path !== "string" || !
|
|
16372
|
+
if (typeof entry.path !== "string" || !isAbsolute14(entry.path))
|
|
16213
16373
|
continue;
|
|
16214
16374
|
let document2;
|
|
16215
16375
|
try {
|
|
16216
|
-
document2 =
|
|
16376
|
+
document2 = realpathSync10(canonicalAgentPath(entry.path, aliases));
|
|
16217
16377
|
} catch {
|
|
16218
16378
|
continue;
|
|
16219
16379
|
}
|
|
@@ -16234,16 +16394,16 @@ function recheckRootAliases(aliases) {
|
|
|
16234
16394
|
}
|
|
16235
16395
|
function nativeSourceDigest(path) {
|
|
16236
16396
|
assertSafePath(path);
|
|
16237
|
-
return
|
|
16397
|
+
return lstatSync20(path, { throwIfNoEntry: false }) ? sha3(readNativeBytes(path, 1024 * 1024)) : null;
|
|
16238
16398
|
}
|
|
16239
16399
|
function readNativeBytes(path, maximum = 64 * 1024 * 1024) {
|
|
16240
16400
|
assertSafePath(path);
|
|
16241
|
-
const before =
|
|
16401
|
+
const before = lstatSync20(path);
|
|
16242
16402
|
if (!before.isFile() || before.size > maximum)
|
|
16243
16403
|
throw new Error("Unsupported or oversized native skill file");
|
|
16244
|
-
const descriptor =
|
|
16404
|
+
const descriptor = openSync11(path, constants11.O_RDONLY | constants11.O_NOFOLLOW | constants11.O_NONBLOCK);
|
|
16245
16405
|
try {
|
|
16246
|
-
const opened =
|
|
16406
|
+
const opened = fstatSync11(descriptor);
|
|
16247
16407
|
if (!opened.isFile() || opened.dev !== before.dev || opened.ino !== before.ino || opened.size !== before.size)
|
|
16248
16408
|
throw new Error("Native skill file changed while reading");
|
|
16249
16409
|
const bytes = Buffer.allocUnsafe(before.size + 1);
|
|
@@ -16254,19 +16414,19 @@ function readNativeBytes(path, maximum = 64 * 1024 * 1024) {
|
|
|
16254
16414
|
break;
|
|
16255
16415
|
length += count;
|
|
16256
16416
|
}
|
|
16257
|
-
const after =
|
|
16417
|
+
const after = fstatSync11(descriptor), current = lstatSync20(path);
|
|
16258
16418
|
if (current.dev !== opened.dev || current.ino !== opened.ino || current.size !== after.size || current.mtimeMs !== after.mtimeMs || current.ctimeMs !== after.ctimeMs || length !== before.size || after.size !== before.size || after.mtimeMs !== opened.mtimeMs || after.ctimeMs !== opened.ctimeMs)
|
|
16259
16419
|
throw new Error("Native skill file changed while reading");
|
|
16260
16420
|
return bytes.subarray(0, length);
|
|
16261
16421
|
} finally {
|
|
16262
|
-
|
|
16422
|
+
closeSync11(descriptor);
|
|
16263
16423
|
}
|
|
16264
16424
|
}
|
|
16265
16425
|
function treeHash(root) {
|
|
16266
|
-
const hash2 =
|
|
16426
|
+
const hash2 = createHash19("sha256");
|
|
16267
16427
|
let bytes = 0, files = 0;
|
|
16268
16428
|
function visit2(path) {
|
|
16269
|
-
const stat =
|
|
16429
|
+
const stat = lstatSync20(path);
|
|
16270
16430
|
if (stat.isSymbolicLink())
|
|
16271
16431
|
throw new Error(`Refusing symlink in skill: ${path}`);
|
|
16272
16432
|
const rel = relative6(root, path);
|
|
@@ -16295,13 +16455,13 @@ function selectNativeMigrationTargets(inventory, manifest) {
|
|
|
16295
16455
|
const identities = new Set;
|
|
16296
16456
|
const selected = [];
|
|
16297
16457
|
for (const target of manifest.targets) {
|
|
16298
|
-
if (!
|
|
16458
|
+
if (!isAbsolute14(target.projectRoot) || resolve13(target.projectRoot) !== target.projectRoot)
|
|
16299
16459
|
throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
|
|
16300
16460
|
const projectRoot = canonicalSystemPath(target.projectRoot), normalized = relative6(projectRoot, resolve13(projectRoot, target.path));
|
|
16301
|
-
if (!existsSync9(projectRoot) || !
|
|
16461
|
+
if (!existsSync9(projectRoot) || !lstatSync20(projectRoot).isDirectory())
|
|
16302
16462
|
throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
|
|
16303
16463
|
assertSafePath(projectRoot);
|
|
16304
|
-
if (
|
|
16464
|
+
if (isAbsolute14(target.path) || target.path.includes("\\") || target.path.includes("\x00") || !normalized || normalized === ".." || normalized.startsWith(`..${sep7}`) || normalized !== target.path || !/^[0-9a-f]{64}$/.test(target.treeSha256))
|
|
16305
16465
|
throw new Error(`Invalid native migration target: ${target.path}`);
|
|
16306
16466
|
const identity5 = `${target.agent}\x00${canonicalSystemPath(projectRoot)}\x00${normalized}`;
|
|
16307
16467
|
if (identities.has(identity5))
|
|
@@ -16344,9 +16504,9 @@ function isCodexSkillDiscoveryInput(path) {
|
|
|
16344
16504
|
}
|
|
16345
16505
|
function inventoryNativeSkills(home = homedir2(), options = {}) {
|
|
16346
16506
|
home = canonicalSystemPath(home);
|
|
16347
|
-
if (options.reviewedCacheAlias !== undefined && (!options.includeVendor || !
|
|
16507
|
+
if (options.reviewedCacheAlias !== undefined && (!options.includeVendor || !isAbsolute14(options.reviewedCacheAlias) || resolve13(options.reviewedCacheAlias) !== options.reviewedCacheAlias))
|
|
16348
16508
|
throw new Error("A reviewed cache alias requires vendor inventory and an exact absolute path");
|
|
16349
|
-
if (options.disabledVendorPaths?.some((path) => !
|
|
16509
|
+
if (options.disabledVendorPaths?.some((path) => !isAbsolute14(path) || resolve13(path) !== path))
|
|
16350
16510
|
throw new Error("Disabled vendor paths must be exact absolute paths");
|
|
16351
16511
|
const reviewedCacheAlias = options.reviewedCacheAlias === undefined ? undefined : canonicalSystemPath(options.reviewedCacheAlias);
|
|
16352
16512
|
const disabledVendorPaths = new Set((options.disabledVendorPaths ?? []).map(canonicalSystemPath));
|
|
@@ -16365,7 +16525,7 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
|
|
|
16365
16525
|
roots.push(["sumi", canonicalAgentPath(join23(project, directory, name), aliases)]);
|
|
16366
16526
|
}
|
|
16367
16527
|
const installationInputs = options.codexInstallationInputRoots ?? [];
|
|
16368
|
-
if (installationInputs.some((input) => resolve13(input) !== input ||
|
|
16528
|
+
if (installationInputs.some((input) => resolve13(input) !== input || realpathSync10(input) !== input || roots.some(([agent, path]) => agent === "codex" && (path === input || path.startsWith(input + sep7) || input.startsWith(path + sep7)))))
|
|
16369
16529
|
throw new Error("Native installation input overlaps an unconditional skill-loading root");
|
|
16370
16530
|
const entries = [], seen = new Set;
|
|
16371
16531
|
const cacheScans = new Map, maxAliasProofEntries = 1e4;
|
|
@@ -16379,13 +16539,13 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
|
|
|
16379
16539
|
}
|
|
16380
16540
|
let reviewedCacheAliasFound = false;
|
|
16381
16541
|
function verifiedSiblingCacheAlias(agent, path, parent) {
|
|
16382
|
-
const link =
|
|
16383
|
-
if (
|
|
16542
|
+
const link = readlinkSync6(path), lexicalTarget = resolve13(parent, link);
|
|
16543
|
+
if (isAbsolute14(link) ? link !== lexicalTarget : dirname14(link) !== ".")
|
|
16384
16544
|
return false;
|
|
16385
16545
|
const target = canonicalSystemPath(lexicalTarget);
|
|
16386
16546
|
if (dirname14(target) !== parent)
|
|
16387
16547
|
return false;
|
|
16388
|
-
if (!
|
|
16548
|
+
if (!lstatSync20(target, { throwIfNoEntry: false })?.isDirectory())
|
|
16389
16549
|
return false;
|
|
16390
16550
|
const scan = cacheScans.get(target);
|
|
16391
16551
|
if (!scan?.complete || scan.entries > maxAliasProofEntries)
|
|
@@ -16410,7 +16570,7 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
|
|
|
16410
16570
|
return scan;
|
|
16411
16571
|
if (!existsSync9(path))
|
|
16412
16572
|
return scan;
|
|
16413
|
-
const stat =
|
|
16573
|
+
const stat = lstatSync20(path);
|
|
16414
16574
|
if (stat.isFile()) {
|
|
16415
16575
|
if (agent === "sumi" && depth === 1 && path.endsWith(".md"))
|
|
16416
16576
|
throw new Error("NATIVE_SKILL_DRIFT: flat Sumi skill documents require a dedicated migration adapter");
|
|
@@ -16427,7 +16587,7 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
|
|
|
16427
16587
|
const marker = join23(path, ".hasna-skills.json");
|
|
16428
16588
|
if (existsSync9(marker)) {
|
|
16429
16589
|
try {
|
|
16430
|
-
managed = JSON.parse(
|
|
16590
|
+
managed = JSON.parse(readFileSync15(marker, "utf8")).managedBy === "@hasna/skills";
|
|
16431
16591
|
} catch {}
|
|
16432
16592
|
}
|
|
16433
16593
|
const bridge = (!vendor || agent === "sumi") && isOwnedCliBridge(path, bridgePaths);
|
|
@@ -16459,7 +16619,7 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
|
|
|
16459
16619
|
if (isVendor && !options.includeVendor)
|
|
16460
16620
|
continue;
|
|
16461
16621
|
const child = join23(path, name);
|
|
16462
|
-
if (isVendor &&
|
|
16622
|
+
if (isVendor && lstatSync20(child, { throwIfNoEntry: false })?.isSymbolicLink()) {
|
|
16463
16623
|
const target = statSync9(child, { throwIfNoEntry: false });
|
|
16464
16624
|
if (target?.isFile() || pluginCache && target?.isDirectory() && verifiedSiblingCacheAlias(agent, child, path)) {
|
|
16465
16625
|
scan.entries++;
|
|
@@ -16502,7 +16662,7 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
|
|
|
16502
16662
|
}
|
|
16503
16663
|
function readOptional(path) {
|
|
16504
16664
|
assertSafePath(path);
|
|
16505
|
-
return existsSync9(path) ?
|
|
16665
|
+
return existsSync9(path) ? readFileSync15(path, "utf8") : null;
|
|
16506
16666
|
}
|
|
16507
16667
|
function jsonObject(text2, path) {
|
|
16508
16668
|
if (text2 === null)
|
|
@@ -16834,23 +16994,23 @@ function projectedHookAcl(path, observed) {
|
|
|
16834
16994
|
if (process.platform !== "darwin")
|
|
16835
16995
|
return;
|
|
16836
16996
|
const identity5 = (stat) => `${stat.dev}:${stat.ino}:${stat.ctimeNs}:${stat.uid}:${stat.mode}:${stat.nlink}:${stat.size}:${stat.mtimeNs}`;
|
|
16837
|
-
const fd =
|
|
16997
|
+
const fd = openSync11(path, constants11.O_RDONLY | constants11.O_NOFOLLOW | constants11.O_NONBLOCK | (observed.isDirectory() ? constants11.O_DIRECTORY : 0));
|
|
16838
16998
|
try {
|
|
16839
|
-
if (identity5(
|
|
16999
|
+
if (identity5(fstatSync11(fd, { bigint: true })) !== identity5(observed) || !hasTrustedDarwinAcl(fd, true) || identity5(fstatSync11(fd, { bigint: true })) !== identity5(observed) || identity5(lstatSync20(path, { bigint: true })) !== identity5(observed))
|
|
16840
17000
|
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
16841
17001
|
} finally {
|
|
16842
|
-
|
|
17002
|
+
closeSync11(fd);
|
|
16843
17003
|
}
|
|
16844
17004
|
}
|
|
16845
17005
|
function projectedHookExecutable(command, expectedResolved) {
|
|
16846
17006
|
try {
|
|
16847
|
-
if (!
|
|
17007
|
+
if (!isAbsolute14(command) || /[\0\r\n]/.test(command) || resolve13(command) !== command)
|
|
16848
17008
|
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
16849
17009
|
command = canonicalSystemPath(command);
|
|
16850
17010
|
const parents2 = (file = command) => {
|
|
16851
17011
|
const result = [];
|
|
16852
17012
|
for (let path = dirname14(file);; path = dirname14(path)) {
|
|
16853
|
-
const stat =
|
|
17013
|
+
const stat = lstatSync20(path, { bigint: true });
|
|
16854
17014
|
if (!stat.isDirectory() || (stat.mode & 0o022n) !== 0n && !(stat.uid === 0n && (stat.mode & 0o1000n) !== 0n))
|
|
16855
17015
|
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
16856
17016
|
projectedHookAcl(path, stat);
|
|
@@ -16860,13 +17020,22 @@ function projectedHookExecutable(command, expectedResolved) {
|
|
|
16860
17020
|
}
|
|
16861
17021
|
return result;
|
|
16862
17022
|
};
|
|
16863
|
-
const parentIdentity = parents2(), link =
|
|
17023
|
+
const parentIdentity = parents2(), link = lstatSync20(command, { bigint: true });
|
|
16864
17024
|
if (link.uid !== BigInt(process.getuid()) || !link.isFile() && !link.isSymbolicLink())
|
|
16865
17025
|
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
16866
17026
|
const linkIdentity = (stat) => `${stat.dev}:${stat.ino}:${stat.mode}:${stat.uid}:${stat.ctimeNs}`;
|
|
16867
|
-
const
|
|
17027
|
+
const target = resolveLauncherCommand(command), resolved = target.entry;
|
|
16868
17028
|
if (expectedResolved !== undefined && resolved !== expectedResolved)
|
|
16869
17029
|
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
17030
|
+
let launcher, launcherParentIdentity;
|
|
17031
|
+
if (target.pinned) {
|
|
17032
|
+
launcherParentIdentity = parents2(target.physical);
|
|
17033
|
+
launcher = snapshot(target.physical, false);
|
|
17034
|
+
projectedHookAcl(launcher.file, launcher.stat);
|
|
17035
|
+
if (launcher.sha256 !== target.pinned.sha256 || (launcher.stat.mode & 0o100n) === 0n)
|
|
17036
|
+
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
17037
|
+
assertPinnedLauncherRuntimeSafe(target.pinned.runtime);
|
|
17038
|
+
}
|
|
16870
17039
|
const resolvedParentIdentity = parents2(resolved);
|
|
16871
17040
|
const manifest = snapshot(join23(dirname14(dirname14(resolved)), "package.json"), false, { readOnlyPackage: true });
|
|
16872
17041
|
projectedHookAcl(manifest.file, manifest.stat);
|
|
@@ -16879,8 +17048,15 @@ function projectedHookExecutable(command, expectedResolved) {
|
|
|
16879
17048
|
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
16880
17049
|
const recheck = () => {
|
|
16881
17050
|
try {
|
|
16882
|
-
|
|
17051
|
+
const again = resolveLauncherCommand(command);
|
|
17052
|
+
if (again.entry !== resolved || again.physical !== target.physical || linkIdentity(lstatSync20(command, { bigint: true })) !== linkIdentity(link) || !isDeepStrictEqual6(parents2(), parentIdentity) || !isDeepStrictEqual6(parents2(resolved), resolvedParentIdentity))
|
|
16883
17053
|
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
17054
|
+
if (launcher) {
|
|
17055
|
+
if (!isDeepStrictEqual6(parents2(target.physical), launcherParentIdentity))
|
|
17056
|
+
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
17057
|
+
projectedHookAcl(launcher.file, launcher.stat);
|
|
17058
|
+
unchanged2(launcher);
|
|
17059
|
+
}
|
|
16884
17060
|
projectedHookAcl(cli.file, cli.stat);
|
|
16885
17061
|
projectedHookAcl(manifest.file, manifest.stat);
|
|
16886
17062
|
unchanged2(cli);
|
|
@@ -17002,7 +17178,7 @@ function claudeSettingsConsumers(home, path, discoveries, aliases) {
|
|
|
17002
17178
|
const canonical6 = (value) => canonicalAgentPath(value, aliases);
|
|
17003
17179
|
const containsSettings = (root) => {
|
|
17004
17180
|
const distance = relative6(canonical6(root), path);
|
|
17005
|
-
return distance === "" || distance !== ".." && !distance.startsWith(`..${sep7}`) && !
|
|
17181
|
+
return distance === "" || distance !== ".." && !distance.startsWith(`..${sep7}`) && !isAbsolute14(distance);
|
|
17006
17182
|
};
|
|
17007
17183
|
return discoveries.filter((binding) => binding.agent === "claude" || binding.agent === "opencode" || canonical6(join23(home, AGENT_ADAPTERS[binding.agent].config)) === path || binding.sources.some((source) => canonical6(source.path) === path) || binding.roots.some(containsSettings) || binding.directories?.some((directory) => containsSettings(directory.path))).map((binding) => binding.agent);
|
|
17008
17184
|
}
|
|
@@ -17035,7 +17211,7 @@ function planClaudeHookEventsUpdate(options) {
|
|
|
17035
17211
|
recheckRootAliases(aliases);
|
|
17036
17212
|
const path = canonicalAgentPath(join23(home, ".claude", "settings.json"), aliases);
|
|
17037
17213
|
assertSafePath(path);
|
|
17038
|
-
const before =
|
|
17214
|
+
const before = lstatSync20(path, { throwIfNoEntry: false }) ? new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(readNativeBytes(path, 1024 * 1024)) : null;
|
|
17039
17215
|
if ((before === null ? "absent" : sha3(before)) !== options.expectedSettingsSha256)
|
|
17040
17216
|
throw new Error("Claude settings preimage changed");
|
|
17041
17217
|
assertClaudeHookEventsReplacement(before, options.replacement, options.events);
|
|
@@ -17102,6 +17278,8 @@ function atomicWrite2(path, content) {
|
|
|
17102
17278
|
function planAgentSettingsWitnessUpgrade(options) {
|
|
17103
17279
|
if (options.targetCodexVersion !== undefined && (options.agent !== "codex" || ![2, 3, 4].includes(options.targetCodexVersion)))
|
|
17104
17280
|
throw new Error("Invalid Codex witness target version");
|
|
17281
|
+
if (options.targetClaudeVersion !== undefined && (options.agent !== "claude" || ![3, 4].includes(options.targetClaudeVersion)))
|
|
17282
|
+
throw new Error("Invalid Claude witness target version");
|
|
17105
17283
|
const home = resolve13(options.home ?? homedir2()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
|
|
17106
17284
|
const snapshot2 = readManagedSkillPolicySnapshot(dataDir2);
|
|
17107
17285
|
if (!snapshot2 || sha3(snapshot2.text) !== options.expectedPolicySha256)
|
|
@@ -17149,7 +17327,7 @@ function planAgentSettingsWitnessUpgrade(options) {
|
|
|
17149
17327
|
replaced.push(source);
|
|
17150
17328
|
}
|
|
17151
17329
|
}
|
|
17152
|
-
const next = options.agent === "sumi" ? upgradeSumiSettingsWitness(previous, options.reviewedPreimage) : options.agent === "claude" ? upgradeClaudeSettingsWitness(previous, options.reviewedPreimage) : options.targetCodexVersion === 4 ? upgradeCodexSettingsWitnessV4(previous, options.reviewedPreimage) : options.targetCodexVersion === 3 ? upgradeCodexSettingsWitnessV3(previous, options.reviewedPreimage) : upgradeCodexSettingsWitness(previous, options.reviewedPreimage);
|
|
17330
|
+
const next = options.agent === "sumi" ? upgradeSumiSettingsWitness(previous, options.reviewedPreimage) : options.agent === "claude" ? options.targetClaudeVersion === 4 ? upgradeClaudeSettingsWitnessV4(previous, options.reviewedPreimage) : upgradeClaudeSettingsWitness(previous, options.reviewedPreimage) : options.targetCodexVersion === 4 ? upgradeCodexSettingsWitnessV4(previous, options.reviewedPreimage) : options.targetCodexVersion === 3 ? upgradeCodexSettingsWitnessV3(previous, options.reviewedPreimage) : upgradeCodexSettingsWitness(previous, options.reviewedPreimage);
|
|
17153
17331
|
const rebound = [];
|
|
17154
17332
|
for (const source of binding.sources) {
|
|
17155
17333
|
if (!replaced.includes(source)) {
|
|
@@ -17195,7 +17373,7 @@ function applyAgentIntegrationUnlocked(plan, options = {}, assertCurrent) {
|
|
|
17195
17373
|
const upgrade = plan.settingsWitnessUpgrade;
|
|
17196
17374
|
if (!plan.managedAgentChecks || !plan.observedPolicy?.before)
|
|
17197
17375
|
throw new Error("Invalid settings witness upgrade plan");
|
|
17198
|
-
const verified = planAgentSettingsWitnessUpgrade({ agent: upgrade.agent, ...upgrade.agent === "codex" ? { targetCodexVersion: upgrade.toHashMode === "codex-settings-v4" ? 4 : upgrade.toHashMode === "codex-settings-v3" ? 3 : 2 } : {}, reviewedPreimage: upgrade.reviewedPreimage, home: plan.managedAgentChecks.home, dataDir: plan.dataDir, expectedPolicySha256: sha3(plan.observedPolicy.before), expectedSettingsSha256: upgrade.currentSettingsSha256 });
|
|
17376
|
+
const verified = planAgentSettingsWitnessUpgrade({ agent: upgrade.agent, ...upgrade.agent === "codex" ? { targetCodexVersion: upgrade.toHashMode === "codex-settings-v4" ? 4 : upgrade.toHashMode === "codex-settings-v3" ? 3 : 2 } : {}, ...upgrade.agent === "claude" && upgrade.toHashMode === "claude-settings-v4" ? { targetClaudeVersion: 4 } : {}, reviewedPreimage: upgrade.reviewedPreimage, home: plan.managedAgentChecks.home, dataDir: plan.dataDir, expectedPolicySha256: sha3(plan.observedPolicy.before), expectedSettingsSha256: upgrade.currentSettingsSha256 });
|
|
17199
17377
|
if (JSON.stringify(verified.changes) !== JSON.stringify(plan.changes) || JSON.stringify(verified.settingsWitnessUpgrade) !== JSON.stringify(upgrade))
|
|
17200
17378
|
throw new Error("Settings witness upgrade plan changed");
|
|
17201
17379
|
provenDiscovery = verified.discoveryBefore[0];
|
|
@@ -17226,7 +17404,7 @@ function applyAgentIntegrationUnlocked(plan, options = {}, assertCurrent) {
|
|
|
17226
17404
|
if (change.before !== null) {
|
|
17227
17405
|
const backup = join23(backupRoot, `${index}-${sha3(change.path).slice(0, 12)}.backup`);
|
|
17228
17406
|
writeFileSync6(backup, change.before, { mode: 384, flag: "wx" });
|
|
17229
|
-
if (
|
|
17407
|
+
if (readFileSync15(backup, "utf8") !== change.before)
|
|
17230
17408
|
throw new Error("Native configuration preservation readback failed");
|
|
17231
17409
|
backups.push(backup);
|
|
17232
17410
|
}
|
|
@@ -17289,11 +17467,11 @@ function applyAgentIntegrationUnlocked(plan, options = {}, assertCurrent) {
|
|
|
17289
17467
|
}
|
|
17290
17468
|
function syncArchiveDirectory(path) {
|
|
17291
17469
|
assertSafePath(path);
|
|
17292
|
-
const descriptor =
|
|
17470
|
+
const descriptor = openSync11(path, constants11.O_RDONLY | constants11.O_DIRECTORY | constants11.O_NOFOLLOW | constants11.O_NONBLOCK);
|
|
17293
17471
|
try {
|
|
17294
|
-
|
|
17472
|
+
fsyncSync5(descriptor);
|
|
17295
17473
|
} finally {
|
|
17296
|
-
|
|
17474
|
+
closeSync11(descriptor);
|
|
17297
17475
|
}
|
|
17298
17476
|
}
|
|
17299
17477
|
function writeArchiveJournal(path, value) {
|
|
@@ -17301,18 +17479,18 @@ function writeArchiveJournal(path, value) {
|
|
|
17301
17479
|
const temporary = `${path}.skills-${randomUUID3()}`;
|
|
17302
17480
|
let descriptor;
|
|
17303
17481
|
try {
|
|
17304
|
-
descriptor =
|
|
17482
|
+
descriptor = openSync11(temporary, constants11.O_WRONLY | constants11.O_CREAT | constants11.O_EXCL | constants11.O_NOFOLLOW, 384);
|
|
17305
17483
|
writeFileSync6(descriptor, `${JSON.stringify(value)}
|
|
17306
17484
|
`);
|
|
17307
|
-
|
|
17308
|
-
|
|
17485
|
+
fsyncSync5(descriptor);
|
|
17486
|
+
closeSync11(descriptor);
|
|
17309
17487
|
descriptor = undefined;
|
|
17310
17488
|
renameSync3(temporary, path);
|
|
17311
17489
|
syncArchiveDirectory(dirname14(path));
|
|
17312
17490
|
} finally {
|
|
17313
17491
|
if (descriptor !== undefined)
|
|
17314
|
-
|
|
17315
|
-
if (
|
|
17492
|
+
closeSync11(descriptor);
|
|
17493
|
+
if (lstatSync20(temporary, { throwIfNoEntry: false }))
|
|
17316
17494
|
unlinkSync4(temporary);
|
|
17317
17495
|
}
|
|
17318
17496
|
}
|
|
@@ -17358,7 +17536,7 @@ function archiveNativeSkillsUnlocked(inventory, options, assertCurrent) {
|
|
|
17358
17536
|
const moved = [];
|
|
17359
17537
|
const verifyArchive = (entry) => {
|
|
17360
17538
|
assertSafePath(entry.archive);
|
|
17361
|
-
const stat =
|
|
17539
|
+
const stat = lstatSync20(entry.archive);
|
|
17362
17540
|
if (entry.discoveryOnly ? !stat.isFile() : !stat.isDirectory())
|
|
17363
17541
|
throw new Error("Archive type changed");
|
|
17364
17542
|
if ((entry.discoveryOnly ? sha3(readNativeBytes(entry.archive)) : treeHash(entry.archive)) !== entry.hash)
|
|
@@ -17409,7 +17587,7 @@ function archiveNativeSkillsUnlocked(inventory, options, assertCurrent) {
|
|
|
17409
17587
|
recheckRootAliases(aliases);
|
|
17410
17588
|
assertSafePath(entry.source);
|
|
17411
17589
|
assertSafePath(entry.archive);
|
|
17412
|
-
if (
|
|
17590
|
+
if (lstatSync20(entry.source, { throwIfNoEntry: false })) {
|
|
17413
17591
|
entry.status = "recovery-required";
|
|
17414
17592
|
entry.conflict = "source-occupied";
|
|
17415
17593
|
continue;
|
|
@@ -17426,7 +17604,7 @@ function archiveNativeSkillsUnlocked(inventory, options, assertCurrent) {
|
|
|
17426
17604
|
syncArchiveDirectory(dirname14(entry.source));
|
|
17427
17605
|
unlinkSync4(entry.archive);
|
|
17428
17606
|
} else {
|
|
17429
|
-
if (
|
|
17607
|
+
if (lstatSync20(entry.source, { throwIfNoEntry: false })) {
|
|
17430
17608
|
entry.status = "recovery-required";
|
|
17431
17609
|
entry.conflict = "source-occupied";
|
|
17432
17610
|
continue;
|
|
@@ -17459,12 +17637,12 @@ function isInertCodexPluginCacheCopy(entry, cache, allowedHostPaths, read2) {
|
|
|
17459
17637
|
return false;
|
|
17460
17638
|
const document2 = join23(entry.path, "SKILL.md");
|
|
17461
17639
|
const inside = relative6(cache, entry.path);
|
|
17462
|
-
if (!inside ||
|
|
17640
|
+
if (!inside || isAbsolute14(inside) || inside.split(sep7).some((segment) => segment === ".."))
|
|
17463
17641
|
return false;
|
|
17464
17642
|
assertSafePath(entry.path);
|
|
17465
|
-
if (!
|
|
17643
|
+
if (!lstatSync20(cache).isDirectory() || !lstatSync20(entry.path).isDirectory() || !lstatSync20(document2).isFile())
|
|
17466
17644
|
return false;
|
|
17467
|
-
if (
|
|
17645
|
+
if (realpathSync10.native(cache) !== cache || realpathSync10.native(entry.path) !== entry.path || realpathSync10.native(document2) !== document2)
|
|
17468
17646
|
return false;
|
|
17469
17647
|
if (!classifyCodexPluginCacheDocument(document2, cache, read2))
|
|
17470
17648
|
return false;
|
|
@@ -17641,9 +17819,9 @@ function isSkillsOwnershipMarker(marker) {
|
|
|
17641
17819
|
function hasSkillsOwnershipMarker(dir) {
|
|
17642
17820
|
const path = join25(dir, SYNC_MARKER_FILE);
|
|
17643
17821
|
try {
|
|
17644
|
-
if (!
|
|
17822
|
+
if (!lstatSync21(path).isFile())
|
|
17645
17823
|
return false;
|
|
17646
|
-
const marker = JSON.parse(
|
|
17824
|
+
const marker = JSON.parse(readFileSync16(path, "utf8"));
|
|
17647
17825
|
return isSkillsOwnershipMarker(marker);
|
|
17648
17826
|
} catch {
|
|
17649
17827
|
return false;
|
|
@@ -17860,7 +18038,7 @@ function writeManagedSkillDirUnlocked(dir, skillMd, options, assertCurrent) {
|
|
|
17860
18038
|
if (dirExists && managed && hasSkillMd && !options.force && isPointerSkillMd(skillMd)) {
|
|
17861
18039
|
let existingIsStub = false;
|
|
17862
18040
|
try {
|
|
17863
|
-
existingIsStub = isPointerSkillMd(
|
|
18041
|
+
existingIsStub = isPointerSkillMd(readFileSync16(skillMdPath, "utf-8"));
|
|
17864
18042
|
} catch {
|
|
17865
18043
|
existingIsStub = false;
|
|
17866
18044
|
}
|
|
@@ -17910,7 +18088,7 @@ function writeManagedSkillDirUnlocked(dir, skillMd, options, assertCurrent) {
|
|
|
17910
18088
|
assertCurrent();
|
|
17911
18089
|
renameDirectory(candidateDir, dir);
|
|
17912
18090
|
assertCurrent();
|
|
17913
|
-
if (
|
|
18091
|
+
if (readFileSync16(skillMdPath, "utf8") !== (skillMd.endsWith(`
|
|
17914
18092
|
`) ? skillMd : `${skillMd}
|
|
17915
18093
|
`))
|
|
17916
18094
|
throw new Error("Managed skill readback failed");
|
|
@@ -17954,7 +18132,7 @@ function sourceSkillMd(skillPath, name, description, kind, preferBundledDocs = f
|
|
|
17954
18132
|
if (kind === undefined || kind === "instruction" || preferBundledDocs) {
|
|
17955
18133
|
const skillMdPath = join25(skillPath, "SKILL.md");
|
|
17956
18134
|
if (existsSync10(skillMdPath))
|
|
17957
|
-
return
|
|
18135
|
+
return readFileSync16(skillMdPath, "utf-8");
|
|
17958
18136
|
}
|
|
17959
18137
|
return pointerSkillMd(name, description);
|
|
17960
18138
|
}
|
|
@@ -17994,7 +18172,7 @@ function resolveSkillAlias(name) {
|
|
|
17994
18172
|
}
|
|
17995
18173
|
|
|
17996
18174
|
// src/lib/project-state.ts
|
|
17997
|
-
import { existsSync as existsSync11, mkdirSync as mkdirSync8, readFileSync as
|
|
18175
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync8, readFileSync as readFileSync17, writeFileSync as writeFileSync8 } from "fs";
|
|
17998
18176
|
import { join as join26 } from "path";
|
|
17999
18177
|
var VALID_PIN_SOURCES = [
|
|
18000
18178
|
"official",
|
|
@@ -18020,7 +18198,7 @@ function loadProjectConfig(targetDir = process.cwd()) {
|
|
|
18020
18198
|
if (!existsSync11(path))
|
|
18021
18199
|
return null;
|
|
18022
18200
|
try {
|
|
18023
|
-
return normalizeProjectConfig(JSON.parse(
|
|
18201
|
+
return normalizeProjectConfig(JSON.parse(readFileSync17(path, "utf-8")));
|
|
18024
18202
|
} catch {
|
|
18025
18203
|
return null;
|
|
18026
18204
|
}
|
|
@@ -18207,7 +18385,7 @@ function createLocalSkillManifest(name, generateSkillMd) {
|
|
|
18207
18385
|
let skillMd = "";
|
|
18208
18386
|
const skillMdPath = join27(sourcePath, "SKILL.md");
|
|
18209
18387
|
if (existsSync12(skillMdPath)) {
|
|
18210
|
-
skillMd =
|
|
18388
|
+
skillMd = readFileSync18(skillMdPath, "utf-8");
|
|
18211
18389
|
} else if (generateSkillMd) {
|
|
18212
18390
|
skillMd = generateSkillMd(name) ?? "";
|
|
18213
18391
|
} else {
|
|
@@ -18333,7 +18511,7 @@ function resolveAgentSkillMd(name, generateSkillMd) {
|
|
|
18333
18511
|
const sourcePath = getSkillPath(name);
|
|
18334
18512
|
const skillMdPath = join27(sourcePath, "SKILL.md");
|
|
18335
18513
|
if (existsSync12(skillMdPath))
|
|
18336
|
-
return
|
|
18514
|
+
return readFileSync18(skillMdPath, "utf-8");
|
|
18337
18515
|
if (generateSkillMd)
|
|
18338
18516
|
return generateSkillMd(name);
|
|
18339
18517
|
return generateMinimalSkillMd(name);
|
|
@@ -18389,14 +18567,14 @@ function readBundledSkillVersion(name) {
|
|
|
18389
18567
|
if (!existsSync12(pkgPath))
|
|
18390
18568
|
return "unknown";
|
|
18391
18569
|
try {
|
|
18392
|
-
const pkg = JSON.parse(
|
|
18570
|
+
const pkg = JSON.parse(readFileSync18(pkgPath, "utf-8"));
|
|
18393
18571
|
return pkg.version || "unknown";
|
|
18394
18572
|
} catch {
|
|
18395
18573
|
return "unknown";
|
|
18396
18574
|
}
|
|
18397
18575
|
}
|
|
18398
18576
|
function readFileIfExists(path) {
|
|
18399
|
-
return existsSync12(path) ?
|
|
18577
|
+
return existsSync12(path) ? readFileSync18(path, "utf-8") : null;
|
|
18400
18578
|
}
|
|
18401
18579
|
function loadProjectConfigCompat(targetDir) {
|
|
18402
18580
|
return loadProjectConfig(targetDir);
|
|
@@ -18444,7 +18622,7 @@ function isInstructionSkillDir(skillPath, meta) {
|
|
|
18444
18622
|
if (!existsSync13(skillMdPath))
|
|
18445
18623
|
return false;
|
|
18446
18624
|
try {
|
|
18447
|
-
return parseSkillFrontmatter(
|
|
18625
|
+
return parseSkillFrontmatter(readFileSync19(skillMdPath, "utf-8"))?.kind === "instruction";
|
|
18448
18626
|
} catch {
|
|
18449
18627
|
return false;
|
|
18450
18628
|
}
|
|
@@ -18495,7 +18673,7 @@ function getSkillRequirements(name) {
|
|
|
18495
18673
|
const meta = getSkill(name);
|
|
18496
18674
|
let dependencies = {};
|
|
18497
18675
|
try {
|
|
18498
|
-
dependencies = JSON.parse(
|
|
18676
|
+
dependencies = JSON.parse(readFileSync19(join28(skillPath, "package.json"), "utf8")).dependencies || {};
|
|
18499
18677
|
} catch {}
|
|
18500
18678
|
return getSkillRequirementsFromContent(name, texts, dependencies, meta);
|
|
18501
18679
|
}
|
|
@@ -18563,7 +18741,7 @@ async function runSkill(name, args, options = {}) {
|
|
|
18563
18741
|
}
|
|
18564
18742
|
let entryPoint2;
|
|
18565
18743
|
try {
|
|
18566
|
-
const pkg = JSON.parse(
|
|
18744
|
+
const pkg = JSON.parse(readFileSync19(pkgPath, "utf-8"));
|
|
18567
18745
|
if (pkg.bin) {
|
|
18568
18746
|
const binValues = Object.values(pkg.bin);
|
|
18569
18747
|
entryPoint2 = binValues[0];
|
|
@@ -18666,7 +18844,7 @@ function generateSkillMd(name) {
|
|
|
18666
18844
|
const pkgPath = join28(skillPath, "package.json");
|
|
18667
18845
|
if (existsSync13(pkgPath)) {
|
|
18668
18846
|
try {
|
|
18669
|
-
const pkg = JSON.parse(
|
|
18847
|
+
const pkg = JSON.parse(readFileSync19(pkgPath, "utf-8"));
|
|
18670
18848
|
if (pkg.bin) {
|
|
18671
18849
|
const binKeys = Object.keys(pkg.bin);
|
|
18672
18850
|
if (binKeys.length > 0)
|
|
@@ -18742,7 +18920,7 @@ function extractEnvVars(text2) {
|
|
|
18742
18920
|
function readIfExists(path) {
|
|
18743
18921
|
try {
|
|
18744
18922
|
if (existsSync13(path)) {
|
|
18745
|
-
return
|
|
18923
|
+
return readFileSync19(path, "utf-8");
|
|
18746
18924
|
}
|
|
18747
18925
|
} catch {}
|
|
18748
18926
|
return null;
|
|
@@ -18869,7 +19047,7 @@ function exactProfileSelection(spec, profile) {
|
|
|
18869
19047
|
}
|
|
18870
19048
|
|
|
18871
19049
|
// src/lib/plugin-projection.ts
|
|
18872
|
-
import { createHash as
|
|
19050
|
+
import { createHash as createHash20 } from "crypto";
|
|
18873
19051
|
import { posix } from "path";
|
|
18874
19052
|
var PLUGIN_PROJECTION_MANIFEST = "plugin-projection.json";
|
|
18875
19053
|
var PLUGIN_PROJECTION_LIMITS = Object.freeze({ files: 1024, bytes: 64 * 1024 * 1024, fileBytes: 16 * 1024 * 1024, metadataBytes: 512 * 1024, registrations: 64, history: 128 });
|
|
@@ -18880,7 +19058,7 @@ function pluginNeed(value, message) {
|
|
|
18880
19058
|
if (!value)
|
|
18881
19059
|
pluginRefusal(message);
|
|
18882
19060
|
}
|
|
18883
|
-
var pluginHash = (bytes) =>
|
|
19061
|
+
var pluginHash = (bytes) => createHash20("sha256").update(bytes).digest("hex");
|
|
18884
19062
|
function pluginObject(value) {
|
|
18885
19063
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
18886
19064
|
}
|
|
@@ -19068,16 +19246,16 @@ function buildPluginProjection(entries) {
|
|
|
19068
19246
|
}
|
|
19069
19247
|
|
|
19070
19248
|
// src/lib/plugin-projection-store.ts
|
|
19071
|
-
import { createHash as
|
|
19072
|
-
import { constants as
|
|
19073
|
-
import { dirname as dirname16, isAbsolute as
|
|
19074
|
-
var READ_FLAGS =
|
|
19075
|
-
var WRITE_FLAGS =
|
|
19249
|
+
import { createHash as createHash21, randomUUID as randomUUID4 } from "crypto";
|
|
19250
|
+
import { constants as constants12, closeSync as closeSync12, fchmodSync as fchmodSync2, fstatSync as fstatSync12, fsyncSync as fsyncSync6, linkSync as linkSync3, lstatSync as lstatSync22, mkdirSync as mkdirSync9, openSync as openSync12, opendirSync as opendirSync4, readSync as readSync9, renameSync as renameSync5, rmdirSync as rmdirSync3, rmSync as rmSync3, unlinkSync as unlinkSync5, writeSync as writeSync3 } from "fs";
|
|
19251
|
+
import { dirname as dirname16, isAbsolute as isAbsolute15, join as join29, parse as parse6, resolve as resolve14 } from "path";
|
|
19252
|
+
var READ_FLAGS = constants12.O_RDONLY | constants12.O_NOFOLLOW | constants12.O_NONBLOCK;
|
|
19253
|
+
var WRITE_FLAGS = constants12.O_WRONLY | constants12.O_CREAT | constants12.O_EXCL | constants12.O_NOFOLLOW | constants12.O_NONBLOCK;
|
|
19076
19254
|
var uid = () => typeof process.getuid === "function" ? BigInt(process.getuid()) : undefined;
|
|
19077
19255
|
var missing = (error) => Boolean(error && typeof error === "object" && "code" in error && error.code === "ENOENT");
|
|
19078
19256
|
function stat(path) {
|
|
19079
19257
|
try {
|
|
19080
|
-
return
|
|
19258
|
+
return lstatSync22(path, { bigint: true });
|
|
19081
19259
|
} catch (error) {
|
|
19082
19260
|
if (missing(error))
|
|
19083
19261
|
return null;
|
|
@@ -19085,7 +19263,7 @@ function stat(path) {
|
|
|
19085
19263
|
}
|
|
19086
19264
|
}
|
|
19087
19265
|
function canonical6(path) {
|
|
19088
|
-
pluginNeed(typeof path === "string" && path.length <= 8192 &&
|
|
19266
|
+
pluginNeed(typeof path === "string" && path.length <= 8192 && isAbsolute15(path) && resolve14(path) === path && !/[\x00-\x1f\x7f]/.test(path), "Plugin storage paths must be canonical absolute paths");
|
|
19089
19267
|
}
|
|
19090
19268
|
function owner(stats, system = false) {
|
|
19091
19269
|
const current = uid();
|
|
@@ -19153,8 +19331,8 @@ function readBytes(path, maximum, kind) {
|
|
|
19153
19331
|
fileShape(before, maximum, kind);
|
|
19154
19332
|
let fd;
|
|
19155
19333
|
try {
|
|
19156
|
-
fd =
|
|
19157
|
-
const opened =
|
|
19334
|
+
fd = openSync12(path, READ_FLAGS);
|
|
19335
|
+
const opened = fstatSync12(fd, { bigint: true });
|
|
19158
19336
|
same3(before, opened);
|
|
19159
19337
|
fileShape(opened, maximum, kind);
|
|
19160
19338
|
const bytes = new Uint8Array(Number(opened.size));
|
|
@@ -19165,7 +19343,7 @@ function readBytes(path, maximum, kind) {
|
|
|
19165
19343
|
offset += count;
|
|
19166
19344
|
}
|
|
19167
19345
|
pluginNeed(readSync9(fd, new Uint8Array(1), 0, 1, null) === 0, "Plugin file grew while being read");
|
|
19168
|
-
same3(opened,
|
|
19346
|
+
same3(opened, fstatSync12(fd, { bigint: true }));
|
|
19169
19347
|
same3(opened, stat(path));
|
|
19170
19348
|
verifyAncestors(chain);
|
|
19171
19349
|
return bytes;
|
|
@@ -19175,7 +19353,7 @@ function readBytes(path, maximum, kind) {
|
|
|
19175
19353
|
return pluginRefusal("Cannot safely read plugin file");
|
|
19176
19354
|
} finally {
|
|
19177
19355
|
if (fd !== undefined)
|
|
19178
|
-
|
|
19356
|
+
closeSync12(fd);
|
|
19179
19357
|
}
|
|
19180
19358
|
}
|
|
19181
19359
|
function exactPaths(entries) {
|
|
@@ -19285,16 +19463,16 @@ function verifyPluginTree(root, witnesses) {
|
|
|
19285
19463
|
function writeExclusive(path, bytes, mode) {
|
|
19286
19464
|
let fd, created;
|
|
19287
19465
|
try {
|
|
19288
|
-
fd =
|
|
19289
|
-
|
|
19290
|
-
created =
|
|
19466
|
+
fd = openSync12(path, WRITE_FLAGS, mode);
|
|
19467
|
+
fchmodSync2(fd, mode);
|
|
19468
|
+
created = fstatSync12(fd, { bigint: true });
|
|
19291
19469
|
let offset = 0;
|
|
19292
19470
|
while (offset < bytes.byteLength) {
|
|
19293
|
-
const count =
|
|
19471
|
+
const count = writeSync3(fd, bytes, offset, bytes.byteLength - offset);
|
|
19294
19472
|
pluginNeed(count > 0, "Plugin file write did not progress");
|
|
19295
19473
|
offset += count;
|
|
19296
19474
|
}
|
|
19297
|
-
|
|
19475
|
+
fsyncSync6(fd);
|
|
19298
19476
|
} catch (error) {
|
|
19299
19477
|
if (created) {
|
|
19300
19478
|
same3(created, stat(path), true);
|
|
@@ -19303,7 +19481,7 @@ function writeExclusive(path, bytes, mode) {
|
|
|
19303
19481
|
throw error;
|
|
19304
19482
|
} finally {
|
|
19305
19483
|
if (fd !== undefined)
|
|
19306
|
-
|
|
19484
|
+
closeSync12(fd);
|
|
19307
19485
|
}
|
|
19308
19486
|
}
|
|
19309
19487
|
function materializePluginTree(root, entries) {
|
|
@@ -19406,11 +19584,11 @@ function pluginExecutableDigest(path) {
|
|
|
19406
19584
|
fileShape(before, maximum, "executable");
|
|
19407
19585
|
let fd;
|
|
19408
19586
|
try {
|
|
19409
|
-
fd =
|
|
19410
|
-
const opened =
|
|
19587
|
+
fd = openSync12(path, READ_FLAGS);
|
|
19588
|
+
const opened = fstatSync12(fd, { bigint: true });
|
|
19411
19589
|
same3(before, opened);
|
|
19412
19590
|
fileShape(opened, maximum, "executable");
|
|
19413
|
-
const hash2 =
|
|
19591
|
+
const hash2 = createHash21("sha256"), buffer = new Uint8Array(64 * 1024);
|
|
19414
19592
|
let remaining = Number(opened.size);
|
|
19415
19593
|
while (remaining > 0) {
|
|
19416
19594
|
const count = readSync9(fd, buffer, 0, Math.min(buffer.byteLength, remaining), null);
|
|
@@ -19419,7 +19597,7 @@ function pluginExecutableDigest(path) {
|
|
|
19419
19597
|
remaining -= count;
|
|
19420
19598
|
}
|
|
19421
19599
|
pluginNeed(readSync9(fd, buffer, 0, 1, null) === 0, "Plugin executable grew during hashing");
|
|
19422
|
-
same3(opened,
|
|
19600
|
+
same3(opened, fstatSync12(fd, { bigint: true }));
|
|
19423
19601
|
same3(opened, stat(path));
|
|
19424
19602
|
verifyAncestors(chain);
|
|
19425
19603
|
return `sha256:${hash2.digest("hex")}`;
|
|
@@ -19429,7 +19607,7 @@ function pluginExecutableDigest(path) {
|
|
|
19429
19607
|
return pluginRefusal("Cannot safely hash plugin executable");
|
|
19430
19608
|
} finally {
|
|
19431
19609
|
if (fd !== undefined)
|
|
19432
|
-
|
|
19610
|
+
closeSync12(fd);
|
|
19433
19611
|
}
|
|
19434
19612
|
}
|
|
19435
19613
|
|
|
@@ -19468,7 +19646,7 @@ function validatePluginTarget(value) {
|
|
|
19468
19646
|
for (const registration of value.registrations) {
|
|
19469
19647
|
pluginKeys(registration, ["scope", "projectPath"]);
|
|
19470
19648
|
pluginNeed(registration.scope === "user" || registration.scope === "project", "Unsupported plugin registration scope");
|
|
19471
|
-
pluginNeed(registration.scope === "user" ? registration.projectPath === null : typeof registration.projectPath === "string" &&
|
|
19649
|
+
pluginNeed(registration.scope === "user" ? registration.projectPath === null : typeof registration.projectPath === "string" && isAbsolute16(registration.projectPath) && resolve15(registration.projectPath) === registration.projectPath, "Plugin scope requires its exact project path");
|
|
19472
19650
|
const key = JSON.stringify([registration.scope, registration.projectPath]);
|
|
19473
19651
|
pluginNeed(!scopes.has(key), "Duplicate plugin registration scope");
|
|
19474
19652
|
scopes.add(key);
|
|
@@ -19476,7 +19654,7 @@ function validatePluginTarget(value) {
|
|
|
19476
19654
|
for (const key of ["native", "resolver"]) {
|
|
19477
19655
|
pluginKeys(value[key], key === "native" ? ["version", "executable", "digest"] : ["executable", "digest"]);
|
|
19478
19656
|
pluginText(value[key].executable);
|
|
19479
|
-
pluginNeed(
|
|
19657
|
+
pluginNeed(isAbsolute16(value[key].executable) && resolve15(value[key].executable) === value[key].executable, "Plugin executable must have a canonical absolute path");
|
|
19480
19658
|
pluginDigest(value[key].digest);
|
|
19481
19659
|
}
|
|
19482
19660
|
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)");
|
|
@@ -19628,7 +19806,7 @@ function pluginResolverCommand(binding) {
|
|
|
19628
19806
|
}
|
|
19629
19807
|
function root(options) {
|
|
19630
19808
|
const path = options.storeRoot ?? pluginAdmissionRoot();
|
|
19631
|
-
pluginNeed(
|
|
19809
|
+
pluginNeed(isAbsolute16(path) && resolve15(path) === path, "Invalid plugin admission store root");
|
|
19632
19810
|
return path;
|
|
19633
19811
|
}
|
|
19634
19812
|
function pluginBindingPath(storeRoot, id) {
|
|
@@ -19833,25 +20011,25 @@ function validateManagedPluginWitnesses(value) {
|
|
|
19833
20011
|
pluginNeed(typeof item.bindingId === "string" && /^[a-f0-9]{64}$/.test(item.bindingId) && !seen.has(item.bindingId), "Invalid or duplicate managed plugin witness");
|
|
19834
20012
|
seen.add(item.bindingId);
|
|
19835
20013
|
pluginText(item.storeRoot);
|
|
19836
|
-
pluginNeed(
|
|
20014
|
+
pluginNeed(isAbsolute17(item.storeRoot) && resolve16(item.storeRoot) === item.storeRoot, "Invalid plugin receipt store path");
|
|
19837
20015
|
}
|
|
19838
20016
|
}
|
|
19839
20017
|
function safe3(path) {
|
|
19840
20018
|
pluginText(path);
|
|
19841
|
-
pluginNeed(
|
|
20019
|
+
pluginNeed(isAbsolute17(path) && resolve16(path) === path, "Invalid plugin registry path");
|
|
19842
20020
|
for (let at = path;; at = dirname17(at)) {
|
|
19843
|
-
pluginNeed(!
|
|
20021
|
+
pluginNeed(!lstatSync23(at, { throwIfNoEntry: false })?.isSymbolicLink(), "Plugin registry path traverses a symlink");
|
|
19844
20022
|
if (at === dirname17(at))
|
|
19845
20023
|
break;
|
|
19846
20024
|
}
|
|
19847
20025
|
}
|
|
19848
20026
|
function readRegistry(path) {
|
|
19849
20027
|
safe3(path);
|
|
19850
|
-
const initial =
|
|
20028
|
+
const initial = lstatSync23(path);
|
|
19851
20029
|
pluginNeed(initial.isFile() && initial.size <= 1024 * 1024, "Plugin registry is not a bounded regular file");
|
|
19852
|
-
const fd =
|
|
20030
|
+
const fd = openSync13(path, constants13.O_RDONLY | constants13.O_NOFOLLOW | constants13.O_NONBLOCK);
|
|
19853
20031
|
try {
|
|
19854
|
-
const opened =
|
|
20032
|
+
const opened = fstatSync13(fd);
|
|
19855
20033
|
pluginNeed(opened.isFile() && opened.ino === initial.ino && opened.dev === initial.dev, "Plugin registry changed during open");
|
|
19856
20034
|
const bytes = Buffer.alloc(1024 * 1024 + 1);
|
|
19857
20035
|
let length = 0;
|
|
@@ -19861,7 +20039,7 @@ function readRegistry(path) {
|
|
|
19861
20039
|
break;
|
|
19862
20040
|
length += count;
|
|
19863
20041
|
}
|
|
19864
|
-
const after =
|
|
20042
|
+
const after = fstatSync13(fd), current = lstatSync23(path);
|
|
19865
20043
|
safe3(path);
|
|
19866
20044
|
pluginNeed(length <= 1024 * 1024 && length === opened.size && after.size === opened.size && after.mtimeMs === opened.mtimeMs && after.ctimeMs === opened.ctimeMs && current.dev === opened.dev && current.ino === opened.ino && current.mtimeMs === opened.mtimeMs && current.ctimeMs === opened.ctimeMs, "Plugin registry changed during read");
|
|
19867
20045
|
let value;
|
|
@@ -19873,7 +20051,7 @@ function readRegistry(path) {
|
|
|
19873
20051
|
pluginNeed(pluginObject(value) && value.version === 2 && pluginObject(value.plugins), "Unsupported native plugin registry schema");
|
|
19874
20052
|
return { value, rawDigest: pluginHash(bytes.subarray(0, length)) };
|
|
19875
20053
|
} finally {
|
|
19876
|
-
|
|
20054
|
+
closeSync13(fd);
|
|
19877
20055
|
}
|
|
19878
20056
|
}
|
|
19879
20057
|
function nativeVersionMatches(version, receipt) {
|
|
@@ -19934,7 +20112,7 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
19934
20112
|
return Object.fromEntries(Object.entries(row).filter(([key]) => !["version", "installPath", "sourceProducerPath", "previousProducerPaths", "lastUpdated"].includes(key)));
|
|
19935
20113
|
});
|
|
19936
20114
|
safe3(cacheRoot);
|
|
19937
|
-
const before =
|
|
20115
|
+
const before = lstatSync23(cacheRoot);
|
|
19938
20116
|
pluginNeed(before.isDirectory(), "Invalid managed plugin cache root");
|
|
19939
20117
|
const directory = opendirSync5(cacheRoot), names = [];
|
|
19940
20118
|
try {
|
|
@@ -19957,7 +20135,7 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
19957
20135
|
}
|
|
19958
20136
|
for (const row of rows)
|
|
19959
20137
|
pluginNeed(names.includes(row.version), "Managed native plugin installation is missing");
|
|
19960
|
-
const after =
|
|
20138
|
+
const after = lstatSync23(cacheRoot);
|
|
19961
20139
|
safe3(cacheRoot);
|
|
19962
20140
|
pluginNeed(before.dev === after.dev && before.ino === after.ino && before.mtimeMs === after.mtimeMs && before.ctimeMs === after.ctimeMs, "Managed cache version membership changed during verification");
|
|
19963
20141
|
}
|
|
@@ -19969,22 +20147,22 @@ function captureManagedPluginRegistry(path, managedPlugins) {
|
|
|
19969
20147
|
}
|
|
19970
20148
|
|
|
19971
20149
|
// src/lib/claude-marketplace-registry.ts
|
|
19972
|
-
import { createHash as
|
|
19973
|
-
import { closeSync as
|
|
19974
|
-
import { basename as basename9, dirname as dirname18, isAbsolute as
|
|
20150
|
+
import { createHash as createHash22 } from "crypto";
|
|
20151
|
+
import { closeSync as closeSync14, constants as constants14, fstatSync as fstatSync14, lstatSync as lstatSync24, openSync as openSync14, readSync as readSync11 } from "fs";
|
|
20152
|
+
import { basename as basename9, dirname as dirname18, isAbsolute as isAbsolute18, resolve as resolve17 } from "path";
|
|
19975
20153
|
var CLAUDE_MARKETPLACE_REGISTRY_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
|
|
19976
20154
|
function need6(value, reason) {
|
|
19977
20155
|
if (!value)
|
|
19978
20156
|
throw new Error(`Claude marketplace registry ${reason}`);
|
|
19979
20157
|
}
|
|
19980
20158
|
function absolutePath3(value) {
|
|
19981
|
-
need6(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) &&
|
|
20159
|
+
need6(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute18(value) && resolve17(value) === value, "requires a normalized absolute path");
|
|
19982
20160
|
}
|
|
19983
20161
|
var sameFile2 = (a, b) => a.dev === b.dev && a.ino === b.ino && a.mode === b.mode && a.uid === b.uid && a.gid === b.gid && a.nlink === b.nlink && a.size === b.size && a.mtimeNs === b.mtimeNs && a.ctimeNs === b.ctimeNs;
|
|
19984
20162
|
function parents2(path) {
|
|
19985
20163
|
const result = [];
|
|
19986
20164
|
for (let at = dirname18(path);; at = dirname18(at)) {
|
|
19987
|
-
const stat2 =
|
|
20165
|
+
const stat2 = lstatSync24(at, { bigint: true });
|
|
19988
20166
|
need6(stat2.isDirectory() && !stat2.isSymbolicLink(), "path traverses a symlink or non-directory");
|
|
19989
20167
|
result.push([at, stat2]);
|
|
19990
20168
|
if (at === dirname18(at))
|
|
@@ -19995,12 +20173,12 @@ function readRegistry2(path, budget2) {
|
|
|
19995
20173
|
absolutePath3(path);
|
|
19996
20174
|
need6(basename9(path) === "known_marketplaces.json", "requires known_marketplaces.json");
|
|
19997
20175
|
need6(Number.isSafeInteger(budget2.remaining) && budget2.remaining >= 0, "has an invalid byte budget");
|
|
19998
|
-
const ancestors2 = parents2(path), initial =
|
|
20176
|
+
const ancestors2 = parents2(path), initial = lstatSync24(path, { bigint: true });
|
|
19999
20177
|
need6(initial.isFile() && !initial.isSymbolicLink() && initial.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
|
|
20000
20178
|
need6(initial.size <= BigInt(budget2.remaining), "exceeds its aggregate byte limit");
|
|
20001
|
-
const fd =
|
|
20179
|
+
const fd = openSync14(path, constants14.O_RDONLY | constants14.O_NOFOLLOW | constants14.O_NONBLOCK);
|
|
20002
20180
|
try {
|
|
20003
|
-
const opened =
|
|
20181
|
+
const opened = fstatSync14(fd, { bigint: true });
|
|
20004
20182
|
need6(opened.isFile() && sameFile2(initial, opened), "changed during open");
|
|
20005
20183
|
const bytes = Buffer.alloc(Number(opened.size) + 1);
|
|
20006
20184
|
let length = 0;
|
|
@@ -20010,10 +20188,10 @@ function readRegistry2(path, budget2) {
|
|
|
20010
20188
|
break;
|
|
20011
20189
|
length += count;
|
|
20012
20190
|
}
|
|
20013
|
-
const after =
|
|
20191
|
+
const after = fstatSync14(fd, { bigint: true }), current = lstatSync24(path, { bigint: true });
|
|
20014
20192
|
need6(current.isFile() && sameFile2(opened, after) && sameFile2(after, current) && BigInt(length) === opened.size, "changed during read");
|
|
20015
20193
|
for (const [ancestor, before] of ancestors2) {
|
|
20016
|
-
const now =
|
|
20194
|
+
const now = lstatSync24(ancestor, { bigint: true });
|
|
20017
20195
|
need6(now.isDirectory() && before.dev === now.dev && before.ino === now.ino && before.mode === now.mode, "parent changed during read");
|
|
20018
20196
|
}
|
|
20019
20197
|
budget2.remaining -= length;
|
|
@@ -20023,7 +20201,7 @@ function readRegistry2(path, budget2) {
|
|
|
20023
20201
|
throw new Error("Claude marketplace registry is not strict UTF-8");
|
|
20024
20202
|
}
|
|
20025
20203
|
} finally {
|
|
20026
|
-
|
|
20204
|
+
closeSync14(fd);
|
|
20027
20205
|
}
|
|
20028
20206
|
}
|
|
20029
20207
|
function parse7(text2) {
|
|
@@ -20138,19 +20316,19 @@ function captureClaudeMarketplaceRegistry(path, budget2 = { remaining: 256 * 102
|
|
|
20138
20316
|
const value = parse7(readRegistry2(path, budget2));
|
|
20139
20317
|
for (const [, row] of value.entries)
|
|
20140
20318
|
normalizeRow(row);
|
|
20141
|
-
const
|
|
20142
|
-
return { path, hashMode: "claude-marketplace-registry", sha256:
|
|
20319
|
+
const sha2563 = createHash22("sha256").update("hasna.skills.claude-marketplace-registry.v1\x00").update(JSON.stringify(value)).digest("hex");
|
|
20320
|
+
return { path, hashMode: "claude-marketplace-registry", sha256: sha2563 };
|
|
20143
20321
|
}
|
|
20144
20322
|
function captureClaudeMarketplaceRegistryV2(path, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
20145
20323
|
const value = parse7(readRegistry2(path, budget2));
|
|
20146
20324
|
for (const [, row] of value.entries)
|
|
20147
20325
|
normalizeRow(row, 2);
|
|
20148
|
-
const
|
|
20149
|
-
return { path, hashMode: "claude-marketplace-registry-v2", sha256:
|
|
20326
|
+
const sha2563 = createHash22("sha256").update("hasna.skills.claude-marketplace-registry.v2\x00").update(JSON.stringify(value)).digest("hex");
|
|
20327
|
+
return { path, hashMode: "claude-marketplace-registry-v2", sha256: sha2563 };
|
|
20150
20328
|
}
|
|
20151
20329
|
|
|
20152
20330
|
// src/lib/codex-hook-discovery-recovery.ts
|
|
20153
|
-
import { createHash as
|
|
20331
|
+
import { createHash as createHash23 } from "crypto";
|
|
20154
20332
|
|
|
20155
20333
|
// src/lib/codex-hook-additions-review.ts
|
|
20156
20334
|
var events = { UserPromptSubmit: ["userPromptSubmit", "user_prompt_submit"], SessionStart: ["sessionStart", "session_start"], SubagentStart: ["subagentStart", "subagent_start"] };
|
|
@@ -20158,7 +20336,7 @@ var matchedEvents = { ...events, PreToolUse: ["preToolUse", "pre_tool_use"] };
|
|
|
20158
20336
|
var proofs = new WeakMap;
|
|
20159
20337
|
|
|
20160
20338
|
// src/lib/codex-hook-discovery-recovery.ts
|
|
20161
|
-
var sha4 = (text2) =>
|
|
20339
|
+
var sha4 = (text2) => createHash23("sha256").update(text2).digest("hex");
|
|
20162
20340
|
var fields = [...CODEX_DISCOVERY_PROJECTION_FIELDS];
|
|
20163
20341
|
var proofs2 = new WeakMap;
|
|
20164
20342
|
function assertCodexHookDiscoveryRecovery(binding, witness) {
|
|
@@ -20177,7 +20355,7 @@ function verifiesCodexHookDiscoverySource(binding, source, currentDigest, witnes
|
|
|
20177
20355
|
}
|
|
20178
20356
|
|
|
20179
20357
|
// src/lib/agent-discovery.ts
|
|
20180
|
-
var digest = (text2) =>
|
|
20358
|
+
var digest = (text2) => createHash24("sha256").update(text2).digest("hex");
|
|
20181
20359
|
function parseConfig(text2, path, toml = false) {
|
|
20182
20360
|
try {
|
|
20183
20361
|
const value = toml ? Bun.TOML.parse(text2) : JSON.parse(text2);
|
|
@@ -20189,10 +20367,10 @@ function parseConfig(text2, path, toml = false) {
|
|
|
20189
20367
|
}
|
|
20190
20368
|
}
|
|
20191
20369
|
function safe4(path) {
|
|
20192
|
-
if (!
|
|
20370
|
+
if (!isAbsolute19(path) || path.includes("\x00"))
|
|
20193
20371
|
throw new Error("Expected an absolute native discovery path");
|
|
20194
20372
|
for (let cursor = path;; cursor = dirname19(cursor)) {
|
|
20195
|
-
if (
|
|
20373
|
+
if (lstatSync25(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
20196
20374
|
throw new Error(`Refusing symlink native discovery input: ${cursor}`);
|
|
20197
20375
|
if (dirname19(cursor) === cursor)
|
|
20198
20376
|
break;
|
|
@@ -20202,12 +20380,12 @@ function read2(path, changes) {
|
|
|
20202
20380
|
safe4(path);
|
|
20203
20381
|
if (changes?.has(path))
|
|
20204
20382
|
return changes.get(path);
|
|
20205
|
-
const stat2 =
|
|
20383
|
+
const stat2 = lstatSync25(path, { throwIfNoEntry: false });
|
|
20206
20384
|
if (!stat2)
|
|
20207
20385
|
return null;
|
|
20208
20386
|
if (!stat2.isFile() || stat2.size > 16 * 1024 * 1024)
|
|
20209
20387
|
throw new Error(`Unsupported or oversized native discovery input: ${path}`);
|
|
20210
|
-
return
|
|
20388
|
+
return readFileSync20(path, "utf8");
|
|
20211
20389
|
}
|
|
20212
20390
|
function projectNativeDiscoveryFields(text2, format, fields2, path) {
|
|
20213
20391
|
const object6 = format === "yaml" ? parseHermesConfig(text2) : parseConfig(text2, path, format === "toml");
|
|
@@ -20242,21 +20420,21 @@ function projected(source, changes, budget2 = discoveryByteBudget()) {
|
|
|
20242
20420
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
20243
20421
|
return changes?.has(source.path) ? (source.hashMode === "codex-settings-v4" ? hashCodexSettingsReplacementV4 : source.hashMode === "codex-settings-v3" ? hashCodexSettingsReplacementV3 : source.hashMode === "codex-settings-v2" ? hashCodexSettingsReplacementV2 : hashCodexSettingsReplacement)(changes.get(source.path), budget2) : current;
|
|
20244
20422
|
}
|
|
20245
|
-
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") {
|
|
20423
|
+
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4")) {
|
|
20246
20424
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
20247
20425
|
throw new Error("Claude settings witnesses require exact typed metadata");
|
|
20248
|
-
const current = (source.hashMode === "claude-settings-v3" ? captureClaudeSettingsV3 : source.hashMode === "claude-settings-v2" ? captureClaudeSettingsV2 : captureClaudeSettings)(source.path, budget2).sha256;
|
|
20426
|
+
const current = (source.hashMode === "claude-settings-v4" ? captureClaudeSettingsV4 : source.hashMode === "claude-settings-v3" ? captureClaudeSettingsV3 : source.hashMode === "claude-settings-v2" ? captureClaudeSettingsV2 : captureClaudeSettings)(source.path, budget2).sha256;
|
|
20249
20427
|
if (current !== source.sha256)
|
|
20250
20428
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
20251
|
-
return changes?.has(source.path) ? (source.hashMode === "claude-settings-v3" ? hashClaudeSettingsReplacementV3 : source.hashMode === "claude-settings-v2" ? hashClaudeSettingsReplacementV2 : hashClaudeSettingsReplacement)(changes.get(source.path), budget2) : current;
|
|
20429
|
+
return changes?.has(source.path) ? (source.hashMode === "claude-settings-v4" ? hashClaudeSettingsReplacementV4 : source.hashMode === "claude-settings-v3" ? hashClaudeSettingsReplacementV3 : source.hashMode === "claude-settings-v2" ? hashClaudeSettingsReplacementV2 : hashClaudeSettingsReplacement)(changes.get(source.path), budget2) : current;
|
|
20252
20430
|
}
|
|
20253
20431
|
if (source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2") {
|
|
20254
20432
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256) || changes?.has(source.path))
|
|
20255
20433
|
throw new Error("Claude marketplace witnesses require an exact reviewed registry without synthetic changes");
|
|
20256
|
-
const
|
|
20257
|
-
if (
|
|
20434
|
+
const sha2563 = (source.hashMode === "claude-marketplace-registry-v2" ? captureClaudeMarketplaceRegistryV2 : captureClaudeMarketplaceRegistry)(source.path, budget2).sha256;
|
|
20435
|
+
if (sha2563 !== source.sha256)
|
|
20258
20436
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
20259
|
-
return
|
|
20437
|
+
return sha2563;
|
|
20260
20438
|
}
|
|
20261
20439
|
if (source.hashMode === "claude-plugin-registry") {
|
|
20262
20440
|
if (source.format !== undefined || source.fields !== undefined || !source.managedPlugins || changes?.has(source.path))
|
|
@@ -20293,7 +20471,7 @@ function absentCodexSkillRoots(binding) {
|
|
|
20293
20471
|
return [];
|
|
20294
20472
|
if (binding.agent !== "codex" || !Array.isArray(controls) || controls.length > 4096)
|
|
20295
20473
|
throw new Error("Invalid disabled Codex discovery proof");
|
|
20296
|
-
if (binding.method !== "reviewed" || controls.every((control) =>
|
|
20474
|
+
if (binding.method !== "reviewed" || controls.every((control) => lstatSync25(control.pluginParent, { throwIfNoEntry: false })))
|
|
20297
20475
|
return [];
|
|
20298
20476
|
const cache = dirname19(dirname19(controls[0].pluginParent)), config = join32(dirname19(dirname19(cache)), "config.toml");
|
|
20299
20477
|
const source = binding.sources.find((source2) => source2.path === config && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined);
|
|
@@ -20361,7 +20539,7 @@ function absentRetiredClaudeRoots(binding) {
|
|
|
20361
20539
|
continue;
|
|
20362
20540
|
const root2 = join32(cache, ...parts.slice(0, 3));
|
|
20363
20541
|
safe4(root2);
|
|
20364
|
-
if (
|
|
20542
|
+
if (lstatSync25(root2, { throwIfNoEntry: false }))
|
|
20365
20543
|
continue;
|
|
20366
20544
|
const claude = dirname19(dirname19(cache)), settings = join32(claude, "settings.json"), registry = join32(claude, "plugins/installed_plugins.json");
|
|
20367
20545
|
const full = (path) => binding.sources.find((item) => item.path === path && item.sha256 !== null && item.format === undefined && item.fields === undefined);
|
|
@@ -20380,7 +20558,7 @@ function absentRetiredClaudeRoots(binding) {
|
|
|
20380
20558
|
if (!Array.isArray(rows) || rows.length !== 1 || rows[0]?.scope !== "user" || typeof rows[0]?.installPath !== "string")
|
|
20381
20559
|
continue;
|
|
20382
20560
|
const active = rows[0].installPath;
|
|
20383
|
-
if (rows[0].version !== basename10(active) || resolve18(active) !== active || dirname19(active) !== dirname19(root2) || active === root2 || !
|
|
20561
|
+
if (rows[0].version !== basename10(active) || resolve18(active) !== active || dirname19(active) !== dirname19(root2) || active === root2 || !lstatSync25(active, { throwIfNoEntry: false })?.isDirectory() || realpathSync11(active) !== active)
|
|
20384
20562
|
continue;
|
|
20385
20563
|
const activeManifest = full(join32(active, ".claude-plugin/plugin.json"));
|
|
20386
20564
|
if (!activeManifest || projected(activeManifest) !== activeManifest.sha256)
|
|
@@ -20411,7 +20589,7 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
20411
20589
|
const projection = binding.codexRetiredMaterializations.directories;
|
|
20412
20590
|
if (projection.length !== ordinary.length || projection.some((item, index) => item.path !== ordinary[index]?.path))
|
|
20413
20591
|
throw new Error("Missing retired Codex directory projection");
|
|
20414
|
-
const omitted = [...retiredRoots, ...(binding.codexRetiredMaterializations.parents ?? []).filter((parent) => !
|
|
20592
|
+
const omitted = [...retiredRoots, ...(binding.codexRetiredMaterializations.parents ?? []).filter((parent) => !lstatSync25(parent, { throwIfNoEntry: false }))];
|
|
20415
20593
|
if (projection.every((item) => Array.isArray(item.entries)))
|
|
20416
20594
|
verifyDiscoveryDirectoryProjection(projection, omitted);
|
|
20417
20595
|
else {
|
|
@@ -20425,7 +20603,7 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
20425
20603
|
verifyDiscoveryDirectories(ordinary);
|
|
20426
20604
|
verifyDiscoveryDirectories(projected2, installationRoots);
|
|
20427
20605
|
}
|
|
20428
|
-
const absentRoots = [...absentCodexSkillRoots(binding), ...absentRetiredClaudeRoots(binding), ...retiredRoots.filter((root2) => !
|
|
20606
|
+
const absentRoots = [...absentCodexSkillRoots(binding), ...absentRetiredClaudeRoots(binding), ...retiredRoots.filter((root2) => !lstatSync25(root2, { throwIfNoEntry: false }))];
|
|
20429
20607
|
const budget2 = discoveryByteBudget();
|
|
20430
20608
|
for (const source of binding.sources) {
|
|
20431
20609
|
assertMarketplaceBinding(binding, source);
|
|
@@ -20451,7 +20629,7 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
20451
20629
|
safe4(root2);
|
|
20452
20630
|
for (const root2 of absentRoots) {
|
|
20453
20631
|
safe4(root2);
|
|
20454
|
-
if (
|
|
20632
|
+
if (lstatSync25(root2, { throwIfNoEntry: false }))
|
|
20455
20633
|
throw new Error("Retired native materialization changed during discovery verification");
|
|
20456
20634
|
}
|
|
20457
20635
|
}
|
|
@@ -20483,26 +20661,26 @@ function assertMarketplaceBinding(binding, source) {
|
|
|
20483
20661
|
throw new Error("Sumi settings witnesses require explicit reviewed Sumi configuration");
|
|
20484
20662
|
if ((source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")) && (binding.agent !== "codex" || binding.method !== "reviewed" || basename10(source.path) !== "config.toml"))
|
|
20485
20663
|
throw new Error("Codex settings witnesses require explicit reviewed Codex configuration");
|
|
20486
|
-
if ((source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") && (binding.agent !== "claude" || binding.method !== "reviewed" || basename10(source.path) !== "settings.json"))
|
|
20664
|
+
if ((source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4")) && (binding.agent !== "claude" || binding.method !== "reviewed" || basename10(source.path) !== "settings.json"))
|
|
20487
20665
|
throw new Error("Claude settings witnesses require explicit reviewed Claude configuration");
|
|
20488
20666
|
if ((source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2") && (binding.agent !== "claude" || binding.method !== "reviewed"))
|
|
20489
20667
|
throw new Error("Claude marketplace witnesses require explicit reviewed Claude discovery");
|
|
20490
20668
|
}
|
|
20491
20669
|
function rebindAgentDiscovery(binding, changes) {
|
|
20492
20670
|
const budget2 = discoveryByteBudget();
|
|
20493
|
-
const installationRoots = codexInstallationRoots(binding), absentRoots = [...absentCodexSkillRoots(binding), ...absentRetiredClaudeRoots(binding), ...retiredCodexRoots(binding).filter((root2) => !
|
|
20671
|
+
const installationRoots = codexInstallationRoots(binding), absentRoots = [...absentCodexSkillRoots(binding), ...absentRetiredClaudeRoots(binding), ...retiredCodexRoots(binding).filter((root2) => !lstatSync25(root2, { throwIfNoEntry: false }))];
|
|
20494
20672
|
const rebound = { ...binding, sources: binding.sources.map((source) => {
|
|
20495
20673
|
assertMarketplaceBinding(binding, source);
|
|
20496
20674
|
if (!changes.has(source.path) && (installationRoots.some((root2) => source.path.startsWith(root2 + sep8)) || absentRoots.some((root2) => source.path.startsWith(root2 + sep8)) && source.format === undefined && source.fields === undefined && source.managedPlugins === undefined && [undefined, "bytes"].includes(source.hashMode)))
|
|
20497
20675
|
return source;
|
|
20498
|
-
const
|
|
20499
|
-
if (!changes.has(source.path) &&
|
|
20676
|
+
const sha2563 = projected(source, changes, budget2);
|
|
20677
|
+
if (!changes.has(source.path) && sha2563 !== source.sha256)
|
|
20500
20678
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
20501
|
-
return { ...source, sha256:
|
|
20679
|
+
return { ...source, sha256: sha2563 };
|
|
20502
20680
|
}) };
|
|
20503
20681
|
for (const root2 of absentRoots) {
|
|
20504
20682
|
safe4(root2);
|
|
20505
|
-
if (
|
|
20683
|
+
if (lstatSync25(root2, { throwIfNoEntry: false }))
|
|
20506
20684
|
throw new Error("Retired native materialization changed during discovery rebinding");
|
|
20507
20685
|
}
|
|
20508
20686
|
return rebound;
|
|
@@ -20557,13 +20735,13 @@ function assertProjectDiscovery(agent, directories, home, canonical7 = resolve18
|
|
|
20557
20735
|
for (const name of ["plugin", "plugins"]) {
|
|
20558
20736
|
const path = canonical7(join32(directory, ".sumi", name));
|
|
20559
20737
|
safe4(path);
|
|
20560
|
-
if (
|
|
20738
|
+
if (lstatSync25(path, { throwIfNoEntry: false })?.isDirectory() && readdirSync10(path).length)
|
|
20561
20739
|
throw new Error(`NATIVE_SKILL_DRIFT: project Sumi plugins require a dedicated discovery review: ${path}`);
|
|
20562
20740
|
}
|
|
20563
20741
|
if (agent === "claude") {
|
|
20564
20742
|
const commands = canonical7(join32(directory, ".claude/commands"));
|
|
20565
20743
|
safe4(commands);
|
|
20566
|
-
if (
|
|
20744
|
+
if (lstatSync25(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync10(commands).length)
|
|
20567
20745
|
throw new Error("NATIVE_SKILL_DRIFT: legacy project command discovery requires a dedicated format adapter");
|
|
20568
20746
|
}
|
|
20569
20747
|
}
|
|
@@ -20603,7 +20781,7 @@ function resolveAgentDiscovery(options) {
|
|
|
20603
20781
|
if (config.skills !== undefined && (!Array.isArray(config.skills) || config.skills.some((path) => typeof path !== "string")))
|
|
20604
20782
|
unresolved("skills must be a string array");
|
|
20605
20783
|
for (const value of config.skills ?? []) {
|
|
20606
|
-
if (typeof value !== "string" || /[\0$]/.test(value) || !value || !(
|
|
20784
|
+
if (typeof value !== "string" || /[\0$]/.test(value) || !value || !(isAbsolute19(value) || value.startsWith("~/")))
|
|
20607
20785
|
unresolved("remote or relative skill sources need a dedicated discovery adapter");
|
|
20608
20786
|
roots.add(canonical7(value.startsWith("~/") ? join32(home, value.slice(2)) : value));
|
|
20609
20787
|
}
|
|
@@ -20613,19 +20791,19 @@ function resolveAgentDiscovery(options) {
|
|
|
20613
20791
|
const plugins = [join32(directory, "plugin"), join32(directory, "plugins")];
|
|
20614
20792
|
for (const path of plugins) {
|
|
20615
20793
|
safe4(path);
|
|
20616
|
-
if (
|
|
20794
|
+
if (lstatSync25(path, { throwIfNoEntry: false })?.isDirectory())
|
|
20617
20795
|
for (const name of readdirSync10(path).sort()) {
|
|
20618
20796
|
if (name === "skills-cli.js" && path === plugins[1])
|
|
20619
20797
|
continue;
|
|
20620
20798
|
const target = join32(path, name);
|
|
20621
|
-
if (!
|
|
20799
|
+
if (!lstatSync25(target).isFile())
|
|
20622
20800
|
unresolved("local plugin packages need a dedicated discovery adapter");
|
|
20623
20801
|
witness(target);
|
|
20624
20802
|
}
|
|
20625
20803
|
}
|
|
20626
20804
|
for (const root2 of roots) {
|
|
20627
20805
|
safe4(root2);
|
|
20628
|
-
if (
|
|
20806
|
+
if (lstatSync25(root2, { throwIfNoEntry: false })?.isDirectory() && readdirSync10(root2).some((name) => name.endsWith(".md")))
|
|
20629
20807
|
unresolved("flat markdown skills require a dedicated native migration adapter");
|
|
20630
20808
|
}
|
|
20631
20809
|
}
|
|
@@ -20653,7 +20831,7 @@ function resolveAgentDiscovery(options) {
|
|
|
20653
20831
|
const executable2 = Bun.which("gemini");
|
|
20654
20832
|
if (executable2) {
|
|
20655
20833
|
let packageRoot;
|
|
20656
|
-
for (let directory = dirname19(
|
|
20834
|
+
for (let directory = dirname19(realpathSync11(executable2)), depth = 0;depth < 8; directory = dirname19(directory), depth++) {
|
|
20657
20835
|
const path = join32(directory, "package.json"), raw = read2(path);
|
|
20658
20836
|
if (raw !== null && parseConfig(raw, path).name === "@google/gemini-cli") {
|
|
20659
20837
|
packageRoot = directory;
|
|
@@ -20667,7 +20845,7 @@ function resolveAgentDiscovery(options) {
|
|
|
20667
20845
|
unresolved("installed Gemini package layout is not recognized");
|
|
20668
20846
|
const builtinRoot = join32(packageRoot, "bundle/builtin");
|
|
20669
20847
|
safe4(builtinRoot);
|
|
20670
|
-
if (!
|
|
20848
|
+
if (!lstatSync25(builtinRoot, { throwIfNoEntry: false })?.isDirectory())
|
|
20671
20849
|
unresolved("installed Gemini builtin root is missing");
|
|
20672
20850
|
for (const name of readdirSync10(builtinRoot).sort()) {
|
|
20673
20851
|
const text2 = witness(join32(builtinRoot, name, "SKILL.md"));
|
|
@@ -20685,7 +20863,7 @@ function resolveAgentDiscovery(options) {
|
|
|
20685
20863
|
verifyAgentDiscovery(retained);
|
|
20686
20864
|
if (!retained.sources.some((source) => source.path === canonical7(configPath) && source.format === undefined && source.fields === undefined))
|
|
20687
20865
|
unresolved("retained review is missing the full agent configuration source");
|
|
20688
|
-
if (retained.sources.some((source) => (source.hashMode === "sumi-settings-v1" || source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !== canonical7(configPath)))
|
|
20866
|
+
if (retained.sources.some((source) => (source.hashMode === "sumi-settings-v1" || source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !== canonical7(configPath)))
|
|
20689
20867
|
unresolved("retained settings witness names another configuration source");
|
|
20690
20868
|
const covered = supersedesSettingsProjection(agent, retained.sources, canonical7(configPath)) ? sources.filter((source) => !isSupersededSettingsProjection(agent, canonical7(configPath), source)) : sources;
|
|
20691
20869
|
if (covered.some((source) => !retained.sources.some((saved) => isDeepStrictEqual7(saved, source))) || [...roots].some((root2) => !retained.roots.includes(root2)) || agent === "gemini" && JSON.stringify(retained.builtinNames) !== JSON.stringify(builtinNames))
|
|
@@ -20699,7 +20877,7 @@ function resolveAgentDiscovery(options) {
|
|
|
20699
20877
|
if (review.sources.some((source) => source.format !== undefined || source.fields !== undefined))
|
|
20700
20878
|
throw new Error("Explicit discovery reviews require full source-file hashes");
|
|
20701
20879
|
verifyAgentDiscovery(supplied);
|
|
20702
|
-
if (review.sources.some((source) => (source.hashMode === "sumi-settings-v1" || source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !== canonical7(configPath)))
|
|
20880
|
+
if (review.sources.some((source) => (source.hashMode === "sumi-settings-v1" || source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !== canonical7(configPath)))
|
|
20703
20881
|
throw new Error("Semantic settings witnesses must name the configured agent configuration source");
|
|
20704
20882
|
if (!review.sources.some((source) => source.path === canonical7(configPath)))
|
|
20705
20883
|
throw new Error("Discovery review must include the agent configuration source");
|
|
@@ -20708,7 +20886,7 @@ function resolveAgentDiscovery(options) {
|
|
|
20708
20886
|
if (agent !== "claude" || source.sha256 === null || source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || source.hashMode !== undefined && source.hashMode !== "bytes" || basename10(source.path) !== "plugin.json" || !source.path.endsWith(join32(sep8, ".claude-plugin", "plugin.json")))
|
|
20709
20887
|
return source;
|
|
20710
20888
|
const pluginRoot = dirname19(dirname19(source.path)), hooksPath = join32(pluginRoot, "hooks/hooks.json");
|
|
20711
|
-
const hookStat =
|
|
20889
|
+
const hookStat = lstatSync25(hooksPath, { throwIfNoEntry: false });
|
|
20712
20890
|
const text2 = read2(source.path);
|
|
20713
20891
|
if (text2 === null)
|
|
20714
20892
|
throw new Error("Reviewed Claude plugin manifest is missing");
|
|
@@ -20749,7 +20927,7 @@ function resolveAgentDiscovery(options) {
|
|
|
20749
20927
|
unresolved("plugin hooks require a separate no-skill-injection review");
|
|
20750
20928
|
const commands = join32(root2, "commands");
|
|
20751
20929
|
safe4(commands);
|
|
20752
|
-
if (agent === "claude" && (manifest.commands !== undefined ||
|
|
20930
|
+
if (agent === "claude" && (manifest.commands !== undefined || lstatSync25(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync10(commands).length))
|
|
20753
20931
|
unresolved("legacy command discovery requires retirement or a dedicated format adapter");
|
|
20754
20932
|
const rootSkill = witness(join32(root2, "SKILL.md"));
|
|
20755
20933
|
if (rootSkill !== null)
|
|
@@ -20771,7 +20949,7 @@ function resolveAgentDiscovery(options) {
|
|
|
20771
20949
|
const installed = registrations === null ? {} : parseConfig(registrations, join32(home, ".claude/plugins/installed_plugins.json")).plugins;
|
|
20772
20950
|
const commands = canonical7(join32(home, ".claude/commands"));
|
|
20773
20951
|
safe4(commands);
|
|
20774
|
-
if (
|
|
20952
|
+
if (lstatSync25(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync10(commands).length)
|
|
20775
20953
|
unresolved("legacy home command discovery requires a dedicated format adapter");
|
|
20776
20954
|
for (const [id, enabled] of Object.entries(config.enabledPlugins ?? {})) {
|
|
20777
20955
|
if (enabled === false)
|
|
@@ -20791,7 +20969,7 @@ function resolveAgentDiscovery(options) {
|
|
|
20791
20969
|
unresolved("unsupported plugin enablement");
|
|
20792
20970
|
const split = id.lastIndexOf("@"), name = id.slice(0, split), marketplace = id.slice(split + 1);
|
|
20793
20971
|
const market = config.marketplaces?.[marketplace] ?? (marketplace === "personal" ? { source_type: "local", source: home } : undefined);
|
|
20794
|
-
if (split < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !
|
|
20972
|
+
if (split < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !isAbsolute19(market.source))
|
|
20795
20973
|
unresolved("enabled plugin marketplace is not an explicit local source");
|
|
20796
20974
|
const catalogText = witness(join32(market.source, ".agents/plugins/marketplace.json"));
|
|
20797
20975
|
if (catalogText === null)
|
|
@@ -20807,13 +20985,13 @@ function resolveAgentDiscovery(options) {
|
|
|
20807
20985
|
if ((config.plugin?.length ?? 0) > 0 || config.skills?.urls?.length)
|
|
20808
20986
|
unresolved("external plugin or remote skill source");
|
|
20809
20987
|
for (const path of config.skills?.paths ?? []) {
|
|
20810
|
-
if (typeof path !== "string" || !
|
|
20988
|
+
if (typeof path !== "string" || !isAbsolute19(path))
|
|
20811
20989
|
unresolved("relative or malformed added skill root");
|
|
20812
20990
|
roots.add(path);
|
|
20813
20991
|
}
|
|
20814
20992
|
const localPlugins = join32(home, ".config/opencode/plugins");
|
|
20815
20993
|
safe4(localPlugins);
|
|
20816
|
-
if (
|
|
20994
|
+
if (lstatSync25(localPlugins, { throwIfNoEntry: false }) && readdirSync10(localPlugins).some((name) => name !== "skills-cli.js"))
|
|
20817
20995
|
unresolved("additional local plugin hooks require review");
|
|
20818
20996
|
} else if (agent === "sumi") {
|
|
20819
20997
|
if ((config.plugin?.length ?? 0) > 0 || (config.plugins?.length ?? 0) > 0 || sources.some((source) => source.path !== canonical7(configPath) && source.path !== canonical7(join32(sumiConfigDirectory(home), "sumi.jsonc")) && source.sha256 !== null))
|
|
@@ -20821,7 +20999,7 @@ function resolveAgentDiscovery(options) {
|
|
|
20821
20999
|
} else if (agent === "hermes") {
|
|
20822
21000
|
for (const directory of [join32(home, ".hermes/plugins"), join32(home, ".hermes/hermes-agent")]) {
|
|
20823
21001
|
safe4(directory);
|
|
20824
|
-
if (
|
|
21002
|
+
if (lstatSync25(directory, { throwIfNoEntry: false }))
|
|
20825
21003
|
unresolved("installed runtime/plugin discovery requires reviewed source bindings");
|
|
20826
21004
|
}
|
|
20827
21005
|
if (Bun.which("hermes") || Object.keys(config.plugins ?? {}).length)
|
|
@@ -20831,11 +21009,11 @@ function resolveAgentDiscovery(options) {
|
|
|
20831
21009
|
unresolved("custom extension or skill paths");
|
|
20832
21010
|
const directory = join32(home, ".gemini/extensions");
|
|
20833
21011
|
safe4(directory);
|
|
20834
|
-
if (
|
|
21012
|
+
if (lstatSync25(directory, { throwIfNoEntry: false }))
|
|
20835
21013
|
for (const name of readdirSync10(directory)) {
|
|
20836
21014
|
const root2 = join32(directory, name);
|
|
20837
21015
|
safe4(root2);
|
|
20838
|
-
if (!
|
|
21016
|
+
if (!lstatSync25(root2)?.isDirectory())
|
|
20839
21017
|
continue;
|
|
20840
21018
|
const raw = witness(join32(root2, "gemini-extension.json"));
|
|
20841
21019
|
if (raw === null)
|
|
@@ -20868,14 +21046,14 @@ function nativeRootMatch(path) {
|
|
|
20868
21046
|
function physicalPath(path) {
|
|
20869
21047
|
let cursor = resolve19(path);
|
|
20870
21048
|
const suffix = [];
|
|
20871
|
-
while (!
|
|
21049
|
+
while (!lstatSync26(cursor, { throwIfNoEntry: false })) {
|
|
20872
21050
|
suffix.unshift(basename11(cursor));
|
|
20873
21051
|
const parent = dirname20(cursor);
|
|
20874
21052
|
if (parent === cursor)
|
|
20875
21053
|
return resolve19(path);
|
|
20876
21054
|
cursor = parent;
|
|
20877
21055
|
}
|
|
20878
|
-
return resolve19(
|
|
21056
|
+
return resolve19(realpathSync12(cursor), ...suffix);
|
|
20879
21057
|
}
|
|
20880
21058
|
function contains(root2, path) {
|
|
20881
21059
|
return path === root2 || path.startsWith(root2 + sep9);
|
|
@@ -20913,7 +21091,7 @@ function configuredRoots(home, explicitHome) {
|
|
|
20913
21091
|
continue;
|
|
20914
21092
|
}
|
|
20915
21093
|
const nativeHome = join33(home, agent === "opencode" ? ".config/opencode" : `.${agent}`);
|
|
20916
|
-
if (!
|
|
21094
|
+
if (!lstatSync26(nativeHome, { throwIfNoEntry: false }))
|
|
20917
21095
|
continue;
|
|
20918
21096
|
roots.push(...resolveAgentDiscovery({ home, agent, canonical: physicalPath }).roots);
|
|
20919
21097
|
}
|
|
@@ -21091,14 +21269,14 @@ function physicalImportPath(path) {
|
|
|
21091
21269
|
suffix.unshift(basename12(ancestor));
|
|
21092
21270
|
ancestor = dirname21(ancestor);
|
|
21093
21271
|
}
|
|
21094
|
-
return join34(
|
|
21272
|
+
return join34(realpathSync13(ancestor), ...suffix);
|
|
21095
21273
|
}
|
|
21096
21274
|
function assertDisjointImportPaths(source, destination) {
|
|
21097
|
-
const sourcePath =
|
|
21275
|
+
const sourcePath = realpathSync13(source);
|
|
21098
21276
|
const destinationPath = physicalImportPath(destination);
|
|
21099
21277
|
const contains2 = (parent, child) => {
|
|
21100
21278
|
const path = relative7(parent, child);
|
|
21101
|
-
return path === "" || !
|
|
21279
|
+
return path === "" || !isAbsolute20(path) && path !== ".." && !path.startsWith(`..${sep10}`);
|
|
21102
21280
|
};
|
|
21103
21281
|
if (contains2(sourcePath, destinationPath) || contains2(destinationPath, sourcePath)) {
|
|
21104
21282
|
throw new Error("Source and destination skill directories must not overlap");
|
|
@@ -21379,7 +21557,7 @@ function safeIsDirectory(path) {
|
|
|
21379
21557
|
}
|
|
21380
21558
|
}
|
|
21381
21559
|
function isSafeRelativePath2(value) {
|
|
21382
|
-
if (!value.trim() ||
|
|
21560
|
+
if (!value.trim() || isAbsolute20(value))
|
|
21383
21561
|
return false;
|
|
21384
21562
|
const normalized = normalize4(value).replace(/\\/g, "/");
|
|
21385
21563
|
return normalized !== ".." && !normalized.startsWith("../") && !normalized.includes("/../");
|
|
@@ -21594,7 +21772,7 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
21594
21772
|
continue;
|
|
21595
21773
|
let content;
|
|
21596
21774
|
try {
|
|
21597
|
-
content =
|
|
21775
|
+
content = readFileSync21(skillMdPath, "utf-8");
|
|
21598
21776
|
} catch {
|
|
21599
21777
|
continue;
|
|
21600
21778
|
}
|
|
@@ -21631,7 +21809,7 @@ function findExtensionSkillPath(name) {
|
|
|
21631
21809
|
continue;
|
|
21632
21810
|
let content;
|
|
21633
21811
|
try {
|
|
21634
|
-
content =
|
|
21812
|
+
content = readFileSync21(skillMdPath, "utf-8");
|
|
21635
21813
|
} catch {
|
|
21636
21814
|
continue;
|
|
21637
21815
|
}
|
|
@@ -21695,8 +21873,8 @@ function getAllTags(catalog) {
|
|
|
21695
21873
|
return Array.from(tagSet).sort();
|
|
21696
21874
|
}
|
|
21697
21875
|
// src/lib/run-state.ts
|
|
21698
|
-
import { createHash as
|
|
21699
|
-
import { existsSync as existsSync16, mkdirSync as mkdirSync11, readFileSync as
|
|
21876
|
+
import { createHash as createHash25, randomBytes } from "crypto";
|
|
21877
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync11, readFileSync as readFileSync23, readdirSync as readdirSync13, statSync as statSync12, writeFileSync as writeFileSync10 } from "fs";
|
|
21700
21878
|
import { extname, join as join36, relative as relative8 } from "path";
|
|
21701
21879
|
function createSkillRun(params, targetDir = process.cwd()) {
|
|
21702
21880
|
const now = new Date;
|
|
@@ -21768,7 +21946,7 @@ function appendRunEvent(context, event, data = {}) {
|
|
|
21768
21946
|
const line = JSON.stringify({ ts: new Date().toISOString(), event, ...data }) + `
|
|
21769
21947
|
`;
|
|
21770
21948
|
const path = join36(context.runDir, "events.ndjson");
|
|
21771
|
-
const previous = existsSync16(path) ?
|
|
21949
|
+
const previous = existsSync16(path) ? readFileSync23(path, "utf-8") : "";
|
|
21772
21950
|
writeFileSync10(path, previous + line);
|
|
21773
21951
|
}
|
|
21774
21952
|
function listSkillRuns(targetDir = process.cwd(), limit = 50) {
|
|
@@ -21818,11 +21996,11 @@ function collectRunArtifacts(context) {
|
|
|
21818
21996
|
const artifacts = [];
|
|
21819
21997
|
for (const path of walkFiles(context.exportDir)) {
|
|
21820
21998
|
const stat2 = statSync12(path);
|
|
21821
|
-
const bytes =
|
|
21999
|
+
const bytes = readFileSync23(path);
|
|
21822
22000
|
artifacts.push({
|
|
21823
22001
|
path: toProjectRelative(context.targetDir, path),
|
|
21824
22002
|
mime: mimeForPath(path),
|
|
21825
|
-
sha256:
|
|
22003
|
+
sha256: createHash25("sha256").update(bytes).digest("hex"),
|
|
21826
22004
|
sizeBytes: stat2.size
|
|
21827
22005
|
});
|
|
21828
22006
|
}
|
|
@@ -21833,7 +22011,7 @@ function readRunRecord(runDir) {
|
|
|
21833
22011
|
if (!existsSync16(path))
|
|
21834
22012
|
return null;
|
|
21835
22013
|
try {
|
|
21836
|
-
return JSON.parse(
|
|
22014
|
+
return JSON.parse(readFileSync23(path, "utf-8"));
|
|
21837
22015
|
} catch {
|
|
21838
22016
|
return null;
|
|
21839
22017
|
}
|
|
@@ -41241,7 +41419,7 @@ function clone2(value) {
|
|
|
41241
41419
|
return value === undefined ? undefined : JSON.parse(JSON.stringify(value));
|
|
41242
41420
|
}
|
|
41243
41421
|
// src/lib/canonical-json.ts
|
|
41244
|
-
import { createHash as
|
|
41422
|
+
import { createHash as createHash26 } from "crypto";
|
|
41245
41423
|
function canonicalJson2(value, maximumBytes = 2 * 1024 * 1024) {
|
|
41246
41424
|
return canonicalJsonAtDepth(value, maximumBytes, 64);
|
|
41247
41425
|
}
|
|
@@ -41285,7 +41463,7 @@ function canonicalJsonAtDepth(value, maximumBytes, maximumDepth) {
|
|
|
41285
41463
|
return visit3(value, 0);
|
|
41286
41464
|
}
|
|
41287
41465
|
function canonicalJsonSha256(value, maximumBytes) {
|
|
41288
|
-
return
|
|
41466
|
+
return createHash26("sha256").update(canonicalJson2(value, maximumBytes)).digest("hex");
|
|
41289
41467
|
}
|
|
41290
41468
|
|
|
41291
41469
|
// src/lib/remote-recurring-contract.ts
|
|
@@ -43348,7 +43526,7 @@ async function createRemoteSkillsClient(env = process.env) {
|
|
|
43348
43526
|
return connection ? new RemoteSkillsClient(connection.apiKey, connection.apiOrigin) : null;
|
|
43349
43527
|
}
|
|
43350
43528
|
// src/lib/scheduler.ts
|
|
43351
|
-
import { existsSync as existsSync17, readFileSync as
|
|
43529
|
+
import { existsSync as existsSync17, readFileSync as readFileSync25, writeFileSync as writeFileSync11, mkdirSync as mkdirSync12 } from "fs";
|
|
43352
43530
|
import { join as join37 } from "path";
|
|
43353
43531
|
function getSchedulesPath(targetDir = process.cwd()) {
|
|
43354
43532
|
return join37(targetDir, ".skills", "schedules.json");
|
|
@@ -43357,7 +43535,7 @@ function loadSchedules(targetDir = process.cwd()) {
|
|
|
43357
43535
|
const path = getSchedulesPath(targetDir);
|
|
43358
43536
|
if (existsSync17(path)) {
|
|
43359
43537
|
try {
|
|
43360
|
-
return JSON.parse(
|
|
43538
|
+
return JSON.parse(readFileSync25(path, "utf-8"));
|
|
43361
43539
|
} catch {}
|
|
43362
43540
|
}
|
|
43363
43541
|
return { version: 1, schedules: [] };
|
|
@@ -43552,7 +43730,7 @@ function recordScheduleRun(id, status, targetDir) {
|
|
|
43552
43730
|
saveSchedules(data, targetDir);
|
|
43553
43731
|
}
|
|
43554
43732
|
// src/lib/revision.ts
|
|
43555
|
-
import { createHash as
|
|
43733
|
+
import { createHash as createHash27 } from "crypto";
|
|
43556
43734
|
var REVISION_ID_PATTERN = /^[0-9a-f]{64}$/;
|
|
43557
43735
|
function revisionIdOf(content) {
|
|
43558
43736
|
const canonicalContent = {
|
|
@@ -43574,13 +43752,13 @@ function revisionIdOf(content) {
|
|
|
43574
43752
|
canonicalContent.replacementSlug = content.replacementSlug ?? null;
|
|
43575
43753
|
}
|
|
43576
43754
|
const canonical7 = JSON.stringify(canonicalContent);
|
|
43577
|
-
return
|
|
43755
|
+
return createHash27("sha256").update(canonical7).digest("hex");
|
|
43578
43756
|
}
|
|
43579
43757
|
function revisionIdOfRecord(record8) {
|
|
43580
43758
|
return revisionIdOf(record8);
|
|
43581
43759
|
}
|
|
43582
43760
|
// src/lib/pull.ts
|
|
43583
|
-
import { existsSync as existsSync18, mkdirSync as mkdirSync13, mkdtempSync as mkdtempSync3, readFileSync as
|
|
43761
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync13, mkdtempSync as mkdtempSync3, readFileSync as readFileSync26, renameSync as renameSync7, rmSync as rmSync5, writeFileSync as writeFileSync12 } from "fs";
|
|
43584
43762
|
import { dirname as dirname22, join as join38 } from "path";
|
|
43585
43763
|
|
|
43586
43764
|
// src/lib/skill-bundles.ts
|
|
@@ -43780,7 +43958,7 @@ function reconcileTombstone(slug2, corpusOptions) {
|
|
|
43780
43958
|
}
|
|
43781
43959
|
function readPullMarker(dir) {
|
|
43782
43960
|
try {
|
|
43783
|
-
return JSON.parse(
|
|
43961
|
+
return JSON.parse(readFileSync26(join38(dir, PULL_MARKER_FILE), "utf-8"));
|
|
43784
43962
|
} catch {
|
|
43785
43963
|
return null;
|
|
43786
43964
|
}
|
|
@@ -44017,7 +44195,7 @@ function splitNameVersion(raw) {
|
|
|
44017
44195
|
return version2 ? { name, version: version2 } : { name };
|
|
44018
44196
|
}
|
|
44019
44197
|
// src/lib/recurring-surface.ts
|
|
44020
|
-
import { isAbsolute as
|
|
44198
|
+
import { isAbsolute as isAbsolute21 } from "path";
|
|
44021
44199
|
|
|
44022
44200
|
// src/lib/remote-invitation-recovery.ts
|
|
44023
44201
|
class InvitationEmailInputError extends Error {
|
|
@@ -44115,7 +44293,7 @@ async function requestInvitationEmail(origin, action, input2) {
|
|
|
44115
44293
|
}
|
|
44116
44294
|
|
|
44117
44295
|
// src/lib/remote-private-publications.ts
|
|
44118
|
-
import { createHash as
|
|
44296
|
+
import { createHash as createHash28 } from "crypto";
|
|
44119
44297
|
var PRIVATE_PUBLICATION_MAX_BYTES = 16 * 1024 * 1024;
|
|
44120
44298
|
var failures2 = {
|
|
44121
44299
|
INVALID_REQUEST: [400, "The publication request is invalid."],
|
|
@@ -44162,7 +44340,7 @@ var hash3 = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v);
|
|
|
44162
44340
|
var record9 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
44163
44341
|
var exact = (v, keys) => record9(v) && Object.keys(v).sort().join(",") === keys.sort().join(",");
|
|
44164
44342
|
var date5 = (v) => typeof v === "string" && /^\d{4}-\d\d-\d\dT[0-9:.]+(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/.test(v) && Number.isFinite(Date.parse(v));
|
|
44165
|
-
var publicationSha256 = (bytes) =>
|
|
44343
|
+
var publicationSha256 = (bytes) => createHash28("sha256").update(bytes).digest("hex");
|
|
44166
44344
|
function checkedPublicationDeclaration(value) {
|
|
44167
44345
|
if (!exact(value, ["idempotencyKey", "version", "expectedCurrentVersionId", "manifestText", "archiveSha256", "archiveByteSize"]) || !publicationUuid(value.idempotencyKey) || !(value.expectedCurrentVersionId === null || publicationUuid(value.expectedCurrentVersionId)) || typeof value.version !== "string" || !value.version || value.version.length > 128 || /[\p{Cc}\p{Cs}]/u.test(value.version) || typeof value.manifestText !== "string" || Buffer.byteLength(value.manifestText) > 16384 || !hash3(value.archiveSha256) || !Number.isSafeInteger(value.archiveByteSize) || Number(value.archiveByteSize) < 1 || Number(value.archiveByteSize) > PRIVATE_PUBLICATION_MAX_BYTES)
|
|
44168
44346
|
return bad();
|
|
@@ -44676,7 +44854,7 @@ var stateSchema = exports_external.object({
|
|
|
44676
44854
|
var uuid13 = exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/);
|
|
44677
44855
|
var context = { userId: uuid13.optional(), membershipId: uuid13.optional() };
|
|
44678
44856
|
var page2 = { limit: exports_external.number().int().min(1).max(100).optional(), cursor: exports_external.string().min(1).max(2048).optional() };
|
|
44679
|
-
var directory = exports_external.string().max(4096).refine(
|
|
44857
|
+
var directory = exports_external.string().max(4096).refine(isAbsolute21, "Use an absolute recovery directory");
|
|
44680
44858
|
var email4 = exports_external.string().trim().toLowerCase().email().max(254);
|
|
44681
44859
|
var code = exports_external.string().regex(/^\d{6}$/);
|
|
44682
44860
|
var recurringSurfaceSchemas = {
|
|
@@ -46028,11 +46206,11 @@ function isApiMode(env = process.env) {
|
|
|
46028
46206
|
}
|
|
46029
46207
|
}
|
|
46030
46208
|
// src/lib/native-storage.ts
|
|
46031
|
-
import { createHash as
|
|
46209
|
+
import { createHash as createHash29, createHmac as createHmac2 } from "crypto";
|
|
46032
46210
|
import {
|
|
46033
46211
|
existsSync as existsSync20,
|
|
46034
46212
|
mkdirSync as mkdirSync16,
|
|
46035
|
-
readFileSync as
|
|
46213
|
+
readFileSync as readFileSync27,
|
|
46036
46214
|
readdirSync as readdirSync14,
|
|
46037
46215
|
statSync as statSync13,
|
|
46038
46216
|
writeFileSync as writeFileSync14
|
|
@@ -46199,12 +46377,12 @@ function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
|
|
|
46199
46377
|
const files = [];
|
|
46200
46378
|
if (existsSync20(projectStateDir)) {
|
|
46201
46379
|
for (const filePath of walkFiles2(projectStateDir)) {
|
|
46202
|
-
const bytes =
|
|
46380
|
+
const bytes = readFileSync27(filePath);
|
|
46203
46381
|
const relativePath = toPosix(relative10(targetDir, filePath));
|
|
46204
46382
|
files.push({
|
|
46205
46383
|
path: relativePath,
|
|
46206
46384
|
sizeBytes: bytes.byteLength,
|
|
46207
|
-
sha256:
|
|
46385
|
+
sha256: createHash29("sha256").update(bytes).digest("hex"),
|
|
46208
46386
|
...options.includeFileContents ? { contentBase64: Buffer.from(bytes).toString("base64") } : {}
|
|
46209
46387
|
});
|
|
46210
46388
|
}
|
|
@@ -46229,7 +46407,7 @@ function importSkillsLocalSnapshot(snapshot2, targetDir = process.cwd(), options
|
|
|
46229
46407
|
continue;
|
|
46230
46408
|
}
|
|
46231
46409
|
const bytes = Buffer.from(file2.contentBase64, "base64");
|
|
46232
|
-
const hash4 =
|
|
46410
|
+
const hash4 = createHash29("sha256").update(bytes).digest("hex");
|
|
46233
46411
|
if (hash4 !== file2.sha256) {
|
|
46234
46412
|
throw new Error(`Snapshot file checksum mismatch: ${file2.path}`);
|
|
46235
46413
|
}
|
|
@@ -46561,7 +46739,7 @@ function toIsoString(value) {
|
|
|
46561
46739
|
return Number.isNaN(date6.getTime()) ? value : date6.toISOString();
|
|
46562
46740
|
}
|
|
46563
46741
|
function sha256Hex2(value) {
|
|
46564
|
-
return
|
|
46742
|
+
return createHash29("sha256").update(value).digest("hex");
|
|
46565
46743
|
}
|
|
46566
46744
|
function normalizeHeaders(headers) {
|
|
46567
46745
|
const result = {};
|
|
@@ -46613,15 +46791,15 @@ function toArrayBuffer(bytes) {
|
|
|
46613
46791
|
return buffer;
|
|
46614
46792
|
}
|
|
46615
46793
|
// src/lib/station-snapshot.ts
|
|
46616
|
-
import { createHash as
|
|
46794
|
+
import { createHash as createHash30 } from "crypto";
|
|
46617
46795
|
import {
|
|
46618
46796
|
copyFileSync,
|
|
46619
46797
|
mkdirSync as mkdirSync17,
|
|
46620
|
-
readFileSync as
|
|
46798
|
+
readFileSync as readFileSync28,
|
|
46621
46799
|
statSync as statSync15,
|
|
46622
46800
|
writeFileSync as writeFileSync15
|
|
46623
46801
|
} from "fs";
|
|
46624
|
-
import { dirname as dirname26, isAbsolute as
|
|
46802
|
+
import { dirname as dirname26, isAbsolute as isAbsolute22, relative as relative11, resolve as resolve21, sep as sep13 } from "path";
|
|
46625
46803
|
|
|
46626
46804
|
// src/lib/portable-snapshot-filter.ts
|
|
46627
46805
|
import { readdirSync as readdirSync15, statSync as statSync14 } from "fs";
|
|
@@ -46788,7 +46966,7 @@ function validateStationId(stationId) {
|
|
|
46788
46966
|
}
|
|
46789
46967
|
}
|
|
46790
46968
|
function sha256File(filePath) {
|
|
46791
|
-
return
|
|
46969
|
+
return createHash30("sha256").update(readFileSync28(filePath)).digest("hex");
|
|
46792
46970
|
}
|
|
46793
46971
|
function scanHome(definition, homesRoot) {
|
|
46794
46972
|
const homePath = homePathFor(definition, homesRoot);
|
|
@@ -46887,7 +47065,7 @@ function writeStationSnapshot(options) {
|
|
|
46887
47065
|
for (const plan of plans) {
|
|
46888
47066
|
const destination = resolve21(repoRoot, plan.destination);
|
|
46889
47067
|
const destinationRelative = relative11(repoRoot, destination);
|
|
46890
|
-
if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep13) ||
|
|
47068
|
+
if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep13) || isAbsolute22(destinationRelative)) {
|
|
46891
47069
|
throw new StationSnapshotError("DESTINATION_ESCAPE", `destination escapes repo root: ${plan.destination}`);
|
|
46892
47070
|
}
|
|
46893
47071
|
let existingDigest = null;
|
|
@@ -46939,12 +47117,12 @@ function writeStationSnapshot(options) {
|
|
|
46939
47117
|
};
|
|
46940
47118
|
}
|
|
46941
47119
|
// src/lib/station-hydrate.ts
|
|
46942
|
-
import { createHash as
|
|
47120
|
+
import { createHash as createHash31 } from "crypto";
|
|
46943
47121
|
import {
|
|
46944
47122
|
copyFileSync as copyFileSync2,
|
|
46945
47123
|
mkdirSync as mkdirSync18,
|
|
46946
47124
|
readdirSync as readdirSync16,
|
|
46947
|
-
readFileSync as
|
|
47125
|
+
readFileSync as readFileSync29,
|
|
46948
47126
|
statSync as statSync16,
|
|
46949
47127
|
writeFileSync as writeFileSync16
|
|
46950
47128
|
} from "fs";
|
|
@@ -46963,7 +47141,7 @@ function readSnapshotManifest(repoRoot, stationId) {
|
|
|
46963
47141
|
const manifestPath = join42(snapshotRoot, "sync-manifest.json");
|
|
46964
47142
|
let manifest;
|
|
46965
47143
|
try {
|
|
46966
|
-
manifest = JSON.parse(
|
|
47144
|
+
manifest = JSON.parse(readFileSync29(manifestPath, "utf8"));
|
|
46967
47145
|
} catch (error61) {
|
|
46968
47146
|
fail2("MANIFEST_UNREADABLE", `cannot read snapshot manifest: ${manifestPath}: ${error61.message}`);
|
|
46969
47147
|
}
|
|
@@ -47099,7 +47277,7 @@ function planStationHydration(stationId, repoRoot) {
|
|
|
47099
47277
|
for (const copy of copies) {
|
|
47100
47278
|
let isStub = false;
|
|
47101
47279
|
try {
|
|
47102
|
-
isStub = isPointerSkillMd(
|
|
47280
|
+
isStub = isPointerSkillMd(readFileSync29(copy.fullPath, "utf8"));
|
|
47103
47281
|
} catch {
|
|
47104
47282
|
isStub = false;
|
|
47105
47283
|
}
|
|
@@ -47145,7 +47323,7 @@ function skillSha256(skill) {
|
|
|
47145
47323
|
return sha256File(skill.files[0].winner.fullPath);
|
|
47146
47324
|
}
|
|
47147
47325
|
const joined = skill.files.map((file2) => sha256File(file2.winner.fullPath));
|
|
47148
|
-
return
|
|
47326
|
+
return createHash31("sha256").update(joined.sort().join(`
|
|
47149
47327
|
`)).digest("hex");
|
|
47150
47328
|
}
|
|
47151
47329
|
function writeStationHydration(options) {
|
|
@@ -47237,23 +47415,23 @@ function writeStationHydration(options) {
|
|
|
47237
47415
|
};
|
|
47238
47416
|
}
|
|
47239
47417
|
// src/lib/private-publication-recovery.ts
|
|
47240
|
-
import { constants as
|
|
47241
|
-
import { dirname as dirname28, isAbsolute as
|
|
47418
|
+
import { constants as constants15, closeSync as closeSync15, fsyncSync as fsyncSync7, fstatSync as fstatSync15, lstatSync as lstatSync27, mkdirSync as mkdirSync19, openSync as openSync15, readSync as readSync12, realpathSync as realpathSync14, renameSync as renameSync8, unlinkSync as unlinkSync6, writeFileSync as writeFileSync17 } from "fs";
|
|
47419
|
+
import { dirname as dirname28, isAbsolute as isAbsolute23, join as join43, resolve as resolve23 } from "path";
|
|
47242
47420
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
47243
47421
|
var fail3 = () => {
|
|
47244
47422
|
throw new PrivatePublicationError("PUBLICATION_RECOVERY_INVALID", "The recovery directory is invalid or changed. Preserve it and inspect the existing intent; do not start a replacement automatically.");
|
|
47245
47423
|
};
|
|
47246
47424
|
function safeDirectory(directory2) {
|
|
47247
|
-
if (!
|
|
47425
|
+
if (!isAbsolute23(directory2) || directory2 !== resolve23(directory2) || realpathSync14(directory2) !== directory2)
|
|
47248
47426
|
return fail3();
|
|
47249
47427
|
for (let path = directory2;; path = dirname28(path)) {
|
|
47250
|
-
const stat2 =
|
|
47428
|
+
const stat2 = lstatSync27(path);
|
|
47251
47429
|
if (!stat2.isDirectory() || stat2.isSymbolicLink())
|
|
47252
47430
|
return fail3();
|
|
47253
47431
|
if (path === dirname28(path))
|
|
47254
47432
|
break;
|
|
47255
47433
|
}
|
|
47256
|
-
const own2 =
|
|
47434
|
+
const own2 = lstatSync27(directory2);
|
|
47257
47435
|
if ((own2.mode & 63) !== 0 || process.getuid && own2.uid !== process.getuid())
|
|
47258
47436
|
return fail3();
|
|
47259
47437
|
return { dev: own2.dev, ino: own2.ino };
|
|
@@ -47265,9 +47443,9 @@ function unchangedDirectory(directory2, identity5) {
|
|
|
47265
47443
|
}
|
|
47266
47444
|
function readOwned(directory2, name, max) {
|
|
47267
47445
|
const identity5 = safeDirectory(directory2), file2 = join43(directory2, name);
|
|
47268
|
-
const fd =
|
|
47446
|
+
const fd = openSync15(file2, constants15.O_RDONLY | constants15.O_NOFOLLOW);
|
|
47269
47447
|
try {
|
|
47270
|
-
const stat2 =
|
|
47448
|
+
const stat2 = fstatSync15(fd);
|
|
47271
47449
|
if (!stat2.isFile() || stat2.nlink !== 1 || stat2.size > max || stat2.size < 1 || (stat2.mode & 63) !== 0 || process.getuid && stat2.uid !== process.getuid())
|
|
47272
47450
|
return fail3();
|
|
47273
47451
|
const buffer = Buffer.alloc(Math.min(max, stat2.size) + 1);
|
|
@@ -47278,22 +47456,22 @@ function readOwned(directory2, name, max) {
|
|
|
47278
47456
|
break;
|
|
47279
47457
|
length += count;
|
|
47280
47458
|
}
|
|
47281
|
-
const bytes = buffer.subarray(0, length), after =
|
|
47459
|
+
const bytes = buffer.subarray(0, length), after = fstatSync15(fd);
|
|
47282
47460
|
unchangedDirectory(directory2, identity5);
|
|
47283
47461
|
if (bytes.length !== stat2.size || stat2.size !== after.size || stat2.mtimeMs !== after.mtimeMs || stat2.ctimeMs !== after.ctimeMs)
|
|
47284
47462
|
return fail3();
|
|
47285
47463
|
return bytes;
|
|
47286
47464
|
} finally {
|
|
47287
|
-
|
|
47465
|
+
closeSync15(fd);
|
|
47288
47466
|
}
|
|
47289
47467
|
}
|
|
47290
47468
|
function writeOwned(directory2, name, bytes) {
|
|
47291
|
-
const fd =
|
|
47469
|
+
const fd = openSync15(join43(directory2, name), constants15.O_WRONLY | constants15.O_CREAT | constants15.O_EXCL | constants15.O_NOFOLLOW, 384);
|
|
47292
47470
|
try {
|
|
47293
47471
|
writeFileSync17(fd, bytes);
|
|
47294
|
-
|
|
47472
|
+
fsyncSync7(fd);
|
|
47295
47473
|
} finally {
|
|
47296
|
-
|
|
47474
|
+
closeSync15(fd);
|
|
47297
47475
|
}
|
|
47298
47476
|
}
|
|
47299
47477
|
function save(directory2, value) {
|
|
@@ -47302,11 +47480,11 @@ function save(directory2, value) {
|
|
|
47302
47480
|
`);
|
|
47303
47481
|
unchangedDirectory(directory2, identity5);
|
|
47304
47482
|
renameSync8(join43(directory2, temporary), join43(directory2, "receipt.json"));
|
|
47305
|
-
const fd =
|
|
47483
|
+
const fd = openSync15(directory2, constants15.O_RDONLY | constants15.O_NOFOLLOW);
|
|
47306
47484
|
try {
|
|
47307
|
-
|
|
47485
|
+
fsyncSync7(fd);
|
|
47308
47486
|
} finally {
|
|
47309
|
-
|
|
47487
|
+
closeSync15(fd);
|
|
47310
47488
|
}
|
|
47311
47489
|
}
|
|
47312
47490
|
function bind(client2, receipt) {
|
|
@@ -47317,20 +47495,20 @@ async function locked(directory2, action) {
|
|
|
47317
47495
|
const identity5 = safeDirectory(directory2), file2 = join43(directory2, "operation.lock");
|
|
47318
47496
|
let fd;
|
|
47319
47497
|
try {
|
|
47320
|
-
fd =
|
|
47498
|
+
fd = openSync15(file2, constants15.O_WRONLY | constants15.O_CREAT | constants15.O_EXCL | constants15.O_NOFOLLOW, 384);
|
|
47321
47499
|
} catch {
|
|
47322
47500
|
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.");
|
|
47323
47501
|
}
|
|
47324
|
-
const lock =
|
|
47502
|
+
const lock = fstatSync15(fd);
|
|
47325
47503
|
try {
|
|
47326
47504
|
writeFileSync17(fd, JSON.stringify({ pid: process.pid }) + `
|
|
47327
47505
|
`);
|
|
47328
|
-
|
|
47506
|
+
fsyncSync7(fd);
|
|
47329
47507
|
return await action();
|
|
47330
47508
|
} finally {
|
|
47331
|
-
|
|
47509
|
+
closeSync15(fd);
|
|
47332
47510
|
unchangedDirectory(directory2, identity5);
|
|
47333
|
-
const now =
|
|
47511
|
+
const now = lstatSync27(file2);
|
|
47334
47512
|
if (now.dev !== lock.dev || now.ino !== lock.ino || !now.isFile() || now.isSymbolicLink())
|
|
47335
47513
|
fail3();
|
|
47336
47514
|
unlinkSync6(file2);
|
|
@@ -47382,15 +47560,15 @@ async function preparePrivatePublication(client2, sourceDirectory, recoveryDirec
|
|
|
47382
47560
|
phase: "prepared",
|
|
47383
47561
|
intent: null
|
|
47384
47562
|
};
|
|
47385
|
-
if (!
|
|
47563
|
+
if (!isAbsolute23(recoveryDirectory) || resolve23(recoveryDirectory) !== recoveryDirectory || realpathSync14(dirname28(recoveryDirectory)) !== dirname28(recoveryDirectory))
|
|
47386
47564
|
return fail3();
|
|
47387
47565
|
mkdirSync19(recoveryDirectory, { mode: 448 });
|
|
47388
47566
|
safeDirectory(recoveryDirectory);
|
|
47389
|
-
const parent =
|
|
47567
|
+
const parent = openSync15(dirname28(recoveryDirectory), constants15.O_RDONLY | constants15.O_NOFOLLOW);
|
|
47390
47568
|
try {
|
|
47391
|
-
|
|
47569
|
+
fsyncSync7(parent);
|
|
47392
47570
|
} finally {
|
|
47393
|
-
|
|
47571
|
+
closeSync15(parent);
|
|
47394
47572
|
}
|
|
47395
47573
|
writeOwned(recoveryDirectory, "bundle.tgz", packed.bytes);
|
|
47396
47574
|
save(recoveryDirectory, receipt);
|
|
@@ -47473,7 +47651,7 @@ async function inspectLocked(client2, directory2, cancel) {
|
|
|
47473
47651
|
return privatePublicationResult(directory2, receipt);
|
|
47474
47652
|
}
|
|
47475
47653
|
// src/lib/skill-context.ts
|
|
47476
|
-
import { createHash as
|
|
47654
|
+
import { createHash as createHash32 } from "crypto";
|
|
47477
47655
|
import { resolve as resolve24 } from "path";
|
|
47478
47656
|
function words(value) {
|
|
47479
47657
|
return new Set(value.toLowerCase().match(/[a-z0-9]+/g) ?? []);
|
|
@@ -47566,7 +47744,7 @@ ${content}`;
|
|
|
47566
47744
|
`);
|
|
47567
47745
|
const receipt = {
|
|
47568
47746
|
schemaVersion: 1,
|
|
47569
|
-
id:
|
|
47747
|
+
id: createHash32("sha256").update(JSON.stringify({ profile: profile.profileRevision, sessionId, selections, omitted })).digest("hex"),
|
|
47570
47748
|
profileId: profile.profileId,
|
|
47571
47749
|
profileRevision: profile.profileRevision,
|
|
47572
47750
|
authority: profile.authority,
|
|
@@ -47582,9 +47760,9 @@ ${content}`;
|
|
|
47582
47760
|
return { context: context2, selections, omitted, receipt };
|
|
47583
47761
|
}
|
|
47584
47762
|
// src/lib/session-reconciliation.ts
|
|
47585
|
-
import { createHash as
|
|
47763
|
+
import { createHash as createHash33 } from "crypto";
|
|
47586
47764
|
var SESSION_RECONCILIATION_PLAN_TTL_MS = 5 * 60 * 1000;
|
|
47587
|
-
var digest3 = (value) =>
|
|
47765
|
+
var digest3 = (value) => createHash33("sha256").update(JSON.stringify(value)).digest("hex");
|
|
47588
47766
|
function exactTimestamp(value) {
|
|
47589
47767
|
const parsed = value === undefined ? Number.NaN : Date.parse(value);
|
|
47590
47768
|
if (!Number.isFinite(parsed) || new Date(parsed).toISOString() !== value) {
|
|
@@ -47702,6 +47880,7 @@ export {
|
|
|
47702
47880
|
upgradeCodexSettingsWitnessV4,
|
|
47703
47881
|
upgradeCodexSettingsWitnessV3,
|
|
47704
47882
|
upgradeCodexSettingsWitness,
|
|
47883
|
+
upgradeClaudeSettingsWitnessV4,
|
|
47705
47884
|
upgradeClaudeSettingsWitness,
|
|
47706
47885
|
updateSkillRun,
|
|
47707
47886
|
unsetConfig,
|
|
@@ -47893,6 +48072,7 @@ export {
|
|
|
47893
48072
|
captureCodexSettingsV2,
|
|
47894
48073
|
captureCodexSettings,
|
|
47895
48074
|
captureCodexNativeSkillCatalog,
|
|
48075
|
+
captureClaudeSettingsV4,
|
|
47896
48076
|
captureClaudeSettingsV3,
|
|
47897
48077
|
captureClaudeSettingsV2,
|
|
47898
48078
|
captureClaudeSettings,
|