@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/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.45",
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 basename3, isAbsolute as isAbsolute3, resolve as resolve2 } from "path";
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(isAbsolute3(control.pluginParent) && resolve2(control.pluginParent) === control.pluginParent && /^[a-f0-9]{64}$/.test(control.manifestSha256));
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) && isAbsolute3(control.pluginParent) && resolve2(control.pluginParent) === control.pluginParent && ["local", "git", "npm"].includes(control.sourceType) && typeof control.sourceSha256 === "string" && /^[a-f0-9]{64}$/.test(control.sourceSha256));
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), parents = proof.parents === undefined ? [] : array3(proof.parents, 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 + parents.length > 0 && new Set(roots).size === roots.length && new Set(parents).size === parents.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(isAbsolute3(root) && resolve2(root) === root);
38628
+ requireBound(isAbsolute4(root) && resolve3(root) === root);
38314
38629
  }
38315
- for (const parent of parents) {
38630
+ for (const parent of parents2) {
38316
38631
  text(parent);
38317
- requireBound(isAbsolute3(parent) && resolve2(parent) === parent);
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) => isAbsolute3(path) && resolve2(path) === path) && typeof input2.sourceSha256 === "string" && /^[a-f0-9]{64}$/.test(input2.sourceSha256));
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) && isAbsolute3(source.path) && resolve2(source.path) === source.path && basename3(source.path) === "config.toml");
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) && isAbsolute3(source.path) && resolve2(source.path) === source.path && basename3(source.path) === "settings.json");
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) && isAbsolute3(source.path) && resolve2(source.path) === source.path && basename3(source.path) === "known_marketplaces.json");
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: sep3, value } = collItem;
42391
+ const { start, key, sep: sep4, value } = collItem;
42073
42392
  const keyProps = resolveProps.resolveProps(start, {
42074
42393
  indicator: "explicit-key-ind",
42075
- next: key ?? sep3?.[0],
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 && !sep3) {
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(sep3 ?? [], {
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, sep3, null, valueProps, onError);
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 sep3 = "";
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 += sep3 + cb;
42231
- sep3 = "";
42549
+ comment += sep4 + cb;
42550
+ sep4 = "";
42232
42551
  break;
42233
42552
  }
42234
42553
  case "newline":
42235
42554
  if (comment)
42236
- sep3 += source;
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: sep3, value } = collItem;
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 ?? sep3?.[0],
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 && !sep3 && !value) {
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 && !sep3 && !props.found) {
42340
- const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end, sep3, null, props, onError);
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(sep3 ?? [], {
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 (sep3)
42364
- for (const st of sep3) {
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, sep3, null, valueProps, onError) : null;
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 sep3 = "";
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 += sep3 + indent.slice(trimIndent) + content;
42577
- sep3 = `
42895
+ value += sep4 + indent.slice(trimIndent) + content;
42896
+ sep4 = `
42578
42897
  `;
42579
42898
  } else if (indent.length > trimIndent || content[0] === "\t") {
42580
- if (sep3 === " ")
42581
- sep3 = `
42899
+ if (sep4 === " ")
42900
+ sep4 = `
42582
42901
  `;
42583
- else if (!prevMoreIndented && sep3 === `
42902
+ else if (!prevMoreIndented && sep4 === `
42584
42903
  `)
42585
- sep3 = `
42904
+ sep4 = `
42586
42905
 
42587
42906
  `;
42588
- value += sep3 + indent.slice(trimIndent) + content;
42589
- sep3 = `
42907
+ value += sep4 + indent.slice(trimIndent) + content;
42908
+ sep4 = `
42590
42909
  `;
42591
42910
  prevMoreIndented = true;
42592
42911
  } else if (content === "") {
42593
- if (sep3 === `
42912
+ if (sep4 === `
42594
42913
  `)
42595
42914
  value += `
42596
42915
  `;
42597
42916
  else
42598
- sep3 = `
42917
+ sep4 = `
42599
42918
  `;
42600
42919
  } else {
42601
- value += sep3 + content;
42602
- sep3 = " ";
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 sep3 = " ";
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 (sep3 === `
43107
+ if (sep4 === `
42789
43108
  `)
42790
- res += sep3;
43109
+ res += sep4;
42791
43110
  else
42792
- sep3 = `
43111
+ sep4 = `
42793
43112
  `;
42794
43113
  } else {
42795
- res += sep3 + match[1];
42796
- sep3 = " ";
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 + sep3 + (match?.[1] ?? "");
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: sep3, value }) {
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 (sep3)
43591
- for (const st of sep3)
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 sep3;
45058
+ let sep4;
44740
45059
  if (scalar.end) {
44741
- sep3 = scalar.end;
44742
- sep3.push(this.sourceToken);
45060
+ sep4 = scalar.end;
45061
+ sep4.push(this.sourceToken);
44743
45062
  delete scalar.end;
44744
45063
  } else
44745
- sep3 = [this.sourceToken];
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: sep3 }]
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 sep3 = it.sep;
44905
- sep3.push(this.sourceToken);
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: sep3 }]
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 sep3 = fc.end.splice(1, fc.end.length);
45107
- sep3.push(this.sourceToken);
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: sep3 }]
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 parse6(src, reviver, options) {
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 = parse6;
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 dirname4, isAbsolute as isAbsolute4, join as join10, resolve as resolve3 } from "path";
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 && (!isAbsolute4(selected) || resolve3(selected) !== join10(resolve3(home), ".hermes")))
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 createHash2 } from "crypto";
45430
- import { lstatSync as lstatSync5, opendirSync } from "fs";
45431
- import { dirname as dirname5, isAbsolute as isAbsolute5, join as join11, resolve as resolve4 } from "path";
45432
- function need(value, message) {
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
- need(typeof path === "string" && path.length <= AGENT_POLICY_LIMITS.pathCharacters && isAbsolute5(path) && resolve4(path) === path && !path.includes("\x00"), "Expected a canonical absolute discovery directory path");
45438
- for (let cursor = path;; cursor = dirname5(cursor)) {
45439
- need(!lstatSync5(cursor, { throwIfNoEntry: false })?.isSymbolicLink(), "Refusing symlink native discovery directory");
45440
- if (dirname5(cursor) === cursor)
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, budget, excludedRoots, omittedRoots = [], rows) {
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 = lstatSync5(path, { throwIfNoEntry: false });
45770
+ const root = lstatSync6(path, { throwIfNoEntry: false });
45452
45771
  if (!root)
45453
45772
  return { path, sha256: null };
45454
- need(root.isDirectory(), "Unsupported native discovery directory input");
45455
- const hash2 = createHash2("sha256");
45773
+ need2(root.isDirectory(), "Unsupported native discovery directory input");
45774
+ const hash2 = createHash3("sha256");
45456
45775
  function walk(current, relative3, before, depth) {
45457
- need(depth <= 64, "Native discovery directory depth limit exceeded");
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
- need(++budget.entries <= AGENT_POLICY_LIMITS.discoveryDirectoryEntries, "Native discovery directory entry limit exceeded");
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
- need(new Set(names).size === names.length, "Ambiguous native discovery directory names");
45786
+ need2(new Set(names).size === names.length, "Ambiguous native discovery directory names");
45468
45787
  for (const name of names.sort()) {
45469
- const child = join11(current, name), childRelative = relative3 ? `${relative3}/${name}` : name;
45788
+ const child = join12(current, name), childRelative = relative3 ? `${relative3}/${name}` : name;
45470
45789
  if (omittedRoots.includes(child))
45471
45790
  continue;
45472
- need(child.length <= AGENT_POLICY_LIMITS.pathCharacters, "Native discovery directory path limit exceeded");
45473
- const stat = lstatSync5(child);
45474
- need(stat.isFile() || stat.isDirectory(), "Refusing symlink or special native discovery directory member");
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
- budget.bytes += Buffer.byteLength(row);
45478
- need(budget.bytes <= AGENT_POLICY_LIMITS.discoveryDirectoryBytes, "Native discovery directory metadata limit exceeded");
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
- need(same(before, lstatSync5(current, { throwIfNoEntry: false })), "Native discovery directory changed while reading");
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
- need(Array.isArray(paths) && paths.length <= AGENT_POLICY_LIMITS.discoveryDirectories && new Set(paths).size === paths.length, "Invalid projected discovery directory collection");
45492
- need(omittedRoots.length <= AGENT_POLICY_LIMITS.discoveryRoots && new Set(omittedRoots).size === omittedRoots.length, "Invalid inactive discovery roots");
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 budget = { entries: 0, bytes: 0 };
45814
+ const budget2 = { entries: 0, bytes: 0 };
45496
45815
  return paths.map((path) => {
45497
45816
  const entries = [];
45498
- return { ...capture(path, budget, [], omittedRoots, entries), entries };
45817
+ return { ...capture(path, budget2, [], omittedRoots, entries), entries };
45499
45818
  });
45500
45819
  }
45501
45820
  function verifyDiscoveryDirectoryProjection(directories, omittedRoots) {
45502
- need(directories.length <= AGENT_POLICY_LIMITS.discoveryDirectories, "Invalid projected discovery directory collection");
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
- need(Array.isArray(directory.entries), "Missing reviewed directory membership inventory");
45507
- const hash2 = createHash2("sha256");
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
- need(typeof row === "string" && ++count <= AGENT_POLICY_LIMITS.discoveryDirectoryEntries, "Invalid reviewed directory membership rows");
45829
+ need2(typeof row === "string" && ++count <= AGENT_POLICY_LIMITS.discoveryDirectoryEntries, "Invalid reviewed directory membership rows");
45511
45830
  bytes += Buffer.byteLength(row);
45512
- need(bytes <= AGENT_POLICY_LIMITS.discoveryDirectoryBytes, "Reviewed directory membership byte limit exceeded");
45831
+ need2(bytes <= AGENT_POLICY_LIMITS.discoveryDirectoryBytes, "Reviewed directory membership byte limit exceeded");
45513
45832
  const value = JSON.parse(row);
45514
- need(Array.isArray(value) && value.length === 2 && typeof value[0] === "string" && value[0] && !isAbsolute5(value[0]) && !value[0].split("/").some((part) => !part || part === "." || part === "..") && ["file", "directory"].includes(value[1]) && row === JSON.stringify(value) + `
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 = join11(directory.path, value[0]);
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
- need(directory.sha256 === null ? directory.entries.length === 0 : hash2.digest("hex") === directory.sha256, "Reviewed directory inventory does not match its fingerprint");
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 : createHash2("sha256").update(kept.join("")).digest("hex") };
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
- need(current.every((item, index) => item.sha256 === expected[index].sha256), "Native discovery directory membership changed outside retired Codex roots");
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
- need(Array.isArray(paths) && paths.length <= AGENT_POLICY_LIMITS.discoveryDirectories && new Set(paths).size === paths.length, "Invalid native discovery directory collection");
45530
- const budget = { entries: 0, bytes: 0 };
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, budget, excludedRoots));
45852
+ return paths.map((path) => capture(path, budget2, excludedRoots));
45534
45853
  }
45535
45854
  function verifyDiscoveryDirectories(directories, excludedRoots = []) {
45536
- need(Array.isArray(directories) && directories.length <= AGENT_POLICY_LIMITS.discoveryDirectories, "Invalid native discovery directory collection");
45855
+ need2(Array.isArray(directories) && directories.length <= AGENT_POLICY_LIMITS.discoveryDirectories, "Invalid native discovery directory collection");
45537
45856
  for (const directory of directories)
45538
- need(directory && typeof directory === "object" && (directory.sha256 === null || typeof directory.sha256 === "string" && /^[a-f0-9]{64}$/.test(directory.sha256)), "Invalid native discovery directory digest");
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
- need(current[i].sha256 === directories[i].sha256, `Native discovery directory membership changed; run skills hook install with a fresh discovery review: ${directories[i].path}`);
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 createHash3 } from "crypto";
45549
- import { closeSync as closeSync5, constants as constants2, fstatSync as fstatSync5, lstatSync as lstatSync6, openSync as openSync5, readSync as readSync2 } from "fs";
45550
- import { dirname as dirname6, isAbsolute as isAbsolute6, resolve as resolve5 } from "path";
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" || !isAbsolute6(path) || path !== resolve5(path) || path.length > AGENT_POLICY_LIMITS.pathCharacters || path.includes("\x00"))
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 = dirname6(cursor)) {
45558
- if (lstatSync6(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
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 (dirname6(cursor) === cursor)
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(budget, bytes) {
45568
- if (bytes > budget.remaining)
45886
+ function consume(budget2, bytes) {
45887
+ if (bytes > budget2.remaining)
45569
45888
  throw new Error("Raw discovery aggregate byte limit exceeded");
45570
- budget.remaining -= bytes;
45889
+ budget2.remaining -= bytes;
45571
45890
  }
45572
- function hashRawDiscoveryFile(path, budget, changes) {
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(budget, bytes);
45579
- return createHash3("sha256").update(text2).digest("hex");
45897
+ consume(budget2, bytes);
45898
+ return createHash4("sha256").update(text2).digest("hex");
45580
45899
  }
45581
- const initial = lstatSync6(path, { throwIfNoEntry: false });
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 > budget.remaining)
45905
+ if (initial.size > budget2.remaining)
45587
45906
  throw new Error("Raw discovery aggregate byte limit exceeded");
45588
- const fd = openSync5(path, constants2.O_RDONLY | constants2.O_NOFOLLOW | constants2.O_NONBLOCK);
45907
+ const fd = openSync6(path, constants3.O_RDONLY | constants3.O_NOFOLLOW | constants3.O_NONBLOCK);
45589
45908
  try {
45590
- const opened = fstatSync5(fd);
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 = createHash3("sha256"), buffer = Buffer.alloc(64 * 1024);
45912
+ const hash2 = createHash4("sha256"), buffer = Buffer.alloc(64 * 1024);
45594
45913
  let bytes = 0;
45595
45914
  while (true) {
45596
- const count = readSync2(fd, buffer, 0, Math.min(buffer.length, AGENT_POLICY_LIMITS.discoveryRawSourceBytes - bytes + 1), null);
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(budget, count);
45921
+ consume(budget2, count);
45603
45922
  hash2.update(buffer.subarray(0, count));
45604
45923
  }
45605
- const final = fstatSync5(fd), current = lstatSync6(path, { throwIfNoEntry: false });
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
- closeSync5(fd);
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 createHash4 } from "crypto";
45620
- import { lstatSync as lstatSync7, readlinkSync } from "fs";
45621
- import { dirname as dirname7, isAbsolute as isAbsolute7, join as join12, parse as parse6, resolve as resolve6, sep as sep3 } from "path";
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 canonical(path) {
45633
- if (typeof path !== "string" || !isAbsolute7(path) || path !== resolve6(path) || path.length > AGENT_POLICY_LIMITS.pathCharacters || path.includes("\x00") || Buffer.from(path).toString("utf8") !== path)
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
- canonical(path);
45956
+ canonical2(path);
45638
45957
  const rows = [], paths = [];
45639
- let metadataBytes = 0, steps = 0, links = 0, cursor = parse6(path).root, pending = path.slice(cursor.length).split(sep3);
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 = lstatSync7(cursor, { bigint: true });
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 = dirname7(cursor);
45981
+ cursor = dirname8(cursor);
45663
45982
  continue;
45664
45983
  }
45665
- const candidate = join12(cursor, component);
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 = lstatSync7(candidate, { bigint: true, throwIfNoEntry: false });
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 = lstatSync7(candidate, { bigint: true });
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 (isAbsolute7(target)) {
45683
- cursor = parse6(target).root;
46001
+ if (isAbsolute8(target)) {
46002
+ cursor = parse7(target).root;
45684
46003
  root();
45685
46004
  }
45686
- const remainder = isAbsolute7(target) ? target.slice(parse6(target).root.length) : target;
45687
- pending = [...remainder.split(sep3), ...pending];
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, budget, changes) {
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 + sep3)) {
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 = budget.pathMetadataRemaining ?? AGENT_POLICY_LIMITS.discoveryPathTotalMetadataBytes;
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
- budget.pathMetadataRemaining = remaining - before.metadataBytes;
45723
- const content = before.file === null ? null : hashRawDiscoveryFile(before.file, budget);
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 createHash4("sha256").update(JSON.stringify({ version: 1, path, rows: before.rows, content })).digest("hex");
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 createHash5 } from "crypto";
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 join13, relative as relative3 } from "path";
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 createHash5("sha256").update(bytes).digest("hex");
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 = join13(current, entry.name);
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((resolve7) => setTimeout(resolve7, 0));
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 createHash6, randomUUID } from "crypto";
46761
+ import { createHash as createHash8, randomUUID } from "crypto";
46305
46762
  import { spawnSync as spawnSync2 } from "child_process";
46306
- import { closeSync as closeSync6, constants as constants3, fstatSync as fstatSync6, fsyncSync, linkSync, lstatSync as lstatSync8, mkdirSync as mkdirSync3, openSync as openSync6, readFileSync as readFileSync10, readlinkSync as readlinkSync2, readSync as readSync3, renameSync, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
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 dirname8, join as join14, parse as parse7, resolve as resolve7 } from "path";
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 resolve7(options.cacheDir ?? join14(getDataDirReadOnly(), "selection-cache"));
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 createHash6("sha256").update(JSON.stringify(value)).digest("hex");
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 join14(selectionCacheRoot(options), "objects", hash2(selection.authority), hash2(selection.workspaceId), `${selection.bundleDigest.slice(7)}.tar.gz`);
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 = resolve7(path);
46359
- const root = parse7(absolute).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 = join14(cursor, segments[index]);
46820
+ cursor = join15(cursor, segments[index]);
46364
46821
  try {
46365
- const stat = lstatSync8(cursor);
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 = openSync6(path, constants3.O_RDONLY | constants3.O_NOFOLLOW | constants3.O_NONBLOCK);
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 = fstatSync6(fd);
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 = readSync3(fd, bytes, size, bytes.length - size, null);
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
- closeSync6(fd);
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 = join14(dirname8(path), `.selection-${randomUUID()}.tmp`);
46872
+ const temporary = join15(dirname9(path), `.selection-${randomUUID()}.tmp`);
46416
46873
  try {
46417
- const fd = openSync6(temporary, constants3.O_WRONLY | constants3.O_CREAT | constants3.O_EXCL | constants3.O_NOFOLLOW, mode);
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
- closeSync6(fd);
46880
+ closeSync7(fd);
46424
46881
  }
46425
46882
  renameSync(temporary, path);
46426
46883
  if (durable)
46427
- syncDirectory(dirname8(path));
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 bundle = await inspectSkillBundle(bytes);
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 cacheSelectionBundle(selection, response, options = {}) {
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
- await reader.cancel().catch(() => {});
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 join14(selectionCacheRoot(options), "profiles", `${hash2(profileId)}.json`);
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 join14(resolve7(projectDir), ".skills", SELECTION_LOCK_FILE);
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 join14(selectionCacheRoot(options), "sessions", `${hash2(sessionId)}.json`);
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 = lstatSync8(path, { throwIfNoEntry: false });
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 = lstatSync8(path, { throwIfNoEntry: false });
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 = lstatSync8(stagingPath, { throwIfNoEntry: false });
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 = openSync6(stagingPath, constants3.O_WRONLY | constants3.O_CREAT | constants3.O_EXCL | constants3.O_NOFOLLOW, 384);
46675
- const stat = fstatSync6(fd);
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(dirname8(path));
46683
- const staged = lstatSync8(stagingPath);
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(dirname8(path));
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 = lstatSync8(target, { throwIfNoEntry: false });
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
- closeSync6(fd);
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 = openSync6(guardPath, constants3.O_WRONLY | constants3.O_CREAT | constants3.O_EXCL | constants3.O_NOFOLLOW, 384);
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 = fstatSync6(guardFd);
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: dirname8(dirname8(lock.path)) };
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 = join14(dirname8(dirname8(lock.path)), "session-lock-recoveries", randomUUID());
46741
- const archivePath = join14(directory, "original.write-lock");
46742
- const recordPath = join14(directory, "recovery.json");
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(dirname8(directory));
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 = join14(directory, "publication.write-lock");
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(dirname8(lock.path));
47251
+ syncDirectory(dirname9(lock.path));
46773
47252
  for (const path of archivedPaths) {
46774
- const before = lstatSync8(path, { throwIfNoEntry: false });
47253
+ const before = lstatSync9(path, { throwIfNoEntry: false });
46775
47254
  const bytes = readRegularFile(path, SESSION_LOCK_MAX_BYTES);
46776
- const after = lstatSync8(path, { throwIfNoEntry: false });
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
- closeSync6(guardFd);
46789
- const current = lstatSync8(guardPath, { throwIfNoEntry: false });
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 = lstatSync8(lock.path, { throwIfNoEntry: false });
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 = lstatSync8(path, { throwIfNoEntry: false });
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
- closeSync6(lock.fd);
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 = openSync6(path, constants3.O_RDONLY | constants3.O_DIRECTORY | constants3.O_NOFOLLOW);
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
- closeSync6(fd);
47381
+ closeSync7(fd);
46903
47382
  }
46904
47383
  }
46905
47384
  function archiveBytes(path, bytes) {
46906
47385
  assertRegularPath(path, true);
46907
- const fd = openSync6(path, constants3.O_WRONLY | constants3.O_CREAT | constants3.O_EXCL | constants3.O_NOFOLLOW, 384);
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
- closeSync6(fd);
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 createHash7 } from "crypto";
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 createHash7("sha256").update(bytes).digest("hex");
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 constants4, closeSync as closeSync7, fstatSync as fstatSync7, lstatSync as lstatSync9, mkdirSync as mkdirSync4, openSync as openSync7, readFileSync as readFileSync11, readdirSync as readdirSync5, rmdirSync, unlinkSync as unlinkSync2, ftruncateSync, writeSync } from "fs";
47214
- import { join as join15 } from "path";
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
- lstatSync9(join15(skillPath, DEPENDENCY_PREPARATION_MARKER));
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 = join15(skillPath, DEPENDENCY_PREPARATION_MARKER);
47225
- const state = join15(marker, "state.json"), active = join15(marker, "active");
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 (!lstatSync9(marker).isDirectory() || lstatSync9(marker).isSymbolicLink())
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 (!lstatSync9(state).isFile() || lstatSync9(state).isSymbolicLink() || lstatSync9(state).size > 1024)
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 = openSync7(state, constants4.O_RDWR | constants4.O_NOFOLLOW | (created ? constants4.O_CREAT | constants4.O_EXCL : 0), 384);
47249
- if (!fstatSync7(fd).isFile()) {
47250
- closeSync7(fd);
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
- closeSync7(descriptor);
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
- closeSync7(descriptor);
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
- closeSync7(descriptor);
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
- closeSync7(fd);
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 join16, relative as relative4, resolve as resolve9, sep as sep4 } from "path";
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 = join16(parent, ".codex-remote-plugin-install.json"), stat = lstatSync11(path, { throwIfNoEntry: false });
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 = join16(root, ".codex-plugin/plugin.json"), manifestFile = lstatSync11(manifestPath, { throwIfNoEntry: false });
47851
- if (!lstatSync11(join16(root, ".codex-plugin"), { throwIfNoEntry: false })?.isDirectory() || !manifestFile?.isFile() || manifestFile.size > 1024 * 1024)
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(join16(root, "hooks"), { throwIfNoEntry: false }))
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 = join16(root, ".mcp.json"), mcpPresent = lstatSync11(mcp, { throwIfNoEntry: false });
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 = join16(root, ".app.json"), present = lstatSync11(app, { throwIfNoEntry: false });
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(sep4), enrolled = controls.filter((control) => control.pluginParent === parent);
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 + sep4))) && rule.enabled !== false));
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(sep4), enrolled = controls.filter((control) => control.pluginParent === parent);
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 + sep4))) && rule.enabled !== false)))
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(join16(root, ".codex-plugin/plugin.json"))).hooks !== undefined)
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 = join16(directory, name), stat = lstatSync11(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 + sep4) || !lstatSync11(parent, { throwIfNoEntry: false })?.isDirectory() || realpathSync3(parent) !== parent)
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 = join16(parent, name), stat = lstatSync11(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(join16(root, path), { throwIfNoEntry: false })))
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(sep4);
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 + sep4) || cache.startsWith(input2.sourceRoot + sep4))
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 = join16(input2.sourceRoot, ".codex-plugin/plugin.json"), stat = lstatSync11(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 + sep4))))
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 createHash9 } from "crypto";
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 canonical3(value, depth = 0, budget = { remaining: 65536 }) {
48064
- need3(depth <= 32 && --budget.remaining >= 0);
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) => canonical3(child, depth + 1, budget))];
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, canonical3(child, depth + 1, budget)])];
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, budget = { remaining: 256 * 1024 * 1024 }) {
48085
- need3(Buffer.byteLength(text2) <= 1024 * 1024 && budget.remaining >= Buffer.byteLength(text2));
48086
- budget.remaining -= Buffer.byteLength(text2);
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([canonical3(config2), numericTokens(text2)])}`);
48321
+ return sha(`hasna.skills.codex-settings.v1\x00${JSON.stringify([canonical4(config2), numericTokens(text2)])}`);
48104
48322
  }
48105
- function captureCodexSettings(path, budget = { remaining: 256 * 1024 * 1024 }) {
48106
- const text2 = readNativeSettingsWitnessFile(path, budget, "config.toml");
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) => createHash9("sha256").update(text2).digest("hex"), EFFORT, VERBOSITY;
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 createHash10 } from "crypto";
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 canonical4(value, depth = 0, budget = { remaining: 65536 }) {
48234
- need4(depth <= 32 && --budget.remaining >= 0);
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) => canonical4(child, depth + 1, budget))];
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, canonical4(child, depth + 1, budget)])];
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([canonical4(projected.config), numericTokens2(projected.numericSource)])}`);
48644
+ return sha2(`hasna.skills.codex-settings.v${version2}\x00${JSON.stringify([canonical5(projected.config), numericTokens2(projected.numericSource)])}`);
48427
48645
  }
48428
- function hashCodexSettingsReplacementV2(text2, budget = { remaining: 256 * 1024 * 1024 }) {
48429
- need4(Buffer.byteLength(text2) <= 1024 * 1024 && budget.remaining >= Buffer.byteLength(text2));
48430
- budget.remaining -= Buffer.byteLength(text2);
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, budget = { remaining: 256 * 1024 * 1024 }) {
48434
- const text2 = readNativeSettingsWitnessFile(path, budget, "config.toml");
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, budget = { remaining: 256 * 1024 * 1024 }) {
48438
- need4(Buffer.byteLength(text2) <= 1024 * 1024 && budget.remaining >= Buffer.byteLength(text2));
48439
- budget.remaining -= Buffer.byteLength(text2);
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, budget = { remaining: 256 * 1024 * 1024 }) {
48443
- return { path, hashMode: "codex-settings-v3", sha256: settingsDigest2(readNativeSettingsWitnessFile(path, budget, "config.toml"), 3) };
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, budget = { remaining: 256 * 1024 * 1024 }) {
48446
- need4(Buffer.byteLength(text2) <= 1024 * 1024 && budget.remaining >= Buffer.byteLength(text2));
48447
- budget.remaining -= Buffer.byteLength(text2);
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, budget = { remaining: 256 * 1024 * 1024 }) {
48451
- return { path, hashMode: "codex-settings-v4", sha256: settingsDigest2(readNativeSettingsWitnessFile(path, budget, "config.toml"), 4) };
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) => createHash10("sha256").update(text2).digest("hex"), EFFORT2, VERBOSITY2, MODEL, CODEX_DISCOVERY_PROJECTION_FIELDS, INFERENCE;
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 join17 } from "path";
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 = join17(dataDir2, "agent-policy.json");
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 createHash11 } from "crypto";
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 = createHash11("sha256").update(markdown).digest("hex");
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 join18, resolve as resolve10 } from "path";
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("~/") ? join18(home, value.slice(2)) : value);
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 canonical5 = explicit ? expand(explicit) : xdg ? join18(expand(xdg), "sumi") : join18(custom2 ? expand(custom2) : join18(home, ".hasna-internal/sumi"), "config");
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 canonical5;
48588
- const legacy = join18(home, ".config/sumi");
48589
- const a = lstatSync13(canonical5, { throwIfNoEntry: false }), b = lstatSync13(legacy, { throwIfNoEntry: false });
48590
- if (a && b && realpathSync4(canonical5) !== realpathSync4(legacy))
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 ? canonical5 : b ? legacy : canonical5;
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()) && ![canonical5, legacy].includes(physical))
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 join18(sumiConfigDirectory(home), "sumi.json");
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 createHash12 } from "crypto";
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: createHash12("sha256").update(content).digest("hex") };
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 join19 } from "path";
48929
+ import { join as join20 } from "path";
48711
48930
  function getProjectStateDir(targetDir = process.cwd()) {
48712
- return join19(targetDir, SKILLS_PROJECT_DIR);
48931
+ return join20(targetDir, SKILLS_PROJECT_DIR);
48713
48932
  }
48714
48933
  function getProjectConfigPath(targetDir = process.cwd()) {
48715
- return join19(getProjectStateDir(targetDir), PROJECT_CONFIG_FILE);
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 join20 } from "path";
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 join20(getPortableSkillsRoot(), skillName);
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" ? join20(base, ".pi", "skills") : join20(homedir2(), ".pi", "agent", "skills");
49114
+ return scope === "project" ? join21(base, ".pi", "skills") : join21(homedir2(), ".pi", "agent", "skills");
48896
49115
  case "opencode":
48897
- return scope === "project" ? join20(base, ".opencode", "skills") : join20(homedir2(), ".config", "opencode", "skills");
49116
+ return scope === "project" ? join21(base, ".opencode", "skills") : join21(homedir2(), ".config", "opencode", "skills");
48898
49117
  default:
48899
- return scope === "project" ? join20(base, `.${agent}`, "skills") : join20(homedir2(), `.${agent}`, "skills");
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 = join20(getSkillPath(name), "package.json");
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 join21 } from "path";
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 = join21(skillPath, "SKILL.md");
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(join21(skillPath, "SKILL.md")),
49003
- readme: readIfExists(join21(skillPath, "README.md")),
49004
- claudeMd: readIfExists(join21(skillPath, "CLAUDE.md"))
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(join21(skillPath, file2));
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(join21(skillPath, "package.json"), "utf8")).dependencies || {};
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 = join21(skillPath, "package.json");
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 = join21(skillPath, entryPoint2);
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(join21(skillPath, "node_modules")) || hasDependencyPreparationMarker(skillPath)) {
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(join21(cwd, "package.json"), "utf8"));
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 createHash13 } from "crypto";
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) => createHash13("sha256").update(bytes).digest("hex");
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 join22, parse as parse9, resolve as resolve11 } from "path";
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 canonical5(path) {
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
- canonical5(path);
49453
- const result = [], parent = dirname12(path), filesystemRoot = parse9(parent).root;
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 = join22(current, segment);
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 = join22(directory, name), entryStat = stat(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 = join22(absolute, pin), pinStat = stat(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 join23, resolve as resolve12 } from "path";
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 join23(storeRoot, "bindings", `${id}.json`);
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 join23(storeRoot, "receipts", id, `${digest.slice(7)}.json`);
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 === join23(storeRoot, "objects", id, digest.slice(7)), "Plugin receipt points outside its immutable materialization");
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 join24, resolve as resolve13 } from "path";
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 = join24(dirname13(path), "cache", market, name);
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 === join24(cacheRoot, row.version), "Managed plugin cache path or version is outside its registration");
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(join24(cacheRoot, version2), { nativeRuntime: `claude-${target.native.version}` }));
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(join24(cacheRoot, version2));
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 createHash14 } from "crypto";
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, budget) {
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(budget.remaining) && budget.remaining >= 0, "has an invalid byte budget");
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(budget.remaining), "exceeds its aggregate byte limit");
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
- budget.remaining -= length;
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 parse10(text2) {
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, budget = { remaining: 256 * 1024 * 1024 }) {
50193
- const value = parse10(readRegistry2(path, budget));
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 = createHash14("sha256").update("hasna.skills.claude-marketplace-registry.v1\x00").update(JSON.stringify(value)).digest("hex");
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, budget = { remaining: 256 * 1024 * 1024 }) {
50200
- const value = parse10(readRegistry2(path, budget));
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 = createHash14("sha256").update("hasna.skills.claude-marketplace-registry.v2\x00").update(JSON.stringify(value)).digest("hex");
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 createHash15 } from "crypto";
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) => createHash15("sha256").update(text2).digest("hex"), fields, proofs2;
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 createHash16 } from "crypto";
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 join25, resolve as resolve15, sep as sep5 } from "path";
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 isSupersededCodexProjection(agent, configPath, source) {
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 supersedesCodexProjection(sources, configPath) {
50296
- return sources.some((source) => source.path === configPath && (source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")));
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, budget = discoveryByteBudget()) {
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, budget).sha256;
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), budget) : current;
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, budget).sha256;
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), budget) : current;
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, budget).sha256;
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, budget, changes);
50337
- return hashRawDiscoveryFile(source.path, budget, changes);
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 = join25(dirname15(dirname15(cache)), "config.toml");
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(join25(codex, "config.toml")) ?? "");
50363
- const hooks = read(join25(codex, "hooks.json"));
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 = join25(dirname15(dirname15(cache)), "config.toml");
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 === join25(root, ".codex-plugin/plugin.json") && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined && [undefined, "bytes"].includes(source2.hashMode));
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 = sep5 + ".claude" + sep5 + "plugins" + sep5 + "cache" + sep5, at = source.path.indexOf(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(sep5);
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 = join25(cache, ...parts.slice(0, 3));
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 = join25(claude, "settings.json"), registry2 = join25(claude, "plugins/installed_plugins.json");
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(join25(active, ".claude-plugin/plugin.json"));
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 + sep5) || root.startsWith(row.installPath + sep5))))
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 + sep5));
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 + sep5)));
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 budget = discoveryByteBudget();
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 + sep5)) && source.format === undefined && source.fields === undefined && source.managedPlugins === undefined && [undefined, "bytes"].includes(source.hashMode)) {
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, budget);
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 = join25(dirname15(dirname15(cache)), "config.toml"), home = dirname15(dirname15(dirname15(cache)));
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]) => join25(home, path));
50508
- if (!configSource || proof.plugins.some((input2) => nativeRoots.some((root) => root === input2.sourceRoot || root.startsWith(input2.sourceRoot + sep5) || input2.sourceRoot.startsWith(root + sep5)) || binding.sources.some((source) => basename8(source.path) === "config.toml" && (source.path === input2.sourceRoot || source.path.startsWith(input2.sourceRoot + sep5)))))
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 === join25(input2.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined)))
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 join25(home, agent === "hermes" ? ".hermes/config.yaml" : agent === "opencode" ? ".config/opencode/opencode.json" : `.${agent}/${agent === "codex" ? "config.toml" : agent === "cursor" ? "hooks.json" : "settings.json"}`);
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 canonical6 = options.canonical ?? resolve15, home = resolve15(options.home), agent = options.agent;
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: canonical6(path), sha256: null, ...format ? { format, fields: fields2 } : {} };
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" ? ["skills", "plugin", "plugins", "permissions"] : ["version"]);
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(join25(directory, "sumi.jsonc")) !== null)
50795
+ if (witness(join26(directory, "sumi.jsonc")) !== null)
50552
50796
  unresolved("JSONC configuration requires a supported format adapter");
50553
- for (const root of [directory, join25(home, ".claude"), join25(home, ".agents")])
50797
+ for (const root of [directory, join26(home, ".claude"), join26(home, ".agents")])
50554
50798
  for (const name of ["skill", "skills"])
50555
- roots.add(canonical6(join25(root, name)));
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(canonical6(value.startsWith("~/") ? join25(home, value.slice(2)) : value));
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 = [join25(directory, "plugin"), join25(directory, "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 = join25(path, name);
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(join25(home, ".hermes/active_profile"));
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("~/") ? join25(home, normalized.slice(2)) : resolve15(home, ".hermes", normalized);
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 = join25(directory, "package.json"), raw = read(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 = join25(packageRoot, "bundle/builtin");
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(join25(builtinRoot, name, "SKILL.md"));
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 === canonical6(configPath) && source.format === undefined && source.fields === undefined))
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 !== canonical6(configPath)))
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 = supersedesCodexProjection(retained.sources, canonical6(configPath)) ? sources.filter((source) => !isSupersededCodexProjection(agent, canonical6(configPath), source)) : sources;
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 !== canonical6(configPath)))
50659
- throw new Error("Semantic settings witnesses must name the configured Claude configuration source");
50660
- if (!review.sources.some((source) => source.path === canonical6(configPath)))
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 = supersedesCodexProjection(review.sources, canonical6(configPath)) ? sources.filter((source) => !isSupersededCodexProjection(agent, canonical6(configPath), source)) : sources;
50663
- return { ...supplied, roots: [...new Set([...roots, ...supplied.roots])].sort(), sources: [...reviewedSources, ...review.sources], ...agent === "gemini" ? { builtinNames } : {} };
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 = canonical6(root);
50937
+ root = canonical7(root);
50667
50938
  safe4(root);
50668
- const manifestPath = join25(root, agent === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json");
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(join25(root, "hooks/hooks.json"));
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 = join25(root, "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(join25(root, "SKILL.md"));
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(join25(root, "skills"));
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 + sep5))
50961
+ if (path !== root && !path.startsWith(root + sep6))
50691
50962
  unresolved("plugin skill path escapes its root");
50692
- roots.add(path.endsWith(`${sep5}SKILL.md`) ? dirname15(path) : path);
50963
+ roots.add(path.endsWith(`${sep6}SKILL.md`) ? dirname15(path) : path);
50693
50964
  }
50694
50965
  }
50695
50966
  if (agent === "claude") {
50696
- const registrations = witness(join25(home, ".claude/plugins/installed_plugins.json"));
50697
- const installed = registrations === null ? {} : parseConfig(registrations, join25(home, ".claude/plugins/installed_plugins.json")).plugins;
50698
- const commands = canonical6(join25(home, ".claude/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(join25(market.source, ".agents/plugins/marketplace.json"));
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, join25(market.source, ".agents/plugins/marketplace.json")), matches = Array.isArray(catalog.plugins) ? catalog.plugins.filter((item) => item.name === name) : [];
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(join25(home, ".config/opencode/opencode.jsonc")) !== null || witness(join25(home, ".config/opencode/config.json")) !== null)
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 = join25(home, ".config/opencode/plugins");
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 !== canonical6(configPath) && source.path !== canonical6(join25(sumiConfigDirectory(home), "sumi.jsonc")) && source.sha256 !== null))
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 [join25(home, ".hermes/plugins"), join25(home, ".hermes/hermes-agent")]) {
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 = join25(home, ".gemini/extensions");
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 = join25(directory, name);
51033
+ const root = join26(directory, name);
50763
51034
  safe4(root);
50764
51035
  if (!lstatSync18(root)?.isDirectory())
50765
51036
  continue;
50766
- const raw = witness(join25(root, "gemini-extension.json"));
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, join25(root, "gemini-extension.json"));
50770
- if (manifest.hooks !== undefined || witness(join25(root, "hooks/hooks.json")) !== null || witness(join25(root, ".gemini-extension-install.json")) !== null)
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(join25(root, "skills"));
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([join25(home, ".hermes/plugins"), join25(home, ".hermes/hermes-agent")].map((path) => canonical6(path))) } : {} };
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) => createHash16("sha256").update(text2).digest("hex");
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 join26, resolve as resolve16, sep as sep6 } from "path";
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(sep6).filter(Boolean);
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 + sep6);
51100
+ return path === root || path.startsWith(root + sep7);
50828
51101
  }
50829
51102
  function configuredRoots(home, explicitHome) {
50830
- const homeData = join26(home, ".hasna", "skills");
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 = join26(home, agent === "opencode" ? ".config/opencode" : `.${agent}`);
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) => join26(home, ...parts));
50877
- defaults.push(join26(home, ".codex/plugins/cache"), join26(home, ".claude/plugins/cache"), join26(home, ".claude/plugins/synced"), join26(home, ".gemini/extensions"));
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 join27, normalize as normalize3, relative as relative5, resolve as resolve17, sep as sep7 } from "path";
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 ? join27(options.homeDir, ".hasna", "skills") : migrate ? getDataDir() : getDataDirReadOnly();
50921
- const cache = join27(appDir, SKILLS_CACHE_DIRNAME);
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 = join27(appDir, INSTALLED_SKILLS_DIRNAME);
51197
+ const installed = join28(appDir, INSTALLED_SKILLS_DIRNAME);
50925
51198
  return installed;
50926
51199
  }
50927
51200
  function getPortableSkillPath(name, options = {}) {
50928
- return join27(getPortableSkillsRoot(options), normalizePortableSkillName(name));
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 = join27(root, entry);
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(join27(readOnlyRoot, skillName), options);
51260
+ assertPortableAuthoringPath(join28(readOnlyRoot, skillName), options);
50988
51261
  const root = getPortableSkillsRoot(options);
50989
- const skillPath = join27(root, skillName);
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 join27(realpathSync7(ancestor), ...suffix);
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(`..${sep7}`);
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 = join27(resolvePortableSkillsRoot(options, false), skillName);
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 = join27(root, skillName);
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 = join27(skillPath, "skill.json");
51077
- const skillMdPath = join27(skillPath, "SKILL.md");
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(join27(skillPath, "skill.json")),
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 = join27(skillPath, command.entry);
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(join27(skillPath, "AGENTS.md"))) {
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 join28 } from "path";
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 = join28(dir, entry.name, "SKILL.md");
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(join28(dir, entry.name)) ? { serverOwned: true } : {},
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 = join28(config2.extensionsDir, entry.name);
51454
- const skillMdPath = join28(skillDir, "SKILL.md");
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 createHash17 } from "crypto";
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 createHash17("sha256").update(canonicalJson2(value, maximumBytes)).digest("hex");
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, budget, 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;
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
- budget = exports_external.object({ reservedCredits: integer2, settledCredits: integer2, admittedOccurrences: integer2 });
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: budget,
52189
- currentPeriod: budget.extend(period.shape).nullable(),
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 join29 } from "path";
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 join29(dirname18(file2), basename11(file2).replace(/^credentials/, "identity") + ".json");
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 createHash18 } from "crypto";
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, budget2 = 15000, signal) {
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, budget2)));
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) => createHash18("sha256").update(bytes).digest("hex");
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 join30, resolve as resolve18 } from "path";
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(join30(this.directory, name), constants12.O_RDONLY | constants12.O_NOFOLLOW | constants12.O_NONBLOCK);
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(join30(this.directory, name));
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(join30(this.directory, name), constants12.O_WRONLY | constants12.O_CREAT | constants12.O_EXCL | constants12.O_NOFOLLOW, 384);
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(join30(this.directory, name), join30(this.directory, "state.json"));
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(join30(this.directory, "operation.lock"), constants12.O_WRONLY | constants12.O_CREAT | constants12.O_EXCL | constants12.O_NOFOLLOW, 384);
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(join30(this.directory, "operation.lock"));
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(join30(this.directory, "operation.lock"));
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 createHash19, randomBytes } from "crypto";
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 join31, relative as relative6 } from "path";
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 = join31(root, "runs", day, id);
57148
- const logsDir = join31(runDir, "logs");
57149
- const exportDir = join31(root, "exports", skillName, id);
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(join31(root, "tmp"), { recursive: true });
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(join31(context2.logsDir, "stdout.log"), stdout);
57205
- writeFileSync10(join31(context2.logsDir, "stderr.log"), stderr);
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 = join31(context2.runDir, "events.ndjson");
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 = join31(getProjectStateDir(targetDir), "runs");
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(join31(runsRoot, day, runId));
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(join31(context2.runDir, "run.json"), JSON.stringify(context2.record, null, 2) + `
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(join31(context2.runDir, "artifacts.json"), JSON.stringify({ runId: context2.record.id, artifacts }, null, 2) + `
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: createHash19("sha256").update(bytes).digest("hex"),
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 = join31(runDir, "run.json");
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 = join31(dir, entry);
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 join32 } from "path";
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 ? join32(home, HASNA_HOME_DIR2) : null;
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 join32(configRoot, name);
57838
+ return join33(configRoot, name);
57566
57839
  const root = hasnaHomeDir2(env);
57567
- return root ? join32(root, name, CONFIG_SUBDIR2) : null;
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: join32(directory2, file2), tier: "disk" }];
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 createHash20 } from "crypto";
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 join33, resolve as resolve19 } from "path";
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(join33(tmpdir(), "skills-execution-"));
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 = join33(runDirectory, entry.path);
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"] : [], join33(runDirectory, declaredEntry), ...args], runDirectory, { ...env, ...secretEnv }, input2, timeoutMs);
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:${createHash20("sha256").update(input2).digest("hex")}`,
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(join33(runDirectory, ".execution-receipt.json"), JSON.stringify({ ...receipt, stdout: undefined, stderr: undefined }), { mode: 384 });
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 join34 } from "path";
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 = join34(agentSkillsPath, f);
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 join35 } from "path";
60207
+ import { dirname as dirname21, join as join36 } from "path";
59935
60208
  import { Database } from "bun:sqlite";
59936
60209
  function getFeedbackDbPath() {
59937
- return join35(getDataDir(), "skills.db");
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 = join35(getDataDir(), "feedback.jsonl");
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 join36 } from "path";
60407
+ import { join as join37 } from "path";
60135
60408
  function getSchedulesPath(targetDir = process.cwd()) {
60136
- return join36(targetDir, ".skills", "schedules.json");
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 = join36(targetDir, ".skills");
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 createHash21, createHmac } from "crypto";
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 join37, normalize as normalize4, relative as relative7, sep as sep8 } from "path";
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: join37(getDataDir(), "skills.db")
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: createHash21("sha256").update(bytes).digest("hex"),
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 = join37(dir, entry);
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 join38, resolve as resolve20 } from "path";
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 = join38(directory2, name);
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(join38(directory2, name), constants14.O_WRONLY | constants14.O_CREAT | constants14.O_EXCL | constants14.O_NOFOLLOW, 384);
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(join38(directory2, temporary), join38(directory2, "receipt.json"));
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 = join38(directory2, "operation.lock");
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 = parse11;
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 parse11(string6) {
63052
+ function parse12(string6) {
62780
63053
  if (!string6) {
62781
63054
  throw new TypeError("argument string is required");
62782
63055
  }