@hasna/skills 0.10.47 → 0.10.49
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 +34 -0
- package/bin/index.js +1091 -649
- package/bin/maintenance.js +18 -0
- package/bin/mcp.js +65 -2
- 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.js +414 -262
- 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 +397 -245
- 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/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
|
|
|
@@ -9538,9 +9538,9 @@ function assertAgentPolicyCollections(policy) {
|
|
|
9538
9538
|
}
|
|
9539
9539
|
|
|
9540
9540
|
// src/lib/agent-discovery.ts
|
|
9541
|
-
import { createHash as
|
|
9542
|
-
import { lstatSync as
|
|
9543
|
-
import { basename as basename10, dirname as dirname19, isAbsolute as
|
|
9541
|
+
import { createHash as createHash24 } from "crypto";
|
|
9542
|
+
import { lstatSync as lstatSync25, readFileSync as readFileSync20, readdirSync as readdirSync10, realpathSync as realpathSync11 } from "fs";
|
|
9543
|
+
import { basename as basename10, dirname as dirname19, isAbsolute as isAbsolute19, join as join32, resolve as resolve18, sep as sep8 } from "path";
|
|
9544
9544
|
import { isDeepStrictEqual as isDeepStrictEqual7 } from "util";
|
|
9545
9545
|
|
|
9546
9546
|
// node_modules/yaml/dist/index.js
|
|
@@ -10230,12 +10230,12 @@ function projectReviewedClaudePluginManifest(text2, reviewedSha256) {
|
|
|
10230
10230
|
}
|
|
10231
10231
|
|
|
10232
10232
|
// src/lib/plugin-discovery.ts
|
|
10233
|
-
import { closeSync as
|
|
10234
|
-
import { basename as basename8, dirname as dirname17, isAbsolute as
|
|
10233
|
+
import { closeSync as closeSync13, constants as constants13, fstatSync as fstatSync13, lstatSync as lstatSync23, openSync as openSync13, opendirSync as opendirSync5, readSync as readSync10 } from "fs";
|
|
10234
|
+
import { basename as basename8, dirname as dirname17, isAbsolute as isAbsolute17, join as join31, resolve as resolve16 } from "path";
|
|
10235
10235
|
|
|
10236
10236
|
// src/lib/plugin-admission.ts
|
|
10237
10237
|
import { homedir as homedir5 } from "os";
|
|
10238
|
-
import { isAbsolute as
|
|
10238
|
+
import { isAbsolute as isAbsolute16, join as join30, resolve as resolve15 } from "path";
|
|
10239
10239
|
|
|
10240
10240
|
// src/lib/selection-cache.ts
|
|
10241
10241
|
import { createHash as createHash9, randomUUID } from "crypto";
|
|
@@ -11572,7 +11572,7 @@ function replaceSkillSession(expected, replacement, plan, options = {}, beforeCo
|
|
|
11572
11572
|
// package.json
|
|
11573
11573
|
var package_default = {
|
|
11574
11574
|
name: "@hasna/skills",
|
|
11575
|
-
version: "0.10.
|
|
11575
|
+
version: "0.10.49",
|
|
11576
11576
|
description: "Skills library for AI coding agents",
|
|
11577
11577
|
type: "module",
|
|
11578
11578
|
bin: {
|
|
@@ -13401,7 +13401,7 @@ async function prepareSkillDependencies(skillPath, env, timeoutMs = DEFAULT_PREP
|
|
|
13401
13401
|
}
|
|
13402
13402
|
|
|
13403
13403
|
// src/lib/skillinfo.ts
|
|
13404
|
-
import { existsSync as existsSync13, readFileSync as
|
|
13404
|
+
import { existsSync as existsSync13, readFileSync as readFileSync19 } from "fs";
|
|
13405
13405
|
import { join as join28 } from "path";
|
|
13406
13406
|
|
|
13407
13407
|
// src/lib/codex-corpus-write.ts
|
|
@@ -13566,7 +13566,7 @@ function withCodexCorpusWrite(roots, run, options = {}) {
|
|
|
13566
13566
|
}
|
|
13567
13567
|
|
|
13568
13568
|
// src/lib/installer.ts
|
|
13569
|
-
import { existsSync as existsSync12, readFileSync as
|
|
13569
|
+
import { existsSync as existsSync12, readFileSync as readFileSync18, rmSync as rmSync2 } from "fs";
|
|
13570
13570
|
import { join as join27 } from "path";
|
|
13571
13571
|
import { homedir as homedir4 } from "os";
|
|
13572
13572
|
|
|
@@ -13574,10 +13574,10 @@ import { homedir as homedir4 } from "os";
|
|
|
13574
13574
|
import {
|
|
13575
13575
|
cpSync as cpSync2,
|
|
13576
13576
|
existsSync as existsSync10,
|
|
13577
|
-
lstatSync as
|
|
13577
|
+
lstatSync as lstatSync21,
|
|
13578
13578
|
mkdirSync as mkdirSync7,
|
|
13579
13579
|
mkdtempSync,
|
|
13580
|
-
readFileSync as
|
|
13580
|
+
readFileSync as readFileSync16,
|
|
13581
13581
|
readdirSync as readdirSync9,
|
|
13582
13582
|
renameSync as renameSync4,
|
|
13583
13583
|
rmSync,
|
|
@@ -15501,10 +15501,10 @@ function upgradeCodexSettingsWitnessV4(previous, reviewedSettingsPath) {
|
|
|
15501
15501
|
}
|
|
15502
15502
|
|
|
15503
15503
|
// src/lib/agent-integration.ts
|
|
15504
|
-
import { createHash as
|
|
15504
|
+
import { createHash as createHash19, randomUUID as randomUUID3 } from "crypto";
|
|
15505
15505
|
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
|
|
15506
|
+
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";
|
|
15507
|
+
import { dirname as dirname14, join as join23, resolve as resolve13, relative as relative6, isAbsolute as isAbsolute14, sep as sep7 } from "path";
|
|
15508
15508
|
import { homedir as homedir2 } from "os";
|
|
15509
15509
|
|
|
15510
15510
|
// src/lib/managed-policy.ts
|
|
@@ -16068,8 +16068,144 @@ function unchanged2(before) {
|
|
|
16068
16068
|
need5(sameStat(before.stat, after.stat) && after.sha256 === before.sha256, "INPUT_CHANGED");
|
|
16069
16069
|
}
|
|
16070
16070
|
|
|
16071
|
+
// src/cli/commands/runtime-launcher.ts
|
|
16072
|
+
import { createHash as createHash18 } from "crypto";
|
|
16073
|
+
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";
|
|
16074
|
+
import { isAbsolute as isAbsolute13 } from "path";
|
|
16075
|
+
var PINNED_LAUNCHER_SCHEMA = "hasna-skills-pinned-launcher-v1";
|
|
16076
|
+
var LAUNCH_CWD_VARIABLE = "HASNA_SKILLS_LAUNCH_CWD";
|
|
16077
|
+
var PINNED_LAUNCHER_BUN_FLAGS = ["--config=/dev/null", "--no-env-file", "--no-macros", "--no-install"];
|
|
16078
|
+
var PINNED_LAUNCHER_ENV_NAMES = [
|
|
16079
|
+
"HOME",
|
|
16080
|
+
"PATH",
|
|
16081
|
+
"TMPDIR",
|
|
16082
|
+
"TERM",
|
|
16083
|
+
"TERM_PROGRAM",
|
|
16084
|
+
"TERM_PROGRAM_VERSION",
|
|
16085
|
+
"COLORTERM",
|
|
16086
|
+
"LANG",
|
|
16087
|
+
"USER",
|
|
16088
|
+
"LOGNAME",
|
|
16089
|
+
"SHELL",
|
|
16090
|
+
"TZ",
|
|
16091
|
+
"NO_COLOR",
|
|
16092
|
+
"FORCE_COLOR",
|
|
16093
|
+
"CI",
|
|
16094
|
+
"COLUMNS",
|
|
16095
|
+
"LINES",
|
|
16096
|
+
"EDITOR",
|
|
16097
|
+
"VISUAL",
|
|
16098
|
+
"PAGER",
|
|
16099
|
+
"SSH_AUTH_SOCK",
|
|
16100
|
+
"DATABASE_URL",
|
|
16101
|
+
"TERMINAL_CWD",
|
|
16102
|
+
"CODEX_HOME",
|
|
16103
|
+
"HERMES_HOME",
|
|
16104
|
+
"HERMES_ENABLE_PROJECT_PLUGINS",
|
|
16105
|
+
"HOST",
|
|
16106
|
+
"PORT",
|
|
16107
|
+
"NODE_ENV",
|
|
16108
|
+
"AGENT_ID",
|
|
16109
|
+
"ECS_CONTAINER_METADATA_URI_V4"
|
|
16110
|
+
];
|
|
16111
|
+
var PINNED_LAUNCHER_ENV_PREFIXES = ["HASNA", "SKILLS", "SKILL", "MCP", "XDG", "LC", "AWS"];
|
|
16112
|
+
var ENV_PREFIX = new RegExp(`^(${PINNED_LAUNCHER_ENV_PREFIXES.join("|")})_`);
|
|
16113
|
+
var ENV_EXACT = new Set(PINNED_LAUNCHER_ENV_NAMES);
|
|
16114
|
+
function sha2562(bytes) {
|
|
16115
|
+
return createHash18("sha256").update(bytes).digest("hex");
|
|
16116
|
+
}
|
|
16117
|
+
function assertLauncherPath(value, code) {
|
|
16118
|
+
if (typeof value !== "string" || !isAbsolute13(value) || /['\x00-\x1f\x7f]/.test(value))
|
|
16119
|
+
throw new Error(code);
|
|
16120
|
+
}
|
|
16121
|
+
function renderPinnedLauncher(binding) {
|
|
16122
|
+
assertLauncherPath(binding.runtime, "LAUNCHER_RUNTIME_PATH_INVALID");
|
|
16123
|
+
assertLauncherPath(binding.cwd, "LAUNCHER_CWD_PATH_INVALID");
|
|
16124
|
+
assertLauncherPath(binding.entry, "LAUNCHER_ENTRY_PATH_INVALID");
|
|
16125
|
+
const names = PINNED_LAUNCHER_ENV_NAMES.join(" ");
|
|
16126
|
+
const prefixes = PINNED_LAUNCHER_ENV_PREFIXES.join("|");
|
|
16127
|
+
return [
|
|
16128
|
+
"#!/bin/sh -p",
|
|
16129
|
+
`# ${PINNED_LAUNCHER_SCHEMA}`,
|
|
16130
|
+
"# Written by `skills self-update`; rewrite it with `skills self-update`, do not edit by hand.",
|
|
16131
|
+
"# Runs the exact Skills entry below under one exact Bun from one trusted directory with",
|
|
16132
|
+
"# no working-directory configuration (no bunfig.toml, no .env, no macros, no auto-install)",
|
|
16133
|
+
"# and only the environment names allowed here. Everything else, BUN_* and NODE_OPTIONS",
|
|
16134
|
+
"# included, never reaches the runtime. The CLI returns to the caller's directory itself.",
|
|
16135
|
+
"# `-p` keeps the caller's exported functions and shell options out of this shell.",
|
|
16136
|
+
"set -eu",
|
|
16137
|
+
`${LAUNCH_CWD_VARIABLE}=$(pwd -P 2>/dev/null || :)`,
|
|
16138
|
+
`export ${LAUNCH_CWD_VARIABLE}`,
|
|
16139
|
+
`set -- '${binding.runtime}' ${PINNED_LAUNCHER_BUN_FLAGS.join(" ")} '--cwd=${binding.cwd}' '${binding.entry}' "$@"`,
|
|
16140
|
+
"hasna_skills_env=$(LC_ALL=C /usr/bin/awk 'BEGIN {",
|
|
16141
|
+
` n = split("${names}", exact, " ")`,
|
|
16142
|
+
" for (i = 1; i <= n; i++) allow[exact[i]] = 1",
|
|
16143
|
+
" for (name in ENVIRON) {",
|
|
16144
|
+
" if (name !~ /^[A-Za-z_][A-Za-z0-9_]*$/) continue",
|
|
16145
|
+
` if (name == "LC_ALL" || (!(name in allow) && name !~ /^(${prefixes})_/)) continue`,
|
|
16146
|
+
' value = ENVIRON[name]; quoted = ""',
|
|
16147
|
+
' while ((k = index(value, "\\047")) > 0) { quoted = quoted substr(value, 1, k - 1) "\\047\\\\\\047\\047"; value = substr(value, k + 1) }',
|
|
16148
|
+
' printf "\\047%s=%s\\047 ", name, quoted value',
|
|
16149
|
+
" }",
|
|
16150
|
+
"}')",
|
|
16151
|
+
'eval "set -- $hasna_skills_env \\"\\$@\\""',
|
|
16152
|
+
'if [ "${LC_ALL+x}" = x ]; then set -- "LC_ALL=$LC_ALL" "$@"; fi',
|
|
16153
|
+
'exec /usr/bin/env -i "$@"',
|
|
16154
|
+
""
|
|
16155
|
+
].join(`
|
|
16156
|
+
`);
|
|
16157
|
+
}
|
|
16158
|
+
var COMMAND_LINE = new RegExp(`^set -- '([^']+)' ${PINNED_LAUNCHER_BUN_FLAGS.join(" ")} '--cwd=([^']+)' '([^']+)' "\\$@"$`, "m");
|
|
16159
|
+
function parsePinnedLauncher(text2) {
|
|
16160
|
+
const match = COMMAND_LINE.exec(text2);
|
|
16161
|
+
if (!match)
|
|
16162
|
+
return null;
|
|
16163
|
+
const binding = { runtime: match[1], cwd: match[2], entry: match[3] };
|
|
16164
|
+
try {
|
|
16165
|
+
if (renderPinnedLauncher(binding) !== text2)
|
|
16166
|
+
return null;
|
|
16167
|
+
} catch {
|
|
16168
|
+
return null;
|
|
16169
|
+
}
|
|
16170
|
+
return binding;
|
|
16171
|
+
}
|
|
16172
|
+
var PINNED_LAUNCHER_MAX_BYTES = 16 * 1024;
|
|
16173
|
+
function resolveLauncherCommand(path) {
|
|
16174
|
+
const physical = realpathSync9(path);
|
|
16175
|
+
const stat = lstatSync19(physical);
|
|
16176
|
+
if (stat.isFile() && stat.size <= PINNED_LAUNCHER_MAX_BYTES) {
|
|
16177
|
+
const text2 = readFileSync14(physical, "utf8");
|
|
16178
|
+
const binding = parsePinnedLauncher(text2);
|
|
16179
|
+
if (binding) {
|
|
16180
|
+
let entry;
|
|
16181
|
+
try {
|
|
16182
|
+
entry = realpathSync9(binding.entry);
|
|
16183
|
+
} catch {
|
|
16184
|
+
throw new Error("LAUNCHER_ENTRY_UNREADABLE");
|
|
16185
|
+
}
|
|
16186
|
+
if (entry !== binding.entry)
|
|
16187
|
+
throw new Error("LAUNCHER_ENTRY_NOT_PHYSICAL");
|
|
16188
|
+
return { physical, entry, pinned: { ...binding, sha256: sha2562(text2) } };
|
|
16189
|
+
}
|
|
16190
|
+
}
|
|
16191
|
+
return { physical, entry: physical, pinned: null };
|
|
16192
|
+
}
|
|
16193
|
+
function assertPinnedLauncherRuntimeSafe(runtime) {
|
|
16194
|
+
assertLauncherPath(runtime, "LAUNCHER_RUNTIME_PATH_INVALID");
|
|
16195
|
+
let stat;
|
|
16196
|
+
try {
|
|
16197
|
+
stat = lstatSync19(runtime);
|
|
16198
|
+
} catch {
|
|
16199
|
+
throw new Error("LAUNCHER_RUNTIME_UNSAFE");
|
|
16200
|
+
}
|
|
16201
|
+
const uid = process.getuid?.() ?? -1;
|
|
16202
|
+
if (!stat.isFile() || stat.isSymbolicLink() || ![0, uid].includes(stat.uid) || (stat.mode & 18) !== 0 || (stat.mode & 64) === 0) {
|
|
16203
|
+
throw new Error("LAUNCHER_RUNTIME_UNSAFE");
|
|
16204
|
+
}
|
|
16205
|
+
}
|
|
16206
|
+
|
|
16071
16207
|
// src/lib/agent-integration.ts
|
|
16072
|
-
var sha3 = (data) =>
|
|
16208
|
+
var sha3 = (data) => createHash19("sha256").update(data).digest("hex");
|
|
16073
16209
|
var ROOTS = NATIVE_SKILL_ROOTS;
|
|
16074
16210
|
function hasTrustedDarwinAcl(fd, allowDenyOnly = false) {
|
|
16075
16211
|
try {
|
|
@@ -16120,11 +16256,11 @@ function isSystemRootAlias(path) {
|
|
|
16120
16256
|
const target = `/private${path}`, link = `private${path}`;
|
|
16121
16257
|
const identity5 = (stat) => `${stat.dev}:${stat.ino}:${stat.ctimeNs}:${stat.uid}:${stat.mode}`;
|
|
16122
16258
|
try {
|
|
16123
|
-
const before =
|
|
16124
|
-
if (!before.isSymbolicLink() || before.uid !== 0n ||
|
|
16259
|
+
const before = lstatSync20(path, { bigint: true });
|
|
16260
|
+
if (!before.isSymbolicLink() || before.uid !== 0n || readlinkSync6(path) !== link)
|
|
16125
16261
|
return false;
|
|
16126
16262
|
const directories = ["/", "/private", target].map((directory) => {
|
|
16127
|
-
const stat =
|
|
16263
|
+
const stat = lstatSync20(directory, { bigint: true });
|
|
16128
16264
|
if (!stat.isDirectory() || stat.uid !== 0n)
|
|
16129
16265
|
throw new Error("Untrusted system alias directory");
|
|
16130
16266
|
if (directory !== "/private/tmp") {
|
|
@@ -16132,23 +16268,23 @@ function isSystemRootAlias(path) {
|
|
|
16132
16268
|
throw new Error("Writable system alias directory");
|
|
16133
16269
|
} else if ((stat.mode & 0o1000n) === 0n)
|
|
16134
16270
|
throw new Error("Unprotected system temporary directory");
|
|
16135
|
-
const fd =
|
|
16271
|
+
const fd = openSync11(directory, constants11.O_RDONLY | constants11.O_DIRECTORY | constants11.O_NOFOLLOW);
|
|
16136
16272
|
try {
|
|
16137
|
-
if (identity5(
|
|
16273
|
+
if (identity5(fstatSync11(fd, { bigint: true })) !== identity5(stat) || !hasTrustedDarwinAcl(fd) || identity5(fstatSync11(fd, { bigint: true })) !== identity5(stat))
|
|
16138
16274
|
throw new Error("Unverified system alias directory ACL");
|
|
16139
16275
|
} finally {
|
|
16140
|
-
|
|
16276
|
+
closeSync11(fd);
|
|
16141
16277
|
}
|
|
16142
16278
|
return { directory, identity: identity5(stat) };
|
|
16143
16279
|
});
|
|
16144
|
-
return
|
|
16280
|
+
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
16281
|
} catch {
|
|
16146
16282
|
return false;
|
|
16147
16283
|
}
|
|
16148
16284
|
}
|
|
16149
16285
|
function canonicalSystemPath(path) {
|
|
16150
16286
|
const absolute = resolve13(path), root = `/${absolute.split(sep7)[1]}`;
|
|
16151
|
-
if (process.platform !== "darwin" || !["/var", "/tmp", "/etc"].includes(root) || !
|
|
16287
|
+
if (process.platform !== "darwin" || !["/var", "/tmp", "/etc"].includes(root) || !lstatSync20(root, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
16152
16288
|
return absolute;
|
|
16153
16289
|
if (!isSystemRootAlias(root))
|
|
16154
16290
|
throw new Error(`Refusing symlink path: ${root}`);
|
|
@@ -16157,7 +16293,7 @@ function canonicalSystemPath(path) {
|
|
|
16157
16293
|
function assertSafePath(path) {
|
|
16158
16294
|
let cursor = resolve13(path);
|
|
16159
16295
|
while (true) {
|
|
16160
|
-
if (
|
|
16296
|
+
if (lstatSync20(cursor, { throwIfNoEntry: false })?.isSymbolicLink() && !isSystemRootAlias(cursor))
|
|
16161
16297
|
throw new Error(`Refusing symlink path: ${cursor}`);
|
|
16162
16298
|
const parent = dirname14(cursor);
|
|
16163
16299
|
if (parent === cursor)
|
|
@@ -16167,17 +16303,17 @@ function assertSafePath(path) {
|
|
|
16167
16303
|
}
|
|
16168
16304
|
function readRootAlias(home, agent) {
|
|
16169
16305
|
assertSafePath(home);
|
|
16170
|
-
const realHome =
|
|
16171
|
-
const stat =
|
|
16306
|
+
const realHome = realpathSync10(home), alias = join23(realHome, `.${agent}`);
|
|
16307
|
+
const stat = lstatSync20(alias, { throwIfNoEntry: false, bigint: true });
|
|
16172
16308
|
if (!stat?.isSymbolicLink())
|
|
16173
16309
|
throw new Error(`Agent root alias changed after planning: ${alias}`);
|
|
16174
|
-
const link =
|
|
16310
|
+
const link = readlinkSync6(alias), targetPath = resolve13(dirname14(alias), link);
|
|
16175
16311
|
assertSafePath(targetPath);
|
|
16176
|
-
const targetStat =
|
|
16312
|
+
const targetStat = lstatSync20(targetPath, { throwIfNoEntry: false });
|
|
16177
16313
|
if (!targetStat?.isDirectory())
|
|
16178
16314
|
throw new Error(`Agent root alias must target an existing directory: ${alias}`);
|
|
16179
|
-
const target =
|
|
16180
|
-
if (!inside || inside === ".." || inside.startsWith(`..${sep7}`) ||
|
|
16315
|
+
const target = realpathSync10(targetPath), inside = relative6(realHome, target);
|
|
16316
|
+
if (!inside || inside === ".." || inside.startsWith(`..${sep7}`) || isAbsolute14(inside))
|
|
16181
16317
|
throw new Error(`Agent root alias target must be inside the real home: ${alias}`);
|
|
16182
16318
|
return { agent, home: realHome, alias, target, link, aliasIdentity: `${stat.dev}:${stat.ino}:${stat.ctimeNs}`, targetIdentity: `${targetStat.dev}:${targetStat.ino}` };
|
|
16183
16319
|
}
|
|
@@ -16186,7 +16322,7 @@ function rootAliases(home, allowed = false) {
|
|
|
16186
16322
|
return [];
|
|
16187
16323
|
const result = [];
|
|
16188
16324
|
for (const agent of ["claude", "codex"])
|
|
16189
|
-
if (
|
|
16325
|
+
if (lstatSync20(join23(home, `.${agent}`), { throwIfNoEntry: false })?.isSymbolicLink())
|
|
16190
16326
|
result.push(readRootAlias(home, agent));
|
|
16191
16327
|
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
16328
|
throw new Error("Agent root alias targets must not overlap");
|
|
@@ -16203,17 +16339,17 @@ function disabledCodexSkillPaths(config, aliases) {
|
|
|
16203
16339
|
const rows = skills.config;
|
|
16204
16340
|
if (!Array.isArray(rows))
|
|
16205
16341
|
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" || !
|
|
16342
|
+
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
16343
|
return [];
|
|
16208
16344
|
if (rows.some((entry) => entry.name !== undefined && entry.enabled !== false))
|
|
16209
16345
|
return [];
|
|
16210
16346
|
const settings = new Map;
|
|
16211
16347
|
for (const entry of rows) {
|
|
16212
|
-
if (typeof entry.path !== "string" || !
|
|
16348
|
+
if (typeof entry.path !== "string" || !isAbsolute14(entry.path))
|
|
16213
16349
|
continue;
|
|
16214
16350
|
let document2;
|
|
16215
16351
|
try {
|
|
16216
|
-
document2 =
|
|
16352
|
+
document2 = realpathSync10(canonicalAgentPath(entry.path, aliases));
|
|
16217
16353
|
} catch {
|
|
16218
16354
|
continue;
|
|
16219
16355
|
}
|
|
@@ -16234,16 +16370,16 @@ function recheckRootAliases(aliases) {
|
|
|
16234
16370
|
}
|
|
16235
16371
|
function nativeSourceDigest(path) {
|
|
16236
16372
|
assertSafePath(path);
|
|
16237
|
-
return
|
|
16373
|
+
return lstatSync20(path, { throwIfNoEntry: false }) ? sha3(readNativeBytes(path, 1024 * 1024)) : null;
|
|
16238
16374
|
}
|
|
16239
16375
|
function readNativeBytes(path, maximum = 64 * 1024 * 1024) {
|
|
16240
16376
|
assertSafePath(path);
|
|
16241
|
-
const before =
|
|
16377
|
+
const before = lstatSync20(path);
|
|
16242
16378
|
if (!before.isFile() || before.size > maximum)
|
|
16243
16379
|
throw new Error("Unsupported or oversized native skill file");
|
|
16244
|
-
const descriptor =
|
|
16380
|
+
const descriptor = openSync11(path, constants11.O_RDONLY | constants11.O_NOFOLLOW | constants11.O_NONBLOCK);
|
|
16245
16381
|
try {
|
|
16246
|
-
const opened =
|
|
16382
|
+
const opened = fstatSync11(descriptor);
|
|
16247
16383
|
if (!opened.isFile() || opened.dev !== before.dev || opened.ino !== before.ino || opened.size !== before.size)
|
|
16248
16384
|
throw new Error("Native skill file changed while reading");
|
|
16249
16385
|
const bytes = Buffer.allocUnsafe(before.size + 1);
|
|
@@ -16254,19 +16390,19 @@ function readNativeBytes(path, maximum = 64 * 1024 * 1024) {
|
|
|
16254
16390
|
break;
|
|
16255
16391
|
length += count;
|
|
16256
16392
|
}
|
|
16257
|
-
const after =
|
|
16393
|
+
const after = fstatSync11(descriptor), current = lstatSync20(path);
|
|
16258
16394
|
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
16395
|
throw new Error("Native skill file changed while reading");
|
|
16260
16396
|
return bytes.subarray(0, length);
|
|
16261
16397
|
} finally {
|
|
16262
|
-
|
|
16398
|
+
closeSync11(descriptor);
|
|
16263
16399
|
}
|
|
16264
16400
|
}
|
|
16265
16401
|
function treeHash(root) {
|
|
16266
|
-
const hash2 =
|
|
16402
|
+
const hash2 = createHash19("sha256");
|
|
16267
16403
|
let bytes = 0, files = 0;
|
|
16268
16404
|
function visit2(path) {
|
|
16269
|
-
const stat =
|
|
16405
|
+
const stat = lstatSync20(path);
|
|
16270
16406
|
if (stat.isSymbolicLink())
|
|
16271
16407
|
throw new Error(`Refusing symlink in skill: ${path}`);
|
|
16272
16408
|
const rel = relative6(root, path);
|
|
@@ -16295,13 +16431,13 @@ function selectNativeMigrationTargets(inventory, manifest) {
|
|
|
16295
16431
|
const identities = new Set;
|
|
16296
16432
|
const selected = [];
|
|
16297
16433
|
for (const target of manifest.targets) {
|
|
16298
|
-
if (!
|
|
16434
|
+
if (!isAbsolute14(target.projectRoot) || resolve13(target.projectRoot) !== target.projectRoot)
|
|
16299
16435
|
throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
|
|
16300
16436
|
const projectRoot = canonicalSystemPath(target.projectRoot), normalized = relative6(projectRoot, resolve13(projectRoot, target.path));
|
|
16301
|
-
if (!existsSync9(projectRoot) || !
|
|
16437
|
+
if (!existsSync9(projectRoot) || !lstatSync20(projectRoot).isDirectory())
|
|
16302
16438
|
throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
|
|
16303
16439
|
assertSafePath(projectRoot);
|
|
16304
|
-
if (
|
|
16440
|
+
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
16441
|
throw new Error(`Invalid native migration target: ${target.path}`);
|
|
16306
16442
|
const identity5 = `${target.agent}\x00${canonicalSystemPath(projectRoot)}\x00${normalized}`;
|
|
16307
16443
|
if (identities.has(identity5))
|
|
@@ -16344,9 +16480,9 @@ function isCodexSkillDiscoveryInput(path) {
|
|
|
16344
16480
|
}
|
|
16345
16481
|
function inventoryNativeSkills(home = homedir2(), options = {}) {
|
|
16346
16482
|
home = canonicalSystemPath(home);
|
|
16347
|
-
if (options.reviewedCacheAlias !== undefined && (!options.includeVendor || !
|
|
16483
|
+
if (options.reviewedCacheAlias !== undefined && (!options.includeVendor || !isAbsolute14(options.reviewedCacheAlias) || resolve13(options.reviewedCacheAlias) !== options.reviewedCacheAlias))
|
|
16348
16484
|
throw new Error("A reviewed cache alias requires vendor inventory and an exact absolute path");
|
|
16349
|
-
if (options.disabledVendorPaths?.some((path) => !
|
|
16485
|
+
if (options.disabledVendorPaths?.some((path) => !isAbsolute14(path) || resolve13(path) !== path))
|
|
16350
16486
|
throw new Error("Disabled vendor paths must be exact absolute paths");
|
|
16351
16487
|
const reviewedCacheAlias = options.reviewedCacheAlias === undefined ? undefined : canonicalSystemPath(options.reviewedCacheAlias);
|
|
16352
16488
|
const disabledVendorPaths = new Set((options.disabledVendorPaths ?? []).map(canonicalSystemPath));
|
|
@@ -16365,7 +16501,7 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
|
|
|
16365
16501
|
roots.push(["sumi", canonicalAgentPath(join23(project, directory, name), aliases)]);
|
|
16366
16502
|
}
|
|
16367
16503
|
const installationInputs = options.codexInstallationInputRoots ?? [];
|
|
16368
|
-
if (installationInputs.some((input) => resolve13(input) !== input ||
|
|
16504
|
+
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
16505
|
throw new Error("Native installation input overlaps an unconditional skill-loading root");
|
|
16370
16506
|
const entries = [], seen = new Set;
|
|
16371
16507
|
const cacheScans = new Map, maxAliasProofEntries = 1e4;
|
|
@@ -16379,13 +16515,13 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
|
|
|
16379
16515
|
}
|
|
16380
16516
|
let reviewedCacheAliasFound = false;
|
|
16381
16517
|
function verifiedSiblingCacheAlias(agent, path, parent) {
|
|
16382
|
-
const link =
|
|
16383
|
-
if (
|
|
16518
|
+
const link = readlinkSync6(path), lexicalTarget = resolve13(parent, link);
|
|
16519
|
+
if (isAbsolute14(link) ? link !== lexicalTarget : dirname14(link) !== ".")
|
|
16384
16520
|
return false;
|
|
16385
16521
|
const target = canonicalSystemPath(lexicalTarget);
|
|
16386
16522
|
if (dirname14(target) !== parent)
|
|
16387
16523
|
return false;
|
|
16388
|
-
if (!
|
|
16524
|
+
if (!lstatSync20(target, { throwIfNoEntry: false })?.isDirectory())
|
|
16389
16525
|
return false;
|
|
16390
16526
|
const scan = cacheScans.get(target);
|
|
16391
16527
|
if (!scan?.complete || scan.entries > maxAliasProofEntries)
|
|
@@ -16410,7 +16546,7 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
|
|
|
16410
16546
|
return scan;
|
|
16411
16547
|
if (!existsSync9(path))
|
|
16412
16548
|
return scan;
|
|
16413
|
-
const stat =
|
|
16549
|
+
const stat = lstatSync20(path);
|
|
16414
16550
|
if (stat.isFile()) {
|
|
16415
16551
|
if (agent === "sumi" && depth === 1 && path.endsWith(".md"))
|
|
16416
16552
|
throw new Error("NATIVE_SKILL_DRIFT: flat Sumi skill documents require a dedicated migration adapter");
|
|
@@ -16427,7 +16563,7 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
|
|
|
16427
16563
|
const marker = join23(path, ".hasna-skills.json");
|
|
16428
16564
|
if (existsSync9(marker)) {
|
|
16429
16565
|
try {
|
|
16430
|
-
managed = JSON.parse(
|
|
16566
|
+
managed = JSON.parse(readFileSync15(marker, "utf8")).managedBy === "@hasna/skills";
|
|
16431
16567
|
} catch {}
|
|
16432
16568
|
}
|
|
16433
16569
|
const bridge = (!vendor || agent === "sumi") && isOwnedCliBridge(path, bridgePaths);
|
|
@@ -16459,7 +16595,7 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
|
|
|
16459
16595
|
if (isVendor && !options.includeVendor)
|
|
16460
16596
|
continue;
|
|
16461
16597
|
const child = join23(path, name);
|
|
16462
|
-
if (isVendor &&
|
|
16598
|
+
if (isVendor && lstatSync20(child, { throwIfNoEntry: false })?.isSymbolicLink()) {
|
|
16463
16599
|
const target = statSync9(child, { throwIfNoEntry: false });
|
|
16464
16600
|
if (target?.isFile() || pluginCache && target?.isDirectory() && verifiedSiblingCacheAlias(agent, child, path)) {
|
|
16465
16601
|
scan.entries++;
|
|
@@ -16502,7 +16638,7 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
|
|
|
16502
16638
|
}
|
|
16503
16639
|
function readOptional(path) {
|
|
16504
16640
|
assertSafePath(path);
|
|
16505
|
-
return existsSync9(path) ?
|
|
16641
|
+
return existsSync9(path) ? readFileSync15(path, "utf8") : null;
|
|
16506
16642
|
}
|
|
16507
16643
|
function jsonObject(text2, path) {
|
|
16508
16644
|
if (text2 === null)
|
|
@@ -16834,23 +16970,23 @@ function projectedHookAcl(path, observed) {
|
|
|
16834
16970
|
if (process.platform !== "darwin")
|
|
16835
16971
|
return;
|
|
16836
16972
|
const identity5 = (stat) => `${stat.dev}:${stat.ino}:${stat.ctimeNs}:${stat.uid}:${stat.mode}:${stat.nlink}:${stat.size}:${stat.mtimeNs}`;
|
|
16837
|
-
const fd =
|
|
16973
|
+
const fd = openSync11(path, constants11.O_RDONLY | constants11.O_NOFOLLOW | constants11.O_NONBLOCK | (observed.isDirectory() ? constants11.O_DIRECTORY : 0));
|
|
16838
16974
|
try {
|
|
16839
|
-
if (identity5(
|
|
16975
|
+
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
16976
|
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
16841
16977
|
} finally {
|
|
16842
|
-
|
|
16978
|
+
closeSync11(fd);
|
|
16843
16979
|
}
|
|
16844
16980
|
}
|
|
16845
16981
|
function projectedHookExecutable(command, expectedResolved) {
|
|
16846
16982
|
try {
|
|
16847
|
-
if (!
|
|
16983
|
+
if (!isAbsolute14(command) || /[\0\r\n]/.test(command) || resolve13(command) !== command)
|
|
16848
16984
|
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
16849
16985
|
command = canonicalSystemPath(command);
|
|
16850
16986
|
const parents2 = (file = command) => {
|
|
16851
16987
|
const result = [];
|
|
16852
16988
|
for (let path = dirname14(file);; path = dirname14(path)) {
|
|
16853
|
-
const stat =
|
|
16989
|
+
const stat = lstatSync20(path, { bigint: true });
|
|
16854
16990
|
if (!stat.isDirectory() || (stat.mode & 0o022n) !== 0n && !(stat.uid === 0n && (stat.mode & 0o1000n) !== 0n))
|
|
16855
16991
|
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
16856
16992
|
projectedHookAcl(path, stat);
|
|
@@ -16860,13 +16996,22 @@ function projectedHookExecutable(command, expectedResolved) {
|
|
|
16860
16996
|
}
|
|
16861
16997
|
return result;
|
|
16862
16998
|
};
|
|
16863
|
-
const parentIdentity = parents2(), link =
|
|
16999
|
+
const parentIdentity = parents2(), link = lstatSync20(command, { bigint: true });
|
|
16864
17000
|
if (link.uid !== BigInt(process.getuid()) || !link.isFile() && !link.isSymbolicLink())
|
|
16865
17001
|
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
16866
17002
|
const linkIdentity = (stat) => `${stat.dev}:${stat.ino}:${stat.mode}:${stat.uid}:${stat.ctimeNs}`;
|
|
16867
|
-
const
|
|
17003
|
+
const target = resolveLauncherCommand(command), resolved = target.entry;
|
|
16868
17004
|
if (expectedResolved !== undefined && resolved !== expectedResolved)
|
|
16869
17005
|
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
17006
|
+
let launcher, launcherParentIdentity;
|
|
17007
|
+
if (target.pinned) {
|
|
17008
|
+
launcherParentIdentity = parents2(target.physical);
|
|
17009
|
+
launcher = snapshot(target.physical, false);
|
|
17010
|
+
projectedHookAcl(launcher.file, launcher.stat);
|
|
17011
|
+
if (launcher.sha256 !== target.pinned.sha256 || (launcher.stat.mode & 0o100n) === 0n)
|
|
17012
|
+
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
17013
|
+
assertPinnedLauncherRuntimeSafe(target.pinned.runtime);
|
|
17014
|
+
}
|
|
16870
17015
|
const resolvedParentIdentity = parents2(resolved);
|
|
16871
17016
|
const manifest = snapshot(join23(dirname14(dirname14(resolved)), "package.json"), false, { readOnlyPackage: true });
|
|
16872
17017
|
projectedHookAcl(manifest.file, manifest.stat);
|
|
@@ -16879,8 +17024,15 @@ function projectedHookExecutable(command, expectedResolved) {
|
|
|
16879
17024
|
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
16880
17025
|
const recheck = () => {
|
|
16881
17026
|
try {
|
|
16882
|
-
|
|
17027
|
+
const again = resolveLauncherCommand(command);
|
|
17028
|
+
if (again.entry !== resolved || again.physical !== target.physical || linkIdentity(lstatSync20(command, { bigint: true })) !== linkIdentity(link) || !isDeepStrictEqual6(parents2(), parentIdentity) || !isDeepStrictEqual6(parents2(resolved), resolvedParentIdentity))
|
|
16883
17029
|
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
17030
|
+
if (launcher) {
|
|
17031
|
+
if (!isDeepStrictEqual6(parents2(target.physical), launcherParentIdentity))
|
|
17032
|
+
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
17033
|
+
projectedHookAcl(launcher.file, launcher.stat);
|
|
17034
|
+
unchanged2(launcher);
|
|
17035
|
+
}
|
|
16884
17036
|
projectedHookAcl(cli.file, cli.stat);
|
|
16885
17037
|
projectedHookAcl(manifest.file, manifest.stat);
|
|
16886
17038
|
unchanged2(cli);
|
|
@@ -17002,7 +17154,7 @@ function claudeSettingsConsumers(home, path, discoveries, aliases) {
|
|
|
17002
17154
|
const canonical6 = (value) => canonicalAgentPath(value, aliases);
|
|
17003
17155
|
const containsSettings = (root) => {
|
|
17004
17156
|
const distance = relative6(canonical6(root), path);
|
|
17005
|
-
return distance === "" || distance !== ".." && !distance.startsWith(`..${sep7}`) && !
|
|
17157
|
+
return distance === "" || distance !== ".." && !distance.startsWith(`..${sep7}`) && !isAbsolute14(distance);
|
|
17006
17158
|
};
|
|
17007
17159
|
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
17160
|
}
|
|
@@ -17035,7 +17187,7 @@ function planClaudeHookEventsUpdate(options) {
|
|
|
17035
17187
|
recheckRootAliases(aliases);
|
|
17036
17188
|
const path = canonicalAgentPath(join23(home, ".claude", "settings.json"), aliases);
|
|
17037
17189
|
assertSafePath(path);
|
|
17038
|
-
const before =
|
|
17190
|
+
const before = lstatSync20(path, { throwIfNoEntry: false }) ? new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(readNativeBytes(path, 1024 * 1024)) : null;
|
|
17039
17191
|
if ((before === null ? "absent" : sha3(before)) !== options.expectedSettingsSha256)
|
|
17040
17192
|
throw new Error("Claude settings preimage changed");
|
|
17041
17193
|
assertClaudeHookEventsReplacement(before, options.replacement, options.events);
|
|
@@ -17226,7 +17378,7 @@ function applyAgentIntegrationUnlocked(plan, options = {}, assertCurrent) {
|
|
|
17226
17378
|
if (change.before !== null) {
|
|
17227
17379
|
const backup = join23(backupRoot, `${index}-${sha3(change.path).slice(0, 12)}.backup`);
|
|
17228
17380
|
writeFileSync6(backup, change.before, { mode: 384, flag: "wx" });
|
|
17229
|
-
if (
|
|
17381
|
+
if (readFileSync15(backup, "utf8") !== change.before)
|
|
17230
17382
|
throw new Error("Native configuration preservation readback failed");
|
|
17231
17383
|
backups.push(backup);
|
|
17232
17384
|
}
|
|
@@ -17289,11 +17441,11 @@ function applyAgentIntegrationUnlocked(plan, options = {}, assertCurrent) {
|
|
|
17289
17441
|
}
|
|
17290
17442
|
function syncArchiveDirectory(path) {
|
|
17291
17443
|
assertSafePath(path);
|
|
17292
|
-
const descriptor =
|
|
17444
|
+
const descriptor = openSync11(path, constants11.O_RDONLY | constants11.O_DIRECTORY | constants11.O_NOFOLLOW | constants11.O_NONBLOCK);
|
|
17293
17445
|
try {
|
|
17294
|
-
|
|
17446
|
+
fsyncSync5(descriptor);
|
|
17295
17447
|
} finally {
|
|
17296
|
-
|
|
17448
|
+
closeSync11(descriptor);
|
|
17297
17449
|
}
|
|
17298
17450
|
}
|
|
17299
17451
|
function writeArchiveJournal(path, value) {
|
|
@@ -17301,18 +17453,18 @@ function writeArchiveJournal(path, value) {
|
|
|
17301
17453
|
const temporary = `${path}.skills-${randomUUID3()}`;
|
|
17302
17454
|
let descriptor;
|
|
17303
17455
|
try {
|
|
17304
|
-
descriptor =
|
|
17456
|
+
descriptor = openSync11(temporary, constants11.O_WRONLY | constants11.O_CREAT | constants11.O_EXCL | constants11.O_NOFOLLOW, 384);
|
|
17305
17457
|
writeFileSync6(descriptor, `${JSON.stringify(value)}
|
|
17306
17458
|
`);
|
|
17307
|
-
|
|
17308
|
-
|
|
17459
|
+
fsyncSync5(descriptor);
|
|
17460
|
+
closeSync11(descriptor);
|
|
17309
17461
|
descriptor = undefined;
|
|
17310
17462
|
renameSync3(temporary, path);
|
|
17311
17463
|
syncArchiveDirectory(dirname14(path));
|
|
17312
17464
|
} finally {
|
|
17313
17465
|
if (descriptor !== undefined)
|
|
17314
|
-
|
|
17315
|
-
if (
|
|
17466
|
+
closeSync11(descriptor);
|
|
17467
|
+
if (lstatSync20(temporary, { throwIfNoEntry: false }))
|
|
17316
17468
|
unlinkSync4(temporary);
|
|
17317
17469
|
}
|
|
17318
17470
|
}
|
|
@@ -17358,7 +17510,7 @@ function archiveNativeSkillsUnlocked(inventory, options, assertCurrent) {
|
|
|
17358
17510
|
const moved = [];
|
|
17359
17511
|
const verifyArchive = (entry) => {
|
|
17360
17512
|
assertSafePath(entry.archive);
|
|
17361
|
-
const stat =
|
|
17513
|
+
const stat = lstatSync20(entry.archive);
|
|
17362
17514
|
if (entry.discoveryOnly ? !stat.isFile() : !stat.isDirectory())
|
|
17363
17515
|
throw new Error("Archive type changed");
|
|
17364
17516
|
if ((entry.discoveryOnly ? sha3(readNativeBytes(entry.archive)) : treeHash(entry.archive)) !== entry.hash)
|
|
@@ -17409,7 +17561,7 @@ function archiveNativeSkillsUnlocked(inventory, options, assertCurrent) {
|
|
|
17409
17561
|
recheckRootAliases(aliases);
|
|
17410
17562
|
assertSafePath(entry.source);
|
|
17411
17563
|
assertSafePath(entry.archive);
|
|
17412
|
-
if (
|
|
17564
|
+
if (lstatSync20(entry.source, { throwIfNoEntry: false })) {
|
|
17413
17565
|
entry.status = "recovery-required";
|
|
17414
17566
|
entry.conflict = "source-occupied";
|
|
17415
17567
|
continue;
|
|
@@ -17426,7 +17578,7 @@ function archiveNativeSkillsUnlocked(inventory, options, assertCurrent) {
|
|
|
17426
17578
|
syncArchiveDirectory(dirname14(entry.source));
|
|
17427
17579
|
unlinkSync4(entry.archive);
|
|
17428
17580
|
} else {
|
|
17429
|
-
if (
|
|
17581
|
+
if (lstatSync20(entry.source, { throwIfNoEntry: false })) {
|
|
17430
17582
|
entry.status = "recovery-required";
|
|
17431
17583
|
entry.conflict = "source-occupied";
|
|
17432
17584
|
continue;
|
|
@@ -17459,12 +17611,12 @@ function isInertCodexPluginCacheCopy(entry, cache, allowedHostPaths, read2) {
|
|
|
17459
17611
|
return false;
|
|
17460
17612
|
const document2 = join23(entry.path, "SKILL.md");
|
|
17461
17613
|
const inside = relative6(cache, entry.path);
|
|
17462
|
-
if (!inside ||
|
|
17614
|
+
if (!inside || isAbsolute14(inside) || inside.split(sep7).some((segment) => segment === ".."))
|
|
17463
17615
|
return false;
|
|
17464
17616
|
assertSafePath(entry.path);
|
|
17465
|
-
if (!
|
|
17617
|
+
if (!lstatSync20(cache).isDirectory() || !lstatSync20(entry.path).isDirectory() || !lstatSync20(document2).isFile())
|
|
17466
17618
|
return false;
|
|
17467
|
-
if (
|
|
17619
|
+
if (realpathSync10.native(cache) !== cache || realpathSync10.native(entry.path) !== entry.path || realpathSync10.native(document2) !== document2)
|
|
17468
17620
|
return false;
|
|
17469
17621
|
if (!classifyCodexPluginCacheDocument(document2, cache, read2))
|
|
17470
17622
|
return false;
|
|
@@ -17641,9 +17793,9 @@ function isSkillsOwnershipMarker(marker) {
|
|
|
17641
17793
|
function hasSkillsOwnershipMarker(dir) {
|
|
17642
17794
|
const path = join25(dir, SYNC_MARKER_FILE);
|
|
17643
17795
|
try {
|
|
17644
|
-
if (!
|
|
17796
|
+
if (!lstatSync21(path).isFile())
|
|
17645
17797
|
return false;
|
|
17646
|
-
const marker = JSON.parse(
|
|
17798
|
+
const marker = JSON.parse(readFileSync16(path, "utf8"));
|
|
17647
17799
|
return isSkillsOwnershipMarker(marker);
|
|
17648
17800
|
} catch {
|
|
17649
17801
|
return false;
|
|
@@ -17860,7 +18012,7 @@ function writeManagedSkillDirUnlocked(dir, skillMd, options, assertCurrent) {
|
|
|
17860
18012
|
if (dirExists && managed && hasSkillMd && !options.force && isPointerSkillMd(skillMd)) {
|
|
17861
18013
|
let existingIsStub = false;
|
|
17862
18014
|
try {
|
|
17863
|
-
existingIsStub = isPointerSkillMd(
|
|
18015
|
+
existingIsStub = isPointerSkillMd(readFileSync16(skillMdPath, "utf-8"));
|
|
17864
18016
|
} catch {
|
|
17865
18017
|
existingIsStub = false;
|
|
17866
18018
|
}
|
|
@@ -17910,7 +18062,7 @@ function writeManagedSkillDirUnlocked(dir, skillMd, options, assertCurrent) {
|
|
|
17910
18062
|
assertCurrent();
|
|
17911
18063
|
renameDirectory(candidateDir, dir);
|
|
17912
18064
|
assertCurrent();
|
|
17913
|
-
if (
|
|
18065
|
+
if (readFileSync16(skillMdPath, "utf8") !== (skillMd.endsWith(`
|
|
17914
18066
|
`) ? skillMd : `${skillMd}
|
|
17915
18067
|
`))
|
|
17916
18068
|
throw new Error("Managed skill readback failed");
|
|
@@ -17954,7 +18106,7 @@ function sourceSkillMd(skillPath, name, description, kind, preferBundledDocs = f
|
|
|
17954
18106
|
if (kind === undefined || kind === "instruction" || preferBundledDocs) {
|
|
17955
18107
|
const skillMdPath = join25(skillPath, "SKILL.md");
|
|
17956
18108
|
if (existsSync10(skillMdPath))
|
|
17957
|
-
return
|
|
18109
|
+
return readFileSync16(skillMdPath, "utf-8");
|
|
17958
18110
|
}
|
|
17959
18111
|
return pointerSkillMd(name, description);
|
|
17960
18112
|
}
|
|
@@ -17994,7 +18146,7 @@ function resolveSkillAlias(name) {
|
|
|
17994
18146
|
}
|
|
17995
18147
|
|
|
17996
18148
|
// src/lib/project-state.ts
|
|
17997
|
-
import { existsSync as existsSync11, mkdirSync as mkdirSync8, readFileSync as
|
|
18149
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync8, readFileSync as readFileSync17, writeFileSync as writeFileSync8 } from "fs";
|
|
17998
18150
|
import { join as join26 } from "path";
|
|
17999
18151
|
var VALID_PIN_SOURCES = [
|
|
18000
18152
|
"official",
|
|
@@ -18020,7 +18172,7 @@ function loadProjectConfig(targetDir = process.cwd()) {
|
|
|
18020
18172
|
if (!existsSync11(path))
|
|
18021
18173
|
return null;
|
|
18022
18174
|
try {
|
|
18023
|
-
return normalizeProjectConfig(JSON.parse(
|
|
18175
|
+
return normalizeProjectConfig(JSON.parse(readFileSync17(path, "utf-8")));
|
|
18024
18176
|
} catch {
|
|
18025
18177
|
return null;
|
|
18026
18178
|
}
|
|
@@ -18207,7 +18359,7 @@ function createLocalSkillManifest(name, generateSkillMd) {
|
|
|
18207
18359
|
let skillMd = "";
|
|
18208
18360
|
const skillMdPath = join27(sourcePath, "SKILL.md");
|
|
18209
18361
|
if (existsSync12(skillMdPath)) {
|
|
18210
|
-
skillMd =
|
|
18362
|
+
skillMd = readFileSync18(skillMdPath, "utf-8");
|
|
18211
18363
|
} else if (generateSkillMd) {
|
|
18212
18364
|
skillMd = generateSkillMd(name) ?? "";
|
|
18213
18365
|
} else {
|
|
@@ -18333,7 +18485,7 @@ function resolveAgentSkillMd(name, generateSkillMd) {
|
|
|
18333
18485
|
const sourcePath = getSkillPath(name);
|
|
18334
18486
|
const skillMdPath = join27(sourcePath, "SKILL.md");
|
|
18335
18487
|
if (existsSync12(skillMdPath))
|
|
18336
|
-
return
|
|
18488
|
+
return readFileSync18(skillMdPath, "utf-8");
|
|
18337
18489
|
if (generateSkillMd)
|
|
18338
18490
|
return generateSkillMd(name);
|
|
18339
18491
|
return generateMinimalSkillMd(name);
|
|
@@ -18389,14 +18541,14 @@ function readBundledSkillVersion(name) {
|
|
|
18389
18541
|
if (!existsSync12(pkgPath))
|
|
18390
18542
|
return "unknown";
|
|
18391
18543
|
try {
|
|
18392
|
-
const pkg = JSON.parse(
|
|
18544
|
+
const pkg = JSON.parse(readFileSync18(pkgPath, "utf-8"));
|
|
18393
18545
|
return pkg.version || "unknown";
|
|
18394
18546
|
} catch {
|
|
18395
18547
|
return "unknown";
|
|
18396
18548
|
}
|
|
18397
18549
|
}
|
|
18398
18550
|
function readFileIfExists(path) {
|
|
18399
|
-
return existsSync12(path) ?
|
|
18551
|
+
return existsSync12(path) ? readFileSync18(path, "utf-8") : null;
|
|
18400
18552
|
}
|
|
18401
18553
|
function loadProjectConfigCompat(targetDir) {
|
|
18402
18554
|
return loadProjectConfig(targetDir);
|
|
@@ -18444,7 +18596,7 @@ function isInstructionSkillDir(skillPath, meta) {
|
|
|
18444
18596
|
if (!existsSync13(skillMdPath))
|
|
18445
18597
|
return false;
|
|
18446
18598
|
try {
|
|
18447
|
-
return parseSkillFrontmatter(
|
|
18599
|
+
return parseSkillFrontmatter(readFileSync19(skillMdPath, "utf-8"))?.kind === "instruction";
|
|
18448
18600
|
} catch {
|
|
18449
18601
|
return false;
|
|
18450
18602
|
}
|
|
@@ -18495,7 +18647,7 @@ function getSkillRequirements(name) {
|
|
|
18495
18647
|
const meta = getSkill(name);
|
|
18496
18648
|
let dependencies = {};
|
|
18497
18649
|
try {
|
|
18498
|
-
dependencies = JSON.parse(
|
|
18650
|
+
dependencies = JSON.parse(readFileSync19(join28(skillPath, "package.json"), "utf8")).dependencies || {};
|
|
18499
18651
|
} catch {}
|
|
18500
18652
|
return getSkillRequirementsFromContent(name, texts, dependencies, meta);
|
|
18501
18653
|
}
|
|
@@ -18563,7 +18715,7 @@ async function runSkill(name, args, options = {}) {
|
|
|
18563
18715
|
}
|
|
18564
18716
|
let entryPoint2;
|
|
18565
18717
|
try {
|
|
18566
|
-
const pkg = JSON.parse(
|
|
18718
|
+
const pkg = JSON.parse(readFileSync19(pkgPath, "utf-8"));
|
|
18567
18719
|
if (pkg.bin) {
|
|
18568
18720
|
const binValues = Object.values(pkg.bin);
|
|
18569
18721
|
entryPoint2 = binValues[0];
|
|
@@ -18666,7 +18818,7 @@ function generateSkillMd(name) {
|
|
|
18666
18818
|
const pkgPath = join28(skillPath, "package.json");
|
|
18667
18819
|
if (existsSync13(pkgPath)) {
|
|
18668
18820
|
try {
|
|
18669
|
-
const pkg = JSON.parse(
|
|
18821
|
+
const pkg = JSON.parse(readFileSync19(pkgPath, "utf-8"));
|
|
18670
18822
|
if (pkg.bin) {
|
|
18671
18823
|
const binKeys = Object.keys(pkg.bin);
|
|
18672
18824
|
if (binKeys.length > 0)
|
|
@@ -18742,7 +18894,7 @@ function extractEnvVars(text2) {
|
|
|
18742
18894
|
function readIfExists(path) {
|
|
18743
18895
|
try {
|
|
18744
18896
|
if (existsSync13(path)) {
|
|
18745
|
-
return
|
|
18897
|
+
return readFileSync19(path, "utf-8");
|
|
18746
18898
|
}
|
|
18747
18899
|
} catch {}
|
|
18748
18900
|
return null;
|
|
@@ -18869,7 +19021,7 @@ function exactProfileSelection(spec, profile) {
|
|
|
18869
19021
|
}
|
|
18870
19022
|
|
|
18871
19023
|
// src/lib/plugin-projection.ts
|
|
18872
|
-
import { createHash as
|
|
19024
|
+
import { createHash as createHash20 } from "crypto";
|
|
18873
19025
|
import { posix } from "path";
|
|
18874
19026
|
var PLUGIN_PROJECTION_MANIFEST = "plugin-projection.json";
|
|
18875
19027
|
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 +19032,7 @@ function pluginNeed(value, message) {
|
|
|
18880
19032
|
if (!value)
|
|
18881
19033
|
pluginRefusal(message);
|
|
18882
19034
|
}
|
|
18883
|
-
var pluginHash = (bytes) =>
|
|
19035
|
+
var pluginHash = (bytes) => createHash20("sha256").update(bytes).digest("hex");
|
|
18884
19036
|
function pluginObject(value) {
|
|
18885
19037
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
18886
19038
|
}
|
|
@@ -19068,16 +19220,16 @@ function buildPluginProjection(entries) {
|
|
|
19068
19220
|
}
|
|
19069
19221
|
|
|
19070
19222
|
// 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 =
|
|
19223
|
+
import { createHash as createHash21, randomUUID as randomUUID4 } from "crypto";
|
|
19224
|
+
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";
|
|
19225
|
+
import { dirname as dirname16, isAbsolute as isAbsolute15, join as join29, parse as parse6, resolve as resolve14 } from "path";
|
|
19226
|
+
var READ_FLAGS = constants12.O_RDONLY | constants12.O_NOFOLLOW | constants12.O_NONBLOCK;
|
|
19227
|
+
var WRITE_FLAGS = constants12.O_WRONLY | constants12.O_CREAT | constants12.O_EXCL | constants12.O_NOFOLLOW | constants12.O_NONBLOCK;
|
|
19076
19228
|
var uid = () => typeof process.getuid === "function" ? BigInt(process.getuid()) : undefined;
|
|
19077
19229
|
var missing = (error) => Boolean(error && typeof error === "object" && "code" in error && error.code === "ENOENT");
|
|
19078
19230
|
function stat(path) {
|
|
19079
19231
|
try {
|
|
19080
|
-
return
|
|
19232
|
+
return lstatSync22(path, { bigint: true });
|
|
19081
19233
|
} catch (error) {
|
|
19082
19234
|
if (missing(error))
|
|
19083
19235
|
return null;
|
|
@@ -19085,7 +19237,7 @@ function stat(path) {
|
|
|
19085
19237
|
}
|
|
19086
19238
|
}
|
|
19087
19239
|
function canonical6(path) {
|
|
19088
|
-
pluginNeed(typeof path === "string" && path.length <= 8192 &&
|
|
19240
|
+
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
19241
|
}
|
|
19090
19242
|
function owner(stats, system = false) {
|
|
19091
19243
|
const current = uid();
|
|
@@ -19153,8 +19305,8 @@ function readBytes(path, maximum, kind) {
|
|
|
19153
19305
|
fileShape(before, maximum, kind);
|
|
19154
19306
|
let fd;
|
|
19155
19307
|
try {
|
|
19156
|
-
fd =
|
|
19157
|
-
const opened =
|
|
19308
|
+
fd = openSync12(path, READ_FLAGS);
|
|
19309
|
+
const opened = fstatSync12(fd, { bigint: true });
|
|
19158
19310
|
same3(before, opened);
|
|
19159
19311
|
fileShape(opened, maximum, kind);
|
|
19160
19312
|
const bytes = new Uint8Array(Number(opened.size));
|
|
@@ -19165,7 +19317,7 @@ function readBytes(path, maximum, kind) {
|
|
|
19165
19317
|
offset += count;
|
|
19166
19318
|
}
|
|
19167
19319
|
pluginNeed(readSync9(fd, new Uint8Array(1), 0, 1, null) === 0, "Plugin file grew while being read");
|
|
19168
|
-
same3(opened,
|
|
19320
|
+
same3(opened, fstatSync12(fd, { bigint: true }));
|
|
19169
19321
|
same3(opened, stat(path));
|
|
19170
19322
|
verifyAncestors(chain);
|
|
19171
19323
|
return bytes;
|
|
@@ -19175,7 +19327,7 @@ function readBytes(path, maximum, kind) {
|
|
|
19175
19327
|
return pluginRefusal("Cannot safely read plugin file");
|
|
19176
19328
|
} finally {
|
|
19177
19329
|
if (fd !== undefined)
|
|
19178
|
-
|
|
19330
|
+
closeSync12(fd);
|
|
19179
19331
|
}
|
|
19180
19332
|
}
|
|
19181
19333
|
function exactPaths(entries) {
|
|
@@ -19285,16 +19437,16 @@ function verifyPluginTree(root, witnesses) {
|
|
|
19285
19437
|
function writeExclusive(path, bytes, mode) {
|
|
19286
19438
|
let fd, created;
|
|
19287
19439
|
try {
|
|
19288
|
-
fd =
|
|
19289
|
-
|
|
19290
|
-
created =
|
|
19440
|
+
fd = openSync12(path, WRITE_FLAGS, mode);
|
|
19441
|
+
fchmodSync2(fd, mode);
|
|
19442
|
+
created = fstatSync12(fd, { bigint: true });
|
|
19291
19443
|
let offset = 0;
|
|
19292
19444
|
while (offset < bytes.byteLength) {
|
|
19293
|
-
const count =
|
|
19445
|
+
const count = writeSync3(fd, bytes, offset, bytes.byteLength - offset);
|
|
19294
19446
|
pluginNeed(count > 0, "Plugin file write did not progress");
|
|
19295
19447
|
offset += count;
|
|
19296
19448
|
}
|
|
19297
|
-
|
|
19449
|
+
fsyncSync6(fd);
|
|
19298
19450
|
} catch (error) {
|
|
19299
19451
|
if (created) {
|
|
19300
19452
|
same3(created, stat(path), true);
|
|
@@ -19303,7 +19455,7 @@ function writeExclusive(path, bytes, mode) {
|
|
|
19303
19455
|
throw error;
|
|
19304
19456
|
} finally {
|
|
19305
19457
|
if (fd !== undefined)
|
|
19306
|
-
|
|
19458
|
+
closeSync12(fd);
|
|
19307
19459
|
}
|
|
19308
19460
|
}
|
|
19309
19461
|
function materializePluginTree(root, entries) {
|
|
@@ -19406,11 +19558,11 @@ function pluginExecutableDigest(path) {
|
|
|
19406
19558
|
fileShape(before, maximum, "executable");
|
|
19407
19559
|
let fd;
|
|
19408
19560
|
try {
|
|
19409
|
-
fd =
|
|
19410
|
-
const opened =
|
|
19561
|
+
fd = openSync12(path, READ_FLAGS);
|
|
19562
|
+
const opened = fstatSync12(fd, { bigint: true });
|
|
19411
19563
|
same3(before, opened);
|
|
19412
19564
|
fileShape(opened, maximum, "executable");
|
|
19413
|
-
const hash2 =
|
|
19565
|
+
const hash2 = createHash21("sha256"), buffer = new Uint8Array(64 * 1024);
|
|
19414
19566
|
let remaining = Number(opened.size);
|
|
19415
19567
|
while (remaining > 0) {
|
|
19416
19568
|
const count = readSync9(fd, buffer, 0, Math.min(buffer.byteLength, remaining), null);
|
|
@@ -19419,7 +19571,7 @@ function pluginExecutableDigest(path) {
|
|
|
19419
19571
|
remaining -= count;
|
|
19420
19572
|
}
|
|
19421
19573
|
pluginNeed(readSync9(fd, buffer, 0, 1, null) === 0, "Plugin executable grew during hashing");
|
|
19422
|
-
same3(opened,
|
|
19574
|
+
same3(opened, fstatSync12(fd, { bigint: true }));
|
|
19423
19575
|
same3(opened, stat(path));
|
|
19424
19576
|
verifyAncestors(chain);
|
|
19425
19577
|
return `sha256:${hash2.digest("hex")}`;
|
|
@@ -19429,7 +19581,7 @@ function pluginExecutableDigest(path) {
|
|
|
19429
19581
|
return pluginRefusal("Cannot safely hash plugin executable");
|
|
19430
19582
|
} finally {
|
|
19431
19583
|
if (fd !== undefined)
|
|
19432
|
-
|
|
19584
|
+
closeSync12(fd);
|
|
19433
19585
|
}
|
|
19434
19586
|
}
|
|
19435
19587
|
|
|
@@ -19468,7 +19620,7 @@ function validatePluginTarget(value) {
|
|
|
19468
19620
|
for (const registration of value.registrations) {
|
|
19469
19621
|
pluginKeys(registration, ["scope", "projectPath"]);
|
|
19470
19622
|
pluginNeed(registration.scope === "user" || registration.scope === "project", "Unsupported plugin registration scope");
|
|
19471
|
-
pluginNeed(registration.scope === "user" ? registration.projectPath === null : typeof registration.projectPath === "string" &&
|
|
19623
|
+
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
19624
|
const key = JSON.stringify([registration.scope, registration.projectPath]);
|
|
19473
19625
|
pluginNeed(!scopes.has(key), "Duplicate plugin registration scope");
|
|
19474
19626
|
scopes.add(key);
|
|
@@ -19476,7 +19628,7 @@ function validatePluginTarget(value) {
|
|
|
19476
19628
|
for (const key of ["native", "resolver"]) {
|
|
19477
19629
|
pluginKeys(value[key], key === "native" ? ["version", "executable", "digest"] : ["executable", "digest"]);
|
|
19478
19630
|
pluginText(value[key].executable);
|
|
19479
|
-
pluginNeed(
|
|
19631
|
+
pluginNeed(isAbsolute16(value[key].executable) && resolve15(value[key].executable) === value[key].executable, "Plugin executable must have a canonical absolute path");
|
|
19480
19632
|
pluginDigest(value[key].digest);
|
|
19481
19633
|
}
|
|
19482
19634
|
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 +19780,7 @@ function pluginResolverCommand(binding) {
|
|
|
19628
19780
|
}
|
|
19629
19781
|
function root(options) {
|
|
19630
19782
|
const path = options.storeRoot ?? pluginAdmissionRoot();
|
|
19631
|
-
pluginNeed(
|
|
19783
|
+
pluginNeed(isAbsolute16(path) && resolve15(path) === path, "Invalid plugin admission store root");
|
|
19632
19784
|
return path;
|
|
19633
19785
|
}
|
|
19634
19786
|
function pluginBindingPath(storeRoot, id) {
|
|
@@ -19833,25 +19985,25 @@ function validateManagedPluginWitnesses(value) {
|
|
|
19833
19985
|
pluginNeed(typeof item.bindingId === "string" && /^[a-f0-9]{64}$/.test(item.bindingId) && !seen.has(item.bindingId), "Invalid or duplicate managed plugin witness");
|
|
19834
19986
|
seen.add(item.bindingId);
|
|
19835
19987
|
pluginText(item.storeRoot);
|
|
19836
|
-
pluginNeed(
|
|
19988
|
+
pluginNeed(isAbsolute17(item.storeRoot) && resolve16(item.storeRoot) === item.storeRoot, "Invalid plugin receipt store path");
|
|
19837
19989
|
}
|
|
19838
19990
|
}
|
|
19839
19991
|
function safe3(path) {
|
|
19840
19992
|
pluginText(path);
|
|
19841
|
-
pluginNeed(
|
|
19993
|
+
pluginNeed(isAbsolute17(path) && resolve16(path) === path, "Invalid plugin registry path");
|
|
19842
19994
|
for (let at = path;; at = dirname17(at)) {
|
|
19843
|
-
pluginNeed(!
|
|
19995
|
+
pluginNeed(!lstatSync23(at, { throwIfNoEntry: false })?.isSymbolicLink(), "Plugin registry path traverses a symlink");
|
|
19844
19996
|
if (at === dirname17(at))
|
|
19845
19997
|
break;
|
|
19846
19998
|
}
|
|
19847
19999
|
}
|
|
19848
20000
|
function readRegistry(path) {
|
|
19849
20001
|
safe3(path);
|
|
19850
|
-
const initial =
|
|
20002
|
+
const initial = lstatSync23(path);
|
|
19851
20003
|
pluginNeed(initial.isFile() && initial.size <= 1024 * 1024, "Plugin registry is not a bounded regular file");
|
|
19852
|
-
const fd =
|
|
20004
|
+
const fd = openSync13(path, constants13.O_RDONLY | constants13.O_NOFOLLOW | constants13.O_NONBLOCK);
|
|
19853
20005
|
try {
|
|
19854
|
-
const opened =
|
|
20006
|
+
const opened = fstatSync13(fd);
|
|
19855
20007
|
pluginNeed(opened.isFile() && opened.ino === initial.ino && opened.dev === initial.dev, "Plugin registry changed during open");
|
|
19856
20008
|
const bytes = Buffer.alloc(1024 * 1024 + 1);
|
|
19857
20009
|
let length = 0;
|
|
@@ -19861,7 +20013,7 @@ function readRegistry(path) {
|
|
|
19861
20013
|
break;
|
|
19862
20014
|
length += count;
|
|
19863
20015
|
}
|
|
19864
|
-
const after =
|
|
20016
|
+
const after = fstatSync13(fd), current = lstatSync23(path);
|
|
19865
20017
|
safe3(path);
|
|
19866
20018
|
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
20019
|
let value;
|
|
@@ -19873,7 +20025,7 @@ function readRegistry(path) {
|
|
|
19873
20025
|
pluginNeed(pluginObject(value) && value.version === 2 && pluginObject(value.plugins), "Unsupported native plugin registry schema");
|
|
19874
20026
|
return { value, rawDigest: pluginHash(bytes.subarray(0, length)) };
|
|
19875
20027
|
} finally {
|
|
19876
|
-
|
|
20028
|
+
closeSync13(fd);
|
|
19877
20029
|
}
|
|
19878
20030
|
}
|
|
19879
20031
|
function nativeVersionMatches(version, receipt) {
|
|
@@ -19934,7 +20086,7 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
19934
20086
|
return Object.fromEntries(Object.entries(row).filter(([key]) => !["version", "installPath", "sourceProducerPath", "previousProducerPaths", "lastUpdated"].includes(key)));
|
|
19935
20087
|
});
|
|
19936
20088
|
safe3(cacheRoot);
|
|
19937
|
-
const before =
|
|
20089
|
+
const before = lstatSync23(cacheRoot);
|
|
19938
20090
|
pluginNeed(before.isDirectory(), "Invalid managed plugin cache root");
|
|
19939
20091
|
const directory = opendirSync5(cacheRoot), names = [];
|
|
19940
20092
|
try {
|
|
@@ -19957,7 +20109,7 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
19957
20109
|
}
|
|
19958
20110
|
for (const row of rows)
|
|
19959
20111
|
pluginNeed(names.includes(row.version), "Managed native plugin installation is missing");
|
|
19960
|
-
const after =
|
|
20112
|
+
const after = lstatSync23(cacheRoot);
|
|
19961
20113
|
safe3(cacheRoot);
|
|
19962
20114
|
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
20115
|
}
|
|
@@ -19969,22 +20121,22 @@ function captureManagedPluginRegistry(path, managedPlugins) {
|
|
|
19969
20121
|
}
|
|
19970
20122
|
|
|
19971
20123
|
// src/lib/claude-marketplace-registry.ts
|
|
19972
|
-
import { createHash as
|
|
19973
|
-
import { closeSync as
|
|
19974
|
-
import { basename as basename9, dirname as dirname18, isAbsolute as
|
|
20124
|
+
import { createHash as createHash22 } from "crypto";
|
|
20125
|
+
import { closeSync as closeSync14, constants as constants14, fstatSync as fstatSync14, lstatSync as lstatSync24, openSync as openSync14, readSync as readSync11 } from "fs";
|
|
20126
|
+
import { basename as basename9, dirname as dirname18, isAbsolute as isAbsolute18, resolve as resolve17 } from "path";
|
|
19975
20127
|
var CLAUDE_MARKETPLACE_REGISTRY_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
|
|
19976
20128
|
function need6(value, reason) {
|
|
19977
20129
|
if (!value)
|
|
19978
20130
|
throw new Error(`Claude marketplace registry ${reason}`);
|
|
19979
20131
|
}
|
|
19980
20132
|
function absolutePath3(value) {
|
|
19981
|
-
need6(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) &&
|
|
20133
|
+
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
20134
|
}
|
|
19983
20135
|
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
20136
|
function parents2(path) {
|
|
19985
20137
|
const result = [];
|
|
19986
20138
|
for (let at = dirname18(path);; at = dirname18(at)) {
|
|
19987
|
-
const stat2 =
|
|
20139
|
+
const stat2 = lstatSync24(at, { bigint: true });
|
|
19988
20140
|
need6(stat2.isDirectory() && !stat2.isSymbolicLink(), "path traverses a symlink or non-directory");
|
|
19989
20141
|
result.push([at, stat2]);
|
|
19990
20142
|
if (at === dirname18(at))
|
|
@@ -19995,12 +20147,12 @@ function readRegistry2(path, budget2) {
|
|
|
19995
20147
|
absolutePath3(path);
|
|
19996
20148
|
need6(basename9(path) === "known_marketplaces.json", "requires known_marketplaces.json");
|
|
19997
20149
|
need6(Number.isSafeInteger(budget2.remaining) && budget2.remaining >= 0, "has an invalid byte budget");
|
|
19998
|
-
const ancestors2 = parents2(path), initial =
|
|
20150
|
+
const ancestors2 = parents2(path), initial = lstatSync24(path, { bigint: true });
|
|
19999
20151
|
need6(initial.isFile() && !initial.isSymbolicLink() && initial.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
|
|
20000
20152
|
need6(initial.size <= BigInt(budget2.remaining), "exceeds its aggregate byte limit");
|
|
20001
|
-
const fd =
|
|
20153
|
+
const fd = openSync14(path, constants14.O_RDONLY | constants14.O_NOFOLLOW | constants14.O_NONBLOCK);
|
|
20002
20154
|
try {
|
|
20003
|
-
const opened =
|
|
20155
|
+
const opened = fstatSync14(fd, { bigint: true });
|
|
20004
20156
|
need6(opened.isFile() && sameFile2(initial, opened), "changed during open");
|
|
20005
20157
|
const bytes = Buffer.alloc(Number(opened.size) + 1);
|
|
20006
20158
|
let length = 0;
|
|
@@ -20010,10 +20162,10 @@ function readRegistry2(path, budget2) {
|
|
|
20010
20162
|
break;
|
|
20011
20163
|
length += count;
|
|
20012
20164
|
}
|
|
20013
|
-
const after =
|
|
20165
|
+
const after = fstatSync14(fd, { bigint: true }), current = lstatSync24(path, { bigint: true });
|
|
20014
20166
|
need6(current.isFile() && sameFile2(opened, after) && sameFile2(after, current) && BigInt(length) === opened.size, "changed during read");
|
|
20015
20167
|
for (const [ancestor, before] of ancestors2) {
|
|
20016
|
-
const now =
|
|
20168
|
+
const now = lstatSync24(ancestor, { bigint: true });
|
|
20017
20169
|
need6(now.isDirectory() && before.dev === now.dev && before.ino === now.ino && before.mode === now.mode, "parent changed during read");
|
|
20018
20170
|
}
|
|
20019
20171
|
budget2.remaining -= length;
|
|
@@ -20023,7 +20175,7 @@ function readRegistry2(path, budget2) {
|
|
|
20023
20175
|
throw new Error("Claude marketplace registry is not strict UTF-8");
|
|
20024
20176
|
}
|
|
20025
20177
|
} finally {
|
|
20026
|
-
|
|
20178
|
+
closeSync14(fd);
|
|
20027
20179
|
}
|
|
20028
20180
|
}
|
|
20029
20181
|
function parse7(text2) {
|
|
@@ -20138,19 +20290,19 @@ function captureClaudeMarketplaceRegistry(path, budget2 = { remaining: 256 * 102
|
|
|
20138
20290
|
const value = parse7(readRegistry2(path, budget2));
|
|
20139
20291
|
for (const [, row] of value.entries)
|
|
20140
20292
|
normalizeRow(row);
|
|
20141
|
-
const
|
|
20142
|
-
return { path, hashMode: "claude-marketplace-registry", sha256:
|
|
20293
|
+
const sha2563 = createHash22("sha256").update("hasna.skills.claude-marketplace-registry.v1\x00").update(JSON.stringify(value)).digest("hex");
|
|
20294
|
+
return { path, hashMode: "claude-marketplace-registry", sha256: sha2563 };
|
|
20143
20295
|
}
|
|
20144
20296
|
function captureClaudeMarketplaceRegistryV2(path, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
20145
20297
|
const value = parse7(readRegistry2(path, budget2));
|
|
20146
20298
|
for (const [, row] of value.entries)
|
|
20147
20299
|
normalizeRow(row, 2);
|
|
20148
|
-
const
|
|
20149
|
-
return { path, hashMode: "claude-marketplace-registry-v2", sha256:
|
|
20300
|
+
const sha2563 = createHash22("sha256").update("hasna.skills.claude-marketplace-registry.v2\x00").update(JSON.stringify(value)).digest("hex");
|
|
20301
|
+
return { path, hashMode: "claude-marketplace-registry-v2", sha256: sha2563 };
|
|
20150
20302
|
}
|
|
20151
20303
|
|
|
20152
20304
|
// src/lib/codex-hook-discovery-recovery.ts
|
|
20153
|
-
import { createHash as
|
|
20305
|
+
import { createHash as createHash23 } from "crypto";
|
|
20154
20306
|
|
|
20155
20307
|
// src/lib/codex-hook-additions-review.ts
|
|
20156
20308
|
var events = { UserPromptSubmit: ["userPromptSubmit", "user_prompt_submit"], SessionStart: ["sessionStart", "session_start"], SubagentStart: ["subagentStart", "subagent_start"] };
|
|
@@ -20158,7 +20310,7 @@ var matchedEvents = { ...events, PreToolUse: ["preToolUse", "pre_tool_use"] };
|
|
|
20158
20310
|
var proofs = new WeakMap;
|
|
20159
20311
|
|
|
20160
20312
|
// src/lib/codex-hook-discovery-recovery.ts
|
|
20161
|
-
var sha4 = (text2) =>
|
|
20313
|
+
var sha4 = (text2) => createHash23("sha256").update(text2).digest("hex");
|
|
20162
20314
|
var fields = [...CODEX_DISCOVERY_PROJECTION_FIELDS];
|
|
20163
20315
|
var proofs2 = new WeakMap;
|
|
20164
20316
|
function assertCodexHookDiscoveryRecovery(binding, witness) {
|
|
@@ -20177,7 +20329,7 @@ function verifiesCodexHookDiscoverySource(binding, source, currentDigest, witnes
|
|
|
20177
20329
|
}
|
|
20178
20330
|
|
|
20179
20331
|
// src/lib/agent-discovery.ts
|
|
20180
|
-
var digest = (text2) =>
|
|
20332
|
+
var digest = (text2) => createHash24("sha256").update(text2).digest("hex");
|
|
20181
20333
|
function parseConfig(text2, path, toml = false) {
|
|
20182
20334
|
try {
|
|
20183
20335
|
const value = toml ? Bun.TOML.parse(text2) : JSON.parse(text2);
|
|
@@ -20189,10 +20341,10 @@ function parseConfig(text2, path, toml = false) {
|
|
|
20189
20341
|
}
|
|
20190
20342
|
}
|
|
20191
20343
|
function safe4(path) {
|
|
20192
|
-
if (!
|
|
20344
|
+
if (!isAbsolute19(path) || path.includes("\x00"))
|
|
20193
20345
|
throw new Error("Expected an absolute native discovery path");
|
|
20194
20346
|
for (let cursor = path;; cursor = dirname19(cursor)) {
|
|
20195
|
-
if (
|
|
20347
|
+
if (lstatSync25(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
20196
20348
|
throw new Error(`Refusing symlink native discovery input: ${cursor}`);
|
|
20197
20349
|
if (dirname19(cursor) === cursor)
|
|
20198
20350
|
break;
|
|
@@ -20202,12 +20354,12 @@ function read2(path, changes) {
|
|
|
20202
20354
|
safe4(path);
|
|
20203
20355
|
if (changes?.has(path))
|
|
20204
20356
|
return changes.get(path);
|
|
20205
|
-
const stat2 =
|
|
20357
|
+
const stat2 = lstatSync25(path, { throwIfNoEntry: false });
|
|
20206
20358
|
if (!stat2)
|
|
20207
20359
|
return null;
|
|
20208
20360
|
if (!stat2.isFile() || stat2.size > 16 * 1024 * 1024)
|
|
20209
20361
|
throw new Error(`Unsupported or oversized native discovery input: ${path}`);
|
|
20210
|
-
return
|
|
20362
|
+
return readFileSync20(path, "utf8");
|
|
20211
20363
|
}
|
|
20212
20364
|
function projectNativeDiscoveryFields(text2, format, fields2, path) {
|
|
20213
20365
|
const object6 = format === "yaml" ? parseHermesConfig(text2) : parseConfig(text2, path, format === "toml");
|
|
@@ -20253,10 +20405,10 @@ function projected(source, changes, budget2 = discoveryByteBudget()) {
|
|
|
20253
20405
|
if (source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2") {
|
|
20254
20406
|
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
20407
|
throw new Error("Claude marketplace witnesses require an exact reviewed registry without synthetic changes");
|
|
20256
|
-
const
|
|
20257
|
-
if (
|
|
20408
|
+
const sha2563 = (source.hashMode === "claude-marketplace-registry-v2" ? captureClaudeMarketplaceRegistryV2 : captureClaudeMarketplaceRegistry)(source.path, budget2).sha256;
|
|
20409
|
+
if (sha2563 !== source.sha256)
|
|
20258
20410
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
20259
|
-
return
|
|
20411
|
+
return sha2563;
|
|
20260
20412
|
}
|
|
20261
20413
|
if (source.hashMode === "claude-plugin-registry") {
|
|
20262
20414
|
if (source.format !== undefined || source.fields !== undefined || !source.managedPlugins || changes?.has(source.path))
|
|
@@ -20293,7 +20445,7 @@ function absentCodexSkillRoots(binding) {
|
|
|
20293
20445
|
return [];
|
|
20294
20446
|
if (binding.agent !== "codex" || !Array.isArray(controls) || controls.length > 4096)
|
|
20295
20447
|
throw new Error("Invalid disabled Codex discovery proof");
|
|
20296
|
-
if (binding.method !== "reviewed" || controls.every((control) =>
|
|
20448
|
+
if (binding.method !== "reviewed" || controls.every((control) => lstatSync25(control.pluginParent, { throwIfNoEntry: false })))
|
|
20297
20449
|
return [];
|
|
20298
20450
|
const cache = dirname19(dirname19(controls[0].pluginParent)), config = join32(dirname19(dirname19(cache)), "config.toml");
|
|
20299
20451
|
const source = binding.sources.find((source2) => source2.path === config && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined);
|
|
@@ -20361,7 +20513,7 @@ function absentRetiredClaudeRoots(binding) {
|
|
|
20361
20513
|
continue;
|
|
20362
20514
|
const root2 = join32(cache, ...parts.slice(0, 3));
|
|
20363
20515
|
safe4(root2);
|
|
20364
|
-
if (
|
|
20516
|
+
if (lstatSync25(root2, { throwIfNoEntry: false }))
|
|
20365
20517
|
continue;
|
|
20366
20518
|
const claude = dirname19(dirname19(cache)), settings = join32(claude, "settings.json"), registry = join32(claude, "plugins/installed_plugins.json");
|
|
20367
20519
|
const full = (path) => binding.sources.find((item) => item.path === path && item.sha256 !== null && item.format === undefined && item.fields === undefined);
|
|
@@ -20380,7 +20532,7 @@ function absentRetiredClaudeRoots(binding) {
|
|
|
20380
20532
|
if (!Array.isArray(rows) || rows.length !== 1 || rows[0]?.scope !== "user" || typeof rows[0]?.installPath !== "string")
|
|
20381
20533
|
continue;
|
|
20382
20534
|
const active = rows[0].installPath;
|
|
20383
|
-
if (rows[0].version !== basename10(active) || resolve18(active) !== active || dirname19(active) !== dirname19(root2) || active === root2 || !
|
|
20535
|
+
if (rows[0].version !== basename10(active) || resolve18(active) !== active || dirname19(active) !== dirname19(root2) || active === root2 || !lstatSync25(active, { throwIfNoEntry: false })?.isDirectory() || realpathSync11(active) !== active)
|
|
20384
20536
|
continue;
|
|
20385
20537
|
const activeManifest = full(join32(active, ".claude-plugin/plugin.json"));
|
|
20386
20538
|
if (!activeManifest || projected(activeManifest) !== activeManifest.sha256)
|
|
@@ -20411,7 +20563,7 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
20411
20563
|
const projection = binding.codexRetiredMaterializations.directories;
|
|
20412
20564
|
if (projection.length !== ordinary.length || projection.some((item, index) => item.path !== ordinary[index]?.path))
|
|
20413
20565
|
throw new Error("Missing retired Codex directory projection");
|
|
20414
|
-
const omitted = [...retiredRoots, ...(binding.codexRetiredMaterializations.parents ?? []).filter((parent) => !
|
|
20566
|
+
const omitted = [...retiredRoots, ...(binding.codexRetiredMaterializations.parents ?? []).filter((parent) => !lstatSync25(parent, { throwIfNoEntry: false }))];
|
|
20415
20567
|
if (projection.every((item) => Array.isArray(item.entries)))
|
|
20416
20568
|
verifyDiscoveryDirectoryProjection(projection, omitted);
|
|
20417
20569
|
else {
|
|
@@ -20425,7 +20577,7 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
20425
20577
|
verifyDiscoveryDirectories(ordinary);
|
|
20426
20578
|
verifyDiscoveryDirectories(projected2, installationRoots);
|
|
20427
20579
|
}
|
|
20428
|
-
const absentRoots = [...absentCodexSkillRoots(binding), ...absentRetiredClaudeRoots(binding), ...retiredRoots.filter((root2) => !
|
|
20580
|
+
const absentRoots = [...absentCodexSkillRoots(binding), ...absentRetiredClaudeRoots(binding), ...retiredRoots.filter((root2) => !lstatSync25(root2, { throwIfNoEntry: false }))];
|
|
20429
20581
|
const budget2 = discoveryByteBudget();
|
|
20430
20582
|
for (const source of binding.sources) {
|
|
20431
20583
|
assertMarketplaceBinding(binding, source);
|
|
@@ -20451,7 +20603,7 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
20451
20603
|
safe4(root2);
|
|
20452
20604
|
for (const root2 of absentRoots) {
|
|
20453
20605
|
safe4(root2);
|
|
20454
|
-
if (
|
|
20606
|
+
if (lstatSync25(root2, { throwIfNoEntry: false }))
|
|
20455
20607
|
throw new Error("Retired native materialization changed during discovery verification");
|
|
20456
20608
|
}
|
|
20457
20609
|
}
|
|
@@ -20490,19 +20642,19 @@ function assertMarketplaceBinding(binding, source) {
|
|
|
20490
20642
|
}
|
|
20491
20643
|
function rebindAgentDiscovery(binding, changes) {
|
|
20492
20644
|
const budget2 = discoveryByteBudget();
|
|
20493
|
-
const installationRoots = codexInstallationRoots(binding), absentRoots = [...absentCodexSkillRoots(binding), ...absentRetiredClaudeRoots(binding), ...retiredCodexRoots(binding).filter((root2) => !
|
|
20645
|
+
const installationRoots = codexInstallationRoots(binding), absentRoots = [...absentCodexSkillRoots(binding), ...absentRetiredClaudeRoots(binding), ...retiredCodexRoots(binding).filter((root2) => !lstatSync25(root2, { throwIfNoEntry: false }))];
|
|
20494
20646
|
const rebound = { ...binding, sources: binding.sources.map((source) => {
|
|
20495
20647
|
assertMarketplaceBinding(binding, source);
|
|
20496
20648
|
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
20649
|
return source;
|
|
20498
|
-
const
|
|
20499
|
-
if (!changes.has(source.path) &&
|
|
20650
|
+
const sha2563 = projected(source, changes, budget2);
|
|
20651
|
+
if (!changes.has(source.path) && sha2563 !== source.sha256)
|
|
20500
20652
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
20501
|
-
return { ...source, sha256:
|
|
20653
|
+
return { ...source, sha256: sha2563 };
|
|
20502
20654
|
}) };
|
|
20503
20655
|
for (const root2 of absentRoots) {
|
|
20504
20656
|
safe4(root2);
|
|
20505
|
-
if (
|
|
20657
|
+
if (lstatSync25(root2, { throwIfNoEntry: false }))
|
|
20506
20658
|
throw new Error("Retired native materialization changed during discovery rebinding");
|
|
20507
20659
|
}
|
|
20508
20660
|
return rebound;
|
|
@@ -20557,13 +20709,13 @@ function assertProjectDiscovery(agent, directories, home, canonical7 = resolve18
|
|
|
20557
20709
|
for (const name of ["plugin", "plugins"]) {
|
|
20558
20710
|
const path = canonical7(join32(directory, ".sumi", name));
|
|
20559
20711
|
safe4(path);
|
|
20560
|
-
if (
|
|
20712
|
+
if (lstatSync25(path, { throwIfNoEntry: false })?.isDirectory() && readdirSync10(path).length)
|
|
20561
20713
|
throw new Error(`NATIVE_SKILL_DRIFT: project Sumi plugins require a dedicated discovery review: ${path}`);
|
|
20562
20714
|
}
|
|
20563
20715
|
if (agent === "claude") {
|
|
20564
20716
|
const commands = canonical7(join32(directory, ".claude/commands"));
|
|
20565
20717
|
safe4(commands);
|
|
20566
|
-
if (
|
|
20718
|
+
if (lstatSync25(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync10(commands).length)
|
|
20567
20719
|
throw new Error("NATIVE_SKILL_DRIFT: legacy project command discovery requires a dedicated format adapter");
|
|
20568
20720
|
}
|
|
20569
20721
|
}
|
|
@@ -20603,7 +20755,7 @@ function resolveAgentDiscovery(options) {
|
|
|
20603
20755
|
if (config.skills !== undefined && (!Array.isArray(config.skills) || config.skills.some((path) => typeof path !== "string")))
|
|
20604
20756
|
unresolved("skills must be a string array");
|
|
20605
20757
|
for (const value of config.skills ?? []) {
|
|
20606
|
-
if (typeof value !== "string" || /[\0$]/.test(value) || !value || !(
|
|
20758
|
+
if (typeof value !== "string" || /[\0$]/.test(value) || !value || !(isAbsolute19(value) || value.startsWith("~/")))
|
|
20607
20759
|
unresolved("remote or relative skill sources need a dedicated discovery adapter");
|
|
20608
20760
|
roots.add(canonical7(value.startsWith("~/") ? join32(home, value.slice(2)) : value));
|
|
20609
20761
|
}
|
|
@@ -20613,19 +20765,19 @@ function resolveAgentDiscovery(options) {
|
|
|
20613
20765
|
const plugins = [join32(directory, "plugin"), join32(directory, "plugins")];
|
|
20614
20766
|
for (const path of plugins) {
|
|
20615
20767
|
safe4(path);
|
|
20616
|
-
if (
|
|
20768
|
+
if (lstatSync25(path, { throwIfNoEntry: false })?.isDirectory())
|
|
20617
20769
|
for (const name of readdirSync10(path).sort()) {
|
|
20618
20770
|
if (name === "skills-cli.js" && path === plugins[1])
|
|
20619
20771
|
continue;
|
|
20620
20772
|
const target = join32(path, name);
|
|
20621
|
-
if (!
|
|
20773
|
+
if (!lstatSync25(target).isFile())
|
|
20622
20774
|
unresolved("local plugin packages need a dedicated discovery adapter");
|
|
20623
20775
|
witness(target);
|
|
20624
20776
|
}
|
|
20625
20777
|
}
|
|
20626
20778
|
for (const root2 of roots) {
|
|
20627
20779
|
safe4(root2);
|
|
20628
|
-
if (
|
|
20780
|
+
if (lstatSync25(root2, { throwIfNoEntry: false })?.isDirectory() && readdirSync10(root2).some((name) => name.endsWith(".md")))
|
|
20629
20781
|
unresolved("flat markdown skills require a dedicated native migration adapter");
|
|
20630
20782
|
}
|
|
20631
20783
|
}
|
|
@@ -20653,7 +20805,7 @@ function resolveAgentDiscovery(options) {
|
|
|
20653
20805
|
const executable2 = Bun.which("gemini");
|
|
20654
20806
|
if (executable2) {
|
|
20655
20807
|
let packageRoot;
|
|
20656
|
-
for (let directory = dirname19(
|
|
20808
|
+
for (let directory = dirname19(realpathSync11(executable2)), depth = 0;depth < 8; directory = dirname19(directory), depth++) {
|
|
20657
20809
|
const path = join32(directory, "package.json"), raw = read2(path);
|
|
20658
20810
|
if (raw !== null && parseConfig(raw, path).name === "@google/gemini-cli") {
|
|
20659
20811
|
packageRoot = directory;
|
|
@@ -20667,7 +20819,7 @@ function resolveAgentDiscovery(options) {
|
|
|
20667
20819
|
unresolved("installed Gemini package layout is not recognized");
|
|
20668
20820
|
const builtinRoot = join32(packageRoot, "bundle/builtin");
|
|
20669
20821
|
safe4(builtinRoot);
|
|
20670
|
-
if (!
|
|
20822
|
+
if (!lstatSync25(builtinRoot, { throwIfNoEntry: false })?.isDirectory())
|
|
20671
20823
|
unresolved("installed Gemini builtin root is missing");
|
|
20672
20824
|
for (const name of readdirSync10(builtinRoot).sort()) {
|
|
20673
20825
|
const text2 = witness(join32(builtinRoot, name, "SKILL.md"));
|
|
@@ -20705,10 +20857,10 @@ function resolveAgentDiscovery(options) {
|
|
|
20705
20857
|
throw new Error("Discovery review must include the agent configuration source");
|
|
20706
20858
|
const reviewedSources = supersedesSettingsProjection(agent, review.sources, canonical7(configPath)) ? sources.filter((source) => !isSupersededSettingsProjection(agent, canonical7(configPath), source)) : sources;
|
|
20707
20859
|
const reviewedSourcesWithManifestProjection = review.sources.map((source) => {
|
|
20708
|
-
if (agent !== "claude" || 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")))
|
|
20860
|
+
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
20861
|
return source;
|
|
20710
20862
|
const pluginRoot = dirname19(dirname19(source.path)), hooksPath = join32(pluginRoot, "hooks/hooks.json");
|
|
20711
|
-
const hookStat =
|
|
20863
|
+
const hookStat = lstatSync25(hooksPath, { throwIfNoEntry: false });
|
|
20712
20864
|
const text2 = read2(source.path);
|
|
20713
20865
|
if (text2 === null)
|
|
20714
20866
|
throw new Error("Reviewed Claude plugin manifest is missing");
|
|
@@ -20749,7 +20901,7 @@ function resolveAgentDiscovery(options) {
|
|
|
20749
20901
|
unresolved("plugin hooks require a separate no-skill-injection review");
|
|
20750
20902
|
const commands = join32(root2, "commands");
|
|
20751
20903
|
safe4(commands);
|
|
20752
|
-
if (agent === "claude" && (manifest.commands !== undefined ||
|
|
20904
|
+
if (agent === "claude" && (manifest.commands !== undefined || lstatSync25(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync10(commands).length))
|
|
20753
20905
|
unresolved("legacy command discovery requires retirement or a dedicated format adapter");
|
|
20754
20906
|
const rootSkill = witness(join32(root2, "SKILL.md"));
|
|
20755
20907
|
if (rootSkill !== null)
|
|
@@ -20771,7 +20923,7 @@ function resolveAgentDiscovery(options) {
|
|
|
20771
20923
|
const installed = registrations === null ? {} : parseConfig(registrations, join32(home, ".claude/plugins/installed_plugins.json")).plugins;
|
|
20772
20924
|
const commands = canonical7(join32(home, ".claude/commands"));
|
|
20773
20925
|
safe4(commands);
|
|
20774
|
-
if (
|
|
20926
|
+
if (lstatSync25(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync10(commands).length)
|
|
20775
20927
|
unresolved("legacy home command discovery requires a dedicated format adapter");
|
|
20776
20928
|
for (const [id, enabled] of Object.entries(config.enabledPlugins ?? {})) {
|
|
20777
20929
|
if (enabled === false)
|
|
@@ -20791,7 +20943,7 @@ function resolveAgentDiscovery(options) {
|
|
|
20791
20943
|
unresolved("unsupported plugin enablement");
|
|
20792
20944
|
const split = id.lastIndexOf("@"), name = id.slice(0, split), marketplace = id.slice(split + 1);
|
|
20793
20945
|
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" || !
|
|
20946
|
+
if (split < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !isAbsolute19(market.source))
|
|
20795
20947
|
unresolved("enabled plugin marketplace is not an explicit local source");
|
|
20796
20948
|
const catalogText = witness(join32(market.source, ".agents/plugins/marketplace.json"));
|
|
20797
20949
|
if (catalogText === null)
|
|
@@ -20807,13 +20959,13 @@ function resolveAgentDiscovery(options) {
|
|
|
20807
20959
|
if ((config.plugin?.length ?? 0) > 0 || config.skills?.urls?.length)
|
|
20808
20960
|
unresolved("external plugin or remote skill source");
|
|
20809
20961
|
for (const path of config.skills?.paths ?? []) {
|
|
20810
|
-
if (typeof path !== "string" || !
|
|
20962
|
+
if (typeof path !== "string" || !isAbsolute19(path))
|
|
20811
20963
|
unresolved("relative or malformed added skill root");
|
|
20812
20964
|
roots.add(path);
|
|
20813
20965
|
}
|
|
20814
20966
|
const localPlugins = join32(home, ".config/opencode/plugins");
|
|
20815
20967
|
safe4(localPlugins);
|
|
20816
|
-
if (
|
|
20968
|
+
if (lstatSync25(localPlugins, { throwIfNoEntry: false }) && readdirSync10(localPlugins).some((name) => name !== "skills-cli.js"))
|
|
20817
20969
|
unresolved("additional local plugin hooks require review");
|
|
20818
20970
|
} else if (agent === "sumi") {
|
|
20819
20971
|
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 +20973,7 @@ function resolveAgentDiscovery(options) {
|
|
|
20821
20973
|
} else if (agent === "hermes") {
|
|
20822
20974
|
for (const directory of [join32(home, ".hermes/plugins"), join32(home, ".hermes/hermes-agent")]) {
|
|
20823
20975
|
safe4(directory);
|
|
20824
|
-
if (
|
|
20976
|
+
if (lstatSync25(directory, { throwIfNoEntry: false }))
|
|
20825
20977
|
unresolved("installed runtime/plugin discovery requires reviewed source bindings");
|
|
20826
20978
|
}
|
|
20827
20979
|
if (Bun.which("hermes") || Object.keys(config.plugins ?? {}).length)
|
|
@@ -20831,11 +20983,11 @@ function resolveAgentDiscovery(options) {
|
|
|
20831
20983
|
unresolved("custom extension or skill paths");
|
|
20832
20984
|
const directory = join32(home, ".gemini/extensions");
|
|
20833
20985
|
safe4(directory);
|
|
20834
|
-
if (
|
|
20986
|
+
if (lstatSync25(directory, { throwIfNoEntry: false }))
|
|
20835
20987
|
for (const name of readdirSync10(directory)) {
|
|
20836
20988
|
const root2 = join32(directory, name);
|
|
20837
20989
|
safe4(root2);
|
|
20838
|
-
if (!
|
|
20990
|
+
if (!lstatSync25(root2)?.isDirectory())
|
|
20839
20991
|
continue;
|
|
20840
20992
|
const raw = witness(join32(root2, "gemini-extension.json"));
|
|
20841
20993
|
if (raw === null)
|
|
@@ -20868,14 +21020,14 @@ function nativeRootMatch(path) {
|
|
|
20868
21020
|
function physicalPath(path) {
|
|
20869
21021
|
let cursor = resolve19(path);
|
|
20870
21022
|
const suffix = [];
|
|
20871
|
-
while (!
|
|
21023
|
+
while (!lstatSync26(cursor, { throwIfNoEntry: false })) {
|
|
20872
21024
|
suffix.unshift(basename11(cursor));
|
|
20873
21025
|
const parent = dirname20(cursor);
|
|
20874
21026
|
if (parent === cursor)
|
|
20875
21027
|
return resolve19(path);
|
|
20876
21028
|
cursor = parent;
|
|
20877
21029
|
}
|
|
20878
|
-
return resolve19(
|
|
21030
|
+
return resolve19(realpathSync12(cursor), ...suffix);
|
|
20879
21031
|
}
|
|
20880
21032
|
function contains(root2, path) {
|
|
20881
21033
|
return path === root2 || path.startsWith(root2 + sep9);
|
|
@@ -20913,7 +21065,7 @@ function configuredRoots(home, explicitHome) {
|
|
|
20913
21065
|
continue;
|
|
20914
21066
|
}
|
|
20915
21067
|
const nativeHome = join33(home, agent === "opencode" ? ".config/opencode" : `.${agent}`);
|
|
20916
|
-
if (!
|
|
21068
|
+
if (!lstatSync26(nativeHome, { throwIfNoEntry: false }))
|
|
20917
21069
|
continue;
|
|
20918
21070
|
roots.push(...resolveAgentDiscovery({ home, agent, canonical: physicalPath }).roots);
|
|
20919
21071
|
}
|
|
@@ -21091,14 +21243,14 @@ function physicalImportPath(path) {
|
|
|
21091
21243
|
suffix.unshift(basename12(ancestor));
|
|
21092
21244
|
ancestor = dirname21(ancestor);
|
|
21093
21245
|
}
|
|
21094
|
-
return join34(
|
|
21246
|
+
return join34(realpathSync13(ancestor), ...suffix);
|
|
21095
21247
|
}
|
|
21096
21248
|
function assertDisjointImportPaths(source, destination) {
|
|
21097
|
-
const sourcePath =
|
|
21249
|
+
const sourcePath = realpathSync13(source);
|
|
21098
21250
|
const destinationPath = physicalImportPath(destination);
|
|
21099
21251
|
const contains2 = (parent, child) => {
|
|
21100
21252
|
const path = relative7(parent, child);
|
|
21101
|
-
return path === "" || !
|
|
21253
|
+
return path === "" || !isAbsolute20(path) && path !== ".." && !path.startsWith(`..${sep10}`);
|
|
21102
21254
|
};
|
|
21103
21255
|
if (contains2(sourcePath, destinationPath) || contains2(destinationPath, sourcePath)) {
|
|
21104
21256
|
throw new Error("Source and destination skill directories must not overlap");
|
|
@@ -21379,7 +21531,7 @@ function safeIsDirectory(path) {
|
|
|
21379
21531
|
}
|
|
21380
21532
|
}
|
|
21381
21533
|
function isSafeRelativePath2(value) {
|
|
21382
|
-
if (!value.trim() ||
|
|
21534
|
+
if (!value.trim() || isAbsolute20(value))
|
|
21383
21535
|
return false;
|
|
21384
21536
|
const normalized = normalize4(value).replace(/\\/g, "/");
|
|
21385
21537
|
return normalized !== ".." && !normalized.startsWith("../") && !normalized.includes("/../");
|
|
@@ -21594,7 +21746,7 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
21594
21746
|
continue;
|
|
21595
21747
|
let content;
|
|
21596
21748
|
try {
|
|
21597
|
-
content =
|
|
21749
|
+
content = readFileSync21(skillMdPath, "utf-8");
|
|
21598
21750
|
} catch {
|
|
21599
21751
|
continue;
|
|
21600
21752
|
}
|
|
@@ -21631,7 +21783,7 @@ function findExtensionSkillPath(name) {
|
|
|
21631
21783
|
continue;
|
|
21632
21784
|
let content;
|
|
21633
21785
|
try {
|
|
21634
|
-
content =
|
|
21786
|
+
content = readFileSync21(skillMdPath, "utf-8");
|
|
21635
21787
|
} catch {
|
|
21636
21788
|
continue;
|
|
21637
21789
|
}
|
|
@@ -21695,8 +21847,8 @@ function getAllTags(catalog) {
|
|
|
21695
21847
|
return Array.from(tagSet).sort();
|
|
21696
21848
|
}
|
|
21697
21849
|
// src/lib/run-state.ts
|
|
21698
|
-
import { createHash as
|
|
21699
|
-
import { existsSync as existsSync16, mkdirSync as mkdirSync11, readFileSync as
|
|
21850
|
+
import { createHash as createHash25, randomBytes } from "crypto";
|
|
21851
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync11, readFileSync as readFileSync23, readdirSync as readdirSync13, statSync as statSync12, writeFileSync as writeFileSync10 } from "fs";
|
|
21700
21852
|
import { extname, join as join36, relative as relative8 } from "path";
|
|
21701
21853
|
function createSkillRun(params, targetDir = process.cwd()) {
|
|
21702
21854
|
const now = new Date;
|
|
@@ -21768,7 +21920,7 @@ function appendRunEvent(context, event, data = {}) {
|
|
|
21768
21920
|
const line = JSON.stringify({ ts: new Date().toISOString(), event, ...data }) + `
|
|
21769
21921
|
`;
|
|
21770
21922
|
const path = join36(context.runDir, "events.ndjson");
|
|
21771
|
-
const previous = existsSync16(path) ?
|
|
21923
|
+
const previous = existsSync16(path) ? readFileSync23(path, "utf-8") : "";
|
|
21772
21924
|
writeFileSync10(path, previous + line);
|
|
21773
21925
|
}
|
|
21774
21926
|
function listSkillRuns(targetDir = process.cwd(), limit = 50) {
|
|
@@ -21818,11 +21970,11 @@ function collectRunArtifacts(context) {
|
|
|
21818
21970
|
const artifacts = [];
|
|
21819
21971
|
for (const path of walkFiles(context.exportDir)) {
|
|
21820
21972
|
const stat2 = statSync12(path);
|
|
21821
|
-
const bytes =
|
|
21973
|
+
const bytes = readFileSync23(path);
|
|
21822
21974
|
artifacts.push({
|
|
21823
21975
|
path: toProjectRelative(context.targetDir, path),
|
|
21824
21976
|
mime: mimeForPath(path),
|
|
21825
|
-
sha256:
|
|
21977
|
+
sha256: createHash25("sha256").update(bytes).digest("hex"),
|
|
21826
21978
|
sizeBytes: stat2.size
|
|
21827
21979
|
});
|
|
21828
21980
|
}
|
|
@@ -21833,7 +21985,7 @@ function readRunRecord(runDir) {
|
|
|
21833
21985
|
if (!existsSync16(path))
|
|
21834
21986
|
return null;
|
|
21835
21987
|
try {
|
|
21836
|
-
return JSON.parse(
|
|
21988
|
+
return JSON.parse(readFileSync23(path, "utf-8"));
|
|
21837
21989
|
} catch {
|
|
21838
21990
|
return null;
|
|
21839
21991
|
}
|
|
@@ -41241,7 +41393,7 @@ function clone2(value) {
|
|
|
41241
41393
|
return value === undefined ? undefined : JSON.parse(JSON.stringify(value));
|
|
41242
41394
|
}
|
|
41243
41395
|
// src/lib/canonical-json.ts
|
|
41244
|
-
import { createHash as
|
|
41396
|
+
import { createHash as createHash26 } from "crypto";
|
|
41245
41397
|
function canonicalJson2(value, maximumBytes = 2 * 1024 * 1024) {
|
|
41246
41398
|
return canonicalJsonAtDepth(value, maximumBytes, 64);
|
|
41247
41399
|
}
|
|
@@ -41285,7 +41437,7 @@ function canonicalJsonAtDepth(value, maximumBytes, maximumDepth) {
|
|
|
41285
41437
|
return visit3(value, 0);
|
|
41286
41438
|
}
|
|
41287
41439
|
function canonicalJsonSha256(value, maximumBytes) {
|
|
41288
|
-
return
|
|
41440
|
+
return createHash26("sha256").update(canonicalJson2(value, maximumBytes)).digest("hex");
|
|
41289
41441
|
}
|
|
41290
41442
|
|
|
41291
41443
|
// src/lib/remote-recurring-contract.ts
|
|
@@ -43348,7 +43500,7 @@ async function createRemoteSkillsClient(env = process.env) {
|
|
|
43348
43500
|
return connection ? new RemoteSkillsClient(connection.apiKey, connection.apiOrigin) : null;
|
|
43349
43501
|
}
|
|
43350
43502
|
// src/lib/scheduler.ts
|
|
43351
|
-
import { existsSync as existsSync17, readFileSync as
|
|
43503
|
+
import { existsSync as existsSync17, readFileSync as readFileSync25, writeFileSync as writeFileSync11, mkdirSync as mkdirSync12 } from "fs";
|
|
43352
43504
|
import { join as join37 } from "path";
|
|
43353
43505
|
function getSchedulesPath(targetDir = process.cwd()) {
|
|
43354
43506
|
return join37(targetDir, ".skills", "schedules.json");
|
|
@@ -43357,7 +43509,7 @@ function loadSchedules(targetDir = process.cwd()) {
|
|
|
43357
43509
|
const path = getSchedulesPath(targetDir);
|
|
43358
43510
|
if (existsSync17(path)) {
|
|
43359
43511
|
try {
|
|
43360
|
-
return JSON.parse(
|
|
43512
|
+
return JSON.parse(readFileSync25(path, "utf-8"));
|
|
43361
43513
|
} catch {}
|
|
43362
43514
|
}
|
|
43363
43515
|
return { version: 1, schedules: [] };
|
|
@@ -43552,7 +43704,7 @@ function recordScheduleRun(id, status, targetDir) {
|
|
|
43552
43704
|
saveSchedules(data, targetDir);
|
|
43553
43705
|
}
|
|
43554
43706
|
// src/lib/revision.ts
|
|
43555
|
-
import { createHash as
|
|
43707
|
+
import { createHash as createHash27 } from "crypto";
|
|
43556
43708
|
var REVISION_ID_PATTERN = /^[0-9a-f]{64}$/;
|
|
43557
43709
|
function revisionIdOf(content) {
|
|
43558
43710
|
const canonicalContent = {
|
|
@@ -43574,13 +43726,13 @@ function revisionIdOf(content) {
|
|
|
43574
43726
|
canonicalContent.replacementSlug = content.replacementSlug ?? null;
|
|
43575
43727
|
}
|
|
43576
43728
|
const canonical7 = JSON.stringify(canonicalContent);
|
|
43577
|
-
return
|
|
43729
|
+
return createHash27("sha256").update(canonical7).digest("hex");
|
|
43578
43730
|
}
|
|
43579
43731
|
function revisionIdOfRecord(record8) {
|
|
43580
43732
|
return revisionIdOf(record8);
|
|
43581
43733
|
}
|
|
43582
43734
|
// src/lib/pull.ts
|
|
43583
|
-
import { existsSync as existsSync18, mkdirSync as mkdirSync13, mkdtempSync as mkdtempSync3, readFileSync as
|
|
43735
|
+
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
43736
|
import { dirname as dirname22, join as join38 } from "path";
|
|
43585
43737
|
|
|
43586
43738
|
// src/lib/skill-bundles.ts
|
|
@@ -43780,7 +43932,7 @@ function reconcileTombstone(slug2, corpusOptions) {
|
|
|
43780
43932
|
}
|
|
43781
43933
|
function readPullMarker(dir) {
|
|
43782
43934
|
try {
|
|
43783
|
-
return JSON.parse(
|
|
43935
|
+
return JSON.parse(readFileSync26(join38(dir, PULL_MARKER_FILE), "utf-8"));
|
|
43784
43936
|
} catch {
|
|
43785
43937
|
return null;
|
|
43786
43938
|
}
|
|
@@ -44017,7 +44169,7 @@ function splitNameVersion(raw) {
|
|
|
44017
44169
|
return version2 ? { name, version: version2 } : { name };
|
|
44018
44170
|
}
|
|
44019
44171
|
// src/lib/recurring-surface.ts
|
|
44020
|
-
import { isAbsolute as
|
|
44172
|
+
import { isAbsolute as isAbsolute21 } from "path";
|
|
44021
44173
|
|
|
44022
44174
|
// src/lib/remote-invitation-recovery.ts
|
|
44023
44175
|
class InvitationEmailInputError extends Error {
|
|
@@ -44115,7 +44267,7 @@ async function requestInvitationEmail(origin, action, input2) {
|
|
|
44115
44267
|
}
|
|
44116
44268
|
|
|
44117
44269
|
// src/lib/remote-private-publications.ts
|
|
44118
|
-
import { createHash as
|
|
44270
|
+
import { createHash as createHash28 } from "crypto";
|
|
44119
44271
|
var PRIVATE_PUBLICATION_MAX_BYTES = 16 * 1024 * 1024;
|
|
44120
44272
|
var failures2 = {
|
|
44121
44273
|
INVALID_REQUEST: [400, "The publication request is invalid."],
|
|
@@ -44162,7 +44314,7 @@ var hash3 = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v);
|
|
|
44162
44314
|
var record9 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
44163
44315
|
var exact = (v, keys) => record9(v) && Object.keys(v).sort().join(",") === keys.sort().join(",");
|
|
44164
44316
|
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) =>
|
|
44317
|
+
var publicationSha256 = (bytes) => createHash28("sha256").update(bytes).digest("hex");
|
|
44166
44318
|
function checkedPublicationDeclaration(value) {
|
|
44167
44319
|
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
44320
|
return bad();
|
|
@@ -44676,7 +44828,7 @@ var stateSchema = exports_external.object({
|
|
|
44676
44828
|
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
44829
|
var context = { userId: uuid13.optional(), membershipId: uuid13.optional() };
|
|
44678
44830
|
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(
|
|
44831
|
+
var directory = exports_external.string().max(4096).refine(isAbsolute21, "Use an absolute recovery directory");
|
|
44680
44832
|
var email4 = exports_external.string().trim().toLowerCase().email().max(254);
|
|
44681
44833
|
var code = exports_external.string().regex(/^\d{6}$/);
|
|
44682
44834
|
var recurringSurfaceSchemas = {
|
|
@@ -46028,11 +46180,11 @@ function isApiMode(env = process.env) {
|
|
|
46028
46180
|
}
|
|
46029
46181
|
}
|
|
46030
46182
|
// src/lib/native-storage.ts
|
|
46031
|
-
import { createHash as
|
|
46183
|
+
import { createHash as createHash29, createHmac as createHmac2 } from "crypto";
|
|
46032
46184
|
import {
|
|
46033
46185
|
existsSync as existsSync20,
|
|
46034
46186
|
mkdirSync as mkdirSync16,
|
|
46035
|
-
readFileSync as
|
|
46187
|
+
readFileSync as readFileSync27,
|
|
46036
46188
|
readdirSync as readdirSync14,
|
|
46037
46189
|
statSync as statSync13,
|
|
46038
46190
|
writeFileSync as writeFileSync14
|
|
@@ -46199,12 +46351,12 @@ function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
|
|
|
46199
46351
|
const files = [];
|
|
46200
46352
|
if (existsSync20(projectStateDir)) {
|
|
46201
46353
|
for (const filePath of walkFiles2(projectStateDir)) {
|
|
46202
|
-
const bytes =
|
|
46354
|
+
const bytes = readFileSync27(filePath);
|
|
46203
46355
|
const relativePath = toPosix(relative10(targetDir, filePath));
|
|
46204
46356
|
files.push({
|
|
46205
46357
|
path: relativePath,
|
|
46206
46358
|
sizeBytes: bytes.byteLength,
|
|
46207
|
-
sha256:
|
|
46359
|
+
sha256: createHash29("sha256").update(bytes).digest("hex"),
|
|
46208
46360
|
...options.includeFileContents ? { contentBase64: Buffer.from(bytes).toString("base64") } : {}
|
|
46209
46361
|
});
|
|
46210
46362
|
}
|
|
@@ -46229,7 +46381,7 @@ function importSkillsLocalSnapshot(snapshot2, targetDir = process.cwd(), options
|
|
|
46229
46381
|
continue;
|
|
46230
46382
|
}
|
|
46231
46383
|
const bytes = Buffer.from(file2.contentBase64, "base64");
|
|
46232
|
-
const hash4 =
|
|
46384
|
+
const hash4 = createHash29("sha256").update(bytes).digest("hex");
|
|
46233
46385
|
if (hash4 !== file2.sha256) {
|
|
46234
46386
|
throw new Error(`Snapshot file checksum mismatch: ${file2.path}`);
|
|
46235
46387
|
}
|
|
@@ -46561,7 +46713,7 @@ function toIsoString(value) {
|
|
|
46561
46713
|
return Number.isNaN(date6.getTime()) ? value : date6.toISOString();
|
|
46562
46714
|
}
|
|
46563
46715
|
function sha256Hex2(value) {
|
|
46564
|
-
return
|
|
46716
|
+
return createHash29("sha256").update(value).digest("hex");
|
|
46565
46717
|
}
|
|
46566
46718
|
function normalizeHeaders(headers) {
|
|
46567
46719
|
const result = {};
|
|
@@ -46613,15 +46765,15 @@ function toArrayBuffer(bytes) {
|
|
|
46613
46765
|
return buffer;
|
|
46614
46766
|
}
|
|
46615
46767
|
// src/lib/station-snapshot.ts
|
|
46616
|
-
import { createHash as
|
|
46768
|
+
import { createHash as createHash30 } from "crypto";
|
|
46617
46769
|
import {
|
|
46618
46770
|
copyFileSync,
|
|
46619
46771
|
mkdirSync as mkdirSync17,
|
|
46620
|
-
readFileSync as
|
|
46772
|
+
readFileSync as readFileSync28,
|
|
46621
46773
|
statSync as statSync15,
|
|
46622
46774
|
writeFileSync as writeFileSync15
|
|
46623
46775
|
} from "fs";
|
|
46624
|
-
import { dirname as dirname26, isAbsolute as
|
|
46776
|
+
import { dirname as dirname26, isAbsolute as isAbsolute22, relative as relative11, resolve as resolve21, sep as sep13 } from "path";
|
|
46625
46777
|
|
|
46626
46778
|
// src/lib/portable-snapshot-filter.ts
|
|
46627
46779
|
import { readdirSync as readdirSync15, statSync as statSync14 } from "fs";
|
|
@@ -46788,7 +46940,7 @@ function validateStationId(stationId) {
|
|
|
46788
46940
|
}
|
|
46789
46941
|
}
|
|
46790
46942
|
function sha256File(filePath) {
|
|
46791
|
-
return
|
|
46943
|
+
return createHash30("sha256").update(readFileSync28(filePath)).digest("hex");
|
|
46792
46944
|
}
|
|
46793
46945
|
function scanHome(definition, homesRoot) {
|
|
46794
46946
|
const homePath = homePathFor(definition, homesRoot);
|
|
@@ -46887,7 +47039,7 @@ function writeStationSnapshot(options) {
|
|
|
46887
47039
|
for (const plan of plans) {
|
|
46888
47040
|
const destination = resolve21(repoRoot, plan.destination);
|
|
46889
47041
|
const destinationRelative = relative11(repoRoot, destination);
|
|
46890
|
-
if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep13) ||
|
|
47042
|
+
if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep13) || isAbsolute22(destinationRelative)) {
|
|
46891
47043
|
throw new StationSnapshotError("DESTINATION_ESCAPE", `destination escapes repo root: ${plan.destination}`);
|
|
46892
47044
|
}
|
|
46893
47045
|
let existingDigest = null;
|
|
@@ -46939,12 +47091,12 @@ function writeStationSnapshot(options) {
|
|
|
46939
47091
|
};
|
|
46940
47092
|
}
|
|
46941
47093
|
// src/lib/station-hydrate.ts
|
|
46942
|
-
import { createHash as
|
|
47094
|
+
import { createHash as createHash31 } from "crypto";
|
|
46943
47095
|
import {
|
|
46944
47096
|
copyFileSync as copyFileSync2,
|
|
46945
47097
|
mkdirSync as mkdirSync18,
|
|
46946
47098
|
readdirSync as readdirSync16,
|
|
46947
|
-
readFileSync as
|
|
47099
|
+
readFileSync as readFileSync29,
|
|
46948
47100
|
statSync as statSync16,
|
|
46949
47101
|
writeFileSync as writeFileSync16
|
|
46950
47102
|
} from "fs";
|
|
@@ -46963,7 +47115,7 @@ function readSnapshotManifest(repoRoot, stationId) {
|
|
|
46963
47115
|
const manifestPath = join42(snapshotRoot, "sync-manifest.json");
|
|
46964
47116
|
let manifest;
|
|
46965
47117
|
try {
|
|
46966
|
-
manifest = JSON.parse(
|
|
47118
|
+
manifest = JSON.parse(readFileSync29(manifestPath, "utf8"));
|
|
46967
47119
|
} catch (error61) {
|
|
46968
47120
|
fail2("MANIFEST_UNREADABLE", `cannot read snapshot manifest: ${manifestPath}: ${error61.message}`);
|
|
46969
47121
|
}
|
|
@@ -47099,7 +47251,7 @@ function planStationHydration(stationId, repoRoot) {
|
|
|
47099
47251
|
for (const copy of copies) {
|
|
47100
47252
|
let isStub = false;
|
|
47101
47253
|
try {
|
|
47102
|
-
isStub = isPointerSkillMd(
|
|
47254
|
+
isStub = isPointerSkillMd(readFileSync29(copy.fullPath, "utf8"));
|
|
47103
47255
|
} catch {
|
|
47104
47256
|
isStub = false;
|
|
47105
47257
|
}
|
|
@@ -47145,7 +47297,7 @@ function skillSha256(skill) {
|
|
|
47145
47297
|
return sha256File(skill.files[0].winner.fullPath);
|
|
47146
47298
|
}
|
|
47147
47299
|
const joined = skill.files.map((file2) => sha256File(file2.winner.fullPath));
|
|
47148
|
-
return
|
|
47300
|
+
return createHash31("sha256").update(joined.sort().join(`
|
|
47149
47301
|
`)).digest("hex");
|
|
47150
47302
|
}
|
|
47151
47303
|
function writeStationHydration(options) {
|
|
@@ -47237,23 +47389,23 @@ function writeStationHydration(options) {
|
|
|
47237
47389
|
};
|
|
47238
47390
|
}
|
|
47239
47391
|
// src/lib/private-publication-recovery.ts
|
|
47240
|
-
import { constants as
|
|
47241
|
-
import { dirname as dirname28, isAbsolute as
|
|
47392
|
+
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";
|
|
47393
|
+
import { dirname as dirname28, isAbsolute as isAbsolute23, join as join43, resolve as resolve23 } from "path";
|
|
47242
47394
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
47243
47395
|
var fail3 = () => {
|
|
47244
47396
|
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
47397
|
};
|
|
47246
47398
|
function safeDirectory(directory2) {
|
|
47247
|
-
if (!
|
|
47399
|
+
if (!isAbsolute23(directory2) || directory2 !== resolve23(directory2) || realpathSync14(directory2) !== directory2)
|
|
47248
47400
|
return fail3();
|
|
47249
47401
|
for (let path = directory2;; path = dirname28(path)) {
|
|
47250
|
-
const stat2 =
|
|
47402
|
+
const stat2 = lstatSync27(path);
|
|
47251
47403
|
if (!stat2.isDirectory() || stat2.isSymbolicLink())
|
|
47252
47404
|
return fail3();
|
|
47253
47405
|
if (path === dirname28(path))
|
|
47254
47406
|
break;
|
|
47255
47407
|
}
|
|
47256
|
-
const own2 =
|
|
47408
|
+
const own2 = lstatSync27(directory2);
|
|
47257
47409
|
if ((own2.mode & 63) !== 0 || process.getuid && own2.uid !== process.getuid())
|
|
47258
47410
|
return fail3();
|
|
47259
47411
|
return { dev: own2.dev, ino: own2.ino };
|
|
@@ -47265,9 +47417,9 @@ function unchangedDirectory(directory2, identity5) {
|
|
|
47265
47417
|
}
|
|
47266
47418
|
function readOwned(directory2, name, max) {
|
|
47267
47419
|
const identity5 = safeDirectory(directory2), file2 = join43(directory2, name);
|
|
47268
|
-
const fd =
|
|
47420
|
+
const fd = openSync15(file2, constants15.O_RDONLY | constants15.O_NOFOLLOW);
|
|
47269
47421
|
try {
|
|
47270
|
-
const stat2 =
|
|
47422
|
+
const stat2 = fstatSync15(fd);
|
|
47271
47423
|
if (!stat2.isFile() || stat2.nlink !== 1 || stat2.size > max || stat2.size < 1 || (stat2.mode & 63) !== 0 || process.getuid && stat2.uid !== process.getuid())
|
|
47272
47424
|
return fail3();
|
|
47273
47425
|
const buffer = Buffer.alloc(Math.min(max, stat2.size) + 1);
|
|
@@ -47278,22 +47430,22 @@ function readOwned(directory2, name, max) {
|
|
|
47278
47430
|
break;
|
|
47279
47431
|
length += count;
|
|
47280
47432
|
}
|
|
47281
|
-
const bytes = buffer.subarray(0, length), after =
|
|
47433
|
+
const bytes = buffer.subarray(0, length), after = fstatSync15(fd);
|
|
47282
47434
|
unchangedDirectory(directory2, identity5);
|
|
47283
47435
|
if (bytes.length !== stat2.size || stat2.size !== after.size || stat2.mtimeMs !== after.mtimeMs || stat2.ctimeMs !== after.ctimeMs)
|
|
47284
47436
|
return fail3();
|
|
47285
47437
|
return bytes;
|
|
47286
47438
|
} finally {
|
|
47287
|
-
|
|
47439
|
+
closeSync15(fd);
|
|
47288
47440
|
}
|
|
47289
47441
|
}
|
|
47290
47442
|
function writeOwned(directory2, name, bytes) {
|
|
47291
|
-
const fd =
|
|
47443
|
+
const fd = openSync15(join43(directory2, name), constants15.O_WRONLY | constants15.O_CREAT | constants15.O_EXCL | constants15.O_NOFOLLOW, 384);
|
|
47292
47444
|
try {
|
|
47293
47445
|
writeFileSync17(fd, bytes);
|
|
47294
|
-
|
|
47446
|
+
fsyncSync7(fd);
|
|
47295
47447
|
} finally {
|
|
47296
|
-
|
|
47448
|
+
closeSync15(fd);
|
|
47297
47449
|
}
|
|
47298
47450
|
}
|
|
47299
47451
|
function save(directory2, value) {
|
|
@@ -47302,11 +47454,11 @@ function save(directory2, value) {
|
|
|
47302
47454
|
`);
|
|
47303
47455
|
unchangedDirectory(directory2, identity5);
|
|
47304
47456
|
renameSync8(join43(directory2, temporary), join43(directory2, "receipt.json"));
|
|
47305
|
-
const fd =
|
|
47457
|
+
const fd = openSync15(directory2, constants15.O_RDONLY | constants15.O_NOFOLLOW);
|
|
47306
47458
|
try {
|
|
47307
|
-
|
|
47459
|
+
fsyncSync7(fd);
|
|
47308
47460
|
} finally {
|
|
47309
|
-
|
|
47461
|
+
closeSync15(fd);
|
|
47310
47462
|
}
|
|
47311
47463
|
}
|
|
47312
47464
|
function bind(client2, receipt) {
|
|
@@ -47317,20 +47469,20 @@ async function locked(directory2, action) {
|
|
|
47317
47469
|
const identity5 = safeDirectory(directory2), file2 = join43(directory2, "operation.lock");
|
|
47318
47470
|
let fd;
|
|
47319
47471
|
try {
|
|
47320
|
-
fd =
|
|
47472
|
+
fd = openSync15(file2, constants15.O_WRONLY | constants15.O_CREAT | constants15.O_EXCL | constants15.O_NOFOLLOW, 384);
|
|
47321
47473
|
} catch {
|
|
47322
47474
|
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
47475
|
}
|
|
47324
|
-
const lock =
|
|
47476
|
+
const lock = fstatSync15(fd);
|
|
47325
47477
|
try {
|
|
47326
47478
|
writeFileSync17(fd, JSON.stringify({ pid: process.pid }) + `
|
|
47327
47479
|
`);
|
|
47328
|
-
|
|
47480
|
+
fsyncSync7(fd);
|
|
47329
47481
|
return await action();
|
|
47330
47482
|
} finally {
|
|
47331
|
-
|
|
47483
|
+
closeSync15(fd);
|
|
47332
47484
|
unchangedDirectory(directory2, identity5);
|
|
47333
|
-
const now =
|
|
47485
|
+
const now = lstatSync27(file2);
|
|
47334
47486
|
if (now.dev !== lock.dev || now.ino !== lock.ino || !now.isFile() || now.isSymbolicLink())
|
|
47335
47487
|
fail3();
|
|
47336
47488
|
unlinkSync6(file2);
|
|
@@ -47382,15 +47534,15 @@ async function preparePrivatePublication(client2, sourceDirectory, recoveryDirec
|
|
|
47382
47534
|
phase: "prepared",
|
|
47383
47535
|
intent: null
|
|
47384
47536
|
};
|
|
47385
|
-
if (!
|
|
47537
|
+
if (!isAbsolute23(recoveryDirectory) || resolve23(recoveryDirectory) !== recoveryDirectory || realpathSync14(dirname28(recoveryDirectory)) !== dirname28(recoveryDirectory))
|
|
47386
47538
|
return fail3();
|
|
47387
47539
|
mkdirSync19(recoveryDirectory, { mode: 448 });
|
|
47388
47540
|
safeDirectory(recoveryDirectory);
|
|
47389
|
-
const parent =
|
|
47541
|
+
const parent = openSync15(dirname28(recoveryDirectory), constants15.O_RDONLY | constants15.O_NOFOLLOW);
|
|
47390
47542
|
try {
|
|
47391
|
-
|
|
47543
|
+
fsyncSync7(parent);
|
|
47392
47544
|
} finally {
|
|
47393
|
-
|
|
47545
|
+
closeSync15(parent);
|
|
47394
47546
|
}
|
|
47395
47547
|
writeOwned(recoveryDirectory, "bundle.tgz", packed.bytes);
|
|
47396
47548
|
save(recoveryDirectory, receipt);
|
|
@@ -47473,7 +47625,7 @@ async function inspectLocked(client2, directory2, cancel) {
|
|
|
47473
47625
|
return privatePublicationResult(directory2, receipt);
|
|
47474
47626
|
}
|
|
47475
47627
|
// src/lib/skill-context.ts
|
|
47476
|
-
import { createHash as
|
|
47628
|
+
import { createHash as createHash32 } from "crypto";
|
|
47477
47629
|
import { resolve as resolve24 } from "path";
|
|
47478
47630
|
function words(value) {
|
|
47479
47631
|
return new Set(value.toLowerCase().match(/[a-z0-9]+/g) ?? []);
|
|
@@ -47566,7 +47718,7 @@ ${content}`;
|
|
|
47566
47718
|
`);
|
|
47567
47719
|
const receipt = {
|
|
47568
47720
|
schemaVersion: 1,
|
|
47569
|
-
id:
|
|
47721
|
+
id: createHash32("sha256").update(JSON.stringify({ profile: profile.profileRevision, sessionId, selections, omitted })).digest("hex"),
|
|
47570
47722
|
profileId: profile.profileId,
|
|
47571
47723
|
profileRevision: profile.profileRevision,
|
|
47572
47724
|
authority: profile.authority,
|
|
@@ -47582,9 +47734,9 @@ ${content}`;
|
|
|
47582
47734
|
return { context: context2, selections, omitted, receipt };
|
|
47583
47735
|
}
|
|
47584
47736
|
// src/lib/session-reconciliation.ts
|
|
47585
|
-
import { createHash as
|
|
47737
|
+
import { createHash as createHash33 } from "crypto";
|
|
47586
47738
|
var SESSION_RECONCILIATION_PLAN_TTL_MS = 5 * 60 * 1000;
|
|
47587
|
-
var digest3 = (value) =>
|
|
47739
|
+
var digest3 = (value) => createHash33("sha256").update(JSON.stringify(value)).digest("hex");
|
|
47588
47740
|
function exactTimestamp(value) {
|
|
47589
47741
|
const parsed = value === undefined ? Number.NaN : Date.parse(value);
|
|
47590
47742
|
if (!Number.isFinite(parsed) || new Date(parsed).toISOString() !== value) {
|