@hasna/skills 0.10.45 → 0.10.47
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 +17 -0
- package/bin/index.js +1857 -1474
- package/bin/maintenance.js +7 -2
- package/bin/mcp.js +1097 -824
- package/bin/migrate.js +7 -5
- package/bin/server.js +29 -10
- package/bin/worker.js +12 -7
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1491 -1182
- package/dist/lib/agent-discovery.d.ts +1 -1
- package/dist/lib/agent-integration.d.ts +2 -2
- package/dist/lib/agent-sumi.d.ts +3 -0
- package/dist/lib/claude-plugin-manifest-witness.d.ts +9 -0
- package/dist/lib/claude-settings-witness.d.ts +5 -1
- package/dist/lib/profile-client.d.ts +6 -2
- package/dist/lib/remote-files.d.ts +1 -1
- package/dist/lib/selection-cache.d.ts +5 -0
- package/dist/lib/selection-resolver.d.ts +1 -0
- package/dist/lib/session-reconciliation.d.ts +6 -3
- package/dist/lib/sumi-settings-witness.d.ts +14 -0
- package/dist/sdk/index.js +1080 -754
- package/dist/server/skills-api.d.ts +1 -0
- package/dist/server/types.d.ts +3 -1
- package/dist/types/skill-selection.d.ts +2 -0
- package/migrations/postgres/0011_skill_authorization_epoch.sql +22 -0
- package/migrations/sqlite/0011_skill_authorization_epoch.sql +17 -0
- package/package.json +1 -1
package/bin/mcp.js
CHANGED
|
@@ -20019,7 +20019,7 @@ var package_default;
|
|
|
20019
20019
|
var init_package = __esm(() => {
|
|
20020
20020
|
package_default = {
|
|
20021
20021
|
name: "@hasna/skills",
|
|
20022
|
-
version: "0.10.
|
|
20022
|
+
version: "0.10.47",
|
|
20023
20023
|
description: "Skills library for AI coding agents",
|
|
20024
20024
|
type: "module",
|
|
20025
20025
|
bin: {
|
|
@@ -38209,8 +38209,323 @@ var init_agent_adapters = __esm(() => {
|
|
|
38209
38209
|
INTEGRATION_AGENTS = ["claude", "codex", "gemini", "opencode", "cursor", "hermes", "sumi"];
|
|
38210
38210
|
});
|
|
38211
38211
|
|
|
38212
|
+
// src/lib/claude-settings-witness.ts
|
|
38213
|
+
import { createHash as createHash2 } from "crypto";
|
|
38214
|
+
import { closeSync as closeSync5, constants as constants2, fstatSync as fstatSync5, lstatSync as lstatSync5, openSync as openSync5, readSync as readSync2 } from "fs";
|
|
38215
|
+
import { basename as basename3, dirname as dirname4, isAbsolute as isAbsolute3, resolve as resolve2 } from "path";
|
|
38216
|
+
function need(value, reason) {
|
|
38217
|
+
if (!value)
|
|
38218
|
+
throw new Error(`Claude settings witness ${reason}`);
|
|
38219
|
+
}
|
|
38220
|
+
function absolutePath(value) {
|
|
38221
|
+
need(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_SETTINGS_WITNESS_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute3(value) && resolve2(value) === value, "requires a normalized absolute path");
|
|
38222
|
+
}
|
|
38223
|
+
function parents(path) {
|
|
38224
|
+
const result = [];
|
|
38225
|
+
for (let at = dirname4(path);; at = dirname4(at)) {
|
|
38226
|
+
const stat = lstatSync5(at, { bigint: true });
|
|
38227
|
+
need(stat.isDirectory() && !stat.isSymbolicLink(), "path traverses a symlink or non-directory");
|
|
38228
|
+
result.push([at, stat]);
|
|
38229
|
+
if (at === dirname4(at))
|
|
38230
|
+
return result;
|
|
38231
|
+
}
|
|
38232
|
+
}
|
|
38233
|
+
function readNativeSettingsWitnessFile(path, budget, filename = "settings.json") {
|
|
38234
|
+
absolutePath(path);
|
|
38235
|
+
need(basename3(path) === filename, `requires ${filename}`);
|
|
38236
|
+
need(Number.isSafeInteger(budget.remaining) && budget.remaining >= 0, "has an invalid byte budget");
|
|
38237
|
+
const ancestors = parents(path), initial = lstatSync5(path, { bigint: true });
|
|
38238
|
+
need(initial.isFile() && !initial.isSymbolicLink() && initial.size <= BigInt(CLAUDE_SETTINGS_WITNESS_LIMITS.bytes), "is not a bounded regular file");
|
|
38239
|
+
need(initial.size <= BigInt(budget.remaining), "exceeds its aggregate byte limit");
|
|
38240
|
+
const fd = openSync5(path, constants2.O_RDONLY | constants2.O_NOFOLLOW | constants2.O_NONBLOCK);
|
|
38241
|
+
try {
|
|
38242
|
+
const opened = fstatSync5(fd, { bigint: true });
|
|
38243
|
+
need(opened.isFile() && sameFile(initial, opened), "changed during open");
|
|
38244
|
+
const bytes = Buffer.alloc(Number(opened.size) + 1);
|
|
38245
|
+
let length = 0;
|
|
38246
|
+
while (length < bytes.length) {
|
|
38247
|
+
const count = readSync2(fd, bytes, length, bytes.length - length, null);
|
|
38248
|
+
if (!count)
|
|
38249
|
+
break;
|
|
38250
|
+
length += count;
|
|
38251
|
+
}
|
|
38252
|
+
const after = fstatSync5(fd, { bigint: true }), current = lstatSync5(path, { bigint: true });
|
|
38253
|
+
need(current.isFile() && sameFile(opened, after) && sameFile(after, current) && BigInt(length) === opened.size, "changed during read");
|
|
38254
|
+
for (const [ancestor, before] of ancestors) {
|
|
38255
|
+
const now = lstatSync5(ancestor, { bigint: true });
|
|
38256
|
+
need(now.isDirectory() && before.dev === now.dev && before.ino === now.ino && before.mode === now.mode, "parent changed during read");
|
|
38257
|
+
}
|
|
38258
|
+
budget.remaining -= length;
|
|
38259
|
+
try {
|
|
38260
|
+
return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes.subarray(0, length));
|
|
38261
|
+
} catch {
|
|
38262
|
+
throw new Error("Claude settings witness is not strict UTF-8");
|
|
38263
|
+
}
|
|
38264
|
+
} finally {
|
|
38265
|
+
closeSync5(fd);
|
|
38266
|
+
}
|
|
38267
|
+
}
|
|
38268
|
+
function parse6(text) {
|
|
38269
|
+
let at = 0, nodes = 0;
|
|
38270
|
+
const numberPattern = /-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?/y;
|
|
38271
|
+
const space = () => {
|
|
38272
|
+
while (at < text.length && /[\x20\t\r\n]/.test(text[at]))
|
|
38273
|
+
at++;
|
|
38274
|
+
};
|
|
38275
|
+
function string5() {
|
|
38276
|
+
need(text[at] === '"', "contains invalid JSON");
|
|
38277
|
+
const start = at++;
|
|
38278
|
+
while (at < text.length) {
|
|
38279
|
+
const character = text[at++];
|
|
38280
|
+
if (character === '"') {
|
|
38281
|
+
let value2;
|
|
38282
|
+
try {
|
|
38283
|
+
value2 = JSON.parse(text.slice(start, at));
|
|
38284
|
+
} catch {
|
|
38285
|
+
throw new Error("Claude settings witness contains invalid JSON string");
|
|
38286
|
+
}
|
|
38287
|
+
need(value2.length <= CLAUDE_SETTINGS_WITNESS_LIMITS.stringCharacters, "exceeds its string limit");
|
|
38288
|
+
return value2;
|
|
38289
|
+
}
|
|
38290
|
+
if (character === "\\")
|
|
38291
|
+
at++;
|
|
38292
|
+
}
|
|
38293
|
+
throw new Error("Claude settings witness contains an unterminated JSON string");
|
|
38294
|
+
}
|
|
38295
|
+
function value(depth) {
|
|
38296
|
+
need(depth <= CLAUDE_SETTINGS_WITNESS_LIMITS.depth && ++nodes <= CLAUDE_SETTINGS_WITNESS_LIMITS.nodes, "exceeds its nesting or node limit");
|
|
38297
|
+
space();
|
|
38298
|
+
const character = text[at];
|
|
38299
|
+
if (character === '"')
|
|
38300
|
+
return { kind: "string", value: string5() };
|
|
38301
|
+
if (character === "{" || character === "[") {
|
|
38302
|
+
at++;
|
|
38303
|
+
space();
|
|
38304
|
+
const object4 = character === "{", end = object4 ? "}" : "]", entries = [], items = [], keys = new Set;
|
|
38305
|
+
if (text[at] !== end)
|
|
38306
|
+
while (true) {
|
|
38307
|
+
if (object4) {
|
|
38308
|
+
space();
|
|
38309
|
+
const key = string5();
|
|
38310
|
+
need(!keys.has(key), "contains a duplicate JSON key");
|
|
38311
|
+
keys.add(key);
|
|
38312
|
+
space();
|
|
38313
|
+
need(text[at++] === ":", "contains invalid JSON");
|
|
38314
|
+
entries.push([key, value(depth + 1)]);
|
|
38315
|
+
} else
|
|
38316
|
+
items.push(value(depth + 1));
|
|
38317
|
+
space();
|
|
38318
|
+
if (text[at] === end)
|
|
38319
|
+
break;
|
|
38320
|
+
need(text[at++] === ",", "contains invalid JSON");
|
|
38321
|
+
}
|
|
38322
|
+
at++;
|
|
38323
|
+
return object4 ? { kind: "object", entries } : { kind: "array", items };
|
|
38324
|
+
}
|
|
38325
|
+
for (const literal3 of ["true", "false", "null"])
|
|
38326
|
+
if (text.startsWith(literal3, at)) {
|
|
38327
|
+
at += literal3.length;
|
|
38328
|
+
return { kind: "literal", value: literal3 };
|
|
38329
|
+
}
|
|
38330
|
+
numberPattern.lastIndex = at;
|
|
38331
|
+
const number5 = numberPattern.exec(text);
|
|
38332
|
+
need(number5, "contains invalid JSON");
|
|
38333
|
+
at += number5[0].length;
|
|
38334
|
+
return { kind: "number", value: number5[0] };
|
|
38335
|
+
}
|
|
38336
|
+
const root = value(0);
|
|
38337
|
+
space();
|
|
38338
|
+
need(at === text.length && root.kind === "object", "requires a JSON object without trailing content");
|
|
38339
|
+
need(root.entries.length <= CLAUDE_SETTINGS_WITNESS_LIMITS.rows, "exceeds its settings field limit");
|
|
38340
|
+
return root;
|
|
38341
|
+
}
|
|
38342
|
+
function canonical(value) {
|
|
38343
|
+
if (value.kind === "object")
|
|
38344
|
+
return { kind: "object", entries: value.entries.map(([key, child]) => [key, canonical(child)]).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0) };
|
|
38345
|
+
if (value.kind === "array")
|
|
38346
|
+
return { kind: "array", items: value.items.map(canonical) };
|
|
38347
|
+
return value;
|
|
38348
|
+
}
|
|
38349
|
+
function inferencePreference(key, child, version2) {
|
|
38350
|
+
if (key === "skipDangerousModePermissionPrompt") {
|
|
38351
|
+
need(child.kind === "literal" && (child.value === "true" || child.value === "false"), "contains an invalid dialog acknowledgment");
|
|
38352
|
+
return false;
|
|
38353
|
+
}
|
|
38354
|
+
if (key === "effortLevel") {
|
|
38355
|
+
need(child.kind === "string" && PERSISTED_EFFORT_LEVELS.has(child.value), "contains an invalid persisted effort level");
|
|
38356
|
+
return true;
|
|
38357
|
+
}
|
|
38358
|
+
if (key !== "modelSettings")
|
|
38359
|
+
return false;
|
|
38360
|
+
need(child.kind === "object", "requires an object of model preferences");
|
|
38361
|
+
child.entries = child.entries.filter(([model, preferences]) => {
|
|
38362
|
+
if (version2 === 2 && !BUILTIN_MODEL_SELECTIONS.has(model) || preferences.kind !== "object" || preferences.entries.length !== 1 || preferences.entries[0][0] !== "effortLevel")
|
|
38363
|
+
return true;
|
|
38364
|
+
const effort = preferences.entries[0][1];
|
|
38365
|
+
need(effort.kind === "string" && PERSISTED_EFFORT_LEVELS.has(effort.value), "contains an invalid persisted model effort level");
|
|
38366
|
+
return false;
|
|
38367
|
+
});
|
|
38368
|
+
return child.entries.length === 0;
|
|
38369
|
+
}
|
|
38370
|
+
function settingsDigest(text, version2 = 1) {
|
|
38371
|
+
const value = parse6(text);
|
|
38372
|
+
value.entries = value.entries.filter(([key, child]) => {
|
|
38373
|
+
if (version2 !== 1 && inferencePreference(key, child, version2))
|
|
38374
|
+
return false;
|
|
38375
|
+
if (key === "model") {
|
|
38376
|
+
need(child.kind === "string", "contains an invalid model selection");
|
|
38377
|
+
return !BUILTIN_MODEL_SELECTIONS.has(child.value);
|
|
38378
|
+
}
|
|
38379
|
+
if (BOOLEAN_PREFERENCES.has(key)) {
|
|
38380
|
+
need(child.kind === "literal" && (child.value === "true" || child.value === "false"), "contains an invalid display preference");
|
|
38381
|
+
return false;
|
|
38382
|
+
}
|
|
38383
|
+
if (Object.hasOwn(ENUM_PREFERENCES, key)) {
|
|
38384
|
+
need(child.kind === "string" && ENUM_PREFERENCES[key].includes(child.value), "contains an invalid display preference");
|
|
38385
|
+
return false;
|
|
38386
|
+
}
|
|
38387
|
+
return true;
|
|
38388
|
+
});
|
|
38389
|
+
return createHash2("sha256").update(`hasna.skills.claude-settings.v${version2}\x00`).update(JSON.stringify(canonical(value))).digest("hex");
|
|
38390
|
+
}
|
|
38391
|
+
function hashClaudeSettingsReplacement(text, budget) {
|
|
38392
|
+
need(typeof text === "string", "requires settings text");
|
|
38393
|
+
const bytes = Buffer.byteLength(text);
|
|
38394
|
+
need(bytes <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes && Number.isSafeInteger(budget.remaining) && budget.remaining >= bytes, "exceeds its byte limit");
|
|
38395
|
+
budget.remaining -= bytes;
|
|
38396
|
+
return settingsDigest(text);
|
|
38397
|
+
}
|
|
38398
|
+
function captureClaudeSettings(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
38399
|
+
return { path, hashMode: "claude-settings-v1", sha256: settingsDigest(readNativeSettingsWitnessFile(path, budget)) };
|
|
38400
|
+
}
|
|
38401
|
+
function captureClaudeSettingsV2(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
38402
|
+
return { path, hashMode: "claude-settings-v2", sha256: settingsDigest(readNativeSettingsWitnessFile(path, budget), 2) };
|
|
38403
|
+
}
|
|
38404
|
+
function hashClaudeSettingsReplacementV2(text, budget) {
|
|
38405
|
+
need(typeof text === "string", "requires settings text");
|
|
38406
|
+
const bytes = Buffer.byteLength(text);
|
|
38407
|
+
need(bytes <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes && Number.isSafeInteger(budget.remaining) && budget.remaining >= bytes, "exceeds its byte limit");
|
|
38408
|
+
budget.remaining -= bytes;
|
|
38409
|
+
return settingsDigest(text, 2);
|
|
38410
|
+
}
|
|
38411
|
+
function captureClaudeSettingsV3(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
38412
|
+
return { path, hashMode: "claude-settings-v3", sha256: settingsDigest(readNativeSettingsWitnessFile(path, budget), 3) };
|
|
38413
|
+
}
|
|
38414
|
+
function hashClaudeSettingsReplacementV3(text, budget) {
|
|
38415
|
+
need(typeof text === "string", "requires settings text");
|
|
38416
|
+
const bytes = Buffer.byteLength(text);
|
|
38417
|
+
need(bytes <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes && Number.isSafeInteger(budget.remaining) && budget.remaining >= bytes, "exceeds its byte limit");
|
|
38418
|
+
budget.remaining -= bytes;
|
|
38419
|
+
return settingsDigest(text, 3);
|
|
38420
|
+
}
|
|
38421
|
+
function hashNativeJsonControls(text, excludedMetadata) {
|
|
38422
|
+
need(Buffer.byteLength(text) <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes, "exceeds its byte limit");
|
|
38423
|
+
const value = parse6(text);
|
|
38424
|
+
value.entries = value.entries.filter(([key, child]) => {
|
|
38425
|
+
if (key !== excludedMetadata)
|
|
38426
|
+
return true;
|
|
38427
|
+
need(child.kind === "string" && child.value.length <= 128, "has invalid version metadata");
|
|
38428
|
+
return false;
|
|
38429
|
+
});
|
|
38430
|
+
return createHash2("sha256").update("hasna.skills.native-json-controls.v1\x00").update(JSON.stringify(canonical(value))).digest("hex");
|
|
38431
|
+
}
|
|
38432
|
+
function hashSumiNativeJsonControls(text) {
|
|
38433
|
+
need(Buffer.byteLength(text) <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes, "exceeds its byte limit");
|
|
38434
|
+
const value = parse6(text);
|
|
38435
|
+
value.entries = value.entries.filter(([key, child]) => {
|
|
38436
|
+
if (key === "$schema" || key === "username") {
|
|
38437
|
+
need(child.kind === "string", "has invalid Sumi display metadata");
|
|
38438
|
+
return false;
|
|
38439
|
+
}
|
|
38440
|
+
if (key !== "experimental")
|
|
38441
|
+
return true;
|
|
38442
|
+
need(child.kind === "object", "requires Sumi experimental controls to be an object");
|
|
38443
|
+
child.entries = child.entries.filter(([name, option]) => {
|
|
38444
|
+
if (name !== "statusline" && name !== "compact_tools")
|
|
38445
|
+
return true;
|
|
38446
|
+
need(option.kind === "literal" && (option.value === "true" || option.value === "false"), "has invalid Sumi display preference");
|
|
38447
|
+
return false;
|
|
38448
|
+
});
|
|
38449
|
+
return child.entries.length > 0;
|
|
38450
|
+
});
|
|
38451
|
+
return createHash2("sha256").update("hasna.skills.sumi-settings.v1\x00").update(JSON.stringify(value)).digest("hex");
|
|
38452
|
+
}
|
|
38453
|
+
var CLAUDE_SETTINGS_WITNESS_LIMITS, sameFile = (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, BOOLEAN_PREFERENCES, ENUM_PREFERENCES, BUILTIN_MODEL_SELECTIONS, PERSISTED_EFFORT_LEVELS;
|
|
38454
|
+
var init_claude_settings_witness = __esm(() => {
|
|
38455
|
+
CLAUDE_SETTINGS_WITNESS_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
|
|
38456
|
+
BOOLEAN_PREFERENCES = new Set([
|
|
38457
|
+
"autoScrollEnabled",
|
|
38458
|
+
"axScreenReader",
|
|
38459
|
+
"emojiCompletionEnabled",
|
|
38460
|
+
"prefersReducedMotion",
|
|
38461
|
+
"showTurnDuration",
|
|
38462
|
+
"spinnerTipsEnabled",
|
|
38463
|
+
"syntaxHighlightingDisabled",
|
|
38464
|
+
"terminalProgressBarEnabled",
|
|
38465
|
+
"terminalTitleFromRename",
|
|
38466
|
+
"verbose",
|
|
38467
|
+
"wheelScrollAccelerationEnabled"
|
|
38468
|
+
]);
|
|
38469
|
+
ENUM_PREFERENCES = Object.freeze({
|
|
38470
|
+
editorMode: ["normal", "vim"],
|
|
38471
|
+
tui: ["default", "fullscreen"],
|
|
38472
|
+
viewMode: ["default", "verbose", "focus"]
|
|
38473
|
+
});
|
|
38474
|
+
BUILTIN_MODEL_SELECTIONS = new Set([
|
|
38475
|
+
"default",
|
|
38476
|
+
"best",
|
|
38477
|
+
"fable",
|
|
38478
|
+
"fable[1m]",
|
|
38479
|
+
"sonnet",
|
|
38480
|
+
"sonnet[1m]",
|
|
38481
|
+
"opus",
|
|
38482
|
+
"opus[1m]",
|
|
38483
|
+
"haiku",
|
|
38484
|
+
"opusplan",
|
|
38485
|
+
"claude-fable-5-1",
|
|
38486
|
+
"claude-fable-5",
|
|
38487
|
+
"claude-fable-5[1m]",
|
|
38488
|
+
"claude-opus-5",
|
|
38489
|
+
"claude-sonnet-5",
|
|
38490
|
+
"claude-haiku-4-5-20251001",
|
|
38491
|
+
"claude-opus-4-6",
|
|
38492
|
+
"claude-sonnet-4-5",
|
|
38493
|
+
"claude-sonnet-4-5-20250929",
|
|
38494
|
+
"claude-opus-4-8",
|
|
38495
|
+
"claude-opus-4-8[1m]",
|
|
38496
|
+
"claude-opus-4-7",
|
|
38497
|
+
"claude-sonnet-4-6",
|
|
38498
|
+
"claude-opus-4-5-20251101",
|
|
38499
|
+
"claude-opus-4-5",
|
|
38500
|
+
"claude-haiku-4-5",
|
|
38501
|
+
"claude-fable-5-1[1m]",
|
|
38502
|
+
"claude-opus-5[1m]",
|
|
38503
|
+
"claude-opus-4-7[1m]",
|
|
38504
|
+
"claude-opus-4-6[1m]",
|
|
38505
|
+
"claude-sonnet-4-6[1m]"
|
|
38506
|
+
]);
|
|
38507
|
+
PERSISTED_EFFORT_LEVELS = new Set(["low", "medium", "high", "xhigh"]);
|
|
38508
|
+
});
|
|
38509
|
+
|
|
38510
|
+
// src/lib/sumi-settings-witness.ts
|
|
38511
|
+
function hashSumiSettingsReplacement(text, limits) {
|
|
38512
|
+
const bytes = Buffer.byteLength(text);
|
|
38513
|
+
if (bytes > CLAUDE_SETTINGS_WITNESS_LIMITS.bytes || !Number.isSafeInteger(limits.remaining) || limits.remaining < bytes)
|
|
38514
|
+
throw new Error("Sumi settings witness exceeds its byte limit");
|
|
38515
|
+
limits.remaining -= bytes;
|
|
38516
|
+
return hashSumiNativeJsonControls(text);
|
|
38517
|
+
}
|
|
38518
|
+
function captureSumiSettings(path, limits = budget()) {
|
|
38519
|
+
return { path, hashMode: "sumi-settings-v1", sha256: hashSumiNativeJsonControls(readNativeSettingsWitnessFile(path, limits, "sumi.json")) };
|
|
38520
|
+
}
|
|
38521
|
+
var SUMI_DISCOVERY_PROJECTION_FIELDS, budget = () => ({ remaining: 256 * 1024 * 1024 });
|
|
38522
|
+
var init_sumi_settings_witness = __esm(() => {
|
|
38523
|
+
init_claude_settings_witness();
|
|
38524
|
+
SUMI_DISCOVERY_PROJECTION_FIELDS = ["skills", "plugin", "plugins", "permissions"];
|
|
38525
|
+
});
|
|
38526
|
+
|
|
38212
38527
|
// src/lib/agent-policy-limits.ts
|
|
38213
|
-
import { basename as
|
|
38528
|
+
import { basename as basename4, isAbsolute as isAbsolute4, join as join10, resolve as resolve3, sep as sep3 } from "path";
|
|
38214
38529
|
function object4(value) {
|
|
38215
38530
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
38216
38531
|
}
|
|
@@ -38263,7 +38578,7 @@ function assertAgentPolicyCollections(policy) {
|
|
|
38263
38578
|
text(control.pluginId, 1024);
|
|
38264
38579
|
text(control.namespace, 64);
|
|
38265
38580
|
text(control.pluginParent);
|
|
38266
|
-
requireBound(
|
|
38581
|
+
requireBound(isAbsolute4(control.pluginParent) && resolve3(control.pluginParent) === control.pluginParent && /^[a-f0-9]{64}$/.test(control.manifestSha256));
|
|
38267
38582
|
if (control.remotePluginId !== undefined)
|
|
38268
38583
|
requireBound(typeof control.remotePluginId === "string" && /^[A-Za-z0-9_~-]{1,1024}$/.test(control.remotePluginId));
|
|
38269
38584
|
if (control.skillsOnly !== undefined)
|
|
@@ -38281,7 +38596,7 @@ function assertAgentPolicyCollections(policy) {
|
|
|
38281
38596
|
text(control.pluginId, 1024);
|
|
38282
38597
|
text(control.namespace, 64);
|
|
38283
38598
|
text(control.pluginParent);
|
|
38284
|
-
requireBound(!ids.has(control.pluginId) &&
|
|
38599
|
+
requireBound(!ids.has(control.pluginId) && isAbsolute4(control.pluginParent) && resolve3(control.pluginParent) === control.pluginParent && ["local", "git", "npm"].includes(control.sourceType) && typeof control.sourceSha256 === "string" && /^[a-f0-9]{64}$/.test(control.sourceSha256));
|
|
38285
38600
|
ids.add(control.pluginId);
|
|
38286
38601
|
}
|
|
38287
38602
|
}
|
|
@@ -38306,15 +38621,15 @@ function assertAgentPolicyCollections(policy) {
|
|
|
38306
38621
|
requireBound(object4(value));
|
|
38307
38622
|
text(value.agent, 128);
|
|
38308
38623
|
if (value.codexRetiredMaterializations !== undefined) {
|
|
38309
|
-
const proof = record3(value.codexRetiredMaterializations, 3), roots = array3(proof.roots, AGENT_POLICY_LIMITS.discoveryRoots),
|
|
38310
|
-
requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && Object.keys(proof).every((key) => ["roots", "parents", "directories"].includes(key)) && roots.length +
|
|
38624
|
+
const proof = record3(value.codexRetiredMaterializations, 3), roots = array3(proof.roots, AGENT_POLICY_LIMITS.discoveryRoots), parents2 = proof.parents === undefined ? [] : array3(proof.parents, AGENT_POLICY_LIMITS.discoveryRoots);
|
|
38625
|
+
requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && Object.keys(proof).every((key) => ["roots", "parents", "directories"].includes(key)) && roots.length + parents2.length > 0 && new Set(roots).size === roots.length && new Set(parents2).size === parents2.length);
|
|
38311
38626
|
for (const root of roots) {
|
|
38312
38627
|
text(root);
|
|
38313
|
-
requireBound(
|
|
38628
|
+
requireBound(isAbsolute4(root) && resolve3(root) === root);
|
|
38314
38629
|
}
|
|
38315
|
-
for (const parent of
|
|
38630
|
+
for (const parent of parents2) {
|
|
38316
38631
|
text(parent);
|
|
38317
|
-
requireBound(
|
|
38632
|
+
requireBound(isAbsolute4(parent) && resolve3(parent) === parent);
|
|
38318
38633
|
}
|
|
38319
38634
|
for (const directory of array3(proof.directories, AGENT_POLICY_LIMITS.discoveryDirectories)) {
|
|
38320
38635
|
requireBound(object4(directory));
|
|
@@ -38334,7 +38649,7 @@ function assertAgentPolicyCollections(policy) {
|
|
|
38334
38649
|
text(input2.namespace, 64);
|
|
38335
38650
|
text(input2.pluginParent);
|
|
38336
38651
|
text(input2.sourceRoot);
|
|
38337
|
-
requireBound(!ids.has(input2.pluginId) && [input2.pluginParent, input2.sourceRoot].every((path) =>
|
|
38652
|
+
requireBound(!ids.has(input2.pluginId) && [input2.pluginParent, input2.sourceRoot].every((path) => isAbsolute4(path) && resolve3(path) === path) && typeof input2.sourceSha256 === "string" && /^[a-f0-9]{64}$/.test(input2.sourceSha256));
|
|
38338
38653
|
ids.add(input2.pluginId);
|
|
38339
38654
|
}
|
|
38340
38655
|
if (proof.directories !== undefined)
|
|
@@ -38351,13 +38666,17 @@ function assertAgentPolicyCollections(policy) {
|
|
|
38351
38666
|
text(source.path);
|
|
38352
38667
|
requireBound(source.sha256 === null || typeof source.sha256 === "string" && /^[a-f0-9]{64}$/.test(source.sha256));
|
|
38353
38668
|
if (source.hashMode !== undefined)
|
|
38354
|
-
requireBound(["bytes", "path-bytes", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1", "claude-settings-v2", "claude-settings-v3", "claude-marketplace-registry-v2", "codex-settings-v1", "codex-settings-v2", "codex-settings-v3", "codex-settings-v4"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
|
|
38669
|
+
requireBound(["bytes", "path-bytes", "claude-plugin-manifest-v1", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1", "claude-settings-v2", "claude-settings-v3", "claude-marketplace-registry-v2", "codex-settings-v1", "codex-settings-v2", "codex-settings-v3", "codex-settings-v4", "sumi-settings-v1"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
|
|
38670
|
+
if (source.hashMode === "claude-plugin-manifest-v1")
|
|
38671
|
+
requireBound(agent === "claude" && value.agent === "claude" && ["automatic", "reviewed"].includes(value.method) && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute4(source.path) && resolve3(source.path) === source.path && source.path.endsWith(join10(sep3, ".claude-plugin", "plugin.json")) && source.managedPlugins === undefined);
|
|
38672
|
+
if (source.hashMode === "sumi-settings-v1")
|
|
38673
|
+
requireBound(agent === "sumi" && value.agent === "sumi" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute4(source.path) && resolve3(source.path) === source.path && basename4(source.path) === "sumi.json");
|
|
38355
38674
|
if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4"))
|
|
38356
|
-
requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) &&
|
|
38675
|
+
requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute4(source.path) && resolve3(source.path) === source.path && basename4(source.path) === "config.toml");
|
|
38357
38676
|
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3")
|
|
38358
|
-
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) &&
|
|
38677
|
+
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute4(source.path) && resolve3(source.path) === source.path && basename4(source.path) === "settings.json");
|
|
38359
38678
|
if (source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2")
|
|
38360
|
-
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) &&
|
|
38679
|
+
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute4(source.path) && resolve3(source.path) === source.path && basename4(source.path) === "known_marketplaces.json");
|
|
38361
38680
|
if (source.hashMode === "claude-plugin-registry") {
|
|
38362
38681
|
requireBound(agent === "claude");
|
|
38363
38682
|
const managed = array3(source.managedPlugins, 64);
|
|
@@ -42069,10 +42388,10 @@ var require_resolve_block_map = __commonJS((exports) => {
|
|
|
42069
42388
|
let offset = bm.offset;
|
|
42070
42389
|
let commentEnd = null;
|
|
42071
42390
|
for (const collItem of bm.items) {
|
|
42072
|
-
const { start, key, sep:
|
|
42391
|
+
const { start, key, sep: sep4, value } = collItem;
|
|
42073
42392
|
const keyProps = resolveProps.resolveProps(start, {
|
|
42074
42393
|
indicator: "explicit-key-ind",
|
|
42075
|
-
next: key ??
|
|
42394
|
+
next: key ?? sep4?.[0],
|
|
42076
42395
|
offset,
|
|
42077
42396
|
onError,
|
|
42078
42397
|
parentIndent: bm.indent,
|
|
@@ -42086,7 +42405,7 @@ var require_resolve_block_map = __commonJS((exports) => {
|
|
|
42086
42405
|
else if ("indent" in key && key.indent !== bm.indent)
|
|
42087
42406
|
onError(offset, "BAD_INDENT", startColMsg);
|
|
42088
42407
|
}
|
|
42089
|
-
if (!keyProps.anchor && !keyProps.tag && !
|
|
42408
|
+
if (!keyProps.anchor && !keyProps.tag && !sep4) {
|
|
42090
42409
|
commentEnd = keyProps.end;
|
|
42091
42410
|
if (keyProps.comment) {
|
|
42092
42411
|
if (map3.comment)
|
|
@@ -42111,7 +42430,7 @@ var require_resolve_block_map = __commonJS((exports) => {
|
|
|
42111
42430
|
ctx.atKey = false;
|
|
42112
42431
|
if (utilMapIncludes.mapIncludes(ctx, map3.items, keyNode))
|
|
42113
42432
|
onError(keyStart, "DUPLICATE_KEY", "Map keys must be unique");
|
|
42114
|
-
const valueProps = resolveProps.resolveProps(
|
|
42433
|
+
const valueProps = resolveProps.resolveProps(sep4 ?? [], {
|
|
42115
42434
|
indicator: "map-value-ind",
|
|
42116
42435
|
next: value,
|
|
42117
42436
|
offset: keyNode.range[2],
|
|
@@ -42127,7 +42446,7 @@ var require_resolve_block_map = __commonJS((exports) => {
|
|
|
42127
42446
|
if (ctx.options.strict && keyProps.start < valueProps.found.offset - 1024)
|
|
42128
42447
|
onError(keyNode.range, "KEY_OVER_1024_CHARS", "The : indicator must be at most 1024 chars after the start of an implicit block mapping key");
|
|
42129
42448
|
}
|
|
42130
|
-
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : composeEmptyNode(ctx, offset,
|
|
42449
|
+
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : composeEmptyNode(ctx, offset, sep4, null, valueProps, onError);
|
|
42131
42450
|
if (ctx.schema.compat)
|
|
42132
42451
|
utilFlowIndentCheck.flowIndentCheck(bm.indent, value, onError);
|
|
42133
42452
|
offset = valueNode.range[2];
|
|
@@ -42213,7 +42532,7 @@ var require_resolve_end = __commonJS((exports) => {
|
|
|
42213
42532
|
let comment = "";
|
|
42214
42533
|
if (end) {
|
|
42215
42534
|
let hasSpace = false;
|
|
42216
|
-
let
|
|
42535
|
+
let sep4 = "";
|
|
42217
42536
|
for (const token of end) {
|
|
42218
42537
|
const { source, type } = token;
|
|
42219
42538
|
switch (type) {
|
|
@@ -42227,13 +42546,13 @@ var require_resolve_end = __commonJS((exports) => {
|
|
|
42227
42546
|
if (!comment)
|
|
42228
42547
|
comment = cb;
|
|
42229
42548
|
else
|
|
42230
|
-
comment +=
|
|
42231
|
-
|
|
42549
|
+
comment += sep4 + cb;
|
|
42550
|
+
sep4 = "";
|
|
42232
42551
|
break;
|
|
42233
42552
|
}
|
|
42234
42553
|
case "newline":
|
|
42235
42554
|
if (comment)
|
|
42236
|
-
|
|
42555
|
+
sep4 += source;
|
|
42237
42556
|
hasSpace = true;
|
|
42238
42557
|
break;
|
|
42239
42558
|
default:
|
|
@@ -42273,18 +42592,18 @@ var require_resolve_flow_collection = __commonJS((exports) => {
|
|
|
42273
42592
|
let offset = fc.offset + fc.start.source.length;
|
|
42274
42593
|
for (let i = 0;i < fc.items.length; ++i) {
|
|
42275
42594
|
const collItem = fc.items[i];
|
|
42276
|
-
const { start, key, sep:
|
|
42595
|
+
const { start, key, sep: sep4, value } = collItem;
|
|
42277
42596
|
const props = resolveProps.resolveProps(start, {
|
|
42278
42597
|
flow: fcName,
|
|
42279
42598
|
indicator: "explicit-key-ind",
|
|
42280
|
-
next: key ??
|
|
42599
|
+
next: key ?? sep4?.[0],
|
|
42281
42600
|
offset,
|
|
42282
42601
|
onError,
|
|
42283
42602
|
parentIndent: fc.indent,
|
|
42284
42603
|
startOnNewline: false
|
|
42285
42604
|
});
|
|
42286
42605
|
if (!props.found) {
|
|
42287
|
-
if (!props.anchor && !props.tag && !
|
|
42606
|
+
if (!props.anchor && !props.tag && !sep4 && !value) {
|
|
42288
42607
|
if (i === 0 && props.comma)
|
|
42289
42608
|
onError(props.comma, "UNEXPECTED_TOKEN", `Unexpected , in ${fcName}`);
|
|
42290
42609
|
else if (i < fc.items.length - 1)
|
|
@@ -42336,8 +42655,8 @@ var require_resolve_flow_collection = __commonJS((exports) => {
|
|
|
42336
42655
|
}
|
|
42337
42656
|
}
|
|
42338
42657
|
}
|
|
42339
|
-
if (!isMap && !
|
|
42340
|
-
const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end,
|
|
42658
|
+
if (!isMap && !sep4 && !props.found) {
|
|
42659
|
+
const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end, sep4, null, props, onError);
|
|
42341
42660
|
coll.items.push(valueNode);
|
|
42342
42661
|
offset = valueNode.range[2];
|
|
42343
42662
|
if (isBlock(value))
|
|
@@ -42349,7 +42668,7 @@ var require_resolve_flow_collection = __commonJS((exports) => {
|
|
|
42349
42668
|
if (isBlock(key))
|
|
42350
42669
|
onError(keyNode.range, "BLOCK_IN_FLOW", blockMsg);
|
|
42351
42670
|
ctx.atKey = false;
|
|
42352
|
-
const valueProps = resolveProps.resolveProps(
|
|
42671
|
+
const valueProps = resolveProps.resolveProps(sep4 ?? [], {
|
|
42353
42672
|
flow: fcName,
|
|
42354
42673
|
indicator: "map-value-ind",
|
|
42355
42674
|
next: value,
|
|
@@ -42360,8 +42679,8 @@ var require_resolve_flow_collection = __commonJS((exports) => {
|
|
|
42360
42679
|
});
|
|
42361
42680
|
if (valueProps.found) {
|
|
42362
42681
|
if (!isMap && !props.found && ctx.options.strict) {
|
|
42363
|
-
if (
|
|
42364
|
-
for (const st of
|
|
42682
|
+
if (sep4)
|
|
42683
|
+
for (const st of sep4) {
|
|
42365
42684
|
if (st === valueProps.found)
|
|
42366
42685
|
break;
|
|
42367
42686
|
if (st.type === "newline") {
|
|
@@ -42378,7 +42697,7 @@ var require_resolve_flow_collection = __commonJS((exports) => {
|
|
|
42378
42697
|
else
|
|
42379
42698
|
onError(valueProps.start, "MISSING_CHAR", `Missing , or : between ${fcName} items`);
|
|
42380
42699
|
}
|
|
42381
|
-
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : valueProps.found ? composeEmptyNode(ctx, valueProps.end,
|
|
42700
|
+
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : valueProps.found ? composeEmptyNode(ctx, valueProps.end, sep4, null, valueProps, onError) : null;
|
|
42382
42701
|
if (valueNode) {
|
|
42383
42702
|
if (isBlock(value))
|
|
42384
42703
|
onError(valueNode.range, "BLOCK_IN_FLOW", blockMsg);
|
|
@@ -42555,7 +42874,7 @@ var require_resolve_block_scalar = __commonJS((exports) => {
|
|
|
42555
42874
|
chompStart = i + 1;
|
|
42556
42875
|
}
|
|
42557
42876
|
let value = "";
|
|
42558
|
-
let
|
|
42877
|
+
let sep4 = "";
|
|
42559
42878
|
let prevMoreIndented = false;
|
|
42560
42879
|
for (let i = 0;i < contentStart; ++i)
|
|
42561
42880
|
value += lines[i][0].slice(trimIndent) + `
|
|
@@ -42573,33 +42892,33 @@ var require_resolve_block_scalar = __commonJS((exports) => {
|
|
|
42573
42892
|
indent = "";
|
|
42574
42893
|
}
|
|
42575
42894
|
if (type === Scalar.Scalar.BLOCK_LITERAL) {
|
|
42576
|
-
value +=
|
|
42577
|
-
|
|
42895
|
+
value += sep4 + indent.slice(trimIndent) + content;
|
|
42896
|
+
sep4 = `
|
|
42578
42897
|
`;
|
|
42579
42898
|
} else if (indent.length > trimIndent || content[0] === "\t") {
|
|
42580
|
-
if (
|
|
42581
|
-
|
|
42899
|
+
if (sep4 === " ")
|
|
42900
|
+
sep4 = `
|
|
42582
42901
|
`;
|
|
42583
|
-
else if (!prevMoreIndented &&
|
|
42902
|
+
else if (!prevMoreIndented && sep4 === `
|
|
42584
42903
|
`)
|
|
42585
|
-
|
|
42904
|
+
sep4 = `
|
|
42586
42905
|
|
|
42587
42906
|
`;
|
|
42588
|
-
value +=
|
|
42589
|
-
|
|
42907
|
+
value += sep4 + indent.slice(trimIndent) + content;
|
|
42908
|
+
sep4 = `
|
|
42590
42909
|
`;
|
|
42591
42910
|
prevMoreIndented = true;
|
|
42592
42911
|
} else if (content === "") {
|
|
42593
|
-
if (
|
|
42912
|
+
if (sep4 === `
|
|
42594
42913
|
`)
|
|
42595
42914
|
value += `
|
|
42596
42915
|
`;
|
|
42597
42916
|
else
|
|
42598
|
-
|
|
42917
|
+
sep4 = `
|
|
42599
42918
|
`;
|
|
42600
42919
|
} else {
|
|
42601
|
-
value +=
|
|
42602
|
-
|
|
42920
|
+
value += sep4 + content;
|
|
42921
|
+
sep4 = " ";
|
|
42603
42922
|
prevMoreIndented = false;
|
|
42604
42923
|
}
|
|
42605
42924
|
}
|
|
@@ -42780,27 +43099,27 @@ var require_resolve_flow_scalar = __commonJS((exports) => {
|
|
|
42780
43099
|
if (!match)
|
|
42781
43100
|
return source;
|
|
42782
43101
|
let res = match[1];
|
|
42783
|
-
let
|
|
43102
|
+
let sep4 = " ";
|
|
42784
43103
|
let pos = first.lastIndex;
|
|
42785
43104
|
line.lastIndex = pos;
|
|
42786
43105
|
while (match = line.exec(source)) {
|
|
42787
43106
|
if (match[1] === "") {
|
|
42788
|
-
if (
|
|
43107
|
+
if (sep4 === `
|
|
42789
43108
|
`)
|
|
42790
|
-
res +=
|
|
43109
|
+
res += sep4;
|
|
42791
43110
|
else
|
|
42792
|
-
|
|
43111
|
+
sep4 = `
|
|
42793
43112
|
`;
|
|
42794
43113
|
} else {
|
|
42795
|
-
res +=
|
|
42796
|
-
|
|
43114
|
+
res += sep4 + match[1];
|
|
43115
|
+
sep4 = " ";
|
|
42797
43116
|
}
|
|
42798
43117
|
pos = line.lastIndex;
|
|
42799
43118
|
}
|
|
42800
43119
|
const last = /[ \t]*(.*)/sy;
|
|
42801
43120
|
last.lastIndex = pos;
|
|
42802
43121
|
match = last.exec(source);
|
|
42803
|
-
return res +
|
|
43122
|
+
return res + sep4 + (match?.[1] ?? "");
|
|
42804
43123
|
}
|
|
42805
43124
|
function doubleQuotedValue(source, onError) {
|
|
42806
43125
|
let res = "";
|
|
@@ -43581,14 +43900,14 @@ var require_cst_stringify = __commonJS((exports) => {
|
|
|
43581
43900
|
}
|
|
43582
43901
|
}
|
|
43583
43902
|
}
|
|
43584
|
-
function stringifyItem({ start, key, sep:
|
|
43903
|
+
function stringifyItem({ start, key, sep: sep4, value }) {
|
|
43585
43904
|
let res = "";
|
|
43586
43905
|
for (const st of start)
|
|
43587
43906
|
res += st.source;
|
|
43588
43907
|
if (key)
|
|
43589
43908
|
res += stringifyToken(key);
|
|
43590
|
-
if (
|
|
43591
|
-
for (const st of
|
|
43909
|
+
if (sep4)
|
|
43910
|
+
for (const st of sep4)
|
|
43592
43911
|
res += st.source;
|
|
43593
43912
|
if (value)
|
|
43594
43913
|
res += stringifyToken(value);
|
|
@@ -44736,18 +45055,18 @@ var require_parser = __commonJS((exports) => {
|
|
|
44736
45055
|
if (this.type === "map-value-ind") {
|
|
44737
45056
|
const prev = getPrevProps(this.peek(2));
|
|
44738
45057
|
const start = getFirstKeyStartProps(prev);
|
|
44739
|
-
let
|
|
45058
|
+
let sep4;
|
|
44740
45059
|
if (scalar.end) {
|
|
44741
|
-
|
|
44742
|
-
|
|
45060
|
+
sep4 = scalar.end;
|
|
45061
|
+
sep4.push(this.sourceToken);
|
|
44743
45062
|
delete scalar.end;
|
|
44744
45063
|
} else
|
|
44745
|
-
|
|
45064
|
+
sep4 = [this.sourceToken];
|
|
44746
45065
|
const map3 = {
|
|
44747
45066
|
type: "block-map",
|
|
44748
45067
|
offset: scalar.offset,
|
|
44749
45068
|
indent: scalar.indent,
|
|
44750
|
-
items: [{ start, key: scalar, sep:
|
|
45069
|
+
items: [{ start, key: scalar, sep: sep4 }]
|
|
44751
45070
|
};
|
|
44752
45071
|
this.onKeyLine = true;
|
|
44753
45072
|
this.stack[this.stack.length - 1] = map3;
|
|
@@ -44901,15 +45220,15 @@ var require_parser = __commonJS((exports) => {
|
|
|
44901
45220
|
} else if (isFlowToken(it.key) && !includesToken(it.sep, "newline")) {
|
|
44902
45221
|
const start2 = getFirstKeyStartProps(it.start);
|
|
44903
45222
|
const key = it.key;
|
|
44904
|
-
const
|
|
44905
|
-
|
|
45223
|
+
const sep4 = it.sep;
|
|
45224
|
+
sep4.push(this.sourceToken);
|
|
44906
45225
|
delete it.key;
|
|
44907
45226
|
delete it.sep;
|
|
44908
45227
|
this.stack.push({
|
|
44909
45228
|
type: "block-map",
|
|
44910
45229
|
offset: this.offset,
|
|
44911
45230
|
indent: this.indent,
|
|
44912
|
-
items: [{ start: start2, key, sep:
|
|
45231
|
+
items: [{ start: start2, key, sep: sep4 }]
|
|
44913
45232
|
});
|
|
44914
45233
|
} else if (start.length > 0) {
|
|
44915
45234
|
it.sep = it.sep.concat(start, this.sourceToken);
|
|
@@ -45103,13 +45422,13 @@ var require_parser = __commonJS((exports) => {
|
|
|
45103
45422
|
const prev = getPrevProps(parent);
|
|
45104
45423
|
const start = getFirstKeyStartProps(prev);
|
|
45105
45424
|
fixFlowSeqItems(fc);
|
|
45106
|
-
const
|
|
45107
|
-
|
|
45425
|
+
const sep4 = fc.end.splice(1, fc.end.length);
|
|
45426
|
+
sep4.push(this.sourceToken);
|
|
45108
45427
|
const map3 = {
|
|
45109
45428
|
type: "block-map",
|
|
45110
45429
|
offset: fc.offset,
|
|
45111
45430
|
indent: fc.indent,
|
|
45112
|
-
items: [{ start, key: fc, sep:
|
|
45431
|
+
items: [{ start, key: fc, sep: sep4 }]
|
|
45113
45432
|
};
|
|
45114
45433
|
this.onKeyLine = true;
|
|
45115
45434
|
this.stack[this.stack.length - 1] = map3;
|
|
@@ -45285,7 +45604,7 @@ var require_public_api = __commonJS((exports) => {
|
|
|
45285
45604
|
}
|
|
45286
45605
|
return doc2;
|
|
45287
45606
|
}
|
|
45288
|
-
function
|
|
45607
|
+
function parse7(src, reviver, options) {
|
|
45289
45608
|
let _reviver = undefined;
|
|
45290
45609
|
if (typeof reviver === "function") {
|
|
45291
45610
|
_reviver = reviver;
|
|
@@ -45326,7 +45645,7 @@ var require_public_api = __commonJS((exports) => {
|
|
|
45326
45645
|
return value.toString(options);
|
|
45327
45646
|
return new Document.Document(value, _replacer, options).toString(options);
|
|
45328
45647
|
}
|
|
45329
|
-
exports.parse =
|
|
45648
|
+
exports.parse = parse7;
|
|
45330
45649
|
exports.parseAllDocuments = parseAllDocuments;
|
|
45331
45650
|
exports.parseDocument = parseDocument;
|
|
45332
45651
|
exports.stringify = stringify;
|
|
@@ -45382,7 +45701,7 @@ var init_dist = __esm(() => {
|
|
|
45382
45701
|
});
|
|
45383
45702
|
|
|
45384
45703
|
// src/lib/agent-hermes.ts
|
|
45385
|
-
import { dirname as
|
|
45704
|
+
import { dirname as dirname5, isAbsolute as isAbsolute5, join as join11, resolve as resolve4 } from "path";
|
|
45386
45705
|
function object5(value) {
|
|
45387
45706
|
return Boolean(value && typeof value === "object" && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null));
|
|
45388
45707
|
}
|
|
@@ -45416,7 +45735,7 @@ function assertHermesEnvironment(home) {
|
|
|
45416
45735
|
throw new Error(`NATIVE_SKILL_DRIFT: Hermes ${variable} requires a dedicated discovery adapter; unset it before using this adapter`);
|
|
45417
45736
|
}
|
|
45418
45737
|
const selected = process.env.HERMES_HOME?.trim();
|
|
45419
|
-
if (selected && (!
|
|
45738
|
+
if (selected && (!isAbsolute5(selected) || resolve4(selected) !== join11(resolve4(home), ".hermes")))
|
|
45420
45739
|
throw new Error("NATIVE_SKILL_DRIFT: custom Hermes homes/profiles require their own reviewed bridge");
|
|
45421
45740
|
if (process.env.HERMES_ENABLE_PROJECT_PLUGINS?.trim() && !["0", "false", "no", "off"].includes(process.env.HERMES_ENABLE_PROJECT_PLUGINS.trim().toLowerCase()))
|
|
45422
45741
|
throw new Error("NATIVE_SKILL_DRIFT: Hermes project plugins require a dedicated discovery review");
|
|
@@ -45426,189 +45745,189 @@ var init_agent_hermes = __esm(() => {
|
|
|
45426
45745
|
});
|
|
45427
45746
|
|
|
45428
45747
|
// src/lib/agent-discovery-directories.ts
|
|
45429
|
-
import { createHash as
|
|
45430
|
-
import { lstatSync as
|
|
45431
|
-
import { dirname as
|
|
45432
|
-
function
|
|
45748
|
+
import { createHash as createHash3 } from "crypto";
|
|
45749
|
+
import { lstatSync as lstatSync6, opendirSync } from "fs";
|
|
45750
|
+
import { dirname as dirname6, isAbsolute as isAbsolute6, join as join12, resolve as resolve5 } from "path";
|
|
45751
|
+
function need2(value, message) {
|
|
45433
45752
|
if (!value)
|
|
45434
45753
|
throw new Error(message);
|
|
45435
45754
|
}
|
|
45436
45755
|
function safe(path) {
|
|
45437
|
-
|
|
45438
|
-
for (let cursor = path;; cursor =
|
|
45439
|
-
|
|
45440
|
-
if (
|
|
45756
|
+
need2(typeof path === "string" && path.length <= AGENT_POLICY_LIMITS.pathCharacters && isAbsolute6(path) && resolve5(path) === path && !path.includes("\x00"), "Expected a canonical absolute discovery directory path");
|
|
45757
|
+
for (let cursor = path;; cursor = dirname6(cursor)) {
|
|
45758
|
+
need2(!lstatSync6(cursor, { throwIfNoEntry: false })?.isSymbolicLink(), "Refusing symlink native discovery directory");
|
|
45759
|
+
if (dirname6(cursor) === cursor)
|
|
45441
45760
|
break;
|
|
45442
45761
|
}
|
|
45443
45762
|
}
|
|
45444
45763
|
function same(before, after) {
|
|
45445
45764
|
return Boolean(after && after.isDirectory() && before.dev === after.dev && before.ino === after.ino && before.mtimeMs === after.mtimeMs && before.ctimeMs === after.ctimeMs);
|
|
45446
45765
|
}
|
|
45447
|
-
function capture(path,
|
|
45766
|
+
function capture(path, budget2, excludedRoots, omittedRoots = [], rows) {
|
|
45448
45767
|
safe(path);
|
|
45449
45768
|
if (omittedRoots.some((root2) => path === root2 || path.startsWith(root2 + "/")))
|
|
45450
45769
|
return { path, sha256: null };
|
|
45451
|
-
const root =
|
|
45770
|
+
const root = lstatSync6(path, { throwIfNoEntry: false });
|
|
45452
45771
|
if (!root)
|
|
45453
45772
|
return { path, sha256: null };
|
|
45454
|
-
|
|
45455
|
-
const hash2 =
|
|
45773
|
+
need2(root.isDirectory(), "Unsupported native discovery directory input");
|
|
45774
|
+
const hash2 = createHash3("sha256");
|
|
45456
45775
|
function walk(current, relative3, before, depth) {
|
|
45457
|
-
|
|
45776
|
+
need2(depth <= 64, "Native discovery directory depth limit exceeded");
|
|
45458
45777
|
const names = [], directory = opendirSync(current);
|
|
45459
45778
|
try {
|
|
45460
45779
|
for (let entry = directory.readSync();entry; entry = directory.readSync()) {
|
|
45461
|
-
|
|
45780
|
+
need2(++budget2.entries <= AGENT_POLICY_LIMITS.discoveryDirectoryEntries, "Native discovery directory entry limit exceeded");
|
|
45462
45781
|
names.push(entry.name);
|
|
45463
45782
|
}
|
|
45464
45783
|
} finally {
|
|
45465
45784
|
directory.closeSync();
|
|
45466
45785
|
}
|
|
45467
|
-
|
|
45786
|
+
need2(new Set(names).size === names.length, "Ambiguous native discovery directory names");
|
|
45468
45787
|
for (const name of names.sort()) {
|
|
45469
|
-
const child =
|
|
45788
|
+
const child = join12(current, name), childRelative = relative3 ? `${relative3}/${name}` : name;
|
|
45470
45789
|
if (omittedRoots.includes(child))
|
|
45471
45790
|
continue;
|
|
45472
|
-
|
|
45473
|
-
const stat =
|
|
45474
|
-
|
|
45791
|
+
need2(child.length <= AGENT_POLICY_LIMITS.pathCharacters, "Native discovery directory path limit exceeded");
|
|
45792
|
+
const stat = lstatSync6(child);
|
|
45793
|
+
need2(stat.isFile() || stat.isDirectory(), "Refusing symlink or special native discovery directory member");
|
|
45475
45794
|
const row = JSON.stringify([childRelative, stat.isDirectory() ? "directory" : "file"]) + `
|
|
45476
45795
|
`;
|
|
45477
|
-
|
|
45478
|
-
|
|
45796
|
+
budget2.bytes += Buffer.byteLength(row);
|
|
45797
|
+
need2(budget2.bytes <= AGENT_POLICY_LIMITS.discoveryDirectoryBytes, "Native discovery directory metadata limit exceeded");
|
|
45479
45798
|
hash2.update(row);
|
|
45480
45799
|
rows?.push(row);
|
|
45481
45800
|
if (stat.isDirectory() && !excludedRoots.includes(child))
|
|
45482
45801
|
walk(child, childRelative, stat, depth + 1);
|
|
45483
45802
|
}
|
|
45484
|
-
|
|
45803
|
+
need2(same(before, lstatSync6(current, { throwIfNoEntry: false })), "Native discovery directory changed while reading");
|
|
45485
45804
|
}
|
|
45486
45805
|
walk(path, "", root, 0);
|
|
45487
45806
|
safe(path);
|
|
45488
45807
|
return { path, sha256: hash2.digest("hex") };
|
|
45489
45808
|
}
|
|
45490
45809
|
function captureDiscoveryDirectoryProjection(paths, omittedRoots) {
|
|
45491
|
-
|
|
45492
|
-
|
|
45810
|
+
need2(Array.isArray(paths) && paths.length <= AGENT_POLICY_LIMITS.discoveryDirectories && new Set(paths).size === paths.length, "Invalid projected discovery directory collection");
|
|
45811
|
+
need2(omittedRoots.length <= AGENT_POLICY_LIMITS.discoveryRoots && new Set(omittedRoots).size === omittedRoots.length, "Invalid inactive discovery roots");
|
|
45493
45812
|
for (const root of omittedRoots)
|
|
45494
45813
|
safe(root);
|
|
45495
|
-
const
|
|
45814
|
+
const budget2 = { entries: 0, bytes: 0 };
|
|
45496
45815
|
return paths.map((path) => {
|
|
45497
45816
|
const entries = [];
|
|
45498
|
-
return { ...capture(path,
|
|
45817
|
+
return { ...capture(path, budget2, [], omittedRoots, entries), entries };
|
|
45499
45818
|
});
|
|
45500
45819
|
}
|
|
45501
45820
|
function verifyDiscoveryDirectoryProjection(directories, omittedRoots) {
|
|
45502
|
-
|
|
45821
|
+
need2(directories.length <= AGENT_POLICY_LIMITS.discoveryDirectories, "Invalid projected discovery directory collection");
|
|
45503
45822
|
let count = 0, bytes = 0;
|
|
45504
45823
|
const expected = directories.map((directory) => {
|
|
45505
45824
|
safe(directory.path);
|
|
45506
|
-
|
|
45507
|
-
const hash2 =
|
|
45825
|
+
need2(Array.isArray(directory.entries), "Missing reviewed directory membership inventory");
|
|
45826
|
+
const hash2 = createHash3("sha256");
|
|
45508
45827
|
const kept = [];
|
|
45509
45828
|
for (const row of directory.entries) {
|
|
45510
|
-
|
|
45829
|
+
need2(typeof row === "string" && ++count <= AGENT_POLICY_LIMITS.discoveryDirectoryEntries, "Invalid reviewed directory membership rows");
|
|
45511
45830
|
bytes += Buffer.byteLength(row);
|
|
45512
|
-
|
|
45831
|
+
need2(bytes <= AGENT_POLICY_LIMITS.discoveryDirectoryBytes, "Reviewed directory membership byte limit exceeded");
|
|
45513
45832
|
const value = JSON.parse(row);
|
|
45514
|
-
|
|
45833
|
+
need2(Array.isArray(value) && value.length === 2 && typeof value[0] === "string" && value[0] && !isAbsolute6(value[0]) && !value[0].split("/").some((part) => !part || part === "." || part === "..") && ["file", "directory"].includes(value[1]) && row === JSON.stringify(value) + `
|
|
45515
45834
|
`, "Invalid reviewed directory member");
|
|
45516
45835
|
hash2.update(row);
|
|
45517
|
-
const path =
|
|
45836
|
+
const path = join12(directory.path, value[0]);
|
|
45518
45837
|
if (!omittedRoots.some((root) => path === root || path.startsWith(root + "/")))
|
|
45519
45838
|
kept.push(row);
|
|
45520
45839
|
}
|
|
45521
|
-
|
|
45840
|
+
need2(directory.sha256 === null ? directory.entries.length === 0 : hash2.digest("hex") === directory.sha256, "Reviewed directory inventory does not match its fingerprint");
|
|
45522
45841
|
const absent = omittedRoots.some((root) => directory.path === root || directory.path.startsWith(root + "/"));
|
|
45523
|
-
return { path: directory.path, sha256: absent || directory.sha256 === null ? null :
|
|
45842
|
+
return { path: directory.path, sha256: absent || directory.sha256 === null ? null : createHash3("sha256").update(kept.join("")).digest("hex") };
|
|
45524
45843
|
});
|
|
45525
45844
|
const current = captureDiscoveryDirectoryProjection(directories.map((item) => item.path), omittedRoots);
|
|
45526
|
-
|
|
45845
|
+
need2(current.every((item, index) => item.sha256 === expected[index].sha256), "Native discovery directory membership changed outside retired Codex roots");
|
|
45527
45846
|
}
|
|
45528
45847
|
function captureDiscoveryDirectories(paths, excludedRoots = []) {
|
|
45529
|
-
|
|
45530
|
-
const
|
|
45848
|
+
need2(Array.isArray(paths) && paths.length <= AGENT_POLICY_LIMITS.discoveryDirectories && new Set(paths).size === paths.length, "Invalid native discovery directory collection");
|
|
45849
|
+
const budget2 = { entries: 0, bytes: 0 };
|
|
45531
45850
|
for (const root of excludedRoots)
|
|
45532
45851
|
safe(root);
|
|
45533
|
-
return paths.map((path) => capture(path,
|
|
45852
|
+
return paths.map((path) => capture(path, budget2, excludedRoots));
|
|
45534
45853
|
}
|
|
45535
45854
|
function verifyDiscoveryDirectories(directories, excludedRoots = []) {
|
|
45536
|
-
|
|
45855
|
+
need2(Array.isArray(directories) && directories.length <= AGENT_POLICY_LIMITS.discoveryDirectories, "Invalid native discovery directory collection");
|
|
45537
45856
|
for (const directory of directories)
|
|
45538
|
-
|
|
45857
|
+
need2(directory && typeof directory === "object" && (directory.sha256 === null || typeof directory.sha256 === "string" && /^[a-f0-9]{64}$/.test(directory.sha256)), "Invalid native discovery directory digest");
|
|
45539
45858
|
const current = captureDiscoveryDirectories(directories.map((directory) => directory.path), excludedRoots);
|
|
45540
45859
|
for (let i = 0;i < directories.length; i++)
|
|
45541
|
-
|
|
45860
|
+
need2(current[i].sha256 === directories[i].sha256, `Native discovery directory membership changed; run skills hook install with a fresh discovery review: ${directories[i].path}`);
|
|
45542
45861
|
}
|
|
45543
45862
|
var init_agent_discovery_directories = __esm(() => {
|
|
45544
45863
|
init_agent_policy_limits();
|
|
45545
45864
|
});
|
|
45546
45865
|
|
|
45547
45866
|
// src/lib/agent-discovery-bytes.ts
|
|
45548
|
-
import { createHash as
|
|
45549
|
-
import { closeSync as
|
|
45550
|
-
import { dirname as
|
|
45867
|
+
import { createHash as createHash4 } from "crypto";
|
|
45868
|
+
import { closeSync as closeSync6, constants as constants3, fstatSync as fstatSync6, lstatSync as lstatSync7, openSync as openSync6, readSync as readSync3 } from "fs";
|
|
45869
|
+
import { dirname as dirname7, isAbsolute as isAbsolute7, resolve as resolve6 } from "path";
|
|
45551
45870
|
function discoveryByteBudget() {
|
|
45552
45871
|
return { remaining: AGENT_POLICY_LIMITS.discoveryRawTotalBytes };
|
|
45553
45872
|
}
|
|
45554
45873
|
function safe2(path) {
|
|
45555
|
-
if (typeof path !== "string" || !
|
|
45874
|
+
if (typeof path !== "string" || !isAbsolute7(path) || path !== resolve6(path) || path.length > AGENT_POLICY_LIMITS.pathCharacters || path.includes("\x00"))
|
|
45556
45875
|
throw new Error("Expected a canonical absolute raw discovery path");
|
|
45557
|
-
for (let cursor = path;; cursor =
|
|
45558
|
-
if (
|
|
45876
|
+
for (let cursor = path;; cursor = dirname7(cursor)) {
|
|
45877
|
+
if (lstatSync7(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
45559
45878
|
throw new Error("Refusing symlink raw discovery input");
|
|
45560
|
-
if (
|
|
45879
|
+
if (dirname7(cursor) === cursor)
|
|
45561
45880
|
break;
|
|
45562
45881
|
}
|
|
45563
45882
|
}
|
|
45564
45883
|
function same2(left, right) {
|
|
45565
45884
|
return left.dev === right.dev && left.ino === right.ino && left.size === right.size && left.mtimeMs === right.mtimeMs && left.ctimeMs === right.ctimeMs;
|
|
45566
45885
|
}
|
|
45567
|
-
function consume(
|
|
45568
|
-
if (bytes >
|
|
45886
|
+
function consume(budget2, bytes) {
|
|
45887
|
+
if (bytes > budget2.remaining)
|
|
45569
45888
|
throw new Error("Raw discovery aggregate byte limit exceeded");
|
|
45570
|
-
|
|
45889
|
+
budget2.remaining -= bytes;
|
|
45571
45890
|
}
|
|
45572
|
-
function hashRawDiscoveryFile(path,
|
|
45891
|
+
function hashRawDiscoveryFile(path, budget2, changes) {
|
|
45573
45892
|
safe2(path);
|
|
45574
45893
|
if (changes?.has(path)) {
|
|
45575
45894
|
const text2 = changes.get(path), bytes = Buffer.byteLength(text2);
|
|
45576
45895
|
if (bytes > AGENT_POLICY_LIMITS.discoveryRawSourceBytes)
|
|
45577
45896
|
throw new Error("Raw discovery file byte limit exceeded");
|
|
45578
|
-
consume(
|
|
45579
|
-
return
|
|
45897
|
+
consume(budget2, bytes);
|
|
45898
|
+
return createHash4("sha256").update(text2).digest("hex");
|
|
45580
45899
|
}
|
|
45581
|
-
const initial =
|
|
45900
|
+
const initial = lstatSync7(path, { throwIfNoEntry: false });
|
|
45582
45901
|
if (!initial)
|
|
45583
45902
|
return null;
|
|
45584
45903
|
if (!initial.isFile() || initial.size > AGENT_POLICY_LIMITS.discoveryRawSourceBytes)
|
|
45585
45904
|
throw new Error("Unsupported or oversized raw discovery input");
|
|
45586
|
-
if (initial.size >
|
|
45905
|
+
if (initial.size > budget2.remaining)
|
|
45587
45906
|
throw new Error("Raw discovery aggregate byte limit exceeded");
|
|
45588
|
-
const fd =
|
|
45907
|
+
const fd = openSync6(path, constants3.O_RDONLY | constants3.O_NOFOLLOW | constants3.O_NONBLOCK);
|
|
45589
45908
|
try {
|
|
45590
|
-
const opened =
|
|
45909
|
+
const opened = fstatSync6(fd);
|
|
45591
45910
|
if (!opened.isFile() || !same2(initial, opened))
|
|
45592
45911
|
throw new Error("Raw discovery input changed during open");
|
|
45593
|
-
const hash2 =
|
|
45912
|
+
const hash2 = createHash4("sha256"), buffer = Buffer.alloc(64 * 1024);
|
|
45594
45913
|
let bytes = 0;
|
|
45595
45914
|
while (true) {
|
|
45596
|
-
const count =
|
|
45915
|
+
const count = readSync3(fd, buffer, 0, Math.min(buffer.length, AGENT_POLICY_LIMITS.discoveryRawSourceBytes - bytes + 1), null);
|
|
45597
45916
|
if (!count)
|
|
45598
45917
|
break;
|
|
45599
45918
|
bytes += count;
|
|
45600
45919
|
if (bytes > AGENT_POLICY_LIMITS.discoveryRawSourceBytes)
|
|
45601
45920
|
throw new Error("Raw discovery file byte limit exceeded");
|
|
45602
|
-
consume(
|
|
45921
|
+
consume(budget2, count);
|
|
45603
45922
|
hash2.update(buffer.subarray(0, count));
|
|
45604
45923
|
}
|
|
45605
|
-
const final =
|
|
45924
|
+
const final = fstatSync6(fd), current = lstatSync7(path, { throwIfNoEntry: false });
|
|
45606
45925
|
safe2(path);
|
|
45607
45926
|
if (!current?.isFile() || !same2(opened, final) || !same2(final, current) || bytes !== final.size)
|
|
45608
45927
|
throw new Error("Raw discovery input changed during read");
|
|
45609
45928
|
return hash2.digest("hex");
|
|
45610
45929
|
} finally {
|
|
45611
|
-
|
|
45930
|
+
closeSync6(fd);
|
|
45612
45931
|
}
|
|
45613
45932
|
}
|
|
45614
45933
|
var init_agent_discovery_bytes = __esm(() => {
|
|
@@ -45616,9 +45935,9 @@ var init_agent_discovery_bytes = __esm(() => {
|
|
|
45616
45935
|
});
|
|
45617
45936
|
|
|
45618
45937
|
// src/lib/agent-discovery-path-bytes.ts
|
|
45619
|
-
import { createHash as
|
|
45620
|
-
import { lstatSync as
|
|
45621
|
-
import { dirname as
|
|
45938
|
+
import { createHash as createHash5 } from "crypto";
|
|
45939
|
+
import { lstatSync as lstatSync8, readlinkSync } from "fs";
|
|
45940
|
+
import { dirname as dirname8, isAbsolute as isAbsolute8, join as join13, parse as parse7, resolve as resolve7, sep as sep4 } from "path";
|
|
45622
45941
|
function identity2(stat, mutable = false) {
|
|
45623
45942
|
return {
|
|
45624
45943
|
dev: String(stat.dev),
|
|
@@ -45629,14 +45948,14 @@ function identity2(stat, mutable = false) {
|
|
|
45629
45948
|
...mutable ? { size: String(stat.size), mtimeNs: String(stat.mtimeNs), ctimeNs: String(stat.ctimeNs) } : {}
|
|
45630
45949
|
};
|
|
45631
45950
|
}
|
|
45632
|
-
function
|
|
45633
|
-
if (typeof path !== "string" || !
|
|
45951
|
+
function canonical2(path) {
|
|
45952
|
+
if (typeof path !== "string" || !isAbsolute8(path) || path !== resolve7(path) || path.length > AGENT_POLICY_LIMITS.pathCharacters || path.includes("\x00") || Buffer.from(path).toString("utf8") !== path)
|
|
45634
45953
|
throw new Error("Expected a canonical absolute discovery path");
|
|
45635
45954
|
}
|
|
45636
45955
|
function trace(path) {
|
|
45637
|
-
|
|
45956
|
+
canonical2(path);
|
|
45638
45957
|
const rows = [], paths = [];
|
|
45639
|
-
let metadataBytes = 0, steps = 0, links = 0, cursor =
|
|
45958
|
+
let metadataBytes = 0, steps = 0, links = 0, cursor = parse7(path).root, pending = path.slice(cursor.length).split(sep4);
|
|
45640
45959
|
function record4(path2, row) {
|
|
45641
45960
|
const value = { path: path2, ...row };
|
|
45642
45961
|
metadataBytes += Buffer.byteLength(JSON.stringify(value));
|
|
@@ -45646,7 +45965,7 @@ function trace(path) {
|
|
|
45646
45965
|
paths.push(path2);
|
|
45647
45966
|
}
|
|
45648
45967
|
function root() {
|
|
45649
|
-
const stat =
|
|
45968
|
+
const stat = lstatSync8(cursor, { bigint: true });
|
|
45650
45969
|
if (!stat.isDirectory())
|
|
45651
45970
|
throw new Error("Unsupported discovery path root");
|
|
45652
45971
|
record4(cursor, { type: "directory", ...identity2(stat) });
|
|
@@ -45659,13 +45978,13 @@ function trace(path) {
|
|
|
45659
45978
|
if (!component || component === ".")
|
|
45660
45979
|
continue;
|
|
45661
45980
|
if (component === "..") {
|
|
45662
|
-
cursor =
|
|
45981
|
+
cursor = dirname8(cursor);
|
|
45663
45982
|
continue;
|
|
45664
45983
|
}
|
|
45665
|
-
const candidate =
|
|
45984
|
+
const candidate = join13(cursor, component);
|
|
45666
45985
|
if (candidate.length > AGENT_POLICY_LIMITS.pathCharacters)
|
|
45667
45986
|
throw new Error("Discovery resolved path length limit exceeded");
|
|
45668
|
-
const stat =
|
|
45987
|
+
const stat = lstatSync8(candidate, { bigint: true, throwIfNoEntry: false });
|
|
45669
45988
|
if (!stat) {
|
|
45670
45989
|
record4(candidate, { type: "missing", remaining: pending });
|
|
45671
45990
|
return { rows, paths, file: null, missing: candidate, metadataBytes };
|
|
@@ -45673,18 +45992,18 @@ function trace(path) {
|
|
|
45673
45992
|
if (stat.isSymbolicLink()) {
|
|
45674
45993
|
if (++links > AGENT_POLICY_LIMITS.discoveryPathLinks || stat.size > BigInt(AGENT_POLICY_LIMITS.pathCharacters))
|
|
45675
45994
|
throw new Error("Discovery path link limit exceeded");
|
|
45676
|
-
const rawTarget = readlinkSync(candidate, { encoding: "buffer" }), target = rawTarget.toString("utf8"), after =
|
|
45995
|
+
const rawTarget = readlinkSync(candidate, { encoding: "buffer" }), target = rawTarget.toString("utf8"), after = lstatSync8(candidate, { bigint: true });
|
|
45677
45996
|
if (!rawTarget.equals(Buffer.from(target, "utf8")))
|
|
45678
45997
|
throw new Error("Unsupported non-UTF8 discovery link target");
|
|
45679
45998
|
if (!target || target.includes("\x00") || Buffer.byteLength(target) > AGENT_POLICY_LIMITS.pathCharacters || !after.isSymbolicLink() || JSON.stringify(identity2(stat, true)) !== JSON.stringify(identity2(after, true)))
|
|
45680
45999
|
throw new Error("Discovery link changed during read");
|
|
45681
46000
|
record4(candidate, { type: "link", target, ...identity2(stat, true) });
|
|
45682
|
-
if (
|
|
45683
|
-
cursor =
|
|
46001
|
+
if (isAbsolute8(target)) {
|
|
46002
|
+
cursor = parse7(target).root;
|
|
45684
46003
|
root();
|
|
45685
46004
|
}
|
|
45686
|
-
const remainder =
|
|
45687
|
-
pending = [...remainder.split(
|
|
46005
|
+
const remainder = isAbsolute8(target) ? target.slice(parse7(target).root.length) : target;
|
|
46006
|
+
pending = [...remainder.split(sep4), ...pending];
|
|
45688
46007
|
if (pending.length + steps > AGENT_POLICY_LIMITS.discoveryPathSteps)
|
|
45689
46008
|
throw new Error("Discovery path step limit exceeded");
|
|
45690
46009
|
continue;
|
|
@@ -45703,12 +46022,12 @@ function trace(path) {
|
|
|
45703
46022
|
}
|
|
45704
46023
|
throw new Error("Unsupported directory discovery path input");
|
|
45705
46024
|
}
|
|
45706
|
-
function hashDiscoveryPathFile(path,
|
|
46025
|
+
function hashDiscoveryPathFile(path, budget2, changes) {
|
|
45707
46026
|
const before = trace(path);
|
|
45708
46027
|
let createsMissingPath = false;
|
|
45709
46028
|
if (before.missing !== null && changes) {
|
|
45710
46029
|
for (const target of changes.keys()) {
|
|
45711
|
-
if (target === before.missing || target.startsWith(before.missing +
|
|
46030
|
+
if (target === before.missing || target.startsWith(before.missing + sep4)) {
|
|
45712
46031
|
createsMissingPath = true;
|
|
45713
46032
|
break;
|
|
45714
46033
|
}
|
|
@@ -45716,27 +46035,165 @@ function hashDiscoveryPathFile(path, budget, changes) {
|
|
|
45716
46035
|
}
|
|
45717
46036
|
if (createsMissingPath || changes?.has(path) || before.paths.some((path2) => changes?.has(path2)))
|
|
45718
46037
|
throw new Error("Discovery path witness intersects a planned write; use bytes mode for owned configuration");
|
|
45719
|
-
const remaining =
|
|
46038
|
+
const remaining = budget2.pathMetadataRemaining ?? AGENT_POLICY_LIMITS.discoveryPathTotalMetadataBytes;
|
|
45720
46039
|
if (before.metadataBytes > remaining)
|
|
45721
46040
|
throw new Error("Discovery path aggregate metadata limit exceeded");
|
|
45722
|
-
|
|
45723
|
-
const content = before.file === null ? null : hashRawDiscoveryFile(before.file,
|
|
46041
|
+
budget2.pathMetadataRemaining = remaining - before.metadataBytes;
|
|
46042
|
+
const content = before.file === null ? null : hashRawDiscoveryFile(before.file, budget2);
|
|
45724
46043
|
if (before.file !== null && content === null)
|
|
45725
46044
|
throw new Error("Discovery path input changed during read");
|
|
45726
46045
|
const after = trace(path);
|
|
45727
46046
|
if (JSON.stringify(before.rows) !== JSON.stringify(after.rows) || before.file !== after.file)
|
|
45728
46047
|
throw new Error("Discovery path input changed during read");
|
|
45729
|
-
return
|
|
46048
|
+
return createHash5("sha256").update(JSON.stringify({ version: 1, path, rows: before.rows, content })).digest("hex");
|
|
45730
46049
|
}
|
|
45731
46050
|
var init_agent_discovery_path_bytes = __esm(() => {
|
|
45732
46051
|
init_agent_policy_limits();
|
|
45733
46052
|
init_agent_discovery_bytes();
|
|
45734
46053
|
});
|
|
45735
46054
|
|
|
46055
|
+
// src/lib/claude-plugin-manifest-witness.ts
|
|
46056
|
+
import { createHash as createHash6 } from "crypto";
|
|
46057
|
+
function requireValue(value, reason) {
|
|
46058
|
+
if (!value)
|
|
46059
|
+
throw new Error("Claude plugin manifest " + reason);
|
|
46060
|
+
}
|
|
46061
|
+
function parse8(text2) {
|
|
46062
|
+
requireValue(Buffer.byteLength(text2, "utf8") <= CLAUDE_PLUGIN_MANIFEST_LIMITS.bytes, "exceeds its byte limit");
|
|
46063
|
+
let at = 0, nodes = 0;
|
|
46064
|
+
const numberPattern = /-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?/y;
|
|
46065
|
+
const space = () => {
|
|
46066
|
+
while (at < text2.length && /[\x20\t\r\n]/.test(text2[at]))
|
|
46067
|
+
at++;
|
|
46068
|
+
};
|
|
46069
|
+
function string5() {
|
|
46070
|
+
requireValue(text2[at] === '"', "contains invalid JSON");
|
|
46071
|
+
const start = at++;
|
|
46072
|
+
while (at < text2.length) {
|
|
46073
|
+
const character = text2[at++];
|
|
46074
|
+
if (character === '"') {
|
|
46075
|
+
let value2;
|
|
46076
|
+
try {
|
|
46077
|
+
value2 = JSON.parse(text2.slice(start, at));
|
|
46078
|
+
} catch {
|
|
46079
|
+
throw new Error("Claude plugin manifest contains invalid JSON string");
|
|
46080
|
+
}
|
|
46081
|
+
requireValue(value2.length <= CLAUDE_PLUGIN_MANIFEST_LIMITS.stringCharacters, "exceeds its string limit");
|
|
46082
|
+
return value2;
|
|
46083
|
+
}
|
|
46084
|
+
if (character === "\\")
|
|
46085
|
+
at++;
|
|
46086
|
+
}
|
|
46087
|
+
throw new Error("Claude plugin manifest contains an unterminated JSON string");
|
|
46088
|
+
}
|
|
46089
|
+
function value(depth) {
|
|
46090
|
+
requireValue(depth <= CLAUDE_PLUGIN_MANIFEST_LIMITS.depth && ++nodes <= CLAUDE_PLUGIN_MANIFEST_LIMITS.nodes, "exceeds its nesting or node limit");
|
|
46091
|
+
space();
|
|
46092
|
+
const character = text2[at];
|
|
46093
|
+
if (character === '"')
|
|
46094
|
+
return { kind: "string", value: string5() };
|
|
46095
|
+
if (character === "{" || character === "[") {
|
|
46096
|
+
at++;
|
|
46097
|
+
space();
|
|
46098
|
+
const object6 = character === "{", end = object6 ? "}" : "]", entries = [], items = [], keys = new Set;
|
|
46099
|
+
if (text2[at] !== end)
|
|
46100
|
+
while (true) {
|
|
46101
|
+
if (object6) {
|
|
46102
|
+
space();
|
|
46103
|
+
const key = string5();
|
|
46104
|
+
requireValue(!keys.has(key), "contains a duplicate JSON key");
|
|
46105
|
+
keys.add(key);
|
|
46106
|
+
space();
|
|
46107
|
+
requireValue(text2[at++] === ":", "contains invalid JSON");
|
|
46108
|
+
entries.push([key, value(depth + 1)]);
|
|
46109
|
+
} else
|
|
46110
|
+
items.push(value(depth + 1));
|
|
46111
|
+
space();
|
|
46112
|
+
if (text2[at] === end)
|
|
46113
|
+
break;
|
|
46114
|
+
requireValue(text2[at++] === ",", "contains invalid JSON");
|
|
46115
|
+
}
|
|
46116
|
+
at++;
|
|
46117
|
+
return object6 ? { kind: "object", entries } : { kind: "array", items };
|
|
46118
|
+
}
|
|
46119
|
+
for (const literal3 of ["true", "false", "null"])
|
|
46120
|
+
if (text2.startsWith(literal3, at)) {
|
|
46121
|
+
at += literal3.length;
|
|
46122
|
+
return { kind: "literal", value: literal3 };
|
|
46123
|
+
}
|
|
46124
|
+
numberPattern.lastIndex = at;
|
|
46125
|
+
const number5 = numberPattern.exec(text2);
|
|
46126
|
+
requireValue(number5, "contains invalid JSON");
|
|
46127
|
+
at += number5[0].length;
|
|
46128
|
+
return { kind: "number", value: number5[0] };
|
|
46129
|
+
}
|
|
46130
|
+
const root = value(0);
|
|
46131
|
+
space();
|
|
46132
|
+
requireValue(at === text2.length && root.kind === "object", "requires a JSON object without trailing content");
|
|
46133
|
+
return root;
|
|
46134
|
+
}
|
|
46135
|
+
function canonical3(value) {
|
|
46136
|
+
if (value.kind === "string")
|
|
46137
|
+
return JSON.stringify(value.value);
|
|
46138
|
+
if (value.kind === "number")
|
|
46139
|
+
return value.value;
|
|
46140
|
+
if (value.kind === "literal")
|
|
46141
|
+
return value.value;
|
|
46142
|
+
if (value.kind === "array")
|
|
46143
|
+
return "[" + value.items.map(canonical3).join(",") + "]";
|
|
46144
|
+
return "{" + value.entries.map(([key, item]) => JSON.stringify(key) + ":" + canonical3(item)).join(",") + "}";
|
|
46145
|
+
}
|
|
46146
|
+
function validateText(value, field) {
|
|
46147
|
+
requireValue(value?.kind === "string" && value.value.length <= CLAUDE_PLUGIN_MANIFEST_LIMITS.stringCharacters, "has an invalid " + field + " field");
|
|
46148
|
+
}
|
|
46149
|
+
function validateDescriptiveFields(manifest) {
|
|
46150
|
+
const values = new Map(manifest.entries);
|
|
46151
|
+
for (const field of ["description", "version", "homepage", "license"]) {
|
|
46152
|
+
const value = values.get(field);
|
|
46153
|
+
if (value !== undefined)
|
|
46154
|
+
validateText(value, field);
|
|
46155
|
+
}
|
|
46156
|
+
const author = values.get("author");
|
|
46157
|
+
if (author !== undefined) {
|
|
46158
|
+
if (author.kind === "string")
|
|
46159
|
+
validateText(author, "author");
|
|
46160
|
+
else {
|
|
46161
|
+
requireValue(author.kind === "object" && author.entries.every(([key, value]) => ["name", "email", "url"].includes(key) && value.kind === "string" && value.value.length <= CLAUDE_PLUGIN_MANIFEST_LIMITS.stringCharacters), "has an invalid author field");
|
|
46162
|
+
}
|
|
46163
|
+
}
|
|
46164
|
+
const repository = values.get("repository");
|
|
46165
|
+
if (repository !== undefined) {
|
|
46166
|
+
if (repository.kind === "string")
|
|
46167
|
+
validateText(repository, "repository");
|
|
46168
|
+
else
|
|
46169
|
+
requireValue(repository.kind === "object" && repository.entries.every(([key, value]) => ["type", "url", "directory"].includes(key) && value.kind === "string" && value.value.length <= CLAUDE_PLUGIN_MANIFEST_LIMITS.stringCharacters), "has an invalid repository field");
|
|
46170
|
+
}
|
|
46171
|
+
const keywords = values.get("keywords");
|
|
46172
|
+
if (keywords !== undefined)
|
|
46173
|
+
requireValue(keywords.kind === "array" && keywords.items.every((value) => value.kind === "string" && value.value.length <= CLAUDE_PLUGIN_MANIFEST_LIMITS.stringCharacters), "has an invalid keywords field");
|
|
46174
|
+
}
|
|
46175
|
+
function hashClaudePluginManifest(text2) {
|
|
46176
|
+
const manifest = parse8(text2);
|
|
46177
|
+
validateDescriptiveFields(manifest);
|
|
46178
|
+
const discovery = { kind: "object", entries: manifest.entries.filter(([key]) => !DESCRIPTIVE_FIELDS.has(key)) };
|
|
46179
|
+
return createHash6("sha256").update(canonical3(discovery)).digest("hex");
|
|
46180
|
+
}
|
|
46181
|
+
function projectReviewedClaudePluginManifest(text2, reviewedSha256) {
|
|
46182
|
+
if (!/^[a-f0-9]{64}$/.test(reviewedSha256) || createHash6("sha256").update(text2).digest("hex") !== reviewedSha256) {
|
|
46183
|
+
throw new Error("Reviewed Claude plugin manifest changed before semantic projection");
|
|
46184
|
+
}
|
|
46185
|
+
return hashClaudePluginManifest(text2);
|
|
46186
|
+
}
|
|
46187
|
+
var CLAUDE_PLUGIN_MANIFEST_LIMITS, DESCRIPTIVE_FIELDS;
|
|
46188
|
+
var init_claude_plugin_manifest_witness = __esm(() => {
|
|
46189
|
+
CLAUDE_PLUGIN_MANIFEST_LIMITS = Object.freeze({ bytes: 1024 * 1024, depth: 32, nodes: 65536, stringCharacters: 16384 });
|
|
46190
|
+
DESCRIPTIVE_FIELDS = new Set(["description", "version", "author", "homepage", "repository", "license", "keywords"]);
|
|
46191
|
+
});
|
|
46192
|
+
|
|
45736
46193
|
// src/lib/skill-bundle.ts
|
|
45737
|
-
import { createHash as
|
|
46194
|
+
import { createHash as createHash7 } from "crypto";
|
|
45738
46195
|
import { readFileSync as readFileSync9, readdirSync as readdirSync4, statSync as statSync6 } from "fs";
|
|
45739
|
-
import { join as
|
|
46196
|
+
import { join as join14, relative as relative3 } from "path";
|
|
45740
46197
|
import { createGunzip } from "zlib";
|
|
45741
46198
|
function isDotenvFile(lower) {
|
|
45742
46199
|
if (lower === ".env" || lower.startsWith(".env."))
|
|
@@ -45766,7 +46223,7 @@ function ownBytes(view) {
|
|
|
45766
46223
|
return out;
|
|
45767
46224
|
}
|
|
45768
46225
|
function sha256Hex(bytes) {
|
|
45769
|
-
return
|
|
46226
|
+
return createHash7("sha256").update(bytes).digest("hex");
|
|
45770
46227
|
}
|
|
45771
46228
|
function collectSkillBundleEntries(dir) {
|
|
45772
46229
|
const entries = [];
|
|
@@ -45775,7 +46232,7 @@ function collectSkillBundleEntries(dir) {
|
|
|
45775
46232
|
}
|
|
45776
46233
|
function walk(root, current, out) {
|
|
45777
46234
|
for (const entry of readdirSync4(current, { withFileTypes: true })) {
|
|
45778
|
-
const absolute =
|
|
46235
|
+
const absolute = join14(current, entry.name);
|
|
45779
46236
|
const rel = relative3(root, absolute).split("\\").join("/");
|
|
45780
46237
|
const isRootLevel = !rel.includes("/");
|
|
45781
46238
|
if (ANY_SEGMENT_EXCLUDES.has(entry.name.toLowerCase()))
|
|
@@ -45944,7 +46401,7 @@ async function inspectSkillBundle(bundle, options = {}) {
|
|
|
45944
46401
|
parser2.push(chunk);
|
|
45945
46402
|
bytesSinceYield += chunk.byteLength;
|
|
45946
46403
|
if (bytesSinceYield >= 256 * 1024) {
|
|
45947
|
-
await new Promise((
|
|
46404
|
+
await new Promise((resolve8) => setTimeout(resolve8, 0));
|
|
45948
46405
|
bytesSinceYield = 0;
|
|
45949
46406
|
check2();
|
|
45950
46407
|
}
|
|
@@ -46301,24 +46758,24 @@ var init_profile_limits = __esm(() => {
|
|
|
46301
46758
|
});
|
|
46302
46759
|
|
|
46303
46760
|
// src/lib/selection-cache.ts
|
|
46304
|
-
import { createHash as
|
|
46761
|
+
import { createHash as createHash8, randomUUID } from "crypto";
|
|
46305
46762
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
46306
|
-
import { closeSync as
|
|
46763
|
+
import { closeSync as closeSync7, constants as constants4, fstatSync as fstatSync7, fsyncSync, linkSync, lstatSync as lstatSync9, mkdirSync as mkdirSync3, openSync as openSync7, readFileSync as readFileSync10, readlinkSync as readlinkSync2, readSync as readSync4, renameSync, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
|
|
46307
46764
|
import { hostname as hostname3 } from "os";
|
|
46308
|
-
import { dirname as
|
|
46765
|
+
import { dirname as dirname9, join as join15, parse as parse9, resolve as resolve8 } from "path";
|
|
46309
46766
|
import { isDeepStrictEqual } from "util";
|
|
46310
46767
|
function selectionCacheRoot(options = {}) {
|
|
46311
|
-
return
|
|
46768
|
+
return resolve8(options.cacheDir ?? join15(getDataDirReadOnly(), "selection-cache"));
|
|
46312
46769
|
}
|
|
46313
46770
|
function selectionKey(selection) {
|
|
46314
46771
|
validateSelection(selection);
|
|
46315
46772
|
return hash2([selection.authority, selection.workspaceId, selection.slug, selection.version, selection.bundleDigest]);
|
|
46316
46773
|
}
|
|
46317
46774
|
function hash2(value) {
|
|
46318
|
-
return
|
|
46775
|
+
return createHash8("sha256").update(JSON.stringify(value)).digest("hex");
|
|
46319
46776
|
}
|
|
46320
46777
|
function validateSelection(selection) {
|
|
46321
|
-
if (!selection || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(selection.slug) || !isValidSkillVersion(selection.version) || !/^sha256:[a-f0-9]{64}$/.test(selection.bundleDigest) || typeof selection.workspaceId !== "string" || !selection.workspaceId.trim() || typeof selection.profileRevision !== "string" || !selection.profileRevision.trim()) {
|
|
46778
|
+
if (!selection || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(selection.slug) || !isValidSkillVersion(selection.version) || !/^sha256:[a-f0-9]{64}$/.test(selection.bundleDigest) || typeof selection.workspaceId !== "string" || !selection.workspaceId.trim() || selection.authorizationEpoch !== undefined && (typeof selection.authorizationEpoch !== "string" || !/^[a-f0-9]{32}$/.test(selection.authorizationEpoch)) || typeof selection.profileRevision !== "string" || !selection.profileRevision.trim()) {
|
|
46322
46779
|
throw new SkillSelectionError("INVALID_SELECTION", "A skill selection must carry an exact version, digest, workspace and profile revision.");
|
|
46323
46780
|
}
|
|
46324
46781
|
const aliasError = selectionAliasError([selection]);
|
|
@@ -46352,17 +46809,17 @@ function validateResolvedProfile(profile, authority) {
|
|
|
46352
46809
|
}
|
|
46353
46810
|
function selectionBundlePath(selection, options = {}) {
|
|
46354
46811
|
validateSelection(selection);
|
|
46355
|
-
return
|
|
46812
|
+
return join15(selectionCacheRoot(options), "objects", hash2(selection.authority), hash2(selection.workspaceId), `${selection.bundleDigest.slice(7)}.tar.gz`);
|
|
46356
46813
|
}
|
|
46357
46814
|
function assertRegularPath(path, createParents = false) {
|
|
46358
|
-
const absolute =
|
|
46359
|
-
const root =
|
|
46815
|
+
const absolute = resolve8(path);
|
|
46816
|
+
const root = parse9(absolute).root;
|
|
46360
46817
|
let cursor = root;
|
|
46361
46818
|
const segments = absolute.slice(root.length).split("/");
|
|
46362
46819
|
for (let index = 0;index < segments.length; index++) {
|
|
46363
|
-
cursor =
|
|
46820
|
+
cursor = join15(cursor, segments[index]);
|
|
46364
46821
|
try {
|
|
46365
|
-
const stat =
|
|
46822
|
+
const stat = lstatSync9(cursor);
|
|
46366
46823
|
if (stat.isSymbolicLink() || index < segments.length - 1 && !stat.isDirectory()) {
|
|
46367
46824
|
throw new SkillSelectionError("UNSAFE_CACHE_PATH", "Skills cache paths must not traverse symlinks or non-directories.");
|
|
46368
46825
|
}
|
|
@@ -46378,20 +46835,20 @@ function readRegularFile(path, limit) {
|
|
|
46378
46835
|
assertRegularPath(path);
|
|
46379
46836
|
let fd;
|
|
46380
46837
|
try {
|
|
46381
|
-
fd =
|
|
46838
|
+
fd = openSync7(path, constants4.O_RDONLY | constants4.O_NOFOLLOW | constants4.O_NONBLOCK);
|
|
46382
46839
|
} catch (error61) {
|
|
46383
46840
|
if (error61.code === "ENOENT")
|
|
46384
46841
|
return null;
|
|
46385
46842
|
throw error61;
|
|
46386
46843
|
}
|
|
46387
46844
|
try {
|
|
46388
|
-
const stat =
|
|
46845
|
+
const stat = fstatSync7(fd);
|
|
46389
46846
|
if (!stat.isFile() || stat.size > limit)
|
|
46390
46847
|
throw new SkillSelectionError("INVALID_CACHE_FILE", "The Skills cache contains an invalid or oversized file.");
|
|
46391
46848
|
const bytes = Buffer.alloc(stat.size + 1);
|
|
46392
46849
|
let size = 0;
|
|
46393
46850
|
while (size < bytes.length) {
|
|
46394
|
-
const read =
|
|
46851
|
+
const read = readSync4(fd, bytes, size, bytes.length - size, null);
|
|
46395
46852
|
if (!read)
|
|
46396
46853
|
break;
|
|
46397
46854
|
size += read;
|
|
@@ -46400,7 +46857,7 @@ function readRegularFile(path, limit) {
|
|
|
46400
46857
|
throw new SkillSelectionError("INVALID_CACHE_FILE", "The Skills cache file grew during its bounded read.");
|
|
46401
46858
|
return bytes.subarray(0, size);
|
|
46402
46859
|
} finally {
|
|
46403
|
-
|
|
46860
|
+
closeSync7(fd);
|
|
46404
46861
|
}
|
|
46405
46862
|
}
|
|
46406
46863
|
function writeSelectionJson(path, value) {
|
|
@@ -46412,19 +46869,19 @@ function writeSelectionJson(path, value) {
|
|
|
46412
46869
|
}
|
|
46413
46870
|
function atomicWrite(path, bytes, mode, durable = false) {
|
|
46414
46871
|
assertRegularPath(path, true);
|
|
46415
|
-
const temporary =
|
|
46872
|
+
const temporary = join15(dirname9(path), `.selection-${randomUUID()}.tmp`);
|
|
46416
46873
|
try {
|
|
46417
|
-
const fd =
|
|
46874
|
+
const fd = openSync7(temporary, constants4.O_WRONLY | constants4.O_CREAT | constants4.O_EXCL | constants4.O_NOFOLLOW, mode);
|
|
46418
46875
|
try {
|
|
46419
46876
|
writeFileSync3(fd, bytes);
|
|
46420
46877
|
if (durable)
|
|
46421
46878
|
fsyncSync(fd);
|
|
46422
46879
|
} finally {
|
|
46423
|
-
|
|
46880
|
+
closeSync7(fd);
|
|
46424
46881
|
}
|
|
46425
46882
|
renameSync(temporary, path);
|
|
46426
46883
|
if (durable)
|
|
46427
|
-
syncDirectory(
|
|
46884
|
+
syncDirectory(dirname9(path));
|
|
46428
46885
|
} finally {
|
|
46429
46886
|
try {
|
|
46430
46887
|
unlinkSync(temporary);
|
|
@@ -46444,17 +46901,21 @@ function readSelectionJson(path) {
|
|
|
46444
46901
|
throw new SkillSelectionError("INVALID_RECEIPT", "The Skills selection receipt is unreadable; sync the profile again.");
|
|
46445
46902
|
}
|
|
46446
46903
|
}
|
|
46447
|
-
async function verifiedEntries(selection, bytes) {
|
|
46904
|
+
async function verifiedEntries(selection, bytes, signal, deadline) {
|
|
46448
46905
|
if (`sha256:${sha256Hex(bytes)}` !== selection.bundleDigest)
|
|
46449
46906
|
throw new SkillSelectionError("BUNDLE_DIGEST_MISMATCH", "The skill bundle does not match its selected digest.");
|
|
46450
|
-
const
|
|
46907
|
+
const remaining = deadline === undefined ? undefined : Math.floor(deadline - performance.now());
|
|
46908
|
+
signal?.throwIfAborted();
|
|
46909
|
+
if (remaining !== undefined && remaining <= 0)
|
|
46910
|
+
throw new SkillSelectionError("SKILLS_API_UNAVAILABLE", "Skills session authorization deadline exceeded.");
|
|
46911
|
+
const bundle = await inspectSkillBundle(bytes, { signal, ...remaining === undefined ? {} : { limits: { timeoutMs: remaining } } });
|
|
46451
46912
|
return bundle.entries;
|
|
46452
46913
|
}
|
|
46453
46914
|
async function readCachedSelection(selection, options = {}) {
|
|
46454
46915
|
const bytes = readRegularFile(selectionBundlePath(selection, options), SKILL_BUNDLE_INSPECTION_LIMITS.compressedBytes);
|
|
46455
46916
|
return bytes ? verifiedEntries(selection, bytes) : null;
|
|
46456
46917
|
}
|
|
46457
|
-
async function
|
|
46918
|
+
async function verifySelectionBundleResponse(selection, response, signal, deadline) {
|
|
46458
46919
|
validateSelection(selection);
|
|
46459
46920
|
if (!response?.ok)
|
|
46460
46921
|
throw new SkillSelectionError("BUNDLE_UNAVAILABLE", `The selected skill bundle is unavailable${response ? ` (HTTP ${response.status})` : ""}.`);
|
|
@@ -46464,15 +46925,27 @@ async function cacheSelectionBundle(selection, response, options = {}) {
|
|
|
46464
46925
|
await response.body?.cancel();
|
|
46465
46926
|
throw new SkillSelectionError("BUNDLE_IDENTITY_MISMATCH", "The returned bundle does not match the selected version and digest.");
|
|
46466
46927
|
}
|
|
46928
|
+
const epoch = response.headers.get("X-Skill-Authorization-Epoch");
|
|
46929
|
+
if (selection.authorizationEpoch !== undefined && epoch !== selection.authorizationEpoch) {
|
|
46930
|
+
response.body?.cancel().catch(() => {});
|
|
46931
|
+
throw new SkillSelectionError("SESSION_RECONCILIATION_REQUIRED", "The selected bundle lifecycle authorization changed or is unavailable.");
|
|
46932
|
+
}
|
|
46467
46933
|
const maximum = SKILL_BUNDLE_INSPECTION_LIMITS.compressedBytes;
|
|
46468
46934
|
const reader = response.body?.getReader();
|
|
46469
46935
|
if (!reader)
|
|
46470
46936
|
throw new SkillSelectionError("BUNDLE_UNAVAILABLE", "The selected bundle response has no body.");
|
|
46937
|
+
signal?.throwIfAborted();
|
|
46938
|
+
const abort = () => {
|
|
46939
|
+
reader.cancel().catch(() => {});
|
|
46940
|
+
};
|
|
46941
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
46471
46942
|
const chunks = [];
|
|
46472
46943
|
let length = 0;
|
|
46473
46944
|
try {
|
|
46474
46945
|
while (true) {
|
|
46946
|
+
signal?.throwIfAborted();
|
|
46475
46947
|
const next = await reader.read();
|
|
46948
|
+
signal?.throwIfAborted();
|
|
46476
46949
|
if (next.done)
|
|
46477
46950
|
break;
|
|
46478
46951
|
length += next.value.byteLength;
|
|
@@ -46481,9 +46954,10 @@ async function cacheSelectionBundle(selection, response, options = {}) {
|
|
|
46481
46954
|
chunks.push(next.value);
|
|
46482
46955
|
}
|
|
46483
46956
|
} catch (error61) {
|
|
46484
|
-
|
|
46957
|
+
reader.cancel().catch(() => {});
|
|
46485
46958
|
throw error61;
|
|
46486
46959
|
} finally {
|
|
46960
|
+
signal?.removeEventListener("abort", abort);
|
|
46487
46961
|
reader.releaseLock();
|
|
46488
46962
|
}
|
|
46489
46963
|
const bytes = new Uint8Array(length);
|
|
@@ -46492,7 +46966,12 @@ async function cacheSelectionBundle(selection, response, options = {}) {
|
|
|
46492
46966
|
bytes.set(chunk, offset);
|
|
46493
46967
|
offset += chunk.byteLength;
|
|
46494
46968
|
}
|
|
46495
|
-
const entries = await verifiedEntries(selection, bytes);
|
|
46969
|
+
const entries = await verifiedEntries(selection, bytes, signal, deadline);
|
|
46970
|
+
return { bytes, entries };
|
|
46971
|
+
}
|
|
46972
|
+
async function cacheSelectionBundle(selection, response, options = {}) {
|
|
46973
|
+
const { bytes, entries } = await verifySelectionBundleResponse(selection, response);
|
|
46974
|
+
const maximum = SKILL_BUNDLE_INSPECTION_LIMITS.compressedBytes;
|
|
46496
46975
|
const path = selectionBundlePath(selection, options);
|
|
46497
46976
|
const existing = readRegularFile(path, maximum);
|
|
46498
46977
|
if (existing)
|
|
@@ -46502,7 +46981,7 @@ async function cacheSelectionBundle(selection, response, options = {}) {
|
|
|
46502
46981
|
return entries;
|
|
46503
46982
|
}
|
|
46504
46983
|
function profilePath(profileId, options) {
|
|
46505
|
-
return
|
|
46984
|
+
return join15(selectionCacheRoot(options), "profiles", `${hash2(profileId)}.json`);
|
|
46506
46985
|
}
|
|
46507
46986
|
function readSelectionProfile(profileId, options = {}) {
|
|
46508
46987
|
const receipt = readSelectionJson(profilePath(profileId, options));
|
|
@@ -46528,7 +47007,7 @@ function assertFreshCachedProfile(receipt, options = {}) {
|
|
|
46528
47007
|
}
|
|
46529
47008
|
}
|
|
46530
47009
|
function projectSelectionLockPath(projectDir) {
|
|
46531
|
-
return
|
|
47010
|
+
return join15(resolve8(projectDir), ".skills", SELECTION_LOCK_FILE);
|
|
46532
47011
|
}
|
|
46533
47012
|
function readProjectSelection(projectDir) {
|
|
46534
47013
|
const receipt = readSelectionJson(projectSelectionLockPath(projectDir));
|
|
@@ -46539,7 +47018,7 @@ function readProjectSelection(projectDir) {
|
|
|
46539
47018
|
function sessionReceiptPath(sessionId, options = {}) {
|
|
46540
47019
|
if (!sessionId.trim() || sessionId.length > MAX_SKILL_SESSION_ID_CHARS)
|
|
46541
47020
|
throw new SkillSelectionError("INVALID_SESSION", `A Skills session id must contain 1\u2013${MAX_SKILL_SESSION_ID_CHARS} characters.`);
|
|
46542
|
-
return
|
|
47021
|
+
return join15(selectionCacheRoot(options), "sessions", `${hash2(sessionId)}.json`);
|
|
46543
47022
|
}
|
|
46544
47023
|
function skillSessionGeneration(receipt) {
|
|
46545
47024
|
return receipt.generation ?? 0;
|
|
@@ -46636,14 +47115,14 @@ function localLockIdentity() {
|
|
|
46636
47115
|
}
|
|
46637
47116
|
function readSessionLock(sessionId, options) {
|
|
46638
47117
|
const path = `${sessionReceiptPath(sessionId, options)}.write-lock`;
|
|
46639
|
-
const before =
|
|
47118
|
+
const before = lstatSync9(path, { throwIfNoEntry: false });
|
|
46640
47119
|
if (!before)
|
|
46641
47120
|
return null;
|
|
46642
47121
|
if (!before.isFile() || ![1, 2].includes(before.nlink) || (before.mode & 63) !== 0 || process.getuid && before.uid !== process.getuid()) {
|
|
46643
47122
|
throw new SkillSelectionError("SESSION_WRITE_LOCKED", "The session lock is not a private regular file; recovery requires review.");
|
|
46644
47123
|
}
|
|
46645
47124
|
const bytes = readRegularFile(path, SESSION_LOCK_MAX_BYTES);
|
|
46646
|
-
const after =
|
|
47125
|
+
const after = lstatSync9(path, { throwIfNoEntry: false });
|
|
46647
47126
|
if (!bytes || !after?.isFile() || before.dev !== after.dev || before.ino !== after.ino || before.mtimeMs !== after.mtimeMs || before.mode !== after.mode || before.uid !== after.uid || before.gid !== after.gid || before.nlink !== after.nlink) {
|
|
46648
47127
|
throw new SkillSelectionError("SESSION_WRITE_LOCKED", "The session lock changed during inspection; recovery requires review.");
|
|
46649
47128
|
}
|
|
@@ -46660,7 +47139,7 @@ function readSessionLock(sessionId, options) {
|
|
|
46660
47139
|
if (after.nlink === 2) {
|
|
46661
47140
|
stagingPath = `${path}.${marker.operationId}.prepared`;
|
|
46662
47141
|
assertRegularPath(stagingPath);
|
|
46663
|
-
const staged =
|
|
47142
|
+
const staged = lstatSync9(stagingPath, { throwIfNoEntry: false });
|
|
46664
47143
|
if (marker.publication !== "hard-link-v1" || !staged?.isFile() || staged.dev !== after.dev || staged.ino !== after.ino || staged.nlink !== 2 || staged.mode !== after.mode || staged.uid !== after.uid || staged.gid !== after.gid) {
|
|
46665
47144
|
throw new SkillSelectionError("SESSION_WRITE_LOCKED", "The session lock has an unbound publication link; recovery requires review.");
|
|
46666
47145
|
}
|
|
@@ -46671,33 +47150,33 @@ function publishSessionLock(path, marker) {
|
|
|
46671
47150
|
const stagingPath = `${path}.${marker.operationId}.prepared`;
|
|
46672
47151
|
const bytes = Buffer.from(`${JSON.stringify({ ...marker, publication: "hard-link-v1" })}
|
|
46673
47152
|
`);
|
|
46674
|
-
const fd =
|
|
46675
|
-
const stat =
|
|
47153
|
+
const fd = openSync7(stagingPath, constants4.O_WRONLY | constants4.O_CREAT | constants4.O_EXCL | constants4.O_NOFOLLOW, 384);
|
|
47154
|
+
const stat = fstatSync7(fd);
|
|
46676
47155
|
let published = false, handedOff = false;
|
|
46677
47156
|
try {
|
|
46678
47157
|
writeFileSync3(fd, bytes);
|
|
46679
47158
|
fsyncSync(fd);
|
|
46680
47159
|
linkSync(stagingPath, path);
|
|
46681
47160
|
published = true;
|
|
46682
|
-
syncDirectory(
|
|
46683
|
-
const staged =
|
|
47161
|
+
syncDirectory(dirname9(path));
|
|
47162
|
+
const staged = lstatSync9(stagingPath);
|
|
46684
47163
|
if (!staged.isFile() || staged.dev !== stat.dev || staged.ino !== stat.ino) {
|
|
46685
47164
|
throw new SkillSelectionError("SESSION_WRITE_LOCK_CHANGED", "The initialized lock staging inode changed before publication completed.");
|
|
46686
47165
|
}
|
|
46687
47166
|
unlinkSync(stagingPath);
|
|
46688
|
-
syncDirectory(
|
|
47167
|
+
syncDirectory(dirname9(path));
|
|
46689
47168
|
handedOff = true;
|
|
46690
47169
|
return { path, stagingPath, fd, dev: stat.dev, ino: stat.ino };
|
|
46691
47170
|
} finally {
|
|
46692
47171
|
if (!handedOff) {
|
|
46693
47172
|
try {
|
|
46694
47173
|
for (const target of [...published ? [path] : [], stagingPath]) {
|
|
46695
|
-
const current =
|
|
47174
|
+
const current = lstatSync9(target, { throwIfNoEntry: false });
|
|
46696
47175
|
if (current?.isFile() && current.dev === stat.dev && current.ino === stat.ino)
|
|
46697
47176
|
unlinkSync(target);
|
|
46698
47177
|
}
|
|
46699
47178
|
} finally {
|
|
46700
|
-
|
|
47179
|
+
closeSync7(fd);
|
|
46701
47180
|
}
|
|
46702
47181
|
}
|
|
46703
47182
|
}
|
|
@@ -46719,27 +47198,27 @@ function archiveSessionLock(lock, receipt, explicitLocalHost) {
|
|
|
46719
47198
|
const guardPath = `${lock.path}.recovery-guard`;
|
|
46720
47199
|
let guardFd;
|
|
46721
47200
|
try {
|
|
46722
|
-
guardFd =
|
|
47201
|
+
guardFd = openSync7(guardPath, constants4.O_WRONLY | constants4.O_CREAT | constants4.O_EXCL | constants4.O_NOFOLLOW, 384);
|
|
46723
47202
|
} catch (error61) {
|
|
46724
47203
|
if (error61.code === "EEXIST")
|
|
46725
47204
|
return null;
|
|
46726
47205
|
throw error61;
|
|
46727
47206
|
}
|
|
46728
|
-
const guardStat =
|
|
47207
|
+
const guardStat = fstatSync7(guardFd);
|
|
46729
47208
|
try {
|
|
46730
47209
|
writeFileSync3(guardFd, `${JSON.stringify({ schemaVersion: 1, pid: process.pid, operationId: randomUUID() })}
|
|
46731
47210
|
`);
|
|
46732
47211
|
fsyncSync(guardFd);
|
|
46733
|
-
const cacheOptions = { cacheDir:
|
|
47212
|
+
const cacheOptions = { cacheDir: dirname9(dirname9(lock.path)) };
|
|
46734
47213
|
const current = readSessionLock(lock.marker.sessionId, cacheOptions);
|
|
46735
47214
|
if (!current || current.dev !== lock.dev || current.ino !== lock.ino || current.sha256 !== lock.sha256 || current.mtimeMs !== lock.mtimeMs || !writerIsGone(current, explicitLocalHost))
|
|
46736
47215
|
return null;
|
|
46737
47216
|
const currentReceipt = readSkillSessionSnapshotIfExists(lock.marker.sessionId, cacheOptions);
|
|
46738
47217
|
if (currentReceipt?.sha256 !== receipt?.sha256 || currentReceipt?.generation !== receipt?.generation)
|
|
46739
47218
|
return null;
|
|
46740
|
-
const directory =
|
|
46741
|
-
const archivePath =
|
|
46742
|
-
const recordPath =
|
|
47219
|
+
const directory = join15(dirname9(dirname9(lock.path)), "session-lock-recoveries", randomUUID());
|
|
47220
|
+
const archivePath = join15(directory, "original.write-lock");
|
|
47221
|
+
const recordPath = join15(directory, "recovery.json");
|
|
46743
47222
|
assertRegularPath(archivePath, true);
|
|
46744
47223
|
archiveBytes(recordPath, Buffer.from(`${JSON.stringify({
|
|
46745
47224
|
schemaVersion: 1,
|
|
@@ -46754,7 +47233,7 @@ function archiveSessionLock(lock, receipt, explicitLocalHost) {
|
|
|
46754
47233
|
})}
|
|
46755
47234
|
`));
|
|
46756
47235
|
syncDirectory(directory);
|
|
46757
|
-
syncDirectory(
|
|
47236
|
+
syncDirectory(dirname9(directory));
|
|
46758
47237
|
const finalLock = readSessionLock(lock.marker.sessionId, cacheOptions);
|
|
46759
47238
|
if (!finalLock || finalLock.dev !== lock.dev || finalLock.ino !== lock.ino || finalLock.sha256 !== lock.sha256 || readSkillSessionSnapshotIfExists(lock.marker.sessionId, cacheOptions)?.sha256 !== receipt?.sha256)
|
|
46760
47239
|
return null;
|
|
@@ -46764,16 +47243,16 @@ function archiveSessionLock(lock, receipt, explicitLocalHost) {
|
|
|
46764
47243
|
moved = true;
|
|
46765
47244
|
const archivedPaths = [archivePath];
|
|
46766
47245
|
if (finalLock.stagingPath) {
|
|
46767
|
-
const publicationPath =
|
|
47246
|
+
const publicationPath = join15(directory, "publication.write-lock");
|
|
46768
47247
|
renameSync(finalLock.stagingPath, publicationPath);
|
|
46769
47248
|
archivedPaths.push(publicationPath);
|
|
46770
47249
|
}
|
|
46771
47250
|
syncDirectory(directory);
|
|
46772
|
-
syncDirectory(
|
|
47251
|
+
syncDirectory(dirname9(lock.path));
|
|
46773
47252
|
for (const path of archivedPaths) {
|
|
46774
|
-
const before =
|
|
47253
|
+
const before = lstatSync9(path, { throwIfNoEntry: false });
|
|
46775
47254
|
const bytes = readRegularFile(path, SESSION_LOCK_MAX_BYTES);
|
|
46776
|
-
const after =
|
|
47255
|
+
const after = lstatSync9(path, { throwIfNoEntry: false });
|
|
46777
47256
|
if (!before?.isFile() || before.dev !== lock.dev || before.ino !== lock.ino || before.nlink !== archivedPaths.length || before.mtimeMs !== lock.mtimeMs || (before.mode & 63) !== 0 || process.getuid && before.uid !== process.getuid() || !bytes || sha256Hex(bytes) !== lock.sha256 || !after?.isFile() || before.dev !== after.dev || before.ino !== after.ino || before.mtimeMs !== after.mtimeMs || before.mode !== after.mode || before.uid !== after.uid || before.gid !== after.gid || before.nlink !== after.nlink) {
|
|
46778
47257
|
throw new Error("Archived lock ownership or bytes changed");
|
|
46779
47258
|
}
|
|
@@ -46785,8 +47264,8 @@ function archiveSessionLock(lock, receipt, explicitLocalHost) {
|
|
|
46785
47264
|
}
|
|
46786
47265
|
return archivePath;
|
|
46787
47266
|
} finally {
|
|
46788
|
-
|
|
46789
|
-
const current =
|
|
47267
|
+
closeSync7(guardFd);
|
|
47268
|
+
const current = lstatSync9(guardPath, { throwIfNoEntry: false });
|
|
46790
47269
|
if (current?.isFile() && current.dev === guardStat.dev && current.ino === guardStat.ino)
|
|
46791
47270
|
unlinkSync(guardPath);
|
|
46792
47271
|
}
|
|
@@ -46798,7 +47277,7 @@ function withSessionWriteLocks(sessionIds, options, action) {
|
|
|
46798
47277
|
const owned = [];
|
|
46799
47278
|
const assertOwned = () => {
|
|
46800
47279
|
for (const lock of owned) {
|
|
46801
|
-
const current =
|
|
47280
|
+
const current = lstatSync9(lock.path, { throwIfNoEntry: false });
|
|
46802
47281
|
if (!current?.isFile() || current.dev !== lock.dev || current.ino !== lock.ino) {
|
|
46803
47282
|
throw new SkillSelectionError("SESSION_WRITE_LOCK_CHANGED", "A session write lock changed during the operation; no replacement is permitted.");
|
|
46804
47283
|
}
|
|
@@ -46842,12 +47321,12 @@ function withSessionWriteLocks(sessionIds, options, action) {
|
|
|
46842
47321
|
for (const lock of owned.reverse()) {
|
|
46843
47322
|
try {
|
|
46844
47323
|
for (const path of [lock.path, lock.stagingPath]) {
|
|
46845
|
-
const current =
|
|
47324
|
+
const current = lstatSync9(path, { throwIfNoEntry: false });
|
|
46846
47325
|
if (current?.isFile() && current.dev === lock.dev && current.ino === lock.ino)
|
|
46847
47326
|
unlinkSync(path);
|
|
46848
47327
|
}
|
|
46849
47328
|
} finally {
|
|
46850
|
-
|
|
47329
|
+
closeSync7(lock.fd);
|
|
46851
47330
|
}
|
|
46852
47331
|
}
|
|
46853
47332
|
}
|
|
@@ -46895,21 +47374,21 @@ function writeSkillSession(receipt, expected, options = {}) {
|
|
|
46895
47374
|
}
|
|
46896
47375
|
function syncDirectory(path) {
|
|
46897
47376
|
assertRegularPath(path);
|
|
46898
|
-
const fd =
|
|
47377
|
+
const fd = openSync7(path, constants4.O_RDONLY | constants4.O_DIRECTORY | constants4.O_NOFOLLOW);
|
|
46899
47378
|
try {
|
|
46900
47379
|
fsyncSync(fd);
|
|
46901
47380
|
} finally {
|
|
46902
|
-
|
|
47381
|
+
closeSync7(fd);
|
|
46903
47382
|
}
|
|
46904
47383
|
}
|
|
46905
47384
|
function archiveBytes(path, bytes) {
|
|
46906
47385
|
assertRegularPath(path, true);
|
|
46907
|
-
const fd =
|
|
47386
|
+
const fd = openSync7(path, constants4.O_WRONLY | constants4.O_CREAT | constants4.O_EXCL | constants4.O_NOFOLLOW, 384);
|
|
46908
47387
|
try {
|
|
46909
47388
|
writeFileSync3(fd, bytes);
|
|
46910
47389
|
fsyncSync(fd);
|
|
46911
47390
|
} finally {
|
|
46912
|
-
|
|
47391
|
+
closeSync7(fd);
|
|
46913
47392
|
}
|
|
46914
47393
|
}
|
|
46915
47394
|
var SkillSelectionError, MAX_CACHED_PROFILE_AGE_MS, SELECTION_LOCK_FILE = "selection.lock.json", SESSION_LOCK_MAX_BYTES = 4096, SESSION_LOCK_MIN_AGE_MS = 30000;
|
|
@@ -46938,7 +47417,7 @@ __export(exports_remote_files, {
|
|
|
46938
47417
|
decodeRemoteFiles: () => decodeRemoteFiles,
|
|
46939
47418
|
MAX_REMOTE_FILE_BYTES: () => MAX_REMOTE_FILE_BYTES
|
|
46940
47419
|
});
|
|
46941
|
-
import { createHash as
|
|
47420
|
+
import { createHash as createHash9 } from "crypto";
|
|
46942
47421
|
function describeRemoteFiles(files) {
|
|
46943
47422
|
if (files.length > 10)
|
|
46944
47423
|
throw new Error("At most 10 input files are supported");
|
|
@@ -46955,9 +47434,9 @@ function describeRemoteFiles(files) {
|
|
|
46955
47434
|
});
|
|
46956
47435
|
}
|
|
46957
47436
|
function sha256(bytes) {
|
|
46958
|
-
return
|
|
47437
|
+
return createHash9("sha256").update(bytes).digest("hex");
|
|
46959
47438
|
}
|
|
46960
|
-
async function readBoundedResponse(response, maximum) {
|
|
47439
|
+
async function readBoundedResponse(response, maximum, signal) {
|
|
46961
47440
|
if (!Number.isSafeInteger(maximum) || maximum < 0 || maximum > MAX_REMOTE_FILE_BYTES)
|
|
46962
47441
|
throw new Error("Invalid artifact size limit");
|
|
46963
47442
|
const length = response.headers.get("content-length");
|
|
@@ -46968,11 +47447,18 @@ async function readBoundedResponse(response, maximum) {
|
|
|
46968
47447
|
const reader = response.body?.getReader();
|
|
46969
47448
|
if (!reader)
|
|
46970
47449
|
return new Uint8Array;
|
|
47450
|
+
signal?.throwIfAborted();
|
|
47451
|
+
const abort = () => {
|
|
47452
|
+
reader.cancel().catch(() => {});
|
|
47453
|
+
};
|
|
47454
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
46971
47455
|
const chunks = [];
|
|
46972
47456
|
let size = 0;
|
|
46973
47457
|
try {
|
|
46974
47458
|
while (true) {
|
|
47459
|
+
signal?.throwIfAborted();
|
|
46975
47460
|
const next = await reader.read();
|
|
47461
|
+
signal?.throwIfAborted();
|
|
46976
47462
|
if (next.done)
|
|
46977
47463
|
break;
|
|
46978
47464
|
size += next.value.byteLength;
|
|
@@ -46984,6 +47470,7 @@ async function readBoundedResponse(response, maximum) {
|
|
|
46984
47470
|
await reader.cancel().catch(() => {});
|
|
46985
47471
|
throw error61;
|
|
46986
47472
|
} finally {
|
|
47473
|
+
signal?.removeEventListener("abort", abort);
|
|
46987
47474
|
reader.releaseLock();
|
|
46988
47475
|
}
|
|
46989
47476
|
const bytes = new Uint8Array(size);
|
|
@@ -47043,10 +47530,12 @@ function validateSelection2(value) {
|
|
|
47043
47530
|
|
|
47044
47531
|
class HttpProfileClient {
|
|
47045
47532
|
key;
|
|
47533
|
+
signal;
|
|
47046
47534
|
authority;
|
|
47047
47535
|
origin;
|
|
47048
|
-
constructor(key, origin) {
|
|
47536
|
+
constructor(key, origin, signal) {
|
|
47049
47537
|
this.key = key;
|
|
47538
|
+
this.signal = signal;
|
|
47050
47539
|
if (!key.trim())
|
|
47051
47540
|
throw new Error("A Skills credential is required");
|
|
47052
47541
|
this.origin = normalizeSkillsApiOrigin(origin);
|
|
@@ -47060,7 +47549,7 @@ class HttpProfileClient {
|
|
|
47060
47549
|
...init,
|
|
47061
47550
|
redirect: "error",
|
|
47062
47551
|
credentials: "omit",
|
|
47063
|
-
signal: AbortSignal.timeout(15000),
|
|
47552
|
+
signal: this.signal ? AbortSignal.any([this.signal, AbortSignal.timeout(15000)]) : AbortSignal.timeout(15000),
|
|
47064
47553
|
headers: {
|
|
47065
47554
|
"Content-Type": "application/json",
|
|
47066
47555
|
"User-Agent": `hasna-skills/${package_default.version}`,
|
|
@@ -47085,22 +47574,28 @@ class HttpProfileClient {
|
|
|
47085
47574
|
}
|
|
47086
47575
|
async read(response, limit = MAX_PROFILE_DOCUMENT_BYTES) {
|
|
47087
47576
|
try {
|
|
47088
|
-
return JSON.parse(new TextDecoder().decode(await readBoundedResponse(response, limit)));
|
|
47577
|
+
return JSON.parse(new TextDecoder().decode(await readBoundedResponse(response, limit, this.signal)));
|
|
47089
47578
|
} catch {
|
|
47090
47579
|
invalid();
|
|
47091
47580
|
}
|
|
47092
47581
|
}
|
|
47582
|
+
async supportsPinRenewal() {
|
|
47583
|
+
const result = await this.read(await this.request("/capabilities"));
|
|
47584
|
+
if (!object6(result) || !Array.isArray(result.capabilities))
|
|
47585
|
+
invalid();
|
|
47586
|
+
return result.capabilities.includes("skills.session-pin-renewal");
|
|
47587
|
+
}
|
|
47093
47588
|
async resolveProfile(id) {
|
|
47094
47589
|
if (!identifier(id))
|
|
47095
47590
|
throw new Error("Invalid selection profile id");
|
|
47096
|
-
const result = await this.read(await this.request(`/profiles/${encodeURIComponent(id)}/resolve`), MAX_RESOLVED_PROFILE_BYTES);
|
|
47591
|
+
const result = await this.read(await this.request(`/profiles/${encodeURIComponent(id)}/resolve?pinAuthorization=epoch-v1`), MAX_RESOLVED_PROFILE_BYTES);
|
|
47097
47592
|
if (!object6(result) || result.profileId !== id || result.authority !== this.authority || !identifier(result.workspaceId) || !identifier(result.profileRevision) || !Array.isArray(result.selections) || result.selections.length > MAX_PROFILE_SELECTIONS)
|
|
47098
47593
|
invalid();
|
|
47099
47594
|
const seen = new Set;
|
|
47100
47595
|
for (const entry of result.selections) {
|
|
47101
47596
|
validateSelection2(entry);
|
|
47102
47597
|
const item = entry;
|
|
47103
|
-
if (seen.has(item.slug) || item.authority !== this.authority || item.workspaceId !== result.workspaceId || item.profileRevision !== result.profileRevision)
|
|
47598
|
+
if (item.authorizationEpoch !== undefined && (typeof item.authorizationEpoch !== "string" || !/^[a-f0-9]{32}$/.test(item.authorizationEpoch)) || seen.has(item.slug) || item.authority !== this.authority || item.workspaceId !== result.workspaceId || item.profileRevision !== result.profileRevision)
|
|
47104
47599
|
invalid();
|
|
47105
47600
|
seen.add(item.slug);
|
|
47106
47601
|
}
|
|
@@ -47147,7 +47642,7 @@ class HttpProfileClient {
|
|
|
47147
47642
|
return this.request(`/skills/${encodeURIComponent(slug)}/versions/${encodeURIComponent(version2)}/bundle`);
|
|
47148
47643
|
}
|
|
47149
47644
|
}
|
|
47150
|
-
async function createProfileClient() {
|
|
47645
|
+
async function createProfileClient(signal) {
|
|
47151
47646
|
let connection;
|
|
47152
47647
|
try {
|
|
47153
47648
|
connection = await resolveSkillsConnection();
|
|
@@ -47159,7 +47654,7 @@ async function createProfileClient() {
|
|
|
47159
47654
|
}
|
|
47160
47655
|
if (!connection)
|
|
47161
47656
|
throw new Error("Selection profiles require a configured Skills API");
|
|
47162
|
-
return new HttpProfileClient(connection.apiKey, connection.apiOrigin);
|
|
47657
|
+
return new HttpProfileClient(connection.apiKey, connection.apiOrigin, signal);
|
|
47163
47658
|
}
|
|
47164
47659
|
var init_profile_client = __esm(() => {
|
|
47165
47660
|
init_selection_cache();
|
|
@@ -47210,19 +47705,19 @@ function capturePreparationProcess(child, platform = process.platform, signalGro
|
|
|
47210
47705
|
}
|
|
47211
47706
|
|
|
47212
47707
|
// src/lib/dependency-preparation.ts
|
|
47213
|
-
import { constants as
|
|
47214
|
-
import { join as
|
|
47708
|
+
import { constants as constants5, closeSync as closeSync8, fstatSync as fstatSync8, lstatSync as lstatSync10, mkdirSync as mkdirSync4, openSync as openSync8, readFileSync as readFileSync11, readdirSync as readdirSync5, rmdirSync, unlinkSync as unlinkSync2, ftruncateSync, writeSync } from "fs";
|
|
47709
|
+
import { join as join16 } from "path";
|
|
47215
47710
|
function hasDependencyPreparationMarker(skillPath) {
|
|
47216
47711
|
try {
|
|
47217
|
-
|
|
47712
|
+
lstatSync10(join16(skillPath, DEPENDENCY_PREPARATION_MARKER));
|
|
47218
47713
|
return true;
|
|
47219
47714
|
} catch (error61) {
|
|
47220
47715
|
return error61.code !== "ENOENT";
|
|
47221
47716
|
}
|
|
47222
47717
|
}
|
|
47223
47718
|
function claimPreparation(skillPath) {
|
|
47224
|
-
const marker =
|
|
47225
|
-
const state =
|
|
47719
|
+
const marker = join16(skillPath, DEPENDENCY_PREPARATION_MARKER);
|
|
47720
|
+
const state = join16(marker, "state.json"), active = join16(marker, "active");
|
|
47226
47721
|
let created = false;
|
|
47227
47722
|
try {
|
|
47228
47723
|
mkdirSync4(marker, { mode: 448 });
|
|
@@ -47233,21 +47728,21 @@ function claimPreparation(skillPath) {
|
|
|
47233
47728
|
}
|
|
47234
47729
|
let fd;
|
|
47235
47730
|
try {
|
|
47236
|
-
if (!
|
|
47731
|
+
if (!lstatSync10(marker).isDirectory() || lstatSync10(marker).isSymbolicLink())
|
|
47237
47732
|
return;
|
|
47238
47733
|
if (!created) {
|
|
47239
47734
|
if (readdirSync5(marker).some((name) => name !== "state.json"))
|
|
47240
47735
|
return;
|
|
47241
|
-
if (!
|
|
47736
|
+
if (!lstatSync10(state).isFile() || lstatSync10(state).isSymbolicLink() || lstatSync10(state).size > 1024)
|
|
47242
47737
|
return;
|
|
47243
47738
|
const previous = JSON.parse(readFileSync11(state, "utf8"));
|
|
47244
47739
|
if (previous.version !== 1 || previous.status !== "failed" || Object.keys(previous).length !== 2)
|
|
47245
47740
|
return;
|
|
47246
47741
|
}
|
|
47247
47742
|
mkdirSync4(active, { mode: 448 });
|
|
47248
|
-
fd =
|
|
47249
|
-
if (!
|
|
47250
|
-
|
|
47743
|
+
fd = openSync8(state, constants5.O_RDWR | constants5.O_NOFOLLOW | (created ? constants5.O_CREAT | constants5.O_EXCL : 0), 384);
|
|
47744
|
+
if (!fstatSync8(fd).isFile()) {
|
|
47745
|
+
closeSync8(fd);
|
|
47251
47746
|
return;
|
|
47252
47747
|
}
|
|
47253
47748
|
const descriptor = fd;
|
|
@@ -47259,7 +47754,7 @@ function claimPreparation(skillPath) {
|
|
|
47259
47754
|
record4("pending");
|
|
47260
47755
|
return { abandon() {
|
|
47261
47756
|
try {
|
|
47262
|
-
|
|
47757
|
+
closeSync8(descriptor);
|
|
47263
47758
|
} catch {}
|
|
47264
47759
|
}, finish(success2) {
|
|
47265
47760
|
try {
|
|
@@ -47267,7 +47762,7 @@ function claimPreparation(skillPath) {
|
|
|
47267
47762
|
unlinkSync2(state);
|
|
47268
47763
|
else
|
|
47269
47764
|
record4("failed");
|
|
47270
|
-
|
|
47765
|
+
closeSync8(descriptor);
|
|
47271
47766
|
fd = undefined;
|
|
47272
47767
|
rmdirSync(active);
|
|
47273
47768
|
if (success2)
|
|
@@ -47275,7 +47770,7 @@ function claimPreparation(skillPath) {
|
|
|
47275
47770
|
return true;
|
|
47276
47771
|
} catch {
|
|
47277
47772
|
try {
|
|
47278
|
-
|
|
47773
|
+
closeSync8(descriptor);
|
|
47279
47774
|
} catch {}
|
|
47280
47775
|
return false;
|
|
47281
47776
|
}
|
|
@@ -47283,7 +47778,7 @@ function claimPreparation(skillPath) {
|
|
|
47283
47778
|
} catch {
|
|
47284
47779
|
if (fd !== undefined)
|
|
47285
47780
|
try {
|
|
47286
|
-
|
|
47781
|
+
closeSync8(fd);
|
|
47287
47782
|
} catch {}
|
|
47288
47783
|
return;
|
|
47289
47784
|
}
|
|
@@ -47443,283 +47938,6 @@ function isCodexLocalStdioMcpServer(name, server) {
|
|
|
47443
47938
|
}
|
|
47444
47939
|
}
|
|
47445
47940
|
|
|
47446
|
-
// src/lib/claude-settings-witness.ts
|
|
47447
|
-
import { createHash as createHash8 } from "crypto";
|
|
47448
|
-
import { closeSync as closeSync8, constants as constants5, fstatSync as fstatSync8, lstatSync as lstatSync10, openSync as openSync8, readSync as readSync4 } from "fs";
|
|
47449
|
-
import { basename as basename4, dirname as dirname9, isAbsolute as isAbsolute8, resolve as resolve8 } from "path";
|
|
47450
|
-
function need2(value, reason) {
|
|
47451
|
-
if (!value)
|
|
47452
|
-
throw new Error(`Claude settings witness ${reason}`);
|
|
47453
|
-
}
|
|
47454
|
-
function absolutePath(value) {
|
|
47455
|
-
need2(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_SETTINGS_WITNESS_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute8(value) && resolve8(value) === value, "requires a normalized absolute path");
|
|
47456
|
-
}
|
|
47457
|
-
function parents(path) {
|
|
47458
|
-
const result = [];
|
|
47459
|
-
for (let at = dirname9(path);; at = dirname9(at)) {
|
|
47460
|
-
const stat = lstatSync10(at, { bigint: true });
|
|
47461
|
-
need2(stat.isDirectory() && !stat.isSymbolicLink(), "path traverses a symlink or non-directory");
|
|
47462
|
-
result.push([at, stat]);
|
|
47463
|
-
if (at === dirname9(at))
|
|
47464
|
-
return result;
|
|
47465
|
-
}
|
|
47466
|
-
}
|
|
47467
|
-
function readNativeSettingsWitnessFile(path, budget, filename = "settings.json") {
|
|
47468
|
-
absolutePath(path);
|
|
47469
|
-
need2(basename4(path) === filename, `requires ${filename}`);
|
|
47470
|
-
need2(Number.isSafeInteger(budget.remaining) && budget.remaining >= 0, "has an invalid byte budget");
|
|
47471
|
-
const ancestors = parents(path), initial = lstatSync10(path, { bigint: true });
|
|
47472
|
-
need2(initial.isFile() && !initial.isSymbolicLink() && initial.size <= BigInt(CLAUDE_SETTINGS_WITNESS_LIMITS.bytes), "is not a bounded regular file");
|
|
47473
|
-
need2(initial.size <= BigInt(budget.remaining), "exceeds its aggregate byte limit");
|
|
47474
|
-
const fd = openSync8(path, constants5.O_RDONLY | constants5.O_NOFOLLOW | constants5.O_NONBLOCK);
|
|
47475
|
-
try {
|
|
47476
|
-
const opened = fstatSync8(fd, { bigint: true });
|
|
47477
|
-
need2(opened.isFile() && sameFile(initial, opened), "changed during open");
|
|
47478
|
-
const bytes = Buffer.alloc(Number(opened.size) + 1);
|
|
47479
|
-
let length = 0;
|
|
47480
|
-
while (length < bytes.length) {
|
|
47481
|
-
const count = readSync4(fd, bytes, length, bytes.length - length, null);
|
|
47482
|
-
if (!count)
|
|
47483
|
-
break;
|
|
47484
|
-
length += count;
|
|
47485
|
-
}
|
|
47486
|
-
const after = fstatSync8(fd, { bigint: true }), current = lstatSync10(path, { bigint: true });
|
|
47487
|
-
need2(current.isFile() && sameFile(opened, after) && sameFile(after, current) && BigInt(length) === opened.size, "changed during read");
|
|
47488
|
-
for (const [ancestor, before] of ancestors) {
|
|
47489
|
-
const now = lstatSync10(ancestor, { bigint: true });
|
|
47490
|
-
need2(now.isDirectory() && before.dev === now.dev && before.ino === now.ino && before.mode === now.mode, "parent changed during read");
|
|
47491
|
-
}
|
|
47492
|
-
budget.remaining -= length;
|
|
47493
|
-
try {
|
|
47494
|
-
return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes.subarray(0, length));
|
|
47495
|
-
} catch {
|
|
47496
|
-
throw new Error("Claude settings witness is not strict UTF-8");
|
|
47497
|
-
}
|
|
47498
|
-
} finally {
|
|
47499
|
-
closeSync8(fd);
|
|
47500
|
-
}
|
|
47501
|
-
}
|
|
47502
|
-
function parse8(text2) {
|
|
47503
|
-
let at = 0, nodes = 0;
|
|
47504
|
-
const numberPattern = /-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?/y;
|
|
47505
|
-
const space = () => {
|
|
47506
|
-
while (at < text2.length && /[\x20\t\r\n]/.test(text2[at]))
|
|
47507
|
-
at++;
|
|
47508
|
-
};
|
|
47509
|
-
function string5() {
|
|
47510
|
-
need2(text2[at] === '"', "contains invalid JSON");
|
|
47511
|
-
const start = at++;
|
|
47512
|
-
while (at < text2.length) {
|
|
47513
|
-
const character = text2[at++];
|
|
47514
|
-
if (character === '"') {
|
|
47515
|
-
let value2;
|
|
47516
|
-
try {
|
|
47517
|
-
value2 = JSON.parse(text2.slice(start, at));
|
|
47518
|
-
} catch {
|
|
47519
|
-
throw new Error("Claude settings witness contains invalid JSON string");
|
|
47520
|
-
}
|
|
47521
|
-
need2(value2.length <= CLAUDE_SETTINGS_WITNESS_LIMITS.stringCharacters, "exceeds its string limit");
|
|
47522
|
-
return value2;
|
|
47523
|
-
}
|
|
47524
|
-
if (character === "\\")
|
|
47525
|
-
at++;
|
|
47526
|
-
}
|
|
47527
|
-
throw new Error("Claude settings witness contains an unterminated JSON string");
|
|
47528
|
-
}
|
|
47529
|
-
function value(depth) {
|
|
47530
|
-
need2(depth <= CLAUDE_SETTINGS_WITNESS_LIMITS.depth && ++nodes <= CLAUDE_SETTINGS_WITNESS_LIMITS.nodes, "exceeds its nesting or node limit");
|
|
47531
|
-
space();
|
|
47532
|
-
const character = text2[at];
|
|
47533
|
-
if (character === '"')
|
|
47534
|
-
return { kind: "string", value: string5() };
|
|
47535
|
-
if (character === "{" || character === "[") {
|
|
47536
|
-
at++;
|
|
47537
|
-
space();
|
|
47538
|
-
const object7 = character === "{", end = object7 ? "}" : "]", entries = [], items = [], keys = new Set;
|
|
47539
|
-
if (text2[at] !== end)
|
|
47540
|
-
while (true) {
|
|
47541
|
-
if (object7) {
|
|
47542
|
-
space();
|
|
47543
|
-
const key = string5();
|
|
47544
|
-
need2(!keys.has(key), "contains a duplicate JSON key");
|
|
47545
|
-
keys.add(key);
|
|
47546
|
-
space();
|
|
47547
|
-
need2(text2[at++] === ":", "contains invalid JSON");
|
|
47548
|
-
entries.push([key, value(depth + 1)]);
|
|
47549
|
-
} else
|
|
47550
|
-
items.push(value(depth + 1));
|
|
47551
|
-
space();
|
|
47552
|
-
if (text2[at] === end)
|
|
47553
|
-
break;
|
|
47554
|
-
need2(text2[at++] === ",", "contains invalid JSON");
|
|
47555
|
-
}
|
|
47556
|
-
at++;
|
|
47557
|
-
return object7 ? { kind: "object", entries } : { kind: "array", items };
|
|
47558
|
-
}
|
|
47559
|
-
for (const literal3 of ["true", "false", "null"])
|
|
47560
|
-
if (text2.startsWith(literal3, at)) {
|
|
47561
|
-
at += literal3.length;
|
|
47562
|
-
return { kind: "literal", value: literal3 };
|
|
47563
|
-
}
|
|
47564
|
-
numberPattern.lastIndex = at;
|
|
47565
|
-
const number5 = numberPattern.exec(text2);
|
|
47566
|
-
need2(number5, "contains invalid JSON");
|
|
47567
|
-
at += number5[0].length;
|
|
47568
|
-
return { kind: "number", value: number5[0] };
|
|
47569
|
-
}
|
|
47570
|
-
const root = value(0);
|
|
47571
|
-
space();
|
|
47572
|
-
need2(at === text2.length && root.kind === "object", "requires a JSON object without trailing content");
|
|
47573
|
-
need2(root.entries.length <= CLAUDE_SETTINGS_WITNESS_LIMITS.rows, "exceeds its settings field limit");
|
|
47574
|
-
return root;
|
|
47575
|
-
}
|
|
47576
|
-
function canonical2(value) {
|
|
47577
|
-
if (value.kind === "object")
|
|
47578
|
-
return { kind: "object", entries: value.entries.map(([key, child]) => [key, canonical2(child)]).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0) };
|
|
47579
|
-
if (value.kind === "array")
|
|
47580
|
-
return { kind: "array", items: value.items.map(canonical2) };
|
|
47581
|
-
return value;
|
|
47582
|
-
}
|
|
47583
|
-
function inferencePreference(key, child, version2) {
|
|
47584
|
-
if (key === "skipDangerousModePermissionPrompt") {
|
|
47585
|
-
need2(child.kind === "literal" && (child.value === "true" || child.value === "false"), "contains an invalid dialog acknowledgment");
|
|
47586
|
-
return false;
|
|
47587
|
-
}
|
|
47588
|
-
if (key === "effortLevel") {
|
|
47589
|
-
need2(child.kind === "string" && PERSISTED_EFFORT_LEVELS.has(child.value), "contains an invalid persisted effort level");
|
|
47590
|
-
return true;
|
|
47591
|
-
}
|
|
47592
|
-
if (key !== "modelSettings")
|
|
47593
|
-
return false;
|
|
47594
|
-
need2(child.kind === "object", "requires an object of model preferences");
|
|
47595
|
-
child.entries = child.entries.filter(([model, preferences]) => {
|
|
47596
|
-
if (version2 === 2 && !BUILTIN_MODEL_SELECTIONS.has(model) || preferences.kind !== "object" || preferences.entries.length !== 1 || preferences.entries[0][0] !== "effortLevel")
|
|
47597
|
-
return true;
|
|
47598
|
-
const effort = preferences.entries[0][1];
|
|
47599
|
-
need2(effort.kind === "string" && PERSISTED_EFFORT_LEVELS.has(effort.value), "contains an invalid persisted model effort level");
|
|
47600
|
-
return false;
|
|
47601
|
-
});
|
|
47602
|
-
return child.entries.length === 0;
|
|
47603
|
-
}
|
|
47604
|
-
function settingsDigest(text2, version2 = 1) {
|
|
47605
|
-
const value = parse8(text2);
|
|
47606
|
-
value.entries = value.entries.filter(([key, child]) => {
|
|
47607
|
-
if (version2 !== 1 && inferencePreference(key, child, version2))
|
|
47608
|
-
return false;
|
|
47609
|
-
if (key === "model") {
|
|
47610
|
-
need2(child.kind === "string", "contains an invalid model selection");
|
|
47611
|
-
return !BUILTIN_MODEL_SELECTIONS.has(child.value);
|
|
47612
|
-
}
|
|
47613
|
-
if (BOOLEAN_PREFERENCES.has(key)) {
|
|
47614
|
-
need2(child.kind === "literal" && (child.value === "true" || child.value === "false"), "contains an invalid display preference");
|
|
47615
|
-
return false;
|
|
47616
|
-
}
|
|
47617
|
-
if (Object.hasOwn(ENUM_PREFERENCES, key)) {
|
|
47618
|
-
need2(child.kind === "string" && ENUM_PREFERENCES[key].includes(child.value), "contains an invalid display preference");
|
|
47619
|
-
return false;
|
|
47620
|
-
}
|
|
47621
|
-
return true;
|
|
47622
|
-
});
|
|
47623
|
-
return createHash8("sha256").update(`hasna.skills.claude-settings.v${version2}\x00`).update(JSON.stringify(canonical2(value))).digest("hex");
|
|
47624
|
-
}
|
|
47625
|
-
function hashClaudeSettingsReplacement(text2, budget) {
|
|
47626
|
-
need2(typeof text2 === "string", "requires settings text");
|
|
47627
|
-
const bytes = Buffer.byteLength(text2);
|
|
47628
|
-
need2(bytes <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes && Number.isSafeInteger(budget.remaining) && budget.remaining >= bytes, "exceeds its byte limit");
|
|
47629
|
-
budget.remaining -= bytes;
|
|
47630
|
-
return settingsDigest(text2);
|
|
47631
|
-
}
|
|
47632
|
-
function captureClaudeSettings(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
47633
|
-
return { path, hashMode: "claude-settings-v1", sha256: settingsDigest(readNativeSettingsWitnessFile(path, budget)) };
|
|
47634
|
-
}
|
|
47635
|
-
function captureClaudeSettingsV2(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
47636
|
-
return { path, hashMode: "claude-settings-v2", sha256: settingsDigest(readNativeSettingsWitnessFile(path, budget), 2) };
|
|
47637
|
-
}
|
|
47638
|
-
function hashClaudeSettingsReplacementV2(text2, budget) {
|
|
47639
|
-
need2(typeof text2 === "string", "requires settings text");
|
|
47640
|
-
const bytes = Buffer.byteLength(text2);
|
|
47641
|
-
need2(bytes <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes && Number.isSafeInteger(budget.remaining) && budget.remaining >= bytes, "exceeds its byte limit");
|
|
47642
|
-
budget.remaining -= bytes;
|
|
47643
|
-
return settingsDigest(text2, 2);
|
|
47644
|
-
}
|
|
47645
|
-
function captureClaudeSettingsV3(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
47646
|
-
return { path, hashMode: "claude-settings-v3", sha256: settingsDigest(readNativeSettingsWitnessFile(path, budget), 3) };
|
|
47647
|
-
}
|
|
47648
|
-
function hashClaudeSettingsReplacementV3(text2, budget) {
|
|
47649
|
-
need2(typeof text2 === "string", "requires settings text");
|
|
47650
|
-
const bytes = Buffer.byteLength(text2);
|
|
47651
|
-
need2(bytes <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes && Number.isSafeInteger(budget.remaining) && budget.remaining >= bytes, "exceeds its byte limit");
|
|
47652
|
-
budget.remaining -= bytes;
|
|
47653
|
-
return settingsDigest(text2, 3);
|
|
47654
|
-
}
|
|
47655
|
-
function hashNativeJsonControls(text2, excludedMetadata) {
|
|
47656
|
-
need2(Buffer.byteLength(text2) <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes, "exceeds its byte limit");
|
|
47657
|
-
const value = parse8(text2);
|
|
47658
|
-
value.entries = value.entries.filter(([key, child]) => {
|
|
47659
|
-
if (key !== excludedMetadata)
|
|
47660
|
-
return true;
|
|
47661
|
-
need2(child.kind === "string" && child.value.length <= 128, "has invalid version metadata");
|
|
47662
|
-
return false;
|
|
47663
|
-
});
|
|
47664
|
-
return createHash8("sha256").update("hasna.skills.native-json-controls.v1\x00").update(JSON.stringify(canonical2(value))).digest("hex");
|
|
47665
|
-
}
|
|
47666
|
-
var CLAUDE_SETTINGS_WITNESS_LIMITS, sameFile = (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, BOOLEAN_PREFERENCES, ENUM_PREFERENCES, BUILTIN_MODEL_SELECTIONS, PERSISTED_EFFORT_LEVELS;
|
|
47667
|
-
var init_claude_settings_witness = __esm(() => {
|
|
47668
|
-
CLAUDE_SETTINGS_WITNESS_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
|
|
47669
|
-
BOOLEAN_PREFERENCES = new Set([
|
|
47670
|
-
"autoScrollEnabled",
|
|
47671
|
-
"axScreenReader",
|
|
47672
|
-
"emojiCompletionEnabled",
|
|
47673
|
-
"prefersReducedMotion",
|
|
47674
|
-
"showTurnDuration",
|
|
47675
|
-
"spinnerTipsEnabled",
|
|
47676
|
-
"syntaxHighlightingDisabled",
|
|
47677
|
-
"terminalProgressBarEnabled",
|
|
47678
|
-
"terminalTitleFromRename",
|
|
47679
|
-
"verbose",
|
|
47680
|
-
"wheelScrollAccelerationEnabled"
|
|
47681
|
-
]);
|
|
47682
|
-
ENUM_PREFERENCES = Object.freeze({
|
|
47683
|
-
editorMode: ["normal", "vim"],
|
|
47684
|
-
tui: ["default", "fullscreen"],
|
|
47685
|
-
viewMode: ["default", "verbose", "focus"]
|
|
47686
|
-
});
|
|
47687
|
-
BUILTIN_MODEL_SELECTIONS = new Set([
|
|
47688
|
-
"default",
|
|
47689
|
-
"best",
|
|
47690
|
-
"fable",
|
|
47691
|
-
"fable[1m]",
|
|
47692
|
-
"sonnet",
|
|
47693
|
-
"sonnet[1m]",
|
|
47694
|
-
"opus",
|
|
47695
|
-
"opus[1m]",
|
|
47696
|
-
"haiku",
|
|
47697
|
-
"opusplan",
|
|
47698
|
-
"claude-fable-5-1",
|
|
47699
|
-
"claude-fable-5",
|
|
47700
|
-
"claude-fable-5[1m]",
|
|
47701
|
-
"claude-opus-5",
|
|
47702
|
-
"claude-sonnet-5",
|
|
47703
|
-
"claude-haiku-4-5-20251001",
|
|
47704
|
-
"claude-opus-4-6",
|
|
47705
|
-
"claude-sonnet-4-5",
|
|
47706
|
-
"claude-sonnet-4-5-20250929",
|
|
47707
|
-
"claude-opus-4-8",
|
|
47708
|
-
"claude-opus-4-8[1m]",
|
|
47709
|
-
"claude-opus-4-7",
|
|
47710
|
-
"claude-sonnet-4-6",
|
|
47711
|
-
"claude-opus-4-5-20251101",
|
|
47712
|
-
"claude-opus-4-5",
|
|
47713
|
-
"claude-haiku-4-5",
|
|
47714
|
-
"claude-fable-5-1[1m]",
|
|
47715
|
-
"claude-opus-5[1m]",
|
|
47716
|
-
"claude-opus-4-7[1m]",
|
|
47717
|
-
"claude-opus-4-6[1m]",
|
|
47718
|
-
"claude-sonnet-4-6[1m]"
|
|
47719
|
-
]);
|
|
47720
|
-
PERSISTED_EFFORT_LEVELS = new Set(["low", "medium", "high", "xhigh"]);
|
|
47721
|
-
});
|
|
47722
|
-
|
|
47723
47941
|
// src/lib/codex-native-compatibility.ts
|
|
47724
47942
|
function supportsCodexNativeCapability(version2, capability) {
|
|
47725
47943
|
return typeof version2 === "string" && Object.hasOwn(MEASURED_CODEX_CAPABILITIES, version2) && MEASURED_CODEX_CAPABILITIES[version2].includes(capability);
|
|
@@ -47762,7 +47980,7 @@ var init_codex_native_skill_catalog = __esm(() => {
|
|
|
47762
47980
|
});
|
|
47763
47981
|
|
|
47764
47982
|
// src/lib/codex-plugin-skill-controls.ts
|
|
47765
|
-
import { basename as basename5, dirname as dirname10, join as
|
|
47983
|
+
import { basename as basename5, dirname as dirname10, join as join17, relative as relative4, resolve as resolve9, sep as sep5 } from "path";
|
|
47766
47984
|
import { lstatSync as lstatSync11, readdirSync as readdirSync6, readlinkSync as readlinkSync3, realpathSync as realpathSync3 } from "fs";
|
|
47767
47985
|
function refuse() {
|
|
47768
47986
|
throw new Error("CODEX_NATIVE_SKILL_IDENTITY_UNSUPPORTED: review native plugin names and hook controls");
|
|
@@ -47771,7 +47989,7 @@ function remoteInstallationMatches(parent, remotePluginId, read) {
|
|
|
47771
47989
|
try {
|
|
47772
47990
|
if (!remotePluginIdentifier(remotePluginId) || !lstatSync11(parent).isDirectory() || realpathSync3(parent) !== parent)
|
|
47773
47991
|
return false;
|
|
47774
|
-
const path =
|
|
47992
|
+
const path = join17(parent, ".codex-remote-plugin-install.json"), stat = lstatSync11(path, { throwIfNoEntry: false });
|
|
47775
47993
|
if (!stat?.isFile() || stat.isSymbolicLink() || stat.size > 16384)
|
|
47776
47994
|
return false;
|
|
47777
47995
|
const text2 = read(path);
|
|
@@ -47847,8 +48065,8 @@ function isBundledCleanupHooks(root, namespace, value) {
|
|
|
47847
48065
|
return true;
|
|
47848
48066
|
}
|
|
47849
48067
|
function rootControls(root, read) {
|
|
47850
|
-
const manifestPath =
|
|
47851
|
-
if (!lstatSync11(
|
|
48068
|
+
const manifestPath = join17(root, ".codex-plugin/plugin.json"), manifestFile = lstatSync11(manifestPath, { throwIfNoEntry: false });
|
|
48069
|
+
if (!lstatSync11(join17(root, ".codex-plugin"), { throwIfNoEntry: false })?.isDirectory() || !manifestFile?.isFile() || manifestFile.size > 1024 * 1024)
|
|
47852
48070
|
refuse();
|
|
47853
48071
|
let manifest, manifestSha256;
|
|
47854
48072
|
try {
|
|
@@ -47863,9 +48081,9 @@ function rootControls(root, read) {
|
|
|
47863
48081
|
const cacheVersion = basename5(root), declaredVersion = manifest.version === undefined ? "" : typeof manifest.version === "string" ? manifest.version.trim() : null;
|
|
47864
48082
|
if (declaredVersion === null || (declaredVersion ? declaredVersion !== cacheVersion : cacheVersion !== CODEX_DEFAULT_AGENT_PLUGIN_VERSION))
|
|
47865
48083
|
refuse();
|
|
47866
|
-
if (manifest.hooks !== undefined && !isBundledCleanupHooks(root, manifest.name, manifest.hooks) || manifest.commands !== undefined || manifest.mcpServers !== undefined && manifest.mcpServers !== "./.mcp.json" || manifest.apps !== undefined && manifest.apps !== "./.app.json" || lstatSync11(
|
|
48084
|
+
if (manifest.hooks !== undefined && !isBundledCleanupHooks(root, manifest.name, manifest.hooks) || manifest.commands !== undefined || manifest.mcpServers !== undefined && manifest.mcpServers !== "./.mcp.json" || manifest.apps !== undefined && manifest.apps !== "./.app.json" || lstatSync11(join17(root, "hooks"), { throwIfNoEntry: false }))
|
|
47867
48085
|
refuse();
|
|
47868
|
-
const mcp =
|
|
48086
|
+
const mcp = join17(root, ".mcp.json"), mcpPresent = lstatSync11(mcp, { throwIfNoEntry: false });
|
|
47869
48087
|
if (manifest.hooks !== undefined && (manifest.mcpServers !== undefined || mcpPresent))
|
|
47870
48088
|
refuse();
|
|
47871
48089
|
if (mcpPresent && (!mcpPresent.isFile() || mcpPresent.isSymbolicLink() || mcpPresent.size > 1024 * 1024 || realpathSync3(mcp) !== mcp))
|
|
@@ -47873,7 +48091,7 @@ function rootControls(root, read) {
|
|
|
47873
48091
|
if (Boolean(mcpPresent) !== (manifest.mcpServers !== undefined))
|
|
47874
48092
|
refuse();
|
|
47875
48093
|
const mcpSha256 = mcpPresent ? mcpControls(mcp, read) : undefined;
|
|
47876
|
-
const app =
|
|
48094
|
+
const app = join17(root, ".app.json"), present = lstatSync11(app, { throwIfNoEntry: false });
|
|
47877
48095
|
if (present && (!present.isFile() || present.isSymbolicLink() || present.size > 1024 * 1024))
|
|
47878
48096
|
refuse();
|
|
47879
48097
|
if (manifest.apps !== undefined && !present)
|
|
@@ -47883,7 +48101,7 @@ function rootControls(root, read) {
|
|
|
47883
48101
|
}
|
|
47884
48102
|
function reviewedDisabledCodexPluginParent(cache, parent, controls, rules) {
|
|
47885
48103
|
try {
|
|
47886
|
-
const parts = relative4(cache, parent).split(
|
|
48104
|
+
const parts = relative4(cache, parent).split(sep5), enrolled = controls.filter((control) => control.pluginParent === parent);
|
|
47887
48105
|
if (resolve9(parent) !== parent || parts.length !== 2 || parts.some((part) => !identifier2(part)) || !enrolled.length || !Array.isArray(rules))
|
|
47888
48106
|
return false;
|
|
47889
48107
|
for (let cursor = parent;; cursor = dirname10(cursor)) {
|
|
@@ -47893,7 +48111,7 @@ function reviewedDisabledCodexPluginParent(cache, parent, controls, rules) {
|
|
|
47893
48111
|
if (dirname10(cursor) === cursor)
|
|
47894
48112
|
break;
|
|
47895
48113
|
}
|
|
47896
|
-
return enrolled.every((control) => control.namespace === parts[1] && control.pluginId === `${parts[1]}@${parts[0]}` && remotePluginIdentifier(control.remotePluginId) && control.skillsOnly === true && !control.appSha256 && !control.mcpSha256 && control.name.startsWith(control.namespace + ":") && /^[a-f0-9]{64}$/.test(control.manifestSha256) && rules.some((rule) => typeof rule?.name === "string" && rule.name.trim() === control.name && rule.enabled === false) && !rules.some((rule) => (typeof rule?.name === "string" && rule.name.trim() === control.name || typeof rule?.path === "string" && (rule.path === parent || rule.path.startsWith(parent +
|
|
48114
|
+
return enrolled.every((control) => control.namespace === parts[1] && control.pluginId === `${parts[1]}@${parts[0]}` && remotePluginIdentifier(control.remotePluginId) && control.skillsOnly === true && !control.appSha256 && !control.mcpSha256 && control.name.startsWith(control.namespace + ":") && /^[a-f0-9]{64}$/.test(control.manifestSha256) && rules.some((rule) => typeof rule?.name === "string" && rule.name.trim() === control.name && rule.enabled === false) && !rules.some((rule) => (typeof rule?.name === "string" && rule.name.trim() === control.name || typeof rule?.path === "string" && (rule.path === parent || rule.path.startsWith(parent + sep5))) && rule.enabled !== false));
|
|
47897
48115
|
} catch {
|
|
47898
48116
|
return false;
|
|
47899
48117
|
}
|
|
@@ -47903,7 +48121,7 @@ function absentDisabledCodexPluginParent(cache, parent, controls, rules) {
|
|
|
47903
48121
|
}
|
|
47904
48122
|
function reviewedRetiredCodexRoot(cache, root, controls, rules, read, allowAbsent = false) {
|
|
47905
48123
|
try {
|
|
47906
|
-
const parent = dirname10(root), parts = relative4(cache, parent).split(
|
|
48124
|
+
const parent = dirname10(root), parts = relative4(cache, parent).split(sep5), enrolled = controls.filter((control) => control.pluginParent === parent);
|
|
47907
48125
|
if (resolve9(root) !== root || parts.length !== 2 || parts.some((part) => !identifier2(part)) || !basename5(root) || basename5(root) === "latest" || !enrolled.length || !Array.isArray(rules))
|
|
47908
48126
|
return false;
|
|
47909
48127
|
for (let cursor = root;; cursor = dirname10(cursor)) {
|
|
@@ -47913,14 +48131,14 @@ function reviewedRetiredCodexRoot(cache, root, controls, rules, read, allowAbsen
|
|
|
47913
48131
|
if (dirname10(cursor) === cursor)
|
|
47914
48132
|
break;
|
|
47915
48133
|
}
|
|
47916
|
-
if (!enrolled.every((control) => control.namespace === parts[1] && control.pluginId === `${parts[1]}@${parts[0]}` && remotePluginIdentifier(control.remotePluginId) && control.skillsOnly === true && !control.appSha256 && !control.mcpSha256 && control.name.startsWith(control.namespace + ":") && /^[a-f0-9]{64}$/.test(control.manifestSha256) && rules.some((rule) => typeof rule?.name === "string" && rule.name.trim() === control.name && rule.enabled === false) && !rules.some((rule) => (typeof rule?.name === "string" && rule.name.trim() === control.name || typeof rule?.path === "string" && (rule.path === parent || rule.path === root || rule.path.startsWith(root +
|
|
48134
|
+
if (!enrolled.every((control) => control.namespace === parts[1] && control.pluginId === `${parts[1]}@${parts[0]}` && remotePluginIdentifier(control.remotePluginId) && control.skillsOnly === true && !control.appSha256 && !control.mcpSha256 && control.name.startsWith(control.namespace + ":") && /^[a-f0-9]{64}$/.test(control.manifestSha256) && rules.some((rule) => typeof rule?.name === "string" && rule.name.trim() === control.name && rule.enabled === false) && !rules.some((rule) => (typeof rule?.name === "string" && rule.name.trim() === control.name || typeof rule?.path === "string" && (rule.path === parent || rule.path === root || rule.path.startsWith(root + sep5))) && rule.enabled !== false)))
|
|
47917
48135
|
return false;
|
|
47918
48136
|
if (!lstatSync11(root, { throwIfNoEntry: false }))
|
|
47919
48137
|
return allowAbsent && (lstatSync11(parent, { throwIfNoEntry: false }) ? enrolled.every((control) => remoteInstallationMatches(parent, control.remotePluginId, read)) : absentDisabledCodexPluginParent(cache, parent, controls, rules));
|
|
47920
48138
|
if (!enrolled.every((control) => remoteInstallationMatches(parent, control.remotePluginId, read)))
|
|
47921
48139
|
return false;
|
|
47922
48140
|
const parsed = rootControls(root, read);
|
|
47923
|
-
if (JSON.parse(read(
|
|
48141
|
+
if (JSON.parse(read(join17(root, ".codex-plugin/plugin.json"))).hooks !== undefined)
|
|
47924
48142
|
return false;
|
|
47925
48143
|
if (!enrolled.some((control) => control.namespace === parsed.namespace && control.manifestSha256 === parsed.manifestSha256 && !parsed.appSha256 && !parsed.mcpSha256))
|
|
47926
48144
|
return false;
|
|
@@ -47928,7 +48146,7 @@ function reviewedRetiredCodexRoot(cache, root, controls, rules, read, allowAbsen
|
|
|
47928
48146
|
const emptySkills = (directory, depth) => depth <= 64 && readdirSync6(directory).every((name) => {
|
|
47929
48147
|
if (++entries > 4096 || name === "SKILL.md")
|
|
47930
48148
|
return false;
|
|
47931
|
-
const path =
|
|
48149
|
+
const path = join17(directory, name), stat = lstatSync11(path);
|
|
47932
48150
|
return !stat.isSymbolicLink() && (stat.isFile() || stat.isDirectory() && emptySkills(path, depth + 1));
|
|
47933
48151
|
});
|
|
47934
48152
|
return emptySkills(root, 0);
|
|
@@ -47944,7 +48162,7 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache, controls, read, rules)
|
|
|
47944
48162
|
for (const parent of new Set(controls.map((control) => control.pluginParent))) {
|
|
47945
48163
|
if (absentDisabledCodexPluginParent(cache, parent, controls, rules))
|
|
47946
48164
|
continue;
|
|
47947
|
-
if (!parent.startsWith(cache +
|
|
48165
|
+
if (!parent.startsWith(cache + sep5) || !lstatSync11(parent, { throwIfNoEntry: false })?.isDirectory() || realpathSync3(parent) !== parent)
|
|
47948
48166
|
return false;
|
|
47949
48167
|
for (const control of controls.filter((control2) => control2.pluginParent === parent)) {
|
|
47950
48168
|
if (control.remotePluginId !== undefined && !remoteInstallationMatches(parent, control.remotePluginId, read))
|
|
@@ -47955,7 +48173,7 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache, controls, read, rules)
|
|
|
47955
48173
|
if (entries > 4096)
|
|
47956
48174
|
return false;
|
|
47957
48175
|
for (const name of names) {
|
|
47958
|
-
let root =
|
|
48176
|
+
let root = join17(parent, name), stat = lstatSync11(root);
|
|
47959
48177
|
if (stat.isSymbolicLink()) {
|
|
47960
48178
|
const target = resolve9(parent, readlinkSync3(root));
|
|
47961
48179
|
if (name !== "latest" || dirname10(target) !== parent || !lstatSync11(target).isDirectory() || realpathSync3(target) !== target)
|
|
@@ -47963,7 +48181,7 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache, controls, read, rules)
|
|
|
47963
48181
|
root = target;
|
|
47964
48182
|
stat = lstatSync11(root);
|
|
47965
48183
|
}
|
|
47966
|
-
if (!stat.isDirectory() || ![".codex-plugin/plugin.json", ".app.json", "hooks", ".mcp.json"].some((path) => lstatSync11(
|
|
48184
|
+
if (!stat.isDirectory() || ![".codex-plugin/plugin.json", ".app.json", "hooks", ".mcp.json"].some((path) => lstatSync11(join17(root, path), { throwIfNoEntry: false })))
|
|
47967
48185
|
continue;
|
|
47968
48186
|
const parsed = rootControls(root, read);
|
|
47969
48187
|
if (!controls.some((control) => control.pluginParent === parent && control.namespace === parsed.namespace && control.manifestSha256 === parsed.manifestSha256 && control.appSha256 === parsed.appSha256 && control.mcpSha256 === parsed.mcpSha256))
|
|
@@ -47977,10 +48195,10 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache, controls, read, rules)
|
|
|
47977
48195
|
}
|
|
47978
48196
|
function sourceInputUnchanged(input2, cache, read) {
|
|
47979
48197
|
try {
|
|
47980
|
-
const parts = relative4(cache, input2.pluginParent).split(
|
|
47981
|
-
if (parts.length !== 2 || parts.some((part) => !identifier2(part)) || parts[1] !== input2.namespace || input2.pluginId !== `${parts[1]}@${parts[0]}` || !codexPluginSourceIsConfigControlled({ id: input2.pluginId, sourceType: "local", sourceSha256: input2.sourceSha256 }) || input2.sourceSha256 !== hashNativeJsonControls(JSON.stringify({ type: "local", path: input2.sourceRoot })) || resolve9(input2.sourceRoot) !== input2.sourceRoot || !lstatSync11(input2.sourceRoot).isDirectory() || realpathSync3(input2.sourceRoot) !== input2.sourceRoot || input2.sourceRoot === cache || input2.sourceRoot.startsWith(cache +
|
|
48198
|
+
const parts = relative4(cache, input2.pluginParent).split(sep5);
|
|
48199
|
+
if (parts.length !== 2 || parts.some((part) => !identifier2(part)) || parts[1] !== input2.namespace || input2.pluginId !== `${parts[1]}@${parts[0]}` || !codexPluginSourceIsConfigControlled({ id: input2.pluginId, sourceType: "local", sourceSha256: input2.sourceSha256 }) || input2.sourceSha256 !== hashNativeJsonControls(JSON.stringify({ type: "local", path: input2.sourceRoot })) || resolve9(input2.sourceRoot) !== input2.sourceRoot || !lstatSync11(input2.sourceRoot).isDirectory() || realpathSync3(input2.sourceRoot) !== input2.sourceRoot || input2.sourceRoot === cache || input2.sourceRoot.startsWith(cache + sep5) || cache.startsWith(input2.sourceRoot + sep5))
|
|
47982
48200
|
return false;
|
|
47983
|
-
const path =
|
|
48201
|
+
const path = join17(input2.sourceRoot, ".codex-plugin/plugin.json"), stat = lstatSync11(path);
|
|
47984
48202
|
if (!stat.isFile() || stat.size > 1024 * 1024 || realpathSync3(path) !== path)
|
|
47985
48203
|
return false;
|
|
47986
48204
|
const text2 = read(path);
|
|
@@ -47995,7 +48213,7 @@ function reviewedCodexPluginSourceRoots(cache, inputs, read) {
|
|
|
47995
48213
|
if (!Array.isArray(inputs) || inputs.length > 4096 || new Set(inputs.map((input2) => input2.pluginId)).size !== inputs.length || new Set(inputs.map((input2) => input2.sourceRoot)).size !== inputs.length || inputs.some((input2) => !sourceInputUnchanged(input2, cache, read)))
|
|
47996
48214
|
refuse();
|
|
47997
48215
|
const roots = inputs.map((input2) => input2.sourceRoot);
|
|
47998
|
-
if (roots.some((root) => roots.some((other) => root !== other && root.startsWith(other +
|
|
48216
|
+
if (roots.some((root) => roots.some((other) => root !== other && root.startsWith(other + sep5))))
|
|
47999
48217
|
refuse();
|
|
48000
48218
|
return roots;
|
|
48001
48219
|
}
|
|
@@ -48016,7 +48234,7 @@ var init_codex_native_skill_policy = __esm(() => {
|
|
|
48016
48234
|
});
|
|
48017
48235
|
|
|
48018
48236
|
// src/lib/codex-settings-witness-v1.ts
|
|
48019
|
-
import { createHash as
|
|
48237
|
+
import { createHash as createHash10 } from "crypto";
|
|
48020
48238
|
function need3(value) {
|
|
48021
48239
|
if (!value)
|
|
48022
48240
|
throw new Error("Invalid Codex settings witness");
|
|
@@ -48060,8 +48278,8 @@ function numericTokens(text2) {
|
|
|
48060
48278
|
}
|
|
48061
48279
|
return result;
|
|
48062
48280
|
}
|
|
48063
|
-
function
|
|
48064
|
-
need3(depth <= 32 && --
|
|
48281
|
+
function canonical4(value, depth = 0, budget2 = { remaining: 65536 }) {
|
|
48282
|
+
need3(depth <= 32 && --budget2.remaining >= 0);
|
|
48065
48283
|
if (value === null)
|
|
48066
48284
|
return ["null"];
|
|
48067
48285
|
if (typeof value === "string")
|
|
@@ -48077,13 +48295,13 @@ function canonical3(value, depth = 0, budget = { remaining: 65536 }) {
|
|
|
48077
48295
|
return ["date", value.toISOString()];
|
|
48078
48296
|
}
|
|
48079
48297
|
if (Array.isArray(value))
|
|
48080
|
-
return ["array", value.map((child) =>
|
|
48298
|
+
return ["array", value.map((child) => canonical4(child, depth + 1, budget2))];
|
|
48081
48299
|
need3(value && typeof value === "object");
|
|
48082
|
-
return ["object", Object.entries(value).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, child]) => [key,
|
|
48300
|
+
return ["object", Object.entries(value).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, child]) => [key, canonical4(child, depth + 1, budget2)])];
|
|
48083
48301
|
}
|
|
48084
|
-
function hashCodexSettingsReplacement(text2,
|
|
48085
|
-
need3(Buffer.byteLength(text2) <= 1024 * 1024 &&
|
|
48086
|
-
|
|
48302
|
+
function hashCodexSettingsReplacement(text2, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
48303
|
+
need3(Buffer.byteLength(text2) <= 1024 * 1024 && budget2.remaining >= Buffer.byteLength(text2));
|
|
48304
|
+
budget2.remaining -= Buffer.byteLength(text2);
|
|
48087
48305
|
let config2;
|
|
48088
48306
|
try {
|
|
48089
48307
|
config2 = Bun.TOML.parse(text2);
|
|
@@ -48100,13 +48318,13 @@ function hashCodexSettingsReplacement(text2, budget = { remaining: 256 * 1024 *
|
|
|
48100
48318
|
need3(typeof config2[key] === "string" && values.has(config2[key]));
|
|
48101
48319
|
delete config2[key];
|
|
48102
48320
|
}
|
|
48103
|
-
return sha(`hasna.skills.codex-settings.v1\x00${JSON.stringify([
|
|
48321
|
+
return sha(`hasna.skills.codex-settings.v1\x00${JSON.stringify([canonical4(config2), numericTokens(text2)])}`);
|
|
48104
48322
|
}
|
|
48105
|
-
function captureCodexSettings(path,
|
|
48106
|
-
const text2 = readNativeSettingsWitnessFile(path,
|
|
48323
|
+
function captureCodexSettings(path, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
48324
|
+
const text2 = readNativeSettingsWitnessFile(path, budget2, "config.toml");
|
|
48107
48325
|
return { path, hashMode: "codex-settings-v1", sha256: hashCodexSettingsReplacement(text2) };
|
|
48108
48326
|
}
|
|
48109
|
-
var sha = (text2) =>
|
|
48327
|
+
var sha = (text2) => createHash10("sha256").update(text2).digest("hex"), EFFORT, VERBOSITY;
|
|
48110
48328
|
var init_codex_settings_witness_v1 = __esm(() => {
|
|
48111
48329
|
init_claude_settings_witness();
|
|
48112
48330
|
EFFORT = new Set(["none", "minimal", "low", "medium", "high", "xhigh"]);
|
|
@@ -48179,7 +48397,7 @@ function projectRegularCodexMcp(config2, source) {
|
|
|
48179
48397
|
var init_codex_mcp_discovery_projection = () => {};
|
|
48180
48398
|
|
|
48181
48399
|
// src/lib/codex-settings-witness.ts
|
|
48182
|
-
import { createHash as
|
|
48400
|
+
import { createHash as createHash11 } from "crypto";
|
|
48183
48401
|
import { isDeepStrictEqual as isDeepStrictEqual3 } from "util";
|
|
48184
48402
|
function need4(value) {
|
|
48185
48403
|
if (!value)
|
|
@@ -48230,8 +48448,8 @@ function numericTokens2(text2) {
|
|
|
48230
48448
|
}
|
|
48231
48449
|
return result.sort();
|
|
48232
48450
|
}
|
|
48233
|
-
function
|
|
48234
|
-
need4(depth <= 32 && --
|
|
48451
|
+
function canonical5(value, depth = 0, budget2 = { remaining: 65536 }) {
|
|
48452
|
+
need4(depth <= 32 && --budget2.remaining >= 0);
|
|
48235
48453
|
if (value === null)
|
|
48236
48454
|
return ["null"];
|
|
48237
48455
|
if (typeof value === "string")
|
|
@@ -48247,9 +48465,9 @@ function canonical4(value, depth = 0, budget = { remaining: 65536 }) {
|
|
|
48247
48465
|
return ["date", value.toISOString()];
|
|
48248
48466
|
}
|
|
48249
48467
|
if (Array.isArray(value))
|
|
48250
|
-
return ["array", value.map((child) =>
|
|
48468
|
+
return ["array", value.map((child) => canonical5(child, depth + 1, budget2))];
|
|
48251
48469
|
need4(isRecord3(value));
|
|
48252
|
-
return ["object", Object.entries(value).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, child]) => [key,
|
|
48470
|
+
return ["object", Object.entries(value).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, child]) => [key, canonical5(child, depth + 1, budget2)])];
|
|
48253
48471
|
}
|
|
48254
48472
|
function normalize2(config2, version2 = 2) {
|
|
48255
48473
|
if (isRecord3(config2.hooks)) {
|
|
@@ -48423,34 +48641,34 @@ function settingsDigest2(text2, version2 = 2) {
|
|
|
48423
48641
|
const mcp = version2 >= 3 ? projectRegularCodexMcp(config2, text2) : { config: config2, numericSource: text2 };
|
|
48424
48642
|
const projected = version2 === 4 ? projectModelAvailabilityNux(mcp.config, mcp.numericSource) : mcp;
|
|
48425
48643
|
normalize2(projected.config, version2);
|
|
48426
|
-
return sha2(`hasna.skills.codex-settings.v${version2}\x00${JSON.stringify([
|
|
48644
|
+
return sha2(`hasna.skills.codex-settings.v${version2}\x00${JSON.stringify([canonical5(projected.config), numericTokens2(projected.numericSource)])}`);
|
|
48427
48645
|
}
|
|
48428
|
-
function hashCodexSettingsReplacementV2(text2,
|
|
48429
|
-
need4(Buffer.byteLength(text2) <= 1024 * 1024 &&
|
|
48430
|
-
|
|
48646
|
+
function hashCodexSettingsReplacementV2(text2, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
48647
|
+
need4(Buffer.byteLength(text2) <= 1024 * 1024 && budget2.remaining >= Buffer.byteLength(text2));
|
|
48648
|
+
budget2.remaining -= Buffer.byteLength(text2);
|
|
48431
48649
|
return settingsDigest2(text2);
|
|
48432
48650
|
}
|
|
48433
|
-
function captureCodexSettingsV2(path,
|
|
48434
|
-
const text2 = readNativeSettingsWitnessFile(path,
|
|
48651
|
+
function captureCodexSettingsV2(path, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
48652
|
+
const text2 = readNativeSettingsWitnessFile(path, budget2, "config.toml");
|
|
48435
48653
|
return { path, hashMode: "codex-settings-v2", sha256: settingsDigest2(text2) };
|
|
48436
48654
|
}
|
|
48437
|
-
function hashCodexSettingsReplacementV3(text2,
|
|
48438
|
-
need4(Buffer.byteLength(text2) <= 1024 * 1024 &&
|
|
48439
|
-
|
|
48655
|
+
function hashCodexSettingsReplacementV3(text2, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
48656
|
+
need4(Buffer.byteLength(text2) <= 1024 * 1024 && budget2.remaining >= Buffer.byteLength(text2));
|
|
48657
|
+
budget2.remaining -= Buffer.byteLength(text2);
|
|
48440
48658
|
return settingsDigest2(text2, 3);
|
|
48441
48659
|
}
|
|
48442
|
-
function captureCodexSettingsV3(path,
|
|
48443
|
-
return { path, hashMode: "codex-settings-v3", sha256: settingsDigest2(readNativeSettingsWitnessFile(path,
|
|
48660
|
+
function captureCodexSettingsV3(path, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
48661
|
+
return { path, hashMode: "codex-settings-v3", sha256: settingsDigest2(readNativeSettingsWitnessFile(path, budget2, "config.toml"), 3) };
|
|
48444
48662
|
}
|
|
48445
|
-
function hashCodexSettingsReplacementV4(text2,
|
|
48446
|
-
need4(Buffer.byteLength(text2) <= 1024 * 1024 &&
|
|
48447
|
-
|
|
48663
|
+
function hashCodexSettingsReplacementV4(text2, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
48664
|
+
need4(Buffer.byteLength(text2) <= 1024 * 1024 && budget2.remaining >= Buffer.byteLength(text2));
|
|
48665
|
+
budget2.remaining -= Buffer.byteLength(text2);
|
|
48448
48666
|
return settingsDigest2(text2, 4);
|
|
48449
48667
|
}
|
|
48450
|
-
function captureCodexSettingsV4(path,
|
|
48451
|
-
return { path, hashMode: "codex-settings-v4", sha256: settingsDigest2(readNativeSettingsWitnessFile(path,
|
|
48668
|
+
function captureCodexSettingsV4(path, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
48669
|
+
return { path, hashMode: "codex-settings-v4", sha256: settingsDigest2(readNativeSettingsWitnessFile(path, budget2, "config.toml"), 4) };
|
|
48452
48670
|
}
|
|
48453
|
-
var sha2 = (text2) =>
|
|
48671
|
+
var sha2 = (text2) => createHash11("sha256").update(text2).digest("hex"), EFFORT2, VERBOSITY2, MODEL, CODEX_DISCOVERY_PROJECTION_FIELDS, INFERENCE;
|
|
48454
48672
|
var init_codex_settings_witness = __esm(() => {
|
|
48455
48673
|
init_codex_settings_witness_v1();
|
|
48456
48674
|
init_codex_settings_witness_v1();
|
|
@@ -48465,7 +48683,7 @@ var init_codex_settings_witness = __esm(() => {
|
|
|
48465
48683
|
|
|
48466
48684
|
// src/lib/managed-policy.ts
|
|
48467
48685
|
import { closeSync as closeSync9, constants as constants6, fstatSync as fstatSync9, lstatSync as lstatSync12, openSync as openSync9, readSync as readSync5 } from "fs";
|
|
48468
|
-
import { join as
|
|
48686
|
+
import { join as join18 } from "path";
|
|
48469
48687
|
function refusal(reason = "is unreadable") {
|
|
48470
48688
|
return new SkillSelectionError("INVALID_AGENT_POLICY", `The Skills agent loading policy ${reason}; refusing legacy fallback.`);
|
|
48471
48689
|
}
|
|
@@ -48490,7 +48708,7 @@ function parseManagedSkillPolicy(text2) {
|
|
|
48490
48708
|
return value;
|
|
48491
48709
|
}
|
|
48492
48710
|
function readManagedSkillPolicySnapshot(dataDir2 = getDataDirReadOnly()) {
|
|
48493
|
-
const path =
|
|
48711
|
+
const path = join18(dataDir2, "agent-policy.json");
|
|
48494
48712
|
let descriptor, observed = false;
|
|
48495
48713
|
try {
|
|
48496
48714
|
const stat = lstatSync12(path);
|
|
@@ -48543,7 +48761,7 @@ var init_managed_policy = __esm(() => {
|
|
|
48543
48761
|
});
|
|
48544
48762
|
|
|
48545
48763
|
// src/lib/agent-bridge.ts
|
|
48546
|
-
import { createHash as
|
|
48764
|
+
import { createHash as createHash12 } from "crypto";
|
|
48547
48765
|
var CLI_BRIDGE_VERSION = 1, markdown = `---
|
|
48548
48766
|
name: skills-cli
|
|
48549
48767
|
description: Discover, load, author, and run versioned skills through the Skills CLI when a task needs reusable instructions or an executable skill.
|
|
@@ -48559,7 +48777,7 @@ Use the Skills CLI as the skill authority for this station.
|
|
|
48559
48777
|
This bridge contains no skill payloads. Do not copy skill content into agent-native skill directories or load other native skill copies. If a Skills command refuses authority, selection, integrity, or native drift, report that refusal and use its repair guidance; do not substitute bundled or stale local content. Explicit local draft authoring remains available.
|
|
48560
48778
|
`, CLI_BRIDGE_DIGEST, CLI_BRIDGE_FILES;
|
|
48561
48779
|
var init_agent_bridge = __esm(() => {
|
|
48562
|
-
CLI_BRIDGE_DIGEST =
|
|
48780
|
+
CLI_BRIDGE_DIGEST = createHash12("sha256").update(markdown).digest("hex");
|
|
48563
48781
|
CLI_BRIDGE_FILES = Object.freeze({
|
|
48564
48782
|
"SKILL.md": markdown,
|
|
48565
48783
|
".hasna-skills.json": `${JSON.stringify({ managedBy: "@hasna/skills", kind: "cli-bridge", version: CLI_BRIDGE_VERSION, protocol: "selection-v1", contentSha256: CLI_BRIDGE_DIGEST }, null, 2)}
|
|
@@ -48572,39 +48790,39 @@ var init_agent_codex = () => {};
|
|
|
48572
48790
|
|
|
48573
48791
|
// src/lib/agent-sumi.ts
|
|
48574
48792
|
import { existsSync as existsSync8, lstatSync as lstatSync13, realpathSync as realpathSync4 } from "fs";
|
|
48575
|
-
import { join as
|
|
48793
|
+
import { join as join19, resolve as resolve10 } from "path";
|
|
48576
48794
|
function sumiConfigDirectory(home, env = process.env) {
|
|
48577
48795
|
for (const key of ["SUMI_CONFIG", "SUMI_CONFIG_CONTENT"])
|
|
48578
48796
|
if (env[key] !== undefined)
|
|
48579
48797
|
throw new Error(`Sumi ${key} requires a dedicated discovery adapter; unset it before Skills integration`);
|
|
48580
48798
|
const selected = (key) => env[key]?.trim() ? env[key] : undefined;
|
|
48581
|
-
const expand = (value) => resolve10(value === "~" ? home : value.startsWith("~/") ?
|
|
48799
|
+
const expand = (value) => resolve10(value === "~" ? home : value.startsWith("~/") ? join19(home, value.slice(2)) : value);
|
|
48582
48800
|
const explicit = selected("SUMI_CONFIG_DIR");
|
|
48583
48801
|
const xdg = selected("XDG_CONFIG_HOME");
|
|
48584
48802
|
const custom2 = selected("SUMI_HOME");
|
|
48585
|
-
const
|
|
48803
|
+
const canonical6 = explicit ? expand(explicit) : xdg ? join19(expand(xdg), "sumi") : join19(custom2 ? expand(custom2) : join19(home, ".hasna-internal/sumi"), "config");
|
|
48586
48804
|
if (explicit || xdg || custom2)
|
|
48587
|
-
return
|
|
48588
|
-
const legacy =
|
|
48589
|
-
const a = lstatSync13(
|
|
48590
|
-
if (a && b && realpathSync4(
|
|
48805
|
+
return canonical6;
|
|
48806
|
+
const legacy = join19(home, ".config/sumi");
|
|
48807
|
+
const a = lstatSync13(canonical6, { throwIfNoEntry: false }), b = lstatSync13(legacy, { throwIfNoEntry: false });
|
|
48808
|
+
if (a && b && realpathSync4(canonical6) !== realpathSync4(legacy))
|
|
48591
48809
|
throw new Error("Sumi config roots conflict; complete native home adoption before Skills integration");
|
|
48592
|
-
const path = a ?
|
|
48810
|
+
const path = a ? canonical6 : b ? legacy : canonical6;
|
|
48593
48811
|
if (!existsSync8(path))
|
|
48594
48812
|
return path;
|
|
48595
48813
|
const physical = realpathSync4(path);
|
|
48596
|
-
if ((a?.isSymbolicLink() || b?.isSymbolicLink()) && ![
|
|
48814
|
+
if ((a?.isSymbolicLink() || b?.isSymbolicLink()) && ![canonical6, legacy].includes(physical))
|
|
48597
48815
|
throw new Error("Sumi config alias must resolve to its canonical or legacy root");
|
|
48598
48816
|
return physical;
|
|
48599
48817
|
}
|
|
48600
48818
|
function sumiConfigPath(home) {
|
|
48601
|
-
return
|
|
48819
|
+
return join19(sumiConfigDirectory(home), "sumi.json");
|
|
48602
48820
|
}
|
|
48603
48821
|
var init_agent_sumi = () => {};
|
|
48604
48822
|
|
|
48605
48823
|
// src/lib/codex-hook-trust-files.ts
|
|
48606
48824
|
import { closeSync as closeSync10, constants as constants7, fstatSync as fstatSync10, fsyncSync as fsyncSync2, lstatSync as lstatSync14, openSync as openSync10, readSync as readSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
48607
|
-
import { createHash as
|
|
48825
|
+
import { createHash as createHash13 } from "crypto";
|
|
48608
48826
|
import { dirname as dirname11 } from "path";
|
|
48609
48827
|
function need5(value, code) {
|
|
48610
48828
|
if (!value)
|
|
@@ -48639,7 +48857,7 @@ function snapshot(file2, privateFile = false, options = {}) {
|
|
|
48639
48857
|
}
|
|
48640
48858
|
need5(length === Number(before.size) && sameStat(before, fstatSync10(fd, { bigint: true })) && sameStat(before, lstatSync14(file2, { bigint: true })), "INPUT_CHANGED");
|
|
48641
48859
|
const content = bytes.subarray(0, length), text2 = new TextDecoder("utf-8", { fatal: true }).decode(content);
|
|
48642
|
-
return { file: file2, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before, sha256:
|
|
48860
|
+
return { file: file2, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before, sha256: createHash13("sha256").update(content).digest("hex") };
|
|
48643
48861
|
} finally {
|
|
48644
48862
|
closeSync10(fd);
|
|
48645
48863
|
}
|
|
@@ -48653,6 +48871,7 @@ var init_codex_hook_trust_files = () => {};
|
|
|
48653
48871
|
|
|
48654
48872
|
// src/lib/agent-integration.ts
|
|
48655
48873
|
var init_agent_integration = __esm(() => {
|
|
48874
|
+
init_sumi_settings_witness();
|
|
48656
48875
|
init_codex_corpus_write();
|
|
48657
48876
|
init_codex_plugin_skill_controls();
|
|
48658
48877
|
init_codex_native_skill_policy();
|
|
@@ -48707,12 +48926,12 @@ var init_skill_aliases = __esm(() => {
|
|
|
48707
48926
|
|
|
48708
48927
|
// src/lib/project-state.ts
|
|
48709
48928
|
import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync12, writeFileSync as writeFileSync5 } from "fs";
|
|
48710
|
-
import { join as
|
|
48929
|
+
import { join as join20 } from "path";
|
|
48711
48930
|
function getProjectStateDir(targetDir = process.cwd()) {
|
|
48712
|
-
return
|
|
48931
|
+
return join20(targetDir, SKILLS_PROJECT_DIR);
|
|
48713
48932
|
}
|
|
48714
48933
|
function getProjectConfigPath(targetDir = process.cwd()) {
|
|
48715
|
-
return
|
|
48934
|
+
return join20(getProjectStateDir(targetDir), PROJECT_CONFIG_FILE);
|
|
48716
48935
|
}
|
|
48717
48936
|
function loadProjectConfig(targetDir = process.cwd()) {
|
|
48718
48937
|
const path = getProjectConfigPath(targetDir);
|
|
@@ -48828,7 +49047,7 @@ var init_project_state = __esm(() => {
|
|
|
48828
49047
|
|
|
48829
49048
|
// src/lib/installer.ts
|
|
48830
49049
|
import { existsSync as existsSync10, readFileSync as readFileSync13, rmSync } from "fs";
|
|
48831
|
-
import { join as
|
|
49050
|
+
import { join as join21 } from "path";
|
|
48832
49051
|
import { homedir as homedir2 } from "os";
|
|
48833
49052
|
function getSkillPath(name) {
|
|
48834
49053
|
const skillName = normalizeSkillName(getCanonicalSkillName(name));
|
|
@@ -48838,7 +49057,7 @@ function getSkillPath(name) {
|
|
|
48838
49057
|
const extensionPath = findExtensionSkillPath(skillName);
|
|
48839
49058
|
if (extensionPath)
|
|
48840
49059
|
return extensionPath;
|
|
48841
|
-
return
|
|
49060
|
+
return join21(getPortableSkillsRoot(), skillName);
|
|
48842
49061
|
}
|
|
48843
49062
|
function getCanonicalSkillName(name) {
|
|
48844
49063
|
return getSkill(name)?.name ?? resolveSkillAlias(normalizeSkillSlug(name));
|
|
@@ -48892,11 +49111,11 @@ function getAgentSkillsDir(agent, scope = "global", projectDir) {
|
|
|
48892
49111
|
const base = projectDir || process.cwd();
|
|
48893
49112
|
switch (agent) {
|
|
48894
49113
|
case "pi":
|
|
48895
|
-
return scope === "project" ?
|
|
49114
|
+
return scope === "project" ? join21(base, ".pi", "skills") : join21(homedir2(), ".pi", "agent", "skills");
|
|
48896
49115
|
case "opencode":
|
|
48897
|
-
return scope === "project" ?
|
|
49116
|
+
return scope === "project" ? join21(base, ".opencode", "skills") : join21(homedir2(), ".config", "opencode", "skills");
|
|
48898
49117
|
default:
|
|
48899
|
-
return scope === "project" ?
|
|
49118
|
+
return scope === "project" ? join21(base, `.${agent}`, "skills") : join21(homedir2(), `.${agent}`, "skills");
|
|
48900
49119
|
}
|
|
48901
49120
|
}
|
|
48902
49121
|
function warnMissingDependencies(name, targetDir) {
|
|
@@ -48911,7 +49130,7 @@ function warnMissingDependencies(name, targetDir) {
|
|
|
48911
49130
|
}
|
|
48912
49131
|
}
|
|
48913
49132
|
function readBundledSkillVersion(name) {
|
|
48914
|
-
const pkgPath =
|
|
49133
|
+
const pkgPath = join21(getSkillPath(name), "package.json");
|
|
48915
49134
|
if (!existsSync10(pkgPath))
|
|
48916
49135
|
return "unknown";
|
|
48917
49136
|
try {
|
|
@@ -48981,11 +49200,11 @@ var init_skill_doc_file = __esm(() => {
|
|
|
48981
49200
|
|
|
48982
49201
|
// src/lib/skillinfo.ts
|
|
48983
49202
|
import { existsSync as existsSync11, readFileSync as readFileSync14 } from "fs";
|
|
48984
|
-
import { join as
|
|
49203
|
+
import { join as join22 } from "path";
|
|
48985
49204
|
function isInstructionSkillDir(skillPath, meta3) {
|
|
48986
49205
|
if (meta3?.kind === "instruction")
|
|
48987
49206
|
return true;
|
|
48988
|
-
const skillMdPath =
|
|
49207
|
+
const skillMdPath = join22(skillPath, "SKILL.md");
|
|
48989
49208
|
if (!existsSync11(skillMdPath))
|
|
48990
49209
|
return false;
|
|
48991
49210
|
try {
|
|
@@ -48999,9 +49218,9 @@ function getSkillDocs(name) {
|
|
|
48999
49218
|
if (!existsSync11(skillPath))
|
|
49000
49219
|
return null;
|
|
49001
49220
|
return {
|
|
49002
|
-
skillMd: readIfExists(
|
|
49003
|
-
readme: readIfExists(
|
|
49004
|
-
claudeMd: readIfExists(
|
|
49221
|
+
skillMd: readIfExists(join22(skillPath, "SKILL.md")),
|
|
49222
|
+
readme: readIfExists(join22(skillPath, "README.md")),
|
|
49223
|
+
claudeMd: readIfExists(join22(skillPath, "CLAUDE.md"))
|
|
49005
49224
|
};
|
|
49006
49225
|
}
|
|
49007
49226
|
function getSkillBestDoc(name, file2) {
|
|
@@ -49017,14 +49236,14 @@ function getSkillRequirements(name) {
|
|
|
49017
49236
|
return null;
|
|
49018
49237
|
const texts = [];
|
|
49019
49238
|
for (const file2 of ["SKILL.md", "README.md", "CLAUDE.md", ".env.example", ".env.local.example"]) {
|
|
49020
|
-
const content = readIfExists(
|
|
49239
|
+
const content = readIfExists(join22(skillPath, file2));
|
|
49021
49240
|
if (content)
|
|
49022
49241
|
texts.push(content);
|
|
49023
49242
|
}
|
|
49024
49243
|
const meta3 = getSkill(name);
|
|
49025
49244
|
let dependencies = {};
|
|
49026
49245
|
try {
|
|
49027
|
-
dependencies = JSON.parse(readFileSync14(
|
|
49246
|
+
dependencies = JSON.parse(readFileSync14(join22(skillPath, "package.json"), "utf8")).dependencies || {};
|
|
49028
49247
|
} catch {}
|
|
49029
49248
|
return getSkillRequirementsFromContent(name, texts, dependencies, meta3);
|
|
49030
49249
|
}
|
|
@@ -49086,7 +49305,7 @@ async function runSkill(name, args, options = {}) {
|
|
|
49086
49305
|
error: `Skill '${name}' is an instruction skill (kind: instruction) and is not runnable. Instruction skills are consumed by coding agents via SKILL.md, not executed with 'skills run'.`
|
|
49087
49306
|
};
|
|
49088
49307
|
}
|
|
49089
|
-
const pkgPath =
|
|
49308
|
+
const pkgPath = join22(skillPath, "package.json");
|
|
49090
49309
|
if (!existsSync11(pkgPath)) {
|
|
49091
49310
|
return { exitCode: 1, error: `No package.json in skill '${name}'` };
|
|
49092
49311
|
}
|
|
@@ -49106,12 +49325,12 @@ async function runSkill(name, args, options = {}) {
|
|
|
49106
49325
|
} catch {
|
|
49107
49326
|
return { exitCode: 1, error: `Failed to parse package.json for skill '${name}'` };
|
|
49108
49327
|
}
|
|
49109
|
-
const entryPath =
|
|
49328
|
+
const entryPath = join22(skillPath, entryPoint2);
|
|
49110
49329
|
if (!existsSync11(entryPath)) {
|
|
49111
49330
|
return { exitCode: 1, error: `Entry point '${entryPoint2}' not found in skill '${name}'` };
|
|
49112
49331
|
}
|
|
49113
49332
|
const env = { ...process.env, ...options.env };
|
|
49114
|
-
if (!existsSync11(
|
|
49333
|
+
if (!existsSync11(join22(skillPath, "node_modules")) || hasDependencyPreparationMarker(skillPath)) {
|
|
49115
49334
|
const failure = await prepareSkillDependencies(skillPath, env, options.preparationTimeoutMs);
|
|
49116
49335
|
if (failure)
|
|
49117
49336
|
return failure;
|
|
@@ -49137,7 +49356,7 @@ async function runSkill(name, args, options = {}) {
|
|
|
49137
49356
|
function detectProjectSkills(cwd = process.cwd()) {
|
|
49138
49357
|
let pkg;
|
|
49139
49358
|
try {
|
|
49140
|
-
pkg = JSON.parse(readFileSync14(
|
|
49359
|
+
pkg = JSON.parse(readFileSync14(join22(cwd, "package.json"), "utf8"));
|
|
49141
49360
|
} catch {
|
|
49142
49361
|
return { detected: [], recommended: [] };
|
|
49143
49362
|
}
|
|
@@ -49342,7 +49561,7 @@ var init_selection_resolver = __esm(() => {
|
|
|
49342
49561
|
});
|
|
49343
49562
|
|
|
49344
49563
|
// src/lib/plugin-projection.ts
|
|
49345
|
-
import { createHash as
|
|
49564
|
+
import { createHash as createHash14 } from "crypto";
|
|
49346
49565
|
function pluginRefusal(message) {
|
|
49347
49566
|
throw new SkillSelectionError("PLUGIN_ADMISSION_REFUSED", message);
|
|
49348
49567
|
}
|
|
@@ -49420,7 +49639,7 @@ function pluginFileWitnesses(entries) {
|
|
|
49420
49639
|
return { path: item.path, mode: item.mode, size: item.bytes.byteLength, sha256: pluginHash(item.bytes) };
|
|
49421
49640
|
});
|
|
49422
49641
|
}
|
|
49423
|
-
var PLUGIN_PROJECTION_LIMITS, pluginHash = (bytes) =>
|
|
49642
|
+
var PLUGIN_PROJECTION_LIMITS, pluginHash = (bytes) => createHash14("sha256").update(bytes).digest("hex");
|
|
49424
49643
|
var init_plugin_projection = __esm(() => {
|
|
49425
49644
|
init_selection_cache();
|
|
49426
49645
|
PLUGIN_PROJECTION_LIMITS = Object.freeze({ files: 1024, bytes: 64 * 1024 * 1024, fileBytes: 16 * 1024 * 1024, metadataBytes: 512 * 1024, registrations: 64, history: 128 });
|
|
@@ -49428,7 +49647,7 @@ var init_plugin_projection = __esm(() => {
|
|
|
49428
49647
|
|
|
49429
49648
|
// src/lib/plugin-projection-store.ts
|
|
49430
49649
|
import { constants as constants8, closeSync as closeSync11, fchmodSync, fstatSync as fstatSync11, fsyncSync as fsyncSync3, linkSync as linkSync2, lstatSync as lstatSync15, mkdirSync as mkdirSync6, openSync as openSync11, opendirSync as opendirSync2, readSync as readSync7, renameSync as renameSync2, rmdirSync as rmdirSync2, rmSync as rmSync2, unlinkSync as unlinkSync3, writeSync as writeSync2 } from "fs";
|
|
49431
|
-
import { dirname as dirname12, isAbsolute as isAbsolute9, join as
|
|
49650
|
+
import { dirname as dirname12, isAbsolute as isAbsolute9, join as join23, parse as parse10, resolve as resolve11 } from "path";
|
|
49432
49651
|
function stat(path) {
|
|
49433
49652
|
try {
|
|
49434
49653
|
return lstatSync15(path, { bigint: true });
|
|
@@ -49438,7 +49657,7 @@ function stat(path) {
|
|
|
49438
49657
|
return pluginRefusal("Cannot inspect plugin filesystem entry");
|
|
49439
49658
|
}
|
|
49440
49659
|
}
|
|
49441
|
-
function
|
|
49660
|
+
function canonical6(path) {
|
|
49442
49661
|
pluginNeed(typeof path === "string" && path.length <= 8192 && isAbsolute9(path) && resolve11(path) === path && !/[\x00-\x1f\x7f]/.test(path), "Plugin storage paths must be canonical absolute paths");
|
|
49443
49662
|
}
|
|
49444
49663
|
function owner(stats, system = false) {
|
|
@@ -49449,12 +49668,12 @@ function same3(left, right, identityOnly = false) {
|
|
|
49449
49668
|
pluginNeed(right && left.dev === right.dev && left.ino === right.ino && left.mode === right.mode && left.uid === right.uid && left.gid === right.gid && (identityOnly || left.size === right.size && left.nlink === right.nlink && left.mtimeNs === right.mtimeNs && left.ctimeNs === right.ctimeNs), "Plugin filesystem entry changed during access");
|
|
49450
49669
|
}
|
|
49451
49670
|
function ancestors(path, create = false) {
|
|
49452
|
-
|
|
49453
|
-
const result = [], parent = dirname12(path), filesystemRoot =
|
|
49671
|
+
canonical6(path);
|
|
49672
|
+
const result = [], parent = dirname12(path), filesystemRoot = parse10(parent).root;
|
|
49454
49673
|
let current = filesystemRoot;
|
|
49455
49674
|
for (const segment of ["", ...parent.slice(filesystemRoot.length).split("/").filter(Boolean)]) {
|
|
49456
49675
|
if (segment)
|
|
49457
|
-
current =
|
|
49676
|
+
current = join23(current, segment);
|
|
49458
49677
|
let currentStat = stat(current);
|
|
49459
49678
|
if (!currentStat && create) {
|
|
49460
49679
|
try {
|
|
@@ -49562,7 +49781,7 @@ function snapshotPluginTree(root, options = {}) {
|
|
|
49562
49781
|
pluginNeed(++visited <= PLUGIN_PROJECTION_LIMITS.files * 50, "Plugin tree membership exceeds its limit");
|
|
49563
49782
|
const path = relative5 ? `${relative5}/${name}` : name;
|
|
49564
49783
|
pluginNeed(new TextEncoder().encode(path).byteLength <= 100 && !/[\\:\x00-\x1f\x7f]/u.test(path), "Plugin entry path exceeds its limit or is unsafe");
|
|
49565
|
-
const absolute =
|
|
49784
|
+
const absolute = join23(directory, name), entryStat = stat(absolute);
|
|
49566
49785
|
pluginNeed(entryStat, "Plugin tree member disappeared");
|
|
49567
49786
|
if (relative5 === "" && name === ".orphaned_at" && (options.nativeRuntime === "claude-2.1.274" || options.nativeRuntime === "claude-2.1.276")) {
|
|
49568
49787
|
const bytes2 = readBytes(absolute, 32, "native-pin");
|
|
@@ -49579,7 +49798,7 @@ function snapshotPluginTree(root, options = {}) {
|
|
|
49579
49798
|
directories.push({ path: absolute, stat: entryStat, names: pins });
|
|
49580
49799
|
for (const pin of pins) {
|
|
49581
49800
|
pluginNeed(/^[1-9][0-9]{0,9}$/.test(pin) && Number(pin) <= 2147483647, "Unrecognized native plugin pin name");
|
|
49582
|
-
const pinPath =
|
|
49801
|
+
const pinPath = join23(absolute, pin), pinStat = stat(pinPath);
|
|
49583
49802
|
pluginNeed(pinStat, "Native plugin pin disappeared");
|
|
49584
49803
|
const bytes2 = readBytes(pinPath, 4096, "native-pin");
|
|
49585
49804
|
let value;
|
|
@@ -49676,7 +49895,7 @@ var init_selected_manifest = __esm(() => {
|
|
|
49676
49895
|
});
|
|
49677
49896
|
|
|
49678
49897
|
// src/lib/plugin-admission.ts
|
|
49679
|
-
import { isAbsolute as isAbsolute10, join as
|
|
49898
|
+
import { isAbsolute as isAbsolute10, join as join24, resolve as resolve12 } from "path";
|
|
49680
49899
|
function validatePluginTarget(value) {
|
|
49681
49900
|
pluginKeys(value, ["schemaVersion", "pluginId", "registrations", "native", "resolver"]);
|
|
49682
49901
|
pluginNeed(value.schemaVersion === 1, "Invalid plugin admission target");
|
|
@@ -49837,12 +50056,12 @@ function pluginResolverCommand(binding) {
|
|
|
49837
50056
|
}
|
|
49838
50057
|
function pluginBindingPath(storeRoot, id) {
|
|
49839
50058
|
pluginNeed(/^[a-f0-9]{64}$/.test(id), "Invalid plugin binding identifier");
|
|
49840
|
-
return
|
|
50059
|
+
return join24(storeRoot, "bindings", `${id}.json`);
|
|
49841
50060
|
}
|
|
49842
50061
|
function pluginReceiptPath(storeRoot, id, digest) {
|
|
49843
50062
|
pluginNeed(/^[a-f0-9]{64}$/.test(id), "Invalid plugin binding identifier");
|
|
49844
50063
|
pluginDigest(digest);
|
|
49845
|
-
return
|
|
50064
|
+
return join24(storeRoot, "receipts", id, `${digest.slice(7)}.json`);
|
|
49846
50065
|
}
|
|
49847
50066
|
function readPluginBinding(storeRoot, id) {
|
|
49848
50067
|
const value = readPluginJson(pluginBindingPath(storeRoot, id));
|
|
@@ -49862,7 +50081,7 @@ function readPluginAdmissionReceipt(storeRoot, id, digest) {
|
|
|
49862
50081
|
pluginNeed(receipt.plan.bindingId === id && receipt.plan.planDigest === digest, "Plugin receipt identity differs from its filename");
|
|
49863
50082
|
const binding = readPluginBinding(storeRoot, id);
|
|
49864
50083
|
pluginNeed(canonicalJson(binding) === canonicalJson(receipt.plan.binding) && receipt.plan.sourceCommand === pluginResolverCommand(binding), "Plugin receipt binding changed");
|
|
49865
|
-
pluginNeed(receipt.materializedPath ===
|
|
50084
|
+
pluginNeed(receipt.materializedPath === join24(storeRoot, "objects", id, digest.slice(7)), "Plugin receipt points outside its immutable materialization");
|
|
49866
50085
|
pluginText(receipt.admittedAt, 64);
|
|
49867
50086
|
pluginNeed(Number.isFinite(Date.parse(receipt.admittedAt)), "Invalid plugin admission time");
|
|
49868
50087
|
return receipt;
|
|
@@ -49880,7 +50099,7 @@ var init_plugin_admission = __esm(() => {
|
|
|
49880
50099
|
|
|
49881
50100
|
// src/lib/plugin-discovery.ts
|
|
49882
50101
|
import { closeSync as closeSync12, constants as constants9, fstatSync as fstatSync12, lstatSync as lstatSync16, openSync as openSync12, opendirSync as opendirSync3, readSync as readSync8 } from "fs";
|
|
49883
|
-
import { basename as basename6, dirname as dirname13, isAbsolute as isAbsolute11, join as
|
|
50102
|
+
import { basename as basename6, dirname as dirname13, isAbsolute as isAbsolute11, join as join25, resolve as resolve13 } from "path";
|
|
49884
50103
|
function validateManagedPluginWitnesses(value) {
|
|
49885
50104
|
pluginNeed(Array.isArray(value) && value.length > 0 && value.length <= PLUGIN_PROJECTION_LIMITS.registrations, "Invalid managed plugin witness collection");
|
|
49886
50105
|
const seen = new Set;
|
|
@@ -49947,7 +50166,7 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
49947
50166
|
seen.add(target.pluginId);
|
|
49948
50167
|
const rows = plugins[target.pluginId];
|
|
49949
50168
|
pluginNeed(Array.isArray(rows) && rows.length === target.registrations.length, "Managed plugin registration membership changed");
|
|
49950
|
-
const [name, market] = target.pluginId.split("@"), cacheRoot =
|
|
50169
|
+
const [name, market] = target.pluginId.split("@"), cacheRoot = join25(dirname13(path), "cache", market, name);
|
|
49951
50170
|
const scopes = new Set, approvals = new Map, currentFiles = new Map;
|
|
49952
50171
|
plugins[target.pluginId] = rows.map((row) => {
|
|
49953
50172
|
pluginNeed(pluginObject(row), "Invalid managed plugin registration");
|
|
@@ -49960,7 +50179,7 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
49960
50179
|
pluginText(row.sourceProducerPath);
|
|
49961
50180
|
pluginText(row.lastUpdated, 64);
|
|
49962
50181
|
pluginNeed(Number.isFinite(Date.parse(row.lastUpdated)), "Invalid managed plugin update timestamp");
|
|
49963
|
-
pluginNeed(/^(?:[A-Za-z0-9][A-Za-z0-9._+-]*-)?[a-f0-9]{12}$/.test(row.version) && row.installPath ===
|
|
50182
|
+
pluginNeed(/^(?:[A-Za-z0-9][A-Za-z0-9._+-]*-)?[a-f0-9]{12}$/.test(row.version) && row.installPath === join25(cacheRoot, row.version), "Managed plugin cache path or version is outside its registration");
|
|
49964
50183
|
const approval = (producer) => {
|
|
49965
50184
|
pluginText(producer);
|
|
49966
50185
|
const digest = `sha256:${basename6(producer)}`;
|
|
@@ -50003,11 +50222,11 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
50003
50222
|
directory.closeSync();
|
|
50004
50223
|
}
|
|
50005
50224
|
for (const version2 of names.sort()) {
|
|
50006
|
-
const files = pluginFileWitnesses(snapshotPluginTree(
|
|
50225
|
+
const files = pluginFileWitnesses(snapshotPluginTree(join25(cacheRoot, version2), { nativeRuntime: `claude-${target.native.version}` }));
|
|
50007
50226
|
verifiedBytes += files.reduce((total, file2) => total + file2.size, 0);
|
|
50008
50227
|
pluginNeed(verifiedBytes <= 256 * 1024 * 1024, "Managed plugin verification exceeds its aggregate byte budget");
|
|
50009
50228
|
const serialized = JSON.stringify(files);
|
|
50010
|
-
const expected = currentFiles.get(
|
|
50229
|
+
const expected = currentFiles.get(join25(cacheRoot, version2));
|
|
50011
50230
|
pluginNeed(expected === undefined || serialized === expected, "Current native cache differs from its exact registered producer receipt");
|
|
50012
50231
|
pluginNeed([...approvals.values()].some((receipt) => nativeVersionMatches(version2, receipt) && JSON.stringify(receipt.plan.files) === serialized), "A retained native plugin cache version differs from every approved projection");
|
|
50013
50232
|
}
|
|
@@ -50027,7 +50246,7 @@ var init_plugin_discovery = __esm(() => {
|
|
|
50027
50246
|
});
|
|
50028
50247
|
|
|
50029
50248
|
// src/lib/claude-marketplace-registry.ts
|
|
50030
|
-
import { createHash as
|
|
50249
|
+
import { createHash as createHash15 } from "crypto";
|
|
50031
50250
|
import { closeSync as closeSync13, constants as constants10, fstatSync as fstatSync13, lstatSync as lstatSync17, openSync as openSync13, readSync as readSync9 } from "fs";
|
|
50032
50251
|
import { basename as basename7, dirname as dirname14, isAbsolute as isAbsolute12, resolve as resolve14 } from "path";
|
|
50033
50252
|
function need6(value, reason) {
|
|
@@ -50047,13 +50266,13 @@ function parents2(path) {
|
|
|
50047
50266
|
return result;
|
|
50048
50267
|
}
|
|
50049
50268
|
}
|
|
50050
|
-
function readRegistry2(path,
|
|
50269
|
+
function readRegistry2(path, budget2) {
|
|
50051
50270
|
absolutePath2(path);
|
|
50052
50271
|
need6(basename7(path) === "known_marketplaces.json", "requires known_marketplaces.json");
|
|
50053
|
-
need6(Number.isSafeInteger(
|
|
50272
|
+
need6(Number.isSafeInteger(budget2.remaining) && budget2.remaining >= 0, "has an invalid byte budget");
|
|
50054
50273
|
const ancestors2 = parents2(path), initial = lstatSync17(path, { bigint: true });
|
|
50055
50274
|
need6(initial.isFile() && !initial.isSymbolicLink() && initial.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
|
|
50056
|
-
need6(initial.size <= BigInt(
|
|
50275
|
+
need6(initial.size <= BigInt(budget2.remaining), "exceeds its aggregate byte limit");
|
|
50057
50276
|
const fd = openSync13(path, constants10.O_RDONLY | constants10.O_NOFOLLOW | constants10.O_NONBLOCK);
|
|
50058
50277
|
try {
|
|
50059
50278
|
const opened = fstatSync13(fd, { bigint: true });
|
|
@@ -50072,7 +50291,7 @@ function readRegistry2(path, budget) {
|
|
|
50072
50291
|
const now = lstatSync17(ancestor, { bigint: true });
|
|
50073
50292
|
need6(now.isDirectory() && before.dev === now.dev && before.ino === now.ino && before.mode === now.mode, "parent changed during read");
|
|
50074
50293
|
}
|
|
50075
|
-
|
|
50294
|
+
budget2.remaining -= length;
|
|
50076
50295
|
try {
|
|
50077
50296
|
return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes.subarray(0, length));
|
|
50078
50297
|
} catch {
|
|
@@ -50082,7 +50301,7 @@ function readRegistry2(path, budget) {
|
|
|
50082
50301
|
closeSync13(fd);
|
|
50083
50302
|
}
|
|
50084
50303
|
}
|
|
50085
|
-
function
|
|
50304
|
+
function parse11(text2) {
|
|
50086
50305
|
let at = 0, nodes = 0;
|
|
50087
50306
|
const numberPattern = /-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?/y;
|
|
50088
50307
|
const space = () => {
|
|
@@ -50189,18 +50408,18 @@ function normalizeRow(row, version2 = 1) {
|
|
|
50189
50408
|
need6(Number.isFinite(millis) && new Date(millis).toISOString() === updated, "contains an invalid recognized update timestamp");
|
|
50190
50409
|
row.entries = row.entries.map(([key, value]) => [key, key === "lastUpdated" ? { kind: "validated-update-time" } : value]);
|
|
50191
50410
|
}
|
|
50192
|
-
function captureClaudeMarketplaceRegistry(path,
|
|
50193
|
-
const value =
|
|
50411
|
+
function captureClaudeMarketplaceRegistry(path, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
50412
|
+
const value = parse11(readRegistry2(path, budget2));
|
|
50194
50413
|
for (const [, row] of value.entries)
|
|
50195
50414
|
normalizeRow(row);
|
|
50196
|
-
const sha2562 =
|
|
50415
|
+
const sha2562 = createHash15("sha256").update("hasna.skills.claude-marketplace-registry.v1\x00").update(JSON.stringify(value)).digest("hex");
|
|
50197
50416
|
return { path, hashMode: "claude-marketplace-registry", sha256: sha2562 };
|
|
50198
50417
|
}
|
|
50199
|
-
function captureClaudeMarketplaceRegistryV2(path,
|
|
50200
|
-
const value =
|
|
50418
|
+
function captureClaudeMarketplaceRegistryV2(path, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
50419
|
+
const value = parse11(readRegistry2(path, budget2));
|
|
50201
50420
|
for (const [, row] of value.entries)
|
|
50202
50421
|
normalizeRow(row, 2);
|
|
50203
|
-
const sha2562 =
|
|
50422
|
+
const sha2562 = createHash15("sha256").update("hasna.skills.claude-marketplace-registry.v2\x00").update(JSON.stringify(value)).digest("hex");
|
|
50204
50423
|
return { path, hashMode: "claude-marketplace-registry-v2", sha256: sha2562 };
|
|
50205
50424
|
}
|
|
50206
50425
|
var CLAUDE_MARKETPLACE_REGISTRY_LIMITS, sameFile2 = (a, b) => a.dev === b.dev && a.ino === b.ino && a.mode === b.mode && a.uid === b.uid && a.gid === b.gid && a.nlink === b.nlink && a.size === b.size && a.mtimeNs === b.mtimeNs && a.ctimeNs === b.ctimeNs, field = (object7, key) => object7.entries.find(([name]) => name === key)?.[1];
|
|
@@ -50222,7 +50441,7 @@ var init_codex_hook_additions_review = __esm(() => {
|
|
|
50222
50441
|
});
|
|
50223
50442
|
|
|
50224
50443
|
// src/lib/codex-hook-discovery-recovery.ts
|
|
50225
|
-
import { createHash as
|
|
50444
|
+
import { createHash as createHash16 } from "crypto";
|
|
50226
50445
|
function assertCodexHookDiscoveryRecovery(binding, witness) {
|
|
50227
50446
|
const proof = proofs2.get(witness);
|
|
50228
50447
|
need5(!!proof && binding.agent === "codex" && witness.discoverySha256 === sha3(JSON.stringify(binding)), "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
|
|
@@ -50237,7 +50456,7 @@ function verifiesCodexHookDiscoverySource(binding, source, currentDigest, witnes
|
|
|
50237
50456
|
need5(source.sha256 === witness.beforeSha256 && currentDigest === witness.currentSha256, "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
|
|
50238
50457
|
return true;
|
|
50239
50458
|
}
|
|
50240
|
-
var sha3 = (text2) =>
|
|
50459
|
+
var sha3 = (text2) => createHash16("sha256").update(text2).digest("hex"), fields, proofs2;
|
|
50241
50460
|
var init_codex_hook_discovery_recovery = __esm(() => {
|
|
50242
50461
|
init_codex_hook_trust_files();
|
|
50243
50462
|
init_codex_hook_trust_layout();
|
|
@@ -50248,9 +50467,9 @@ var init_codex_hook_discovery_recovery = __esm(() => {
|
|
|
50248
50467
|
});
|
|
50249
50468
|
|
|
50250
50469
|
// src/lib/agent-discovery.ts
|
|
50251
|
-
import { createHash as
|
|
50470
|
+
import { createHash as createHash17 } from "crypto";
|
|
50252
50471
|
import { lstatSync as lstatSync18, readFileSync as readFileSync15, readdirSync as readdirSync7, realpathSync as realpathSync5 } from "fs";
|
|
50253
|
-
import { basename as basename8, dirname as dirname15, isAbsolute as isAbsolute13, join as
|
|
50472
|
+
import { basename as basename8, dirname as dirname15, isAbsolute as isAbsolute13, join as join26, resolve as resolve15, sep as sep6 } from "path";
|
|
50254
50473
|
import { isDeepStrictEqual as isDeepStrictEqual4 } from "util";
|
|
50255
50474
|
function parseConfig(text2, path, toml = false) {
|
|
50256
50475
|
try {
|
|
@@ -50289,33 +50508,45 @@ function projectNativeDiscoveryFields(text2, format, fields2, path) {
|
|
|
50289
50508
|
throw new Error("Expected native discovery configuration object");
|
|
50290
50509
|
return digest(JSON.stringify(Object.fromEntries(fields2.map((field2) => [field2, object7[field2] ?? null]))));
|
|
50291
50510
|
}
|
|
50292
|
-
function
|
|
50511
|
+
function isSupersededSettingsProjection(agent, configPath, source) {
|
|
50512
|
+
if (agent === "sumi")
|
|
50513
|
+
return source.path === configPath && source.format === "json" && isDeepStrictEqual4(source.fields, [...SUMI_DISCOVERY_PROJECTION_FIELDS]);
|
|
50293
50514
|
return agent === "codex" && source.path === configPath && source.format === "toml" && isDeepStrictEqual4(source.fields, [...CODEX_DISCOVERY_PROJECTION_FIELDS]);
|
|
50294
50515
|
}
|
|
50295
|
-
function
|
|
50296
|
-
|
|
50516
|
+
function supersedesSettingsProjection(agent, sources, configPath) {
|
|
50517
|
+
if (agent === "sumi")
|
|
50518
|
+
return sources.some((source) => source.path === configPath && source.hashMode === "sumi-settings-v1");
|
|
50519
|
+
return agent === "codex" && sources.some((source) => source.path === configPath && (source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")));
|
|
50297
50520
|
}
|
|
50298
|
-
function projected(source, changes,
|
|
50521
|
+
function projected(source, changes, budget2 = discoveryByteBudget()) {
|
|
50522
|
+
if (source.hashMode === "sumi-settings-v1") {
|
|
50523
|
+
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
50524
|
+
throw new Error("Sumi settings witnesses require exact typed metadata");
|
|
50525
|
+
const current = captureSumiSettings(source.path, budget2).sha256;
|
|
50526
|
+
if (current !== source.sha256)
|
|
50527
|
+
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
50528
|
+
return changes?.has(source.path) ? hashSumiSettingsReplacement(changes.get(source.path), budget2) : current;
|
|
50529
|
+
}
|
|
50299
50530
|
if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")) {
|
|
50300
50531
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
50301
50532
|
throw new Error("Codex settings witnesses require exact typed metadata");
|
|
50302
|
-
const current = (source.hashMode === "codex-settings-v4" ? captureCodexSettingsV4 : source.hashMode === "codex-settings-v3" ? captureCodexSettingsV3 : source.hashMode === "codex-settings-v2" ? captureCodexSettingsV2 : captureCodexSettings)(source.path,
|
|
50533
|
+
const current = (source.hashMode === "codex-settings-v4" ? captureCodexSettingsV4 : source.hashMode === "codex-settings-v3" ? captureCodexSettingsV3 : source.hashMode === "codex-settings-v2" ? captureCodexSettingsV2 : captureCodexSettings)(source.path, budget2).sha256;
|
|
50303
50534
|
if (current !== source.sha256)
|
|
50304
50535
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
50305
|
-
return changes?.has(source.path) ? (source.hashMode === "codex-settings-v4" ? hashCodexSettingsReplacementV4 : source.hashMode === "codex-settings-v3" ? hashCodexSettingsReplacementV3 : source.hashMode === "codex-settings-v2" ? hashCodexSettingsReplacementV2 : hashCodexSettingsReplacement)(changes.get(source.path),
|
|
50536
|
+
return changes?.has(source.path) ? (source.hashMode === "codex-settings-v4" ? hashCodexSettingsReplacementV4 : source.hashMode === "codex-settings-v3" ? hashCodexSettingsReplacementV3 : source.hashMode === "codex-settings-v2" ? hashCodexSettingsReplacementV2 : hashCodexSettingsReplacement)(changes.get(source.path), budget2) : current;
|
|
50306
50537
|
}
|
|
50307
50538
|
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") {
|
|
50308
50539
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
50309
50540
|
throw new Error("Claude settings witnesses require exact typed metadata");
|
|
50310
|
-
const current = (source.hashMode === "claude-settings-v3" ? captureClaudeSettingsV3 : source.hashMode === "claude-settings-v2" ? captureClaudeSettingsV2 : captureClaudeSettings)(source.path,
|
|
50541
|
+
const current = (source.hashMode === "claude-settings-v3" ? captureClaudeSettingsV3 : source.hashMode === "claude-settings-v2" ? captureClaudeSettingsV2 : captureClaudeSettings)(source.path, budget2).sha256;
|
|
50311
50542
|
if (current !== source.sha256)
|
|
50312
50543
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
50313
|
-
return changes?.has(source.path) ? (source.hashMode === "claude-settings-v3" ? hashClaudeSettingsReplacementV3 : source.hashMode === "claude-settings-v2" ? hashClaudeSettingsReplacementV2 : hashClaudeSettingsReplacement)(changes.get(source.path),
|
|
50544
|
+
return changes?.has(source.path) ? (source.hashMode === "claude-settings-v3" ? hashClaudeSettingsReplacementV3 : source.hashMode === "claude-settings-v2" ? hashClaudeSettingsReplacementV2 : hashClaudeSettingsReplacement)(changes.get(source.path), budget2) : current;
|
|
50314
50545
|
}
|
|
50315
50546
|
if (source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2") {
|
|
50316
50547
|
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))
|
|
50317
50548
|
throw new Error("Claude marketplace witnesses require an exact reviewed registry without synthetic changes");
|
|
50318
|
-
const sha2562 = (source.hashMode === "claude-marketplace-registry-v2" ? captureClaudeMarketplaceRegistryV2 : captureClaudeMarketplaceRegistry)(source.path,
|
|
50549
|
+
const sha2562 = (source.hashMode === "claude-marketplace-registry-v2" ? captureClaudeMarketplaceRegistryV2 : captureClaudeMarketplaceRegistry)(source.path, budget2).sha256;
|
|
50319
50550
|
if (sha2562 !== source.sha256)
|
|
50320
50551
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
50321
50552
|
return sha2562;
|
|
@@ -50325,6 +50556,12 @@ function projected(source, changes, budget = discoveryByteBudget()) {
|
|
|
50325
50556
|
throw new Error("Managed plugin registry witnesses require verified native registrations");
|
|
50326
50557
|
return hashManagedPluginRegistry(source.path, source.managedPlugins);
|
|
50327
50558
|
}
|
|
50559
|
+
if (source.hashMode === "claude-plugin-manifest-v1") {
|
|
50560
|
+
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || changes?.has(source.path))
|
|
50561
|
+
throw new Error("Claude plugin manifest witnesses require a native discovery source without synthetic changes");
|
|
50562
|
+
const text3 = read(source.path);
|
|
50563
|
+
return text3 === null ? null : hashClaudePluginManifest(text3);
|
|
50564
|
+
}
|
|
50328
50565
|
if (source.managedPlugins !== undefined)
|
|
50329
50566
|
throw new Error("Managed plugin rules require a typed registry witness");
|
|
50330
50567
|
if (source.hashMode !== undefined) {
|
|
@@ -50333,8 +50570,8 @@ function projected(source, changes, budget = discoveryByteBudget()) {
|
|
|
50333
50570
|
if (source.format !== undefined || source.fields !== undefined)
|
|
50334
50571
|
throw new Error("Raw discovery witnesses cannot project configuration fields");
|
|
50335
50572
|
if (source.hashMode === "path-bytes")
|
|
50336
|
-
return hashDiscoveryPathFile(source.path,
|
|
50337
|
-
return hashRawDiscoveryFile(source.path,
|
|
50573
|
+
return hashDiscoveryPathFile(source.path, budget2, changes);
|
|
50574
|
+
return hashRawDiscoveryFile(source.path, budget2, changes);
|
|
50338
50575
|
}
|
|
50339
50576
|
const text2 = read(source.path, changes);
|
|
50340
50577
|
if (text2 === null)
|
|
@@ -50351,7 +50588,7 @@ function absentCodexSkillRoots(binding) {
|
|
|
50351
50588
|
throw new Error("Invalid disabled Codex discovery proof");
|
|
50352
50589
|
if (binding.method !== "reviewed" || controls.every((control) => lstatSync18(control.pluginParent, { throwIfNoEntry: false })))
|
|
50353
50590
|
return [];
|
|
50354
|
-
const cache = dirname15(dirname15(controls[0].pluginParent)), config2 =
|
|
50591
|
+
const cache = dirname15(dirname15(controls[0].pluginParent)), config2 = join26(dirname15(dirname15(cache)), "config.toml");
|
|
50355
50592
|
const source = binding.sources.find((source2) => source2.path === config2 && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined);
|
|
50356
50593
|
if (!source || projected(source) !== source.sha256)
|
|
50357
50594
|
throw new Error("Missing current disabled Codex configuration witness");
|
|
@@ -50359,8 +50596,8 @@ function absentCodexSkillRoots(binding) {
|
|
|
50359
50596
|
return [...new Set(controls.map((control) => control.pluginParent))].filter((parent) => !codexDirectHookSelects(cache, parent) && absentDisabledCodexPluginParent(cache, parent, controls, rules));
|
|
50360
50597
|
}
|
|
50361
50598
|
function codexDirectHookSelects(cache, root) {
|
|
50362
|
-
const codex = dirname15(dirname15(cache)), config2 = Bun.TOML.parse(read(
|
|
50363
|
-
const hooks = read(
|
|
50599
|
+
const codex = dirname15(dirname15(cache)), config2 = Bun.TOML.parse(read(join26(codex, "config.toml")) ?? "");
|
|
50600
|
+
const hooks = read(join26(codex, "hooks.json"));
|
|
50364
50601
|
if (hooks !== null)
|
|
50365
50602
|
hashNativeJsonControls(hooks);
|
|
50366
50603
|
return JSON.stringify(config2.hooks ?? {}).includes(root) || hooks !== null && JSON.stringify(JSON.parse(hooks)).includes(root);
|
|
@@ -50372,7 +50609,7 @@ function retiredCodexRoots(binding) {
|
|
|
50372
50609
|
const controls = binding.codexDisabledPluginSkills;
|
|
50373
50610
|
if (binding.agent !== "codex" || binding.method !== "reviewed" || !Array.isArray(controls) || !controls.length || !Array.isArray(proof.roots) || proof.roots.length > AGENT_POLICY_LIMITS.discoveryRoots || new Set(proof.roots).size !== proof.roots.length || !Array.isArray(proof.directories) || proof.parents !== undefined && (!Array.isArray(proof.parents) || proof.parents.length > AGENT_POLICY_LIMITS.discoveryRoots || new Set(proof.parents).size !== proof.parents.length) || !proof.roots.length && !proof.parents?.length)
|
|
50374
50611
|
throw new Error("Invalid retired Codex materialization proof");
|
|
50375
|
-
const cache = dirname15(dirname15(controls[0].pluginParent)), config2 =
|
|
50612
|
+
const cache = dirname15(dirname15(controls[0].pluginParent)), config2 = join26(dirname15(dirname15(cache)), "config.toml");
|
|
50376
50613
|
const source = binding.sources.find((source2) => source2.path === config2 && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined);
|
|
50377
50614
|
if (!source || projected(source) !== source.sha256)
|
|
50378
50615
|
throw new Error("Missing current retired Codex configuration witness");
|
|
@@ -50380,7 +50617,7 @@ function retiredCodexRoots(binding) {
|
|
|
50380
50617
|
if ((proof.parents ?? []).some((parent) => codexDirectHookSelects(cache, parent) || !reviewedDisabledCodexPluginParent(cache, parent, controls, rules)) || !reviewedCodexPluginCapabilitiesUnchanged(cache, controls, (path) => read(path), rules))
|
|
50381
50618
|
throw new Error("Retired Codex parent capabilities changed");
|
|
50382
50619
|
for (const root of proof.roots) {
|
|
50383
|
-
const manifest = binding.sources.find((source2) => source2.path ===
|
|
50620
|
+
const manifest = binding.sources.find((source2) => source2.path === join26(root, ".codex-plugin/plugin.json") && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined && [undefined, "bytes"].includes(source2.hashMode));
|
|
50384
50621
|
if (!manifest || codexDirectHookSelects(cache, root) || !reviewedRetiredCodexRoot(cache, root, controls, rules, (path) => read(path), true))
|
|
50385
50622
|
throw new Error("Retired Codex materialization changed");
|
|
50386
50623
|
}
|
|
@@ -50393,17 +50630,17 @@ function absentRetiredClaudeRoots(binding) {
|
|
|
50393
50630
|
for (const source of binding.sources) {
|
|
50394
50631
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || ![undefined, "bytes"].includes(source.hashMode) || source.sha256 === null)
|
|
50395
50632
|
continue;
|
|
50396
|
-
const marker =
|
|
50633
|
+
const marker = sep6 + ".claude" + sep6 + "plugins" + sep6 + "cache" + sep6, at = source.path.indexOf(marker);
|
|
50397
50634
|
if (at < 0 || source.path.indexOf(marker, at + 1) >= 0)
|
|
50398
50635
|
continue;
|
|
50399
|
-
const cache = source.path.slice(0, at + marker.length - 1), parts = source.path.slice(at + marker.length).split(
|
|
50636
|
+
const cache = source.path.slice(0, at + marker.length - 1), parts = source.path.slice(at + marker.length).split(sep6);
|
|
50400
50637
|
if (parts.length < 4 || parts.slice(0, 3).some((part) => !part || part === "." || part === ".."))
|
|
50401
50638
|
continue;
|
|
50402
|
-
const root =
|
|
50639
|
+
const root = join26(cache, ...parts.slice(0, 3));
|
|
50403
50640
|
safe4(root);
|
|
50404
50641
|
if (lstatSync18(root, { throwIfNoEntry: false }))
|
|
50405
50642
|
continue;
|
|
50406
|
-
const claude = dirname15(dirname15(cache)), settings =
|
|
50643
|
+
const claude = dirname15(dirname15(cache)), settings = join26(claude, "settings.json"), registry2 = join26(claude, "plugins/installed_plugins.json");
|
|
50407
50644
|
const full = (path) => binding.sources.find((item) => item.path === path && item.sha256 !== null && item.format === undefined && item.fields === undefined);
|
|
50408
50645
|
const configSource = full(settings), registrySource = full(registry2);
|
|
50409
50646
|
if (!configSource || !registrySource || projected(configSource) !== configSource.sha256 || projected(registrySource) !== registrySource.sha256)
|
|
@@ -50422,10 +50659,10 @@ function absentRetiredClaudeRoots(binding) {
|
|
|
50422
50659
|
const active = rows[0].installPath;
|
|
50423
50660
|
if (rows[0].version !== basename8(active) || resolve15(active) !== active || dirname15(active) !== dirname15(root) || active === root || !lstatSync18(active, { throwIfNoEntry: false })?.isDirectory() || realpathSync5(active) !== active)
|
|
50424
50661
|
continue;
|
|
50425
|
-
const activeManifest = full(
|
|
50662
|
+
const activeManifest = full(join26(active, ".claude-plugin/plugin.json"));
|
|
50426
50663
|
if (!activeManifest || projected(activeManifest) !== activeManifest.sha256)
|
|
50427
50664
|
continue;
|
|
50428
|
-
if (Object.values(installed.plugins).some((value) => !Array.isArray(value) || value.some((row) => !row || typeof row.installPath !== "string" || row.installPath === root || row.installPath.startsWith(root +
|
|
50665
|
+
if (Object.values(installed.plugins).some((value) => !Array.isArray(value) || value.some((row) => !row || typeof row.installPath !== "string" || row.installPath === root || row.installPath.startsWith(root + sep6) || root.startsWith(row.installPath + sep6))))
|
|
50429
50666
|
continue;
|
|
50430
50667
|
result.add(root);
|
|
50431
50668
|
}
|
|
@@ -50440,10 +50677,10 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
50440
50677
|
throw new Error("Hermes discovery requires directory membership coverage; run skills hook install with a fresh discovery review");
|
|
50441
50678
|
const installationRoots = codexInstallationRoots(binding);
|
|
50442
50679
|
const retiredRoots = retiredCodexRoots(binding);
|
|
50443
|
-
const installationInput = (path) => installationRoots.some((root) => path === root || path.startsWith(root +
|
|
50680
|
+
const installationInput = (path) => installationRoots.some((root) => path === root || path.startsWith(root + sep6));
|
|
50444
50681
|
if (binding.directories !== undefined) {
|
|
50445
50682
|
const projected2 = binding.codexInstallationInputs?.directories ?? [];
|
|
50446
|
-
const ancestors2 = binding.directories.filter((directory) => installationRoots.some((root) => root.startsWith(directory.path +
|
|
50683
|
+
const ancestors2 = binding.directories.filter((directory) => installationRoots.some((root) => root.startsWith(directory.path + sep6)));
|
|
50447
50684
|
if (projected2.length !== ancestors2.length || projected2.some((directory) => !ancestors2.some((original) => original.path === directory.path)))
|
|
50448
50685
|
throw new Error("Missing installation input directory projection");
|
|
50449
50686
|
const ordinary = binding.directories.filter((directory) => !installationInput(directory.path) && !ancestors2.includes(directory));
|
|
@@ -50466,7 +50703,7 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
50466
50703
|
verifyDiscoveryDirectories(projected2, installationRoots);
|
|
50467
50704
|
}
|
|
50468
50705
|
const absentRoots = [...absentCodexSkillRoots(binding), ...absentRetiredClaudeRoots(binding), ...retiredRoots.filter((root) => !lstatSync18(root, { throwIfNoEntry: false }))];
|
|
50469
|
-
const
|
|
50706
|
+
const budget2 = discoveryByteBudget();
|
|
50470
50707
|
for (const source of binding.sources) {
|
|
50471
50708
|
assertMarketplaceBinding(binding, source);
|
|
50472
50709
|
if (source.hashMode === "claude-plugin-registry" && binding.agent !== "claude")
|
|
@@ -50479,11 +50716,11 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
50479
50716
|
safe4(source.path);
|
|
50480
50717
|
continue;
|
|
50481
50718
|
}
|
|
50482
|
-
if (absentRoots.some((root) => source.path.startsWith(root +
|
|
50719
|
+
if (absentRoots.some((root) => source.path.startsWith(root + sep6)) && source.format === undefined && source.fields === undefined && source.managedPlugins === undefined && [undefined, "bytes"].includes(source.hashMode)) {
|
|
50483
50720
|
safe4(source.path);
|
|
50484
50721
|
continue;
|
|
50485
50722
|
}
|
|
50486
|
-
const current = projected(source, undefined,
|
|
50723
|
+
const current = projected(source, undefined, budget2);
|
|
50487
50724
|
if (current !== source.sha256 && !verifiesCodexHookDiscoverySource(binding, source, current, codexRecovery))
|
|
50488
50725
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
50489
50726
|
}
|
|
@@ -50502,12 +50739,12 @@ function codexInstallationRoots(binding) {
|
|
|
50502
50739
|
if (binding.agent !== "codex" || binding.method !== "reviewed" || proof.version !== "codex-cli 0.160.0" || !/^[a-f0-9]{64}$/.test(proof.catalogSha256) || !Array.isArray(proof.plugins) || !proof.plugins.length)
|
|
50503
50740
|
throw new Error("Invalid native installation input proof");
|
|
50504
50741
|
const cache = dirname15(dirname15(proof.plugins[0].pluginParent));
|
|
50505
|
-
const config2 =
|
|
50742
|
+
const config2 = join26(dirname15(dirname15(cache)), "config.toml"), home = dirname15(dirname15(dirname15(cache)));
|
|
50506
50743
|
const configSource = binding.sources.find((source) => source.path === config2 && source.sha256 !== null && (!source.format || source.format === "toml" && source.fields?.includes("plugins")));
|
|
50507
|
-
const nativeRoots = NATIVE_SKILL_ROOTS.filter(([agent]) => agent === "codex").map(([, path]) =>
|
|
50508
|
-
if (!configSource || proof.plugins.some((input2) => nativeRoots.some((root) => root === input2.sourceRoot || root.startsWith(input2.sourceRoot +
|
|
50744
|
+
const nativeRoots = NATIVE_SKILL_ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => join26(home, path));
|
|
50745
|
+
if (!configSource || proof.plugins.some((input2) => nativeRoots.some((root) => root === input2.sourceRoot || root.startsWith(input2.sourceRoot + sep6) || input2.sourceRoot.startsWith(root + sep6)) || binding.sources.some((source) => basename8(source.path) === "config.toml" && (source.path === input2.sourceRoot || source.path.startsWith(input2.sourceRoot + sep6)))))
|
|
50509
50746
|
throw new Error("Native installation input overlaps configuration or loading roots");
|
|
50510
|
-
if (proof.plugins.some((input2) => dirname15(dirname15(input2.pluginParent)) !== cache || !binding.sources.some((source) => source.path ===
|
|
50747
|
+
if (proof.plugins.some((input2) => dirname15(dirname15(input2.pluginParent)) !== cache || !binding.sources.some((source) => source.path === join26(input2.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined)))
|
|
50511
50748
|
throw new Error("Missing native installation input source witness");
|
|
50512
50749
|
return reviewedCodexPluginSourceRoots(cache, proof.plugins, (path) => {
|
|
50513
50750
|
const text2 = read(path);
|
|
@@ -50517,6 +50754,10 @@ function codexInstallationRoots(binding) {
|
|
|
50517
50754
|
});
|
|
50518
50755
|
}
|
|
50519
50756
|
function assertMarketplaceBinding(binding, source) {
|
|
50757
|
+
if (source.hashMode === "claude-plugin-manifest-v1" && (binding.agent !== "claude" || basename8(source.path) !== "plugin.json" || !source.path.endsWith(join26(sep6, ".claude-plugin", "plugin.json"))))
|
|
50758
|
+
throw new Error("Claude plugin manifest witnesses require Claude plugin discovery");
|
|
50759
|
+
if (source.hashMode === "sumi-settings-v1" && (binding.agent !== "sumi" || binding.method !== "reviewed" || basename8(source.path) !== "sumi.json"))
|
|
50760
|
+
throw new Error("Sumi settings witnesses require explicit reviewed Sumi configuration");
|
|
50520
50761
|
if ((source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")) && (binding.agent !== "codex" || binding.method !== "reviewed" || basename8(source.path) !== "config.toml"))
|
|
50521
50762
|
throw new Error("Codex settings witnesses require explicit reviewed Codex configuration");
|
|
50522
50763
|
if ((source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") && (binding.agent !== "claude" || binding.method !== "reviewed" || basename8(source.path) !== "settings.json"))
|
|
@@ -50527,13 +50768,13 @@ function assertMarketplaceBinding(binding, source) {
|
|
|
50527
50768
|
function agentDiscoveryConfigPath(home, agent) {
|
|
50528
50769
|
if (agent === "sumi")
|
|
50529
50770
|
return sumiConfigPath(home);
|
|
50530
|
-
return
|
|
50771
|
+
return join26(home, agent === "hermes" ? ".hermes/config.yaml" : agent === "opencode" ? ".config/opencode/opencode.json" : `.${agent}/${agent === "codex" ? "config.toml" : agent === "cursor" ? "hooks.json" : "settings.json"}`);
|
|
50531
50772
|
}
|
|
50532
50773
|
function resolveAgentDiscovery(options) {
|
|
50533
|
-
const
|
|
50774
|
+
const canonical7 = options.canonical ?? resolve15, home = resolve15(options.home), agent = options.agent;
|
|
50534
50775
|
const sources = [], roots = new Set, builtinNames = [];
|
|
50535
|
-
const witness = (path, format, fields2) => {
|
|
50536
|
-
const source = { path:
|
|
50776
|
+
const witness = (path, format, fields2, hashMode) => {
|
|
50777
|
+
const source = { path: canonical7(path), sha256: null, ...format ? { format, fields: fields2 } : {}, ...hashMode ? { hashMode } : {} };
|
|
50537
50778
|
source.sha256 = projected(source);
|
|
50538
50779
|
sources.push(source);
|
|
50539
50780
|
return read(source.path);
|
|
@@ -50541,36 +50782,39 @@ function resolveAgentDiscovery(options) {
|
|
|
50541
50782
|
if (agent === "hermes")
|
|
50542
50783
|
assertHermesEnvironment(home);
|
|
50543
50784
|
const configPath = agentDiscoveryConfigPath(home, agent);
|
|
50544
|
-
const configText = witness(configPath, agent === "hermes" ? "yaml" : agent === "codex" ? "toml" : "json", agent === "hermes" ? ["skills", "plugins", "hooks"] : agent === "claude" ? ["enabledPlugins", "extraKnownMarketplaces"] : agent === "codex" ? [...CODEX_DISCOVERY_PROJECTION_FIELDS] : agent === "gemini" ? ["skills", "extensions", "security"] : agent === "opencode" ? ["plugin", "skills"] : agent === "sumi" ? [
|
|
50785
|
+
const configText = witness(configPath, agent === "hermes" ? "yaml" : agent === "codex" ? "toml" : "json", agent === "hermes" ? ["skills", "plugins", "hooks"] : agent === "claude" ? ["enabledPlugins", "extraKnownMarketplaces"] : agent === "codex" ? [...CODEX_DISCOVERY_PROJECTION_FIELDS] : agent === "gemini" ? ["skills", "extensions", "security"] : agent === "opencode" ? ["plugin", "skills"] : agent === "sumi" ? [...SUMI_DISCOVERY_PROJECTION_FIELDS] : ["version"]);
|
|
50545
50786
|
const config2 = configText === null ? {} : agent === "hermes" ? parseHermesConfig(configText) : parseConfig(configText, configPath, agent === "codex");
|
|
50546
50787
|
const unresolved = (detail) => {
|
|
50547
50788
|
throw new Error(`Native discovery is unresolved (${agent}: ${detail}); provide a reviewed --discovery-inputs file`);
|
|
50548
50789
|
};
|
|
50790
|
+
if (options.reviewed && (options.reviewed.version !== 1 || !Array.isArray(options.reviewed.agents) || options.reviewed.agents.some((item) => !item || typeof item !== "object") || new Set(options.reviewed.agents.map((item) => item.agent)).size !== options.reviewed.agents.length))
|
|
50791
|
+
throw new Error("Invalid --discovery-inputs version or agents");
|
|
50792
|
+
const review = options.reviewed?.agents.find((item) => item.agent === agent);
|
|
50549
50793
|
if (agent === "sumi") {
|
|
50550
50794
|
const directory = sumiConfigDirectory(home);
|
|
50551
|
-
if (witness(
|
|
50795
|
+
if (witness(join26(directory, "sumi.jsonc")) !== null)
|
|
50552
50796
|
unresolved("JSONC configuration requires a supported format adapter");
|
|
50553
|
-
for (const root of [directory,
|
|
50797
|
+
for (const root of [directory, join26(home, ".claude"), join26(home, ".agents")])
|
|
50554
50798
|
for (const name of ["skill", "skills"])
|
|
50555
|
-
roots.add(
|
|
50799
|
+
roots.add(canonical7(join26(root, name)));
|
|
50556
50800
|
if (config2.skills !== undefined && (!Array.isArray(config2.skills) || config2.skills.some((path) => typeof path !== "string")))
|
|
50557
50801
|
unresolved("skills must be a string array");
|
|
50558
50802
|
for (const value of config2.skills ?? []) {
|
|
50559
50803
|
if (typeof value !== "string" || /[\0$]/.test(value) || !value || !(isAbsolute13(value) || value.startsWith("~/")))
|
|
50560
50804
|
unresolved("remote or relative skill sources need a dedicated discovery adapter");
|
|
50561
|
-
roots.add(
|
|
50805
|
+
roots.add(canonical7(value.startsWith("~/") ? join26(home, value.slice(2)) : value));
|
|
50562
50806
|
}
|
|
50563
50807
|
for (const key of ["plugin", "plugins"])
|
|
50564
50808
|
if (config2[key] !== undefined && !Array.isArray(config2[key]))
|
|
50565
50809
|
unresolved(`${key} must be an array`);
|
|
50566
|
-
const plugins = [
|
|
50810
|
+
const plugins = [join26(directory, "plugin"), join26(directory, "plugins")];
|
|
50567
50811
|
for (const path of plugins) {
|
|
50568
50812
|
safe4(path);
|
|
50569
50813
|
if (lstatSync18(path, { throwIfNoEntry: false })?.isDirectory())
|
|
50570
50814
|
for (const name of readdirSync7(path).sort()) {
|
|
50571
50815
|
if (name === "skills-cli.js" && path === plugins[1])
|
|
50572
50816
|
continue;
|
|
50573
|
-
const target =
|
|
50817
|
+
const target = join26(path, name);
|
|
50574
50818
|
if (!lstatSync18(target).isFile())
|
|
50575
50819
|
unresolved("local plugin packages need a dedicated discovery adapter");
|
|
50576
50820
|
witness(target);
|
|
@@ -50583,7 +50827,7 @@ function resolveAgentDiscovery(options) {
|
|
|
50583
50827
|
}
|
|
50584
50828
|
}
|
|
50585
50829
|
if (agent === "hermes") {
|
|
50586
|
-
const profile = witness(
|
|
50830
|
+
const profile = witness(join26(home, ".hermes/active_profile"));
|
|
50587
50831
|
if (profile?.trim() && profile.trim() !== "default")
|
|
50588
50832
|
unresolved("a non-default profile is active");
|
|
50589
50833
|
const declared = config2.skills?.external_dirs ?? [], paths = typeof declared === "string" ? [declared] : declared;
|
|
@@ -50597,7 +50841,7 @@ function resolveAgentDiscovery(options) {
|
|
|
50597
50841
|
continue;
|
|
50598
50842
|
if (normalized.startsWith("~") && normalized !== "~" && !normalized.startsWith("~/"))
|
|
50599
50843
|
unresolved("user-specific tilde expansion requires a separate discovery adapter");
|
|
50600
|
-
const path = normalized === "~" ? home : normalized.startsWith("~/") ?
|
|
50844
|
+
const path = normalized === "~" ? home : normalized.startsWith("~/") ? join26(home, normalized.slice(2)) : resolve15(home, ".hermes", normalized);
|
|
50601
50845
|
safe4(path);
|
|
50602
50846
|
roots.add(path);
|
|
50603
50847
|
}
|
|
@@ -50607,7 +50851,7 @@ function resolveAgentDiscovery(options) {
|
|
|
50607
50851
|
if (executable) {
|
|
50608
50852
|
let packageRoot;
|
|
50609
50853
|
for (let directory = dirname15(realpathSync5(executable)), depth = 0;depth < 8; directory = dirname15(directory), depth++) {
|
|
50610
|
-
const path =
|
|
50854
|
+
const path = join26(directory, "package.json"), raw = read(path);
|
|
50611
50855
|
if (raw !== null && parseConfig(raw, path).name === "@google/gemini-cli") {
|
|
50612
50856
|
packageRoot = directory;
|
|
50613
50857
|
witness(path);
|
|
@@ -50618,12 +50862,12 @@ function resolveAgentDiscovery(options) {
|
|
|
50618
50862
|
}
|
|
50619
50863
|
if (!packageRoot)
|
|
50620
50864
|
unresolved("installed Gemini package layout is not recognized");
|
|
50621
|
-
const builtinRoot =
|
|
50865
|
+
const builtinRoot = join26(packageRoot, "bundle/builtin");
|
|
50622
50866
|
safe4(builtinRoot);
|
|
50623
50867
|
if (!lstatSync18(builtinRoot, { throwIfNoEntry: false })?.isDirectory())
|
|
50624
50868
|
unresolved("installed Gemini builtin root is missing");
|
|
50625
50869
|
for (const name of readdirSync7(builtinRoot).sort()) {
|
|
50626
|
-
const text2 = witness(
|
|
50870
|
+
const text2 = witness(join26(builtinRoot, name, "SKILL.md"));
|
|
50627
50871
|
const match = text2?.match(/^---\r?\n[\s\S]*?^name:\s*([a-z0-9][a-z0-9-]*)\s*$/m);
|
|
50628
50872
|
if (!match?.[1] || builtinNames.includes(match[1]))
|
|
50629
50873
|
unresolved("installed Gemini builtin name is missing or ambiguous");
|
|
@@ -50636,18 +50880,15 @@ function resolveAgentDiscovery(options) {
|
|
|
50636
50880
|
if (retained.agent !== agent || retained.method !== "reviewed")
|
|
50637
50881
|
unresolved("invalid retained review");
|
|
50638
50882
|
verifyAgentDiscovery(retained);
|
|
50639
|
-
if (!retained.sources.some((source) => source.path ===
|
|
50883
|
+
if (!retained.sources.some((source) => source.path === canonical7(configPath) && source.format === undefined && source.fields === undefined))
|
|
50640
50884
|
unresolved("retained review is missing the full agent configuration source");
|
|
50641
|
-
if (retained.sources.some((source) => (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !==
|
|
50885
|
+
if (retained.sources.some((source) => (source.hashMode === "sumi-settings-v1" || source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !== canonical7(configPath)))
|
|
50642
50886
|
unresolved("retained settings witness names another configuration source");
|
|
50643
|
-
const covered =
|
|
50887
|
+
const covered = supersedesSettingsProjection(agent, retained.sources, canonical7(configPath)) ? sources.filter((source) => !isSupersededSettingsProjection(agent, canonical7(configPath), source)) : sources;
|
|
50644
50888
|
if (covered.some((source) => !retained.sources.some((saved) => isDeepStrictEqual4(saved, source))) || [...roots].some((root) => !retained.roots.includes(root)) || agent === "gemini" && JSON.stringify(retained.builtinNames) !== JSON.stringify(builtinNames))
|
|
50645
50889
|
unresolved("retained review is missing current runtime discovery coverage");
|
|
50646
50890
|
return retained;
|
|
50647
50891
|
}
|
|
50648
|
-
if (options.reviewed && (options.reviewed.version !== 1 || !Array.isArray(options.reviewed.agents) || options.reviewed.agents.some((item) => !item || typeof item !== "object") || new Set(options.reviewed.agents.map((item) => item.agent)).size !== options.reviewed.agents.length))
|
|
50649
|
-
throw new Error("Invalid --discovery-inputs version or agents");
|
|
50650
|
-
const review = options.reviewed?.agents.find((item) => item.agent === agent);
|
|
50651
50892
|
if (review) {
|
|
50652
50893
|
if (review.pluginHooks !== "reviewed-no-skill-injection" || !Array.isArray(review.sources) || !review.sources.length || !Array.isArray(review.roots))
|
|
50653
50894
|
throw new Error("Discovery review must bind sources and confirm plugin hooks do not inject retired skills");
|
|
@@ -50655,47 +50896,77 @@ function resolveAgentDiscovery(options) {
|
|
|
50655
50896
|
if (review.sources.some((source) => source.format !== undefined || source.fields !== undefined))
|
|
50656
50897
|
throw new Error("Explicit discovery reviews require full source-file hashes");
|
|
50657
50898
|
verifyAgentDiscovery(supplied);
|
|
50658
|
-
if (review.sources.some((source) => (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !==
|
|
50659
|
-
throw new Error("Semantic settings witnesses must name the configured
|
|
50660
|
-
if (!review.sources.some((source) => source.path ===
|
|
50899
|
+
if (review.sources.some((source) => (source.hashMode === "sumi-settings-v1" || source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !== canonical7(configPath)))
|
|
50900
|
+
throw new Error("Semantic settings witnesses must name the configured agent configuration source");
|
|
50901
|
+
if (!review.sources.some((source) => source.path === canonical7(configPath)))
|
|
50661
50902
|
throw new Error("Discovery review must include the agent configuration source");
|
|
50662
|
-
const reviewedSources =
|
|
50663
|
-
|
|
50903
|
+
const reviewedSources = supersedesSettingsProjection(agent, review.sources, canonical7(configPath)) ? sources.filter((source) => !isSupersededSettingsProjection(agent, canonical7(configPath), source)) : sources;
|
|
50904
|
+
const reviewedSourcesWithManifestProjection = review.sources.map((source) => {
|
|
50905
|
+
if (agent !== "claude" || source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || source.hashMode !== undefined && source.hashMode !== "bytes" || basename8(source.path) !== "plugin.json" || !source.path.endsWith(join26(sep6, ".claude-plugin", "plugin.json")))
|
|
50906
|
+
return source;
|
|
50907
|
+
const pluginRoot = dirname15(dirname15(source.path)), hooksPath = join26(pluginRoot, "hooks/hooks.json");
|
|
50908
|
+
const hookStat = lstatSync18(hooksPath, { throwIfNoEntry: false });
|
|
50909
|
+
const text2 = read(source.path);
|
|
50910
|
+
if (text2 === null)
|
|
50911
|
+
throw new Error("Reviewed Claude plugin manifest is missing");
|
|
50912
|
+
const manifestSha256 = projectReviewedClaudePluginManifest(text2, source.sha256 ?? "");
|
|
50913
|
+
const manifest = JSON.parse(text2);
|
|
50914
|
+
if (!manifest || typeof manifest !== "object" || Array.isArray(manifest))
|
|
50915
|
+
throw new Error("Reviewed Claude plugin manifest must be an object");
|
|
50916
|
+
const reviewedHookPaths = new Set;
|
|
50917
|
+
if (hookStat)
|
|
50918
|
+
reviewedHookPaths.add(hooksPath);
|
|
50919
|
+
if (manifest.hooks !== undefined) {
|
|
50920
|
+
if (typeof manifest.hooks !== "string")
|
|
50921
|
+
throw new Error("Reviewed Claude plugin manifest has an unsupported hooks target");
|
|
50922
|
+
const declaredHookPath = resolve15(pluginRoot, manifest.hooks);
|
|
50923
|
+
if (!declaredHookPath.startsWith(pluginRoot + sep6))
|
|
50924
|
+
throw new Error("Reviewed Claude plugin hooks target escapes its root");
|
|
50925
|
+
reviewedHookPaths.add(declaredHookPath);
|
|
50926
|
+
}
|
|
50927
|
+
for (const hooksFile of reviewedHookPaths)
|
|
50928
|
+
if (!review.sources.some((hook) => hook.path === canonical7(hooksFile) && hook.sha256 !== null && hook.format === undefined && hook.fields === undefined && hook.managedPlugins === undefined && (hook.hashMode === undefined || hook.hashMode === "bytes")))
|
|
50929
|
+
throw new Error("Reviewed Claude plugin manifest requires separately reviewed exact hook file sources");
|
|
50930
|
+
return { path: source.path, sha256: manifestSha256, hashMode: "claude-plugin-manifest-v1" };
|
|
50931
|
+
});
|
|
50932
|
+
const combined = [...reviewedSources, ...reviewedSourcesWithManifestProjection];
|
|
50933
|
+
const unique = combined.filter((source, index) => combined.findIndex((candidate) => isDeepStrictEqual4(candidate, source)) === index);
|
|
50934
|
+
return { ...supplied, roots: [...new Set([...roots, ...supplied.roots])].sort(), sources: unique, ...agent === "gemini" ? { builtinNames } : {} };
|
|
50664
50935
|
}
|
|
50665
50936
|
function plugin(root) {
|
|
50666
|
-
root =
|
|
50937
|
+
root = canonical7(root);
|
|
50667
50938
|
safe4(root);
|
|
50668
|
-
const manifestPath =
|
|
50669
|
-
const raw = witness(manifestPath);
|
|
50939
|
+
const manifestPath = join26(root, agent === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json");
|
|
50940
|
+
const raw = witness(manifestPath, undefined, undefined, agent === "claude" ? "claude-plugin-manifest-v1" : undefined);
|
|
50670
50941
|
if (raw === null)
|
|
50671
50942
|
unresolved("plugin manifest missing");
|
|
50672
50943
|
const manifest = parseConfig(raw, manifestPath);
|
|
50673
|
-
const hooks = witness(
|
|
50944
|
+
const hooks = witness(join26(root, "hooks/hooks.json"));
|
|
50674
50945
|
if (manifest.hooks !== undefined || hooks !== null)
|
|
50675
50946
|
unresolved("plugin hooks require a separate no-skill-injection review");
|
|
50676
|
-
const commands =
|
|
50947
|
+
const commands = join26(root, "commands");
|
|
50677
50948
|
safe4(commands);
|
|
50678
50949
|
if (agent === "claude" && (manifest.commands !== undefined || lstatSync18(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync7(commands).length))
|
|
50679
50950
|
unresolved("legacy command discovery requires retirement or a dedicated format adapter");
|
|
50680
|
-
const rootSkill = witness(
|
|
50951
|
+
const rootSkill = witness(join26(root, "SKILL.md"));
|
|
50681
50952
|
if (rootSkill !== null)
|
|
50682
50953
|
roots.add(root);
|
|
50683
50954
|
const declared = manifest.skills === undefined ? ["./skills"] : typeof manifest.skills === "string" ? [manifest.skills] : manifest.skills;
|
|
50684
50955
|
if (!Array.isArray(declared) || declared.some((path) => typeof path !== "string"))
|
|
50685
50956
|
unresolved("unsupported plugin skill paths");
|
|
50686
50957
|
if (agent === "claude")
|
|
50687
|
-
roots.add(
|
|
50958
|
+
roots.add(join26(root, "skills"));
|
|
50688
50959
|
for (const value of declared) {
|
|
50689
50960
|
const path = resolve15(root, value);
|
|
50690
|
-
if (path !== root && !path.startsWith(root +
|
|
50961
|
+
if (path !== root && !path.startsWith(root + sep6))
|
|
50691
50962
|
unresolved("plugin skill path escapes its root");
|
|
50692
|
-
roots.add(path.endsWith(`${
|
|
50963
|
+
roots.add(path.endsWith(`${sep6}SKILL.md`) ? dirname15(path) : path);
|
|
50693
50964
|
}
|
|
50694
50965
|
}
|
|
50695
50966
|
if (agent === "claude") {
|
|
50696
|
-
const registrations = witness(
|
|
50697
|
-
const installed = registrations === null ? {} : parseConfig(registrations,
|
|
50698
|
-
const commands =
|
|
50967
|
+
const registrations = witness(join26(home, ".claude/plugins/installed_plugins.json"));
|
|
50968
|
+
const installed = registrations === null ? {} : parseConfig(registrations, join26(home, ".claude/plugins/installed_plugins.json")).plugins;
|
|
50969
|
+
const commands = canonical7(join26(home, ".claude/commands"));
|
|
50699
50970
|
safe4(commands);
|
|
50700
50971
|
if (lstatSync18(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync7(commands).length)
|
|
50701
50972
|
unresolved("legacy home command discovery requires a dedicated format adapter");
|
|
@@ -50719,16 +50990,16 @@ function resolveAgentDiscovery(options) {
|
|
|
50719
50990
|
const market = config2.marketplaces?.[marketplace] ?? (marketplace === "personal" ? { source_type: "local", source: home } : undefined);
|
|
50720
50991
|
if (split < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !isAbsolute13(market.source))
|
|
50721
50992
|
unresolved("enabled plugin marketplace is not an explicit local source");
|
|
50722
|
-
const catalogText = witness(
|
|
50993
|
+
const catalogText = witness(join26(market.source, ".agents/plugins/marketplace.json"));
|
|
50723
50994
|
if (catalogText === null)
|
|
50724
50995
|
unresolved("marketplace catalog missing");
|
|
50725
|
-
const catalog = parseConfig(catalogText,
|
|
50996
|
+
const catalog = parseConfig(catalogText, join26(market.source, ".agents/plugins/marketplace.json")), matches = Array.isArray(catalog.plugins) ? catalog.plugins.filter((item) => item.name === name) : [];
|
|
50726
50997
|
if (matches.length !== 1 || matches[0]?.source?.source !== "local" || typeof matches[0]?.source?.path !== "string")
|
|
50727
50998
|
unresolved("plugin catalog source is missing or ambiguous");
|
|
50728
50999
|
plugin(resolve15(market.source, matches[0].source.path));
|
|
50729
51000
|
}
|
|
50730
51001
|
} else if (agent === "opencode") {
|
|
50731
|
-
if (witness(
|
|
51002
|
+
if (witness(join26(home, ".config/opencode/opencode.jsonc")) !== null || witness(join26(home, ".config/opencode/config.json")) !== null)
|
|
50732
51003
|
unresolved("additional config layers require review");
|
|
50733
51004
|
if ((config2.plugin?.length ?? 0) > 0 || config2.skills?.urls?.length)
|
|
50734
51005
|
unresolved("external plugin or remote skill source");
|
|
@@ -50737,15 +51008,15 @@ function resolveAgentDiscovery(options) {
|
|
|
50737
51008
|
unresolved("relative or malformed added skill root");
|
|
50738
51009
|
roots.add(path);
|
|
50739
51010
|
}
|
|
50740
|
-
const localPlugins =
|
|
51011
|
+
const localPlugins = join26(home, ".config/opencode/plugins");
|
|
50741
51012
|
safe4(localPlugins);
|
|
50742
51013
|
if (lstatSync18(localPlugins, { throwIfNoEntry: false }) && readdirSync7(localPlugins).some((name) => name !== "skills-cli.js"))
|
|
50743
51014
|
unresolved("additional local plugin hooks require review");
|
|
50744
51015
|
} else if (agent === "sumi") {
|
|
50745
|
-
if ((config2.plugin?.length ?? 0) > 0 || (config2.plugins?.length ?? 0) > 0 || sources.some((source) => source.path !==
|
|
51016
|
+
if ((config2.plugin?.length ?? 0) > 0 || (config2.plugins?.length ?? 0) > 0 || sources.some((source) => source.path !== canonical7(configPath) && source.path !== canonical7(join26(sumiConfigDirectory(home), "sumi.jsonc")) && source.sha256 !== null))
|
|
50746
51017
|
unresolved("external or foreign local plugins require review");
|
|
50747
51018
|
} else if (agent === "hermes") {
|
|
50748
|
-
for (const directory of [
|
|
51019
|
+
for (const directory of [join26(home, ".hermes/plugins"), join26(home, ".hermes/hermes-agent")]) {
|
|
50749
51020
|
safe4(directory);
|
|
50750
51021
|
if (lstatSync18(directory, { throwIfNoEntry: false }))
|
|
50751
51022
|
unresolved("installed runtime/plugin discovery requires reviewed source bindings");
|
|
@@ -50755,32 +51026,34 @@ function resolveAgentDiscovery(options) {
|
|
|
50755
51026
|
} else if (agent === "gemini") {
|
|
50756
51027
|
if (Object.keys(config2.extensions ?? {}).length || config2.skills?.paths?.length)
|
|
50757
51028
|
unresolved("custom extension or skill paths");
|
|
50758
|
-
const directory =
|
|
51029
|
+
const directory = join26(home, ".gemini/extensions");
|
|
50759
51030
|
safe4(directory);
|
|
50760
51031
|
if (lstatSync18(directory, { throwIfNoEntry: false }))
|
|
50761
51032
|
for (const name of readdirSync7(directory)) {
|
|
50762
|
-
const root =
|
|
51033
|
+
const root = join26(directory, name);
|
|
50763
51034
|
safe4(root);
|
|
50764
51035
|
if (!lstatSync18(root)?.isDirectory())
|
|
50765
51036
|
continue;
|
|
50766
|
-
const raw = witness(
|
|
51037
|
+
const raw = witness(join26(root, "gemini-extension.json"));
|
|
50767
51038
|
if (raw === null)
|
|
50768
51039
|
unresolved("extension registration missing");
|
|
50769
|
-
const manifest = parseConfig(raw,
|
|
50770
|
-
if (manifest.hooks !== undefined || witness(
|
|
51040
|
+
const manifest = parseConfig(raw, join26(root, "gemini-extension.json"));
|
|
51041
|
+
if (manifest.hooks !== undefined || witness(join26(root, "hooks/hooks.json")) !== null || witness(join26(root, ".gemini-extension-install.json")) !== null)
|
|
50771
51042
|
unresolved("extension hooks or linked registration require review");
|
|
50772
|
-
roots.add(
|
|
51043
|
+
roots.add(join26(root, "skills"));
|
|
50773
51044
|
}
|
|
50774
51045
|
}
|
|
50775
|
-
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([
|
|
51046
|
+
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join26(home, ".hermes/plugins"), join26(home, ".hermes/hermes-agent")].map((path) => canonical7(path))) } : {} };
|
|
50776
51047
|
}
|
|
50777
|
-
var digest = (text2) =>
|
|
51048
|
+
var digest = (text2) => createHash17("sha256").update(text2).digest("hex");
|
|
50778
51049
|
var init_agent_discovery = __esm(() => {
|
|
51050
|
+
init_sumi_settings_witness();
|
|
50779
51051
|
init_agent_policy_limits();
|
|
50780
51052
|
init_agent_hermes();
|
|
50781
51053
|
init_agent_discovery_directories();
|
|
50782
51054
|
init_agent_discovery_bytes();
|
|
50783
51055
|
init_agent_discovery_path_bytes();
|
|
51056
|
+
init_claude_plugin_manifest_witness();
|
|
50784
51057
|
init_plugin_discovery();
|
|
50785
51058
|
init_plugin_admission();
|
|
50786
51059
|
init_claude_marketplace_registry();
|
|
@@ -50796,9 +51069,9 @@ var init_agent_discovery = __esm(() => {
|
|
|
50796
51069
|
// src/lib/authoring-path.ts
|
|
50797
51070
|
import { lstatSync as lstatSync19, realpathSync as realpathSync6 } from "fs";
|
|
50798
51071
|
import { homedir as homedir3 } from "os";
|
|
50799
|
-
import { basename as basename9, dirname as dirname16, join as
|
|
51072
|
+
import { basename as basename9, dirname as dirname16, join as join27, resolve as resolve16, sep as sep7 } from "path";
|
|
50800
51073
|
function pathParts(path) {
|
|
50801
|
-
return resolve16(path).split(
|
|
51074
|
+
return resolve16(path).split(sep7).filter(Boolean);
|
|
50802
51075
|
}
|
|
50803
51076
|
function nativeRootMatch(path) {
|
|
50804
51077
|
const parts = pathParts(path);
|
|
@@ -50824,10 +51097,10 @@ function physicalPath(path) {
|
|
|
50824
51097
|
return resolve16(realpathSync6(cursor), ...suffix);
|
|
50825
51098
|
}
|
|
50826
51099
|
function contains(root, path) {
|
|
50827
|
-
return path === root || path.startsWith(root +
|
|
51100
|
+
return path === root || path.startsWith(root + sep7);
|
|
50828
51101
|
}
|
|
50829
51102
|
function configuredRoots(home, explicitHome) {
|
|
50830
|
-
const homeData =
|
|
51103
|
+
const homeData = join27(home, ".hasna", "skills");
|
|
50831
51104
|
const homePolicy = readManagedSkillPolicySnapshot(homeData);
|
|
50832
51105
|
const configuredPolicy = !explicitHome && resolve16(getDataDirReadOnly()) !== resolve16(homeData) ? readManagedSkillPolicySnapshot(getDataDirReadOnly()) : null;
|
|
50833
51106
|
const policy = homePolicy ?? configuredPolicy;
|
|
@@ -50858,7 +51131,7 @@ function configuredRoots(home, explicitHome) {
|
|
|
50858
51131
|
admitBinding(binding);
|
|
50859
51132
|
continue;
|
|
50860
51133
|
}
|
|
50861
|
-
const nativeHome =
|
|
51134
|
+
const nativeHome = join27(home, agent === "opencode" ? ".config/opencode" : `.${agent}`);
|
|
50862
51135
|
if (!lstatSync19(nativeHome, { throwIfNoEntry: false }))
|
|
50863
51136
|
continue;
|
|
50864
51137
|
roots.push(...resolveAgentDiscovery({ home, agent, canonical: physicalPath }).roots);
|
|
@@ -50873,8 +51146,8 @@ function assertPortableAuthoringPath(path, options = {}) {
|
|
|
50873
51146
|
const candidates = [lexical, physical];
|
|
50874
51147
|
let native = candidates.map(nativeRootMatch).find(Boolean);
|
|
50875
51148
|
const home = resolve16(options.homeDir ?? homedir3());
|
|
50876
|
-
const defaults = NATIVE_DISCOVERY_ROOTS.map((parts) =>
|
|
50877
|
-
defaults.push(
|
|
51149
|
+
const defaults = NATIVE_DISCOVERY_ROOTS.map((parts) => join27(home, ...parts));
|
|
51150
|
+
defaults.push(join27(home, ".codex/plugins/cache"), join27(home, ".claude/plugins/cache"), join27(home, ".claude/plugins/synced"), join27(home, ".gemini/extensions"));
|
|
50878
51151
|
for (const root of defaults) {
|
|
50879
51152
|
if (candidates.some((candidate) => contains(resolve16(root), candidate) || contains(physicalPath(root), candidate)))
|
|
50880
51153
|
native ??= root;
|
|
@@ -50910,22 +51183,22 @@ import {
|
|
|
50910
51183
|
statSync as statSync7,
|
|
50911
51184
|
writeFileSync as writeFileSync6
|
|
50912
51185
|
} from "fs";
|
|
50913
|
-
import { basename as basename10, dirname as dirname17, isAbsolute as isAbsolute14, join as
|
|
51186
|
+
import { basename as basename10, dirname as dirname17, isAbsolute as isAbsolute14, join as join28, normalize as normalize3, relative as relative5, resolve as resolve17, sep as sep8 } from "path";
|
|
50914
51187
|
function getPortableSkillsRoot(options = {}) {
|
|
50915
51188
|
return resolvePortableSkillsRoot(options, true);
|
|
50916
51189
|
}
|
|
50917
51190
|
function resolvePortableSkillsRoot(options, migrate) {
|
|
50918
51191
|
if (options.rootDir)
|
|
50919
51192
|
return options.rootDir;
|
|
50920
|
-
const appDir = options.homeDir ?
|
|
50921
|
-
const cache =
|
|
51193
|
+
const appDir = options.homeDir ? join28(options.homeDir, ".hasna", "skills") : migrate ? getDataDir() : getDataDirReadOnly();
|
|
51194
|
+
const cache = join28(appDir, SKILLS_CACHE_DIRNAME);
|
|
50922
51195
|
if (isOwnerLayoutMigrated(appDir) && safeIsDirectory(cache))
|
|
50923
51196
|
return cache;
|
|
50924
|
-
const installed =
|
|
51197
|
+
const installed = join28(appDir, INSTALLED_SKILLS_DIRNAME);
|
|
50925
51198
|
return installed;
|
|
50926
51199
|
}
|
|
50927
51200
|
function getPortableSkillPath(name, options = {}) {
|
|
50928
|
-
return
|
|
51201
|
+
return join28(getPortableSkillsRoot(options), normalizePortableSkillName(name));
|
|
50929
51202
|
}
|
|
50930
51203
|
function findPortableSkill(name, options = {}) {
|
|
50931
51204
|
let normalized;
|
|
@@ -50951,7 +51224,7 @@ function listPortableSkills(options = {}) {
|
|
|
50951
51224
|
for (const entry of readdirSync8(root).sort()) {
|
|
50952
51225
|
if (entry.startsWith("."))
|
|
50953
51226
|
continue;
|
|
50954
|
-
const path =
|
|
51227
|
+
const path = join28(root, entry);
|
|
50955
51228
|
if (!safeIsDirectory(path))
|
|
50956
51229
|
continue;
|
|
50957
51230
|
try {
|
|
@@ -50984,9 +51257,9 @@ function isOfficialSkillName(name) {
|
|
|
50984
51257
|
function scaffoldPortableSkill(name, options = {}) {
|
|
50985
51258
|
const skillName = normalizeNewPortableSkillName(name);
|
|
50986
51259
|
const readOnlyRoot = resolvePortableSkillsRoot(options, false);
|
|
50987
|
-
assertPortableAuthoringPath(
|
|
51260
|
+
assertPortableAuthoringPath(join28(readOnlyRoot, skillName), options);
|
|
50988
51261
|
const root = getPortableSkillsRoot(options);
|
|
50989
|
-
const skillPath =
|
|
51262
|
+
const skillPath = join28(root, skillName);
|
|
50990
51263
|
assertPortableAuthoringPath(skillPath, options);
|
|
50991
51264
|
if (existsSync12(skillPath)) {
|
|
50992
51265
|
if (!options.overwrite)
|
|
@@ -51011,14 +51284,14 @@ function physicalImportPath(path) {
|
|
|
51011
51284
|
suffix.unshift(basename10(ancestor));
|
|
51012
51285
|
ancestor = dirname17(ancestor);
|
|
51013
51286
|
}
|
|
51014
|
-
return
|
|
51287
|
+
return join28(realpathSync7(ancestor), ...suffix);
|
|
51015
51288
|
}
|
|
51016
51289
|
function assertDisjointImportPaths(source, destination) {
|
|
51017
51290
|
const sourcePath = realpathSync7(source);
|
|
51018
51291
|
const destinationPath = physicalImportPath(destination);
|
|
51019
51292
|
const contains2 = (parent, child) => {
|
|
51020
51293
|
const path = relative5(parent, child);
|
|
51021
|
-
return path === "" || !isAbsolute14(path) && path !== ".." && !path.startsWith(`..${
|
|
51294
|
+
return path === "" || !isAbsolute14(path) && path !== ".." && !path.startsWith(`..${sep8}`);
|
|
51022
51295
|
};
|
|
51023
51296
|
if (contains2(sourcePath, destinationPath) || contains2(destinationPath, sourcePath)) {
|
|
51024
51297
|
throw new Error("Source and destination skill directories must not overlap");
|
|
@@ -51037,11 +51310,11 @@ function portPortableSkill(sourcePath, options = {}) {
|
|
|
51037
51310
|
const via = explicitName ? `Name '${skillName}' matches a bundled official skill.` : `Inferred name '${skillName}'${sourceSlug && sourceSlug !== skillName ? ` (from source folder '${basename10(absoluteSource)}')` : ""} matches a bundled official skill.`;
|
|
51038
51311
|
throw new Error(`${via} Importing it would shadow the official '${skillName}'. ` + `Pass --name to choose a different name, or --allow-shadow to override deliberately.`);
|
|
51039
51312
|
}
|
|
51040
|
-
const readOnlyDestination =
|
|
51313
|
+
const readOnlyDestination = join28(resolvePortableSkillsRoot(options, false), skillName);
|
|
51041
51314
|
assertPortableAuthoringPath(readOnlyDestination, options);
|
|
51042
51315
|
assertDisjointImportPaths(absoluteSource, readOnlyDestination);
|
|
51043
51316
|
const root = getPortableSkillsRoot(options);
|
|
51044
|
-
const destination =
|
|
51317
|
+
const destination = join28(root, skillName);
|
|
51045
51318
|
assertPortableAuthoringPath(destination, options);
|
|
51046
51319
|
assertDisjointImportPaths(absoluteSource, destination);
|
|
51047
51320
|
if (existsSync12(destination)) {
|
|
@@ -51073,8 +51346,8 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
51073
51346
|
const warnings = [...base.warnings];
|
|
51074
51347
|
let manifest;
|
|
51075
51348
|
if (existsSync12(skillPath)) {
|
|
51076
|
-
const skillJsonPath =
|
|
51077
|
-
const skillMdPath =
|
|
51349
|
+
const skillJsonPath = join28(skillPath, "skill.json");
|
|
51350
|
+
const skillMdPath = join28(skillPath, "SKILL.md");
|
|
51078
51351
|
if (!existsSync12(skillJsonPath) && !existsSync12(skillMdPath)) {
|
|
51079
51352
|
add3(issues, "portable.manifest_missing", "Missing portable manifest: expected SKILL.md frontmatter and/or skill.json");
|
|
51080
51353
|
}
|
|
@@ -51094,7 +51367,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
51094
51367
|
add3(issues, "portable.version_missing", "Portable manifest missing version");
|
|
51095
51368
|
}
|
|
51096
51369
|
const contractIssues = validatePortableManifestContract(manifest, {
|
|
51097
|
-
strict: existsSync12(
|
|
51370
|
+
strict: existsSync12(join28(skillPath, "skill.json")),
|
|
51098
51371
|
skillPath
|
|
51099
51372
|
});
|
|
51100
51373
|
for (const issue2 of contractIssues)
|
|
@@ -51134,7 +51407,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
51134
51407
|
add3(issues, "portable.command_entry_unsafe", `Command '${command.name}' entry '${command.entry}' must stay inside the skill directory`);
|
|
51135
51408
|
continue;
|
|
51136
51409
|
}
|
|
51137
|
-
const entryPath =
|
|
51410
|
+
const entryPath = join28(skillPath, command.entry);
|
|
51138
51411
|
if (!existsSync12(entryPath))
|
|
51139
51412
|
add3(issues, "portable.command_entry_missing", `Command '${command.name}' entry '${command.entry}' is missing`);
|
|
51140
51413
|
else if (statSync7(entryPath).isDirectory())
|
|
@@ -51145,7 +51418,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
51145
51418
|
} catch (error61) {
|
|
51146
51419
|
add3(issues, "portable.manifest_invalid", error61.message);
|
|
51147
51420
|
}
|
|
51148
|
-
if (manifest?.kind !== "instruction" && !existsSync12(
|
|
51421
|
+
if (manifest?.kind !== "instruction" && !existsSync12(join28(skillPath, "AGENTS.md"))) {
|
|
51149
51422
|
add3(issues, "portable.agents_missing", "Missing AGENTS.md with build-out instructions for coding agents");
|
|
51150
51423
|
}
|
|
51151
51424
|
}
|
|
@@ -51373,7 +51646,7 @@ var init_search = __esm(() => {
|
|
|
51373
51646
|
|
|
51374
51647
|
// src/lib/registry.ts
|
|
51375
51648
|
import { existsSync as existsSync13, readFileSync as readFileSync16, readdirSync as readdirSync9 } from "fs";
|
|
51376
|
-
import { join as
|
|
51649
|
+
import { join as join29 } from "path";
|
|
51377
51650
|
function parseSkillMdFrontmatter(content) {
|
|
51378
51651
|
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
51379
51652
|
if (!match)
|
|
@@ -51414,7 +51687,7 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
51414
51687
|
for (const entry of entries) {
|
|
51415
51688
|
if (!entry.isDirectory())
|
|
51416
51689
|
continue;
|
|
51417
|
-
const skillMdPath =
|
|
51690
|
+
const skillMdPath = join29(dir, entry.name, "SKILL.md");
|
|
51418
51691
|
if (!existsSync13(skillMdPath))
|
|
51419
51692
|
continue;
|
|
51420
51693
|
let content;
|
|
@@ -51434,7 +51707,7 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
51434
51707
|
category: fm.category || "Development Tools",
|
|
51435
51708
|
tags: fm.tags || [],
|
|
51436
51709
|
...fm.kind ? { kind: fm.kind } : {},
|
|
51437
|
-
...isHostedMetadataSkillDir(
|
|
51710
|
+
...isHostedMetadataSkillDir(join29(dir, entry.name)) ? { serverOwned: true } : {},
|
|
51438
51711
|
source
|
|
51439
51712
|
});
|
|
51440
51713
|
}
|
|
@@ -51450,8 +51723,8 @@ function findExtensionSkillPath(name) {
|
|
|
51450
51723
|
for (const entry of entries) {
|
|
51451
51724
|
if (!entry.isDirectory())
|
|
51452
51725
|
continue;
|
|
51453
|
-
const skillDir =
|
|
51454
|
-
const skillMdPath =
|
|
51726
|
+
const skillDir = join29(config2.extensionsDir, entry.name);
|
|
51727
|
+
const skillMdPath = join29(skillDir, "SKILL.md");
|
|
51455
51728
|
if (!existsSync13(skillMdPath))
|
|
51456
51729
|
continue;
|
|
51457
51730
|
let content;
|
|
@@ -51854,7 +52127,7 @@ var init_remote_customer_operations = __esm(() => {
|
|
|
51854
52127
|
});
|
|
51855
52128
|
|
|
51856
52129
|
// src/lib/canonical-json.ts
|
|
51857
|
-
import { createHash as
|
|
52130
|
+
import { createHash as createHash18 } from "crypto";
|
|
51858
52131
|
function canonicalJson2(value, maximumBytes = 2 * 1024 * 1024) {
|
|
51859
52132
|
return canonicalJsonAtDepth(value, maximumBytes, 64);
|
|
51860
52133
|
}
|
|
@@ -51898,7 +52171,7 @@ function canonicalJsonAtDepth(value, maximumBytes, maximumDepth) {
|
|
|
51898
52171
|
return visit3(value, 0);
|
|
51899
52172
|
}
|
|
51900
52173
|
function canonicalJsonSha256(value, maximumBytes) {
|
|
51901
|
-
return
|
|
52174
|
+
return createHash18("sha256").update(canonicalJson2(value, maximumBytes)).digest("hex");
|
|
51902
52175
|
}
|
|
51903
52176
|
var init_canonical_json = () => {};
|
|
51904
52177
|
|
|
@@ -52077,7 +52350,7 @@ function parseRecurringResult(action, value, input2, identity3) {
|
|
|
52077
52350
|
}
|
|
52078
52351
|
return result;
|
|
52079
52352
|
}
|
|
52080
|
-
var RecurringInputError, RemoteRecurringUnavailableError, RemoteRecurringReadError, RemoteRecurringUnconfirmedError, failures, RemoteRecurringError, uuid3, instant2, integer2, digest2, list, inputs, capabilityNames,
|
|
52353
|
+
var RecurringInputError, RemoteRecurringUnavailableError, RemoteRecurringReadError, RemoteRecurringUnconfirmedError, failures, RemoteRecurringError, uuid3, instant2, integer2, digest2, list, inputs, capabilityNames, budget2, period, preview, consent, refusal2, occurrence, revocation, page = (item) => exports_external.object({ contractVersion: exports_external.literal(1), items: exports_external.array(item).max(100), nextCursor: exports_external.string().min(1).max(2048).nullable() }), results;
|
|
52081
52354
|
var init_remote_recurring = __esm(() => {
|
|
52082
52355
|
init_v4();
|
|
52083
52356
|
init_canonical_json();
|
|
@@ -52163,7 +52436,7 @@ var init_remote_recurring = __esm(() => {
|
|
|
52163
52436
|
occurrences: "recurring.occurrences",
|
|
52164
52437
|
revoke: "recurring.revoke"
|
|
52165
52438
|
};
|
|
52166
|
-
|
|
52439
|
+
budget2 = exports_external.object({ reservedCredits: integer2, settledCredits: integer2, admittedOccurrences: integer2 });
|
|
52167
52440
|
period = exports_external.object({ startsAt: instant2, endsAt: instant2 });
|
|
52168
52441
|
preview = exports_external.object({
|
|
52169
52442
|
contractVersion: exports_external.literal(1),
|
|
@@ -52185,8 +52458,8 @@ var init_remote_recurring = __esm(() => {
|
|
|
52185
52458
|
state: exports_external.enum(["active", "revoked", "expired"]),
|
|
52186
52459
|
activatedAt: instant2,
|
|
52187
52460
|
revokedAt: instant2.nullable(),
|
|
52188
|
-
total:
|
|
52189
|
-
currentPeriod:
|
|
52461
|
+
total: budget2,
|
|
52462
|
+
currentPeriod: budget2.extend(period.shape).nullable(),
|
|
52190
52463
|
nextDueAt: instant2.nullable()
|
|
52191
52464
|
});
|
|
52192
52465
|
refusal2 = exports_external.enum([
|
|
@@ -52649,13 +52922,13 @@ var init_remote_workspace_leave = __esm(() => {
|
|
|
52649
52922
|
|
|
52650
52923
|
// src/lib/auth-store.ts
|
|
52651
52924
|
import { chmodSync, existsSync as existsSync14, mkdirSync as mkdirSync8, readFileSync as readFileSync17, renameSync as renameSync4, statSync as statSync8, unlinkSync as unlinkSync4, writeFileSync as writeFileSync7 } from "fs";
|
|
52652
|
-
import { basename as basename11, dirname as dirname18, join as
|
|
52925
|
+
import { basename as basename11, dirname as dirname18, join as join30 } from "path";
|
|
52653
52926
|
function getAuthFilePath(env = process.env) {
|
|
52654
52927
|
return skillsCredentialFilePath(env);
|
|
52655
52928
|
}
|
|
52656
52929
|
function getIdentityFilePath(env = process.env) {
|
|
52657
52930
|
const file2 = skillsCredentialFilePath(env);
|
|
52658
|
-
return
|
|
52931
|
+
return join30(dirname18(file2), basename11(file2).replace(/^credentials/, "identity") + ".json");
|
|
52659
52932
|
}
|
|
52660
52933
|
function getApiUrl(action, env = process.env, options = {}) {
|
|
52661
52934
|
return requireSkillsApiOrigin(action, env, options);
|
|
@@ -54124,7 +54397,7 @@ var init_remote_invitation_recovery = __esm(() => {
|
|
|
54124
54397
|
});
|
|
54125
54398
|
|
|
54126
54399
|
// src/lib/remote-private-publications.ts
|
|
54127
|
-
import { createHash as
|
|
54400
|
+
import { createHash as createHash19 } from "crypto";
|
|
54128
54401
|
function checkedPublicationDeclaration(value) {
|
|
54129
54402
|
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)
|
|
54130
54403
|
return bad();
|
|
@@ -54144,7 +54417,7 @@ function checkedPublicationView(value, skillId, intentId, declaration) {
|
|
|
54144
54417
|
return invalid4();
|
|
54145
54418
|
return Object.freeze({ ...value });
|
|
54146
54419
|
}
|
|
54147
|
-
async function boundedJson(url2, init, token, mutation,
|
|
54420
|
+
async function boundedJson(url2, init, token, mutation, budget3 = 15000, signal) {
|
|
54148
54421
|
const controller = new AbortController;
|
|
54149
54422
|
let reader;
|
|
54150
54423
|
let response;
|
|
@@ -54199,7 +54472,7 @@ async function boundedJson(url2, init, token, mutation, budget2 = 15000, signal)
|
|
|
54199
54472
|
controller.abort();
|
|
54200
54473
|
reject(timeout);
|
|
54201
54474
|
};
|
|
54202
|
-
timer = setTimeout(abort, Math.max(1, Math.min(15000,
|
|
54475
|
+
timer = setTimeout(abort, Math.max(1, Math.min(15000, budget3)));
|
|
54203
54476
|
signal?.addEventListener("abort", abort, { once: true });
|
|
54204
54477
|
})]);
|
|
54205
54478
|
} catch (error61) {
|
|
@@ -54385,7 +54658,7 @@ var PRIVATE_PUBLICATION_MAX_BYTES, failures2, PrivatePublicationError, bad = ()
|
|
|
54385
54658
|
throw new PrivatePublicationError("INVALID_PUBLICATION_INPUT", "Invalid publication input or recovery data.");
|
|
54386
54659
|
}, invalid4 = () => {
|
|
54387
54660
|
throw new PrivatePublicationError("INVALID_PUBLICATION_RESPONSE", "The server returned an invalid publication result.");
|
|
54388
|
-
}, publicationUuid = (v) => typeof v === "string" && /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(v), hash3 = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v), record10 = (v) => !!v && typeof v === "object" && !Array.isArray(v), exact = (v, keys) => record10(v) && Object.keys(v).sort().join(",") === keys.sort().join(","), date6 = (v) => typeof v === "string" && /^\d{4}-\d\d-\d\dT[0-9:.]+(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/.test(v) && Number.isFinite(Date.parse(v)), publicationSha256 = (bytes) =>
|
|
54661
|
+
}, publicationUuid = (v) => typeof v === "string" && /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(v), hash3 = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v), record10 = (v) => !!v && typeof v === "object" && !Array.isArray(v), exact = (v, keys) => record10(v) && Object.keys(v).sort().join(",") === keys.sort().join(","), date6 = (v) => typeof v === "string" && /^\d{4}-\d\d-\d\dT[0-9:.]+(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/.test(v) && Number.isFinite(Date.parse(v)), publicationSha256 = (bytes) => createHash19("sha256").update(bytes).digest("hex");
|
|
54389
54662
|
var init_remote_private_publications = __esm(() => {
|
|
54390
54663
|
init_fleet_credentials();
|
|
54391
54664
|
init_remote_workspace_selection();
|
|
@@ -54895,7 +55168,7 @@ var init_recurring_customer = __esm(() => {
|
|
|
54895
55168
|
|
|
54896
55169
|
// src/lib/recurring-recovery.ts
|
|
54897
55170
|
import { constants as constants12, closeSync as closeSync15, fsyncSync as fsyncSync4, fstatSync as fstatSync15, lstatSync as lstatSync21, mkdirSync as mkdirSync10, openSync as openSync15, readSync as readSync10, realpathSync as realpathSync8, renameSync as renameSync6, unlinkSync as unlinkSync5, writeFileSync as writeFileSync9 } from "fs";
|
|
54898
|
-
import { dirname as dirname19, isAbsolute as isAbsolute15, join as
|
|
55171
|
+
import { dirname as dirname19, isAbsolute as isAbsolute15, join as join31, resolve as resolve18 } from "path";
|
|
54899
55172
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
54900
55173
|
|
|
54901
55174
|
class RecoveryOwner {
|
|
@@ -54929,7 +55202,7 @@ class RecoveryOwner {
|
|
|
54929
55202
|
}
|
|
54930
55203
|
read(name) {
|
|
54931
55204
|
this.assert();
|
|
54932
|
-
const fd = openSync15(
|
|
55205
|
+
const fd = openSync15(join31(this.directory, name), constants12.O_RDONLY | constants12.O_NOFOLLOW | constants12.O_NONBLOCK);
|
|
54933
55206
|
try {
|
|
54934
55207
|
const before = fstatSync15(fd);
|
|
54935
55208
|
if (!before.isFile() || before.nlink !== 1 || (before.mode & 4095) !== 384 || before.size < 1 || before.size > 8192 || process.getuid && before.uid !== process.getuid())
|
|
@@ -54942,7 +55215,7 @@ class RecoveryOwner {
|
|
|
54942
55215
|
break;
|
|
54943
55216
|
size += n2;
|
|
54944
55217
|
}
|
|
54945
|
-
const after = fstatSync15(fd), path = lstatSync21(
|
|
55218
|
+
const after = fstatSync15(fd), path = lstatSync21(join31(this.directory, name));
|
|
54946
55219
|
if (size !== before.size || after.size !== before.size || before.mtimeMs !== after.mtimeMs || before.ctimeMs !== after.ctimeMs || path.dev !== before.dev || path.ino !== before.ino || !path.isFile() || path.isSymbolicLink())
|
|
54947
55220
|
invalid5();
|
|
54948
55221
|
this.assert();
|
|
@@ -54955,7 +55228,7 @@ class RecoveryOwner {
|
|
|
54955
55228
|
this.assert();
|
|
54956
55229
|
const bytes = canonicalJson2(value, 8192) + `
|
|
54957
55230
|
`;
|
|
54958
|
-
const fd = openSync15(
|
|
55231
|
+
const fd = openSync15(join31(this.directory, name), constants12.O_WRONLY | constants12.O_CREAT | constants12.O_EXCL | constants12.O_NOFOLLOW, 384);
|
|
54959
55232
|
try {
|
|
54960
55233
|
writeFileSync9(fd, bytes);
|
|
54961
55234
|
fsyncSync4(fd);
|
|
@@ -54982,14 +55255,14 @@ class RecoveryOwner {
|
|
|
54982
55255
|
if (this.read("state.json") !== expected)
|
|
54983
55256
|
invalid5();
|
|
54984
55257
|
this.assert();
|
|
54985
|
-
renameSync6(
|
|
55258
|
+
renameSync6(join31(this.directory, name), join31(this.directory, "state.json"));
|
|
54986
55259
|
this.sync();
|
|
54987
55260
|
}
|
|
54988
55261
|
async locked(action) {
|
|
54989
55262
|
this.assert();
|
|
54990
55263
|
let fd;
|
|
54991
55264
|
try {
|
|
54992
|
-
fd = openSync15(
|
|
55265
|
+
fd = openSync15(join31(this.directory, "operation.lock"), constants12.O_WRONLY | constants12.O_CREAT | constants12.O_EXCL | constants12.O_NOFOLLOW, 384);
|
|
54993
55266
|
} catch {
|
|
54994
55267
|
throw new RecurringCustomerError("RECURRING_RECOVERY_BUSY", "Recovery is locked. Confirm the original process has stopped before explicitly reconciling the retained lock; no request was retried.");
|
|
54995
55268
|
}
|
|
@@ -55002,10 +55275,10 @@ class RecoveryOwner {
|
|
|
55002
55275
|
} finally {
|
|
55003
55276
|
closeSync15(fd);
|
|
55004
55277
|
this.assert();
|
|
55005
|
-
const now = lstatSync21(
|
|
55278
|
+
const now = lstatSync21(join31(this.directory, "operation.lock"));
|
|
55006
55279
|
if (owner2.dev !== now.dev || owner2.ino !== now.ino || !now.isFile() || now.isSymbolicLink())
|
|
55007
55280
|
invalid5();
|
|
55008
|
-
unlinkSync5(
|
|
55281
|
+
unlinkSync5(join31(this.directory, "operation.lock"));
|
|
55009
55282
|
this.sync();
|
|
55010
55283
|
}
|
|
55011
55284
|
}
|
|
@@ -57135,21 +57408,21 @@ var init_credential_state = __esm(() => {
|
|
|
57135
57408
|
});
|
|
57136
57409
|
|
|
57137
57410
|
// src/lib/run-state.ts
|
|
57138
|
-
import { createHash as
|
|
57411
|
+
import { createHash as createHash20, randomBytes } from "crypto";
|
|
57139
57412
|
import { existsSync as existsSync15, mkdirSync as mkdirSync11, readFileSync as readFileSync19, readdirSync as readdirSync10, statSync as statSync9, writeFileSync as writeFileSync10 } from "fs";
|
|
57140
|
-
import { extname, join as
|
|
57413
|
+
import { extname, join as join32, relative as relative6 } from "path";
|
|
57141
57414
|
function createSkillRun(params, targetDir = process.cwd()) {
|
|
57142
57415
|
const now = new Date;
|
|
57143
57416
|
const id = createRunId(now);
|
|
57144
57417
|
const day = now.toISOString().slice(0, 10);
|
|
57145
57418
|
const skillName = normalizeSkillName(params.skill);
|
|
57146
57419
|
const root = getProjectStateDir(targetDir);
|
|
57147
|
-
const runDir =
|
|
57148
|
-
const logsDir =
|
|
57149
|
-
const exportDir =
|
|
57420
|
+
const runDir = join32(root, "runs", day, id);
|
|
57421
|
+
const logsDir = join32(runDir, "logs");
|
|
57422
|
+
const exportDir = join32(root, "exports", skillName, id);
|
|
57150
57423
|
mkdirSync11(logsDir, { recursive: true });
|
|
57151
57424
|
mkdirSync11(exportDir, { recursive: true });
|
|
57152
|
-
mkdirSync11(
|
|
57425
|
+
mkdirSync11(join32(root, "tmp"), { recursive: true });
|
|
57153
57426
|
const record11 = {
|
|
57154
57427
|
id,
|
|
57155
57428
|
skill: skillName,
|
|
@@ -57201,22 +57474,22 @@ function updateSkillRun(context2, patch) {
|
|
|
57201
57474
|
return context2.record;
|
|
57202
57475
|
}
|
|
57203
57476
|
function writeRunLogs(context2, stdout = "", stderr = "") {
|
|
57204
|
-
writeFileSync10(
|
|
57205
|
-
writeFileSync10(
|
|
57477
|
+
writeFileSync10(join32(context2.logsDir, "stdout.log"), stdout);
|
|
57478
|
+
writeFileSync10(join32(context2.logsDir, "stderr.log"), stderr);
|
|
57206
57479
|
}
|
|
57207
57480
|
function appendRunEvent(context2, event, data = {}) {
|
|
57208
57481
|
const line = JSON.stringify({ ts: new Date().toISOString(), event, ...data }) + `
|
|
57209
57482
|
`;
|
|
57210
|
-
const path =
|
|
57483
|
+
const path = join32(context2.runDir, "events.ndjson");
|
|
57211
57484
|
const previous = existsSync15(path) ? readFileSync19(path, "utf-8") : "";
|
|
57212
57485
|
writeFileSync10(path, previous + line);
|
|
57213
57486
|
}
|
|
57214
57487
|
function findSkillRun(runId, targetDir = process.cwd()) {
|
|
57215
|
-
const runsRoot =
|
|
57488
|
+
const runsRoot = join32(getProjectStateDir(targetDir), "runs");
|
|
57216
57489
|
if (!existsSync15(runsRoot))
|
|
57217
57490
|
return null;
|
|
57218
57491
|
for (const day of readdirSync10(runsRoot)) {
|
|
57219
|
-
const record11 = readRunRecord(
|
|
57492
|
+
const record11 = readRunRecord(join32(runsRoot, day, runId));
|
|
57220
57493
|
if (record11)
|
|
57221
57494
|
return record11;
|
|
57222
57495
|
}
|
|
@@ -57233,11 +57506,11 @@ function skillRunEnv(context2) {
|
|
|
57233
57506
|
};
|
|
57234
57507
|
}
|
|
57235
57508
|
function writeRunRecord(context2) {
|
|
57236
|
-
writeFileSync10(
|
|
57509
|
+
writeFileSync10(join32(context2.runDir, "run.json"), JSON.stringify(context2.record, null, 2) + `
|
|
57237
57510
|
`);
|
|
57238
57511
|
}
|
|
57239
57512
|
function writeArtifactsManifest(context2, artifacts) {
|
|
57240
|
-
writeFileSync10(
|
|
57513
|
+
writeFileSync10(join32(context2.runDir, "artifacts.json"), JSON.stringify({ runId: context2.record.id, artifacts }, null, 2) + `
|
|
57241
57514
|
`);
|
|
57242
57515
|
}
|
|
57243
57516
|
function collectRunArtifacts(context2) {
|
|
@@ -57250,14 +57523,14 @@ function collectRunArtifacts(context2) {
|
|
|
57250
57523
|
artifacts.push({
|
|
57251
57524
|
path: toProjectRelative(context2.targetDir, path),
|
|
57252
57525
|
mime: mimeForPath(path),
|
|
57253
|
-
sha256:
|
|
57526
|
+
sha256: createHash20("sha256").update(bytes).digest("hex"),
|
|
57254
57527
|
sizeBytes: stat3.size
|
|
57255
57528
|
});
|
|
57256
57529
|
}
|
|
57257
57530
|
return artifacts.sort((a, b) => a.path.localeCompare(b.path));
|
|
57258
57531
|
}
|
|
57259
57532
|
function readRunRecord(runDir) {
|
|
57260
|
-
const path =
|
|
57533
|
+
const path = join32(runDir, "run.json");
|
|
57261
57534
|
if (!existsSync15(path))
|
|
57262
57535
|
return null;
|
|
57263
57536
|
try {
|
|
@@ -57269,7 +57542,7 @@ function readRunRecord(runDir) {
|
|
|
57269
57542
|
function walkFiles(dir) {
|
|
57270
57543
|
const files = [];
|
|
57271
57544
|
for (const entry of readdirSync10(dir)) {
|
|
57272
|
-
const full =
|
|
57545
|
+
const full = join32(dir, entry);
|
|
57273
57546
|
if (statSync9(full).isDirectory())
|
|
57274
57547
|
files.push(...walkFiles(full));
|
|
57275
57548
|
else
|
|
@@ -57526,7 +57799,7 @@ import { closeSync as closeSync16, fstatSync as fstatSync16, openSync as openSyn
|
|
|
57526
57799
|
import { O_NOFOLLOW as O_NOFOLLOW3, O_NONBLOCK as O_NONBLOCK3, O_RDONLY as O_RDONLY3 } from "constants";
|
|
57527
57800
|
import { createRequire as createRequire2 } from "module";
|
|
57528
57801
|
import { hostname as osHostname2 } from "os";
|
|
57529
|
-
import { isAbsolute as isAbsolute17, join as
|
|
57802
|
+
import { isAbsolute as isAbsolute17, join as join33 } from "path";
|
|
57530
57803
|
import { createRequire as createRequire22 } from "module";
|
|
57531
57804
|
function envToken2(name) {
|
|
57532
57805
|
return name.toUpperCase().replace(/-/g, "_");
|
|
@@ -57557,14 +57830,14 @@ function hasnaHomeDir2(env) {
|
|
|
57557
57830
|
if (override)
|
|
57558
57831
|
return override;
|
|
57559
57832
|
const home = homeDir2(env);
|
|
57560
|
-
return home ?
|
|
57833
|
+
return home ? join33(home, HASNA_HOME_DIR2) : null;
|
|
57561
57834
|
}
|
|
57562
57835
|
function appConfigDir2(name, env) {
|
|
57563
57836
|
const configRoot = absoluteOverride2(env, HASNA_CONFIG_HOME_ENV_KEY2);
|
|
57564
57837
|
if (configRoot)
|
|
57565
|
-
return
|
|
57838
|
+
return join33(configRoot, name);
|
|
57566
57839
|
const root = hasnaHomeDir2(env);
|
|
57567
|
-
return root ?
|
|
57840
|
+
return root ? join33(root, name, CONFIG_SUBDIR2) : null;
|
|
57568
57841
|
}
|
|
57569
57842
|
function credentialDiskSourceList2(name, env, profile = null) {
|
|
57570
57843
|
if (!SAFE_APP_SLUG2.test(name))
|
|
@@ -57573,7 +57846,7 @@ function credentialDiskSourceList2(name, env, profile = null) {
|
|
|
57573
57846
|
if (!directory2)
|
|
57574
57847
|
return [];
|
|
57575
57848
|
const file2 = profile ? `${CREDENTIALS_FILE2}-${profile}` : CREDENTIALS_FILE2;
|
|
57576
|
-
return [{ path:
|
|
57849
|
+
return [{ path: join33(directory2, file2), tier: "disk" }];
|
|
57577
57850
|
}
|
|
57578
57851
|
function credentialDiskSources2(name, env) {
|
|
57579
57852
|
return credentialDiskSourceList2(name, env, null).map((s) => s.path);
|
|
@@ -59064,10 +59337,10 @@ __export(exports_selected_run, {
|
|
|
59064
59337
|
prepareSelectedSecretBindings: () => prepareSelectedSecretBindings,
|
|
59065
59338
|
executeSelectedLocal: () => executeSelectedLocal
|
|
59066
59339
|
});
|
|
59067
|
-
import { createHash as
|
|
59340
|
+
import { createHash as createHash21 } from "crypto";
|
|
59068
59341
|
import { spawn } from "child_process";
|
|
59069
59342
|
import { mkdirSync as mkdirSync12, mkdtempSync as mkdtempSync3, writeFileSync as writeFileSync11, realpathSync as realpathSync10 } from "fs";
|
|
59070
|
-
import { dirname as dirname20, join as
|
|
59343
|
+
import { dirname as dirname20, join as join34, resolve as resolve19 } from "path";
|
|
59071
59344
|
import { tmpdir, hostname as stationHostname2 } from "os";
|
|
59072
59345
|
async function resolveSelectedRun(spec, profileId, options = {}) {
|
|
59073
59346
|
const context2 = await resolveSelectionContext(profileId, options);
|
|
@@ -59147,7 +59420,7 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
59147
59420
|
throw new SkillSelectionError("INVALID_SECRET_BINDINGS", "Explicit environment values must be bounded strings without NUL bytes.");
|
|
59148
59421
|
secretEnv[name] = value;
|
|
59149
59422
|
}
|
|
59150
|
-
const runDirectory = mkdtempSync3(
|
|
59423
|
+
const runDirectory = mkdtempSync3(join34(tmpdir(), "skills-execution-"));
|
|
59151
59424
|
const paths = new SkillEntryPaths;
|
|
59152
59425
|
for (const entry of entries) {
|
|
59153
59426
|
paths.add(entry.path, 100, () => {
|
|
@@ -59155,7 +59428,7 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
59155
59428
|
}, () => {
|
|
59156
59429
|
throw new SkillSelectionError("INVALID_BUNDLE_PATH", "The execution bundle path exceeds its limit.");
|
|
59157
59430
|
});
|
|
59158
|
-
const destination =
|
|
59431
|
+
const destination = join34(runDirectory, entry.path);
|
|
59159
59432
|
mkdirSync12(dirname20(destination), { recursive: true, mode: 448 });
|
|
59160
59433
|
writeFileSync11(destination, entry.bytes, { flag: "wx", mode: entry.mode & 511 });
|
|
59161
59434
|
}
|
|
@@ -59183,20 +59456,20 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
59183
59456
|
}
|
|
59184
59457
|
if (bindings)
|
|
59185
59458
|
secretEnv = await resolveSelectedSecrets(bindings, options.createSecretsClient);
|
|
59186
|
-
const result = await subprocess([executable, ...runtimeName === "bun" ? ["--no-env-file"] : [],
|
|
59459
|
+
const result = await subprocess([executable, ...runtimeName === "bun" ? ["--no-env-file"] : [], join34(runDirectory, declaredEntry), ...args], runDirectory, { ...env, ...secretEnv }, input2, timeoutMs);
|
|
59187
59460
|
result.stdout = redactExecutionSecrets(result.stdout, secretEnv);
|
|
59188
59461
|
result.stderr = redactExecutionSecrets(result.stderr, secretEnv);
|
|
59189
59462
|
const receipt = {
|
|
59190
59463
|
selection: selection2,
|
|
59191
59464
|
target: "local",
|
|
59192
59465
|
runtime: runtimeName,
|
|
59193
|
-
inputDigest: `sha256:${
|
|
59466
|
+
inputDigest: `sha256:${createHash21("sha256").update(input2).digest("hex")}`,
|
|
59194
59467
|
runDirectory,
|
|
59195
59468
|
...executionGrant ? { executionGrant } : {},
|
|
59196
59469
|
...bindings ? { secretBinding: { schema: bindings.schema, selection: bindings.selection, consumer: bindings.consumer, secretsAuthority: bindings.secretsAuthority, bindings: bindings.bindings } } : {},
|
|
59197
59470
|
...result
|
|
59198
59471
|
};
|
|
59199
|
-
writeFileSync11(
|
|
59472
|
+
writeFileSync11(join34(runDirectory, ".execution-receipt.json"), JSON.stringify({ ...receipt, stdout: undefined, stderr: undefined }), { mode: 384 });
|
|
59200
59473
|
return receipt;
|
|
59201
59474
|
}
|
|
59202
59475
|
async function subprocess(command, cwd, env, input2, timeoutMs) {
|
|
@@ -59386,7 +59659,7 @@ var init_blog_article = __esm(() => {
|
|
|
59386
59659
|
|
|
59387
59660
|
// src/mcp/operation-tools.ts
|
|
59388
59661
|
import { existsSync as existsSync16, readdirSync as readdirSync11, statSync as statSync10 } from "fs";
|
|
59389
|
-
import { join as
|
|
59662
|
+
import { join as join35 } from "path";
|
|
59390
59663
|
function registerOperationTools(server) {
|
|
59391
59664
|
server.registerTool("cloud_skill_eligibility", {
|
|
59392
59665
|
title: "Cloud Skill Eligibility",
|
|
@@ -59863,7 +60136,7 @@ function registerOperationTools(server) {
|
|
|
59863
60136
|
if (exists) {
|
|
59864
60137
|
try {
|
|
59865
60138
|
skillCount = readdirSync11(agentSkillsPath).filter((f) => {
|
|
59866
|
-
const full =
|
|
60139
|
+
const full = join35(agentSkillsPath, f);
|
|
59867
60140
|
return !f.startsWith(".") && statSync10(full).isDirectory();
|
|
59868
60141
|
}).length;
|
|
59869
60142
|
} catch {}
|
|
@@ -59931,10 +60204,10 @@ var init_operation_tools = __esm(() => {
|
|
|
59931
60204
|
|
|
59932
60205
|
// src/lib/feedback.ts
|
|
59933
60206
|
import { appendFileSync, existsSync as existsSync17, mkdirSync as mkdirSync13 } from "fs";
|
|
59934
|
-
import { dirname as dirname21, join as
|
|
60207
|
+
import { dirname as dirname21, join as join36 } from "path";
|
|
59935
60208
|
import { Database } from "bun:sqlite";
|
|
59936
60209
|
function getFeedbackDbPath() {
|
|
59937
|
-
return
|
|
60210
|
+
return join36(getDataDir(), "skills.db");
|
|
59938
60211
|
}
|
|
59939
60212
|
function getFeedbackDb() {
|
|
59940
60213
|
const dbPath = getFeedbackDbPath();
|
|
@@ -59966,7 +60239,7 @@ function saveFeedback(input2) {
|
|
|
59966
60239
|
throw new Error("Feedback message is required");
|
|
59967
60240
|
const category = input2.category ?? "general";
|
|
59968
60241
|
if (isApiMode()) {
|
|
59969
|
-
const path =
|
|
60242
|
+
const path = join36(getDataDir(), "feedback.jsonl");
|
|
59970
60243
|
const dir = dirname21(path);
|
|
59971
60244
|
if (!existsSync17(dir))
|
|
59972
60245
|
mkdirSync13(dir, { recursive: true });
|
|
@@ -60131,9 +60404,9 @@ var init_resource_meta_tools = __esm(() => {
|
|
|
60131
60404
|
|
|
60132
60405
|
// src/lib/scheduler.ts
|
|
60133
60406
|
import { existsSync as existsSync18, readFileSync as readFileSync21, writeFileSync as writeFileSync12, mkdirSync as mkdirSync14 } from "fs";
|
|
60134
|
-
import { join as
|
|
60407
|
+
import { join as join37 } from "path";
|
|
60135
60408
|
function getSchedulesPath(targetDir = process.cwd()) {
|
|
60136
|
-
return
|
|
60409
|
+
return join37(targetDir, ".skills", "schedules.json");
|
|
60137
60410
|
}
|
|
60138
60411
|
function loadSchedules(targetDir = process.cwd()) {
|
|
60139
60412
|
const path = getSchedulesPath(targetDir);
|
|
@@ -60146,7 +60419,7 @@ function loadSchedules(targetDir = process.cwd()) {
|
|
|
60146
60419
|
}
|
|
60147
60420
|
function saveSchedules(data, targetDir = process.cwd()) {
|
|
60148
60421
|
const path = getSchedulesPath(targetDir);
|
|
60149
|
-
const dir =
|
|
60422
|
+
const dir = join37(targetDir, ".skills");
|
|
60150
60423
|
if (!existsSync18(dir))
|
|
60151
60424
|
mkdirSync14(dir, { recursive: true });
|
|
60152
60425
|
writeFileSync12(path, JSON.stringify(data, null, 2));
|
|
@@ -60418,7 +60691,7 @@ var init_schedule_tools = __esm(() => {
|
|
|
60418
60691
|
});
|
|
60419
60692
|
|
|
60420
60693
|
// src/lib/native-storage.ts
|
|
60421
|
-
import { createHash as
|
|
60694
|
+
import { createHash as createHash22, createHmac } from "crypto";
|
|
60422
60695
|
import {
|
|
60423
60696
|
existsSync as existsSync19,
|
|
60424
60697
|
mkdirSync as mkdirSync15,
|
|
@@ -60427,7 +60700,7 @@ import {
|
|
|
60427
60700
|
statSync as statSync11,
|
|
60428
60701
|
writeFileSync as writeFileSync13
|
|
60429
60702
|
} from "fs";
|
|
60430
|
-
import { dirname as dirname22, join as
|
|
60703
|
+
import { dirname as dirname22, join as join38, normalize as normalize4, relative as relative7, sep as sep9 } from "path";
|
|
60431
60704
|
function resolveSkillsNativeStorageConfig(env = process.env) {
|
|
60432
60705
|
assertNoRetiredModeEnvVars(env, {
|
|
60433
60706
|
app: SKILLS_ENV_NAMESPACE,
|
|
@@ -60468,7 +60741,7 @@ function getSkillsNativeStorageStatus(options = {}) {
|
|
|
60468
60741
|
local: {
|
|
60469
60742
|
dataDir: getDataDir(),
|
|
60470
60743
|
projectStateDir: getProjectStateDir(targetDir),
|
|
60471
|
-
feedbackDbPath:
|
|
60744
|
+
feedbackDbPath: join38(getDataDir(), "skills.db")
|
|
60472
60745
|
},
|
|
60473
60746
|
remote: {
|
|
60474
60747
|
databaseConfigured: Boolean(config2.databaseUrl),
|
|
@@ -60495,7 +60768,7 @@ function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
|
|
|
60495
60768
|
files.push({
|
|
60496
60769
|
path: relativePath,
|
|
60497
60770
|
sizeBytes: bytes.byteLength,
|
|
60498
|
-
sha256:
|
|
60771
|
+
sha256: createHash22("sha256").update(bytes).digest("hex"),
|
|
60499
60772
|
...options.includeFileContents ? { contentBase64: Buffer.from(bytes).toString("base64") } : {}
|
|
60500
60773
|
});
|
|
60501
60774
|
}
|
|
@@ -60549,7 +60822,7 @@ function parsePositiveInteger(value) {
|
|
|
60549
60822
|
function walkFiles2(dir) {
|
|
60550
60823
|
const files = [];
|
|
60551
60824
|
for (const entry of readdirSync12(dir)) {
|
|
60552
|
-
const full =
|
|
60825
|
+
const full = join38(dir, entry);
|
|
60553
60826
|
const stats = statSync11(full);
|
|
60554
60827
|
if (stats.isDirectory())
|
|
60555
60828
|
files.push(...walkFiles2(full));
|
|
@@ -60788,7 +61061,7 @@ var init_private_publication_customer = __esm(() => {
|
|
|
60788
61061
|
|
|
60789
61062
|
// src/lib/private-publication-recovery.ts
|
|
60790
61063
|
import { constants as constants14, closeSync as closeSync18, fsyncSync as fsyncSync5, fstatSync as fstatSync18, lstatSync as lstatSync22, mkdirSync as mkdirSync16, openSync as openSync18, readSync as readSync12, realpathSync as realpathSync11, renameSync as renameSync7, unlinkSync as unlinkSync6, writeFileSync as writeFileSync14 } from "fs";
|
|
60791
|
-
import { dirname as dirname23, isAbsolute as isAbsolute18, join as
|
|
61064
|
+
import { dirname as dirname23, isAbsolute as isAbsolute18, join as join39, resolve as resolve20 } from "path";
|
|
60792
61065
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
60793
61066
|
function safeDirectory(directory2) {
|
|
60794
61067
|
if (!isAbsolute18(directory2) || directory2 !== resolve20(directory2) || realpathSync11(directory2) !== directory2)
|
|
@@ -60811,7 +61084,7 @@ function unchangedDirectory(directory2, identity3) {
|
|
|
60811
61084
|
return fail2();
|
|
60812
61085
|
}
|
|
60813
61086
|
function readOwned(directory2, name, max) {
|
|
60814
|
-
const identity3 = safeDirectory(directory2), file2 =
|
|
61087
|
+
const identity3 = safeDirectory(directory2), file2 = join39(directory2, name);
|
|
60815
61088
|
const fd = openSync18(file2, constants14.O_RDONLY | constants14.O_NOFOLLOW);
|
|
60816
61089
|
try {
|
|
60817
61090
|
const stat3 = fstatSync18(fd);
|
|
@@ -60835,7 +61108,7 @@ function readOwned(directory2, name, max) {
|
|
|
60835
61108
|
}
|
|
60836
61109
|
}
|
|
60837
61110
|
function writeOwned(directory2, name, bytes) {
|
|
60838
|
-
const fd = openSync18(
|
|
61111
|
+
const fd = openSync18(join39(directory2, name), constants14.O_WRONLY | constants14.O_CREAT | constants14.O_EXCL | constants14.O_NOFOLLOW, 384);
|
|
60839
61112
|
try {
|
|
60840
61113
|
writeFileSync14(fd, bytes);
|
|
60841
61114
|
fsyncSync5(fd);
|
|
@@ -60848,7 +61121,7 @@ function save(directory2, value) {
|
|
|
60848
61121
|
writeOwned(directory2, temporary, JSON.stringify(value) + `
|
|
60849
61122
|
`);
|
|
60850
61123
|
unchangedDirectory(directory2, identity3);
|
|
60851
|
-
renameSync7(
|
|
61124
|
+
renameSync7(join39(directory2, temporary), join39(directory2, "receipt.json"));
|
|
60852
61125
|
const fd = openSync18(directory2, constants14.O_RDONLY | constants14.O_NOFOLLOW);
|
|
60853
61126
|
try {
|
|
60854
61127
|
fsyncSync5(fd);
|
|
@@ -60861,7 +61134,7 @@ function bind(client, receipt) {
|
|
|
60861
61134
|
throw new PrivatePublicationError("PUBLICATION_IDENTITY_CHANGED", "The fresh session does not match the recovery directory's server, account and membership.");
|
|
60862
61135
|
}
|
|
60863
61136
|
async function locked(directory2, action) {
|
|
60864
|
-
const identity3 = safeDirectory(directory2), file2 =
|
|
61137
|
+
const identity3 = safeDirectory(directory2), file2 = join39(directory2, "operation.lock");
|
|
60865
61138
|
let fd;
|
|
60866
61139
|
try {
|
|
60867
61140
|
fd = openSync18(file2, constants14.O_WRONLY | constants14.O_CREAT | constants14.O_EXCL | constants14.O_NOFOLLOW, 384);
|
|
@@ -62752,7 +63025,7 @@ var require_content_type = __commonJS((exports) => {
|
|
|
62752
63025
|
var QUOTE_REGEXP = /([\\"])/g;
|
|
62753
63026
|
var TYPE_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+\/[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
|
|
62754
63027
|
exports.format = format;
|
|
62755
|
-
exports.parse =
|
|
63028
|
+
exports.parse = parse12;
|
|
62756
63029
|
function format(obj) {
|
|
62757
63030
|
if (!obj || typeof obj !== "object") {
|
|
62758
63031
|
throw new TypeError("argument obj is required");
|
|
@@ -62776,7 +63049,7 @@ var require_content_type = __commonJS((exports) => {
|
|
|
62776
63049
|
}
|
|
62777
63050
|
return string6;
|
|
62778
63051
|
}
|
|
62779
|
-
function
|
|
63052
|
+
function parse12(string6) {
|
|
62780
63053
|
if (!string6) {
|
|
62781
63054
|
throw new TypeError("argument string is required");
|
|
62782
63055
|
}
|