@hasna/skills 0.10.34 → 0.10.35

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.34",
20022
+ version: "0.10.35",
20023
20023
  description: "Skills library for AI coding agents",
20024
20024
  type: "module",
20025
20025
  bin: {
@@ -48184,6 +48184,55 @@ function sumiConfigPath(home) {
48184
48184
  }
48185
48185
  var init_agent_sumi = () => {};
48186
48186
 
48187
+ // src/lib/codex-hook-trust-files.ts
48188
+ 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";
48189
+ import { createHash as createHash12 } from "crypto";
48190
+ import { dirname as dirname11 } from "path";
48191
+ function need5(value, code) {
48192
+ if (!value)
48193
+ throw new Error(`CODEX_HOOK_TRUST_${code}`);
48194
+ }
48195
+ function safeParents(file2) {
48196
+ for (let p = dirname11(file2);; p = dirname11(p)) {
48197
+ const s = lstatSync14(p);
48198
+ need5(s.isDirectory() && !s.isSymbolicLink(), "UNSAFE_PARENT");
48199
+ need5((s.mode & 18) === 0 || s.uid === 0 && (s.mode & 512) !== 0, "UNSAFE_PARENT");
48200
+ if (dirname11(p) === p)
48201
+ break;
48202
+ }
48203
+ }
48204
+ function snapshot(file2, privateFile = false, options = {}) {
48205
+ const readOnlyPackage = options.readOnlyPackage === true && !privateFile;
48206
+ safeParents(file2);
48207
+ const initial = lstatSync14(file2, { bigint: true });
48208
+ need5(initial.isFile() && initial.uid === BigInt(process.getuid()) && (initial.nlink === 1n || readOnlyPackage && initial.nlink > 1n) && (initial.mode & 0o022n) === 0n && (!privateFile || (initial.mode & 0o777n) === 0o600n), "UNSAFE_FILE");
48209
+ need5(initial.size <= 8n * 1024n * 1024n, "FILE_BOUND");
48210
+ const fd = openSync10(file2, constants7.O_RDONLY | constants7.O_NOFOLLOW | constants7.O_NONBLOCK);
48211
+ try {
48212
+ const before = fstatSync10(fd, { bigint: true });
48213
+ need5(sameStat(initial, before), "INPUT_CHANGED");
48214
+ const bytes = Buffer.alloc(Number(before.size) + 1);
48215
+ let length = 0;
48216
+ while (length < bytes.length) {
48217
+ const n2 = readSync6(fd, bytes, length, bytes.length - length, null);
48218
+ if (!n2)
48219
+ break;
48220
+ length += n2;
48221
+ }
48222
+ need5(length === Number(before.size) && sameStat(before, fstatSync10(fd, { bigint: true })) && sameStat(before, lstatSync14(file2, { bigint: true })), "INPUT_CHANGED");
48223
+ const content = bytes.subarray(0, length), text2 = new TextDecoder("utf-8", { fatal: true }).decode(content);
48224
+ return { file: file2, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before, sha256: createHash12("sha256").update(content).digest("hex") };
48225
+ } finally {
48226
+ closeSync10(fd);
48227
+ }
48228
+ }
48229
+ function unchanged2(before) {
48230
+ const after = snapshot(before.file, before.privateFile, before.readOnlyPackage ? { readOnlyPackage: true } : {});
48231
+ need5(sameStat(before.stat, after.stat) && after.sha256 === before.sha256, "INPUT_CHANGED");
48232
+ }
48233
+ var sameStat = (a, b) => ["dev", "ino", "uid", "nlink", "mode", "size", "mtimeNs", "ctimeNs"].every((key) => a[key] === b[key]);
48234
+ var init_codex_hook_trust_files = () => {};
48235
+
48187
48236
  // src/lib/agent-integration.ts
48188
48237
  var init_agent_integration = __esm(() => {
48189
48238
  init_codex_plugin_skill_controls();
@@ -48200,6 +48249,7 @@ var init_agent_integration = __esm(() => {
48200
48249
  init_agent_sumi();
48201
48250
  init_agent_hermes();
48202
48251
  init_claude_settings_witness();
48252
+ init_codex_hook_trust_files();
48203
48253
  });
48204
48254
 
48205
48255
  // src/lib/home-migration.ts
@@ -48235,7 +48285,7 @@ var init_skill_aliases = __esm(() => {
48235
48285
  });
48236
48286
 
48237
48287
  // src/lib/project-state.ts
48238
- import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync12, writeFileSync as writeFileSync4 } from "fs";
48288
+ import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync12, writeFileSync as writeFileSync5 } from "fs";
48239
48289
  import { join as join19 } from "path";
48240
48290
  function getProjectStateDir(targetDir = process.cwd()) {
48241
48291
  return join19(targetDir, SKILLS_PROJECT_DIR);
@@ -48271,7 +48321,7 @@ function saveProjectConfig(config2, targetDir = process.cwd()) {
48271
48321
  const dir = getProjectStateDir(targetDir);
48272
48322
  mkdirSync5(dir, { recursive: true });
48273
48323
  const normalized = normalizeProjectConfig({ ...config2, updatedAt: new Date().toISOString() });
48274
- writeFileSync4(getProjectConfigPath(targetDir), JSON.stringify(normalized, null, 2) + `
48324
+ writeFileSync5(getProjectConfigPath(targetDir), JSON.stringify(normalized, null, 2) + `
48275
48325
  `);
48276
48326
  }
48277
48327
  function pinProjectSkill(name, details = {}, targetDir = process.cwd()) {
@@ -48870,7 +48920,7 @@ var init_selection_resolver = __esm(() => {
48870
48920
  });
48871
48921
 
48872
48922
  // src/lib/plugin-projection.ts
48873
- import { createHash as createHash12 } from "crypto";
48923
+ import { createHash as createHash13 } from "crypto";
48874
48924
  function pluginRefusal(message) {
48875
48925
  throw new SkillSelectionError("PLUGIN_ADMISSION_REFUSED", message);
48876
48926
  }
@@ -48948,18 +48998,18 @@ function pluginFileWitnesses(entries) {
48948
48998
  return { path: item.path, mode: item.mode, size: item.bytes.byteLength, sha256: pluginHash(item.bytes) };
48949
48999
  });
48950
49000
  }
48951
- var PLUGIN_PROJECTION_LIMITS, pluginHash = (bytes) => createHash12("sha256").update(bytes).digest("hex");
49001
+ var PLUGIN_PROJECTION_LIMITS, pluginHash = (bytes) => createHash13("sha256").update(bytes).digest("hex");
48952
49002
  var init_plugin_projection = __esm(() => {
48953
49003
  init_selection_cache();
48954
49004
  PLUGIN_PROJECTION_LIMITS = Object.freeze({ files: 1024, bytes: 64 * 1024 * 1024, fileBytes: 16 * 1024 * 1024, metadataBytes: 512 * 1024, registrations: 64, history: 128 });
48955
49005
  });
48956
49006
 
48957
49007
  // src/lib/plugin-projection-store.ts
48958
- import { constants as constants7, closeSync as closeSync10, fchmodSync, fstatSync as fstatSync10, fsyncSync as fsyncSync2, linkSync as linkSync2, lstatSync as lstatSync14, mkdirSync as mkdirSync6, openSync as openSync10, opendirSync as opendirSync2, readSync as readSync6, renameSync as renameSync2, rmdirSync as rmdirSync2, rmSync as rmSync2, unlinkSync as unlinkSync3, writeSync as writeSync2 } from "fs";
48959
- import { dirname as dirname11, isAbsolute as isAbsolute9, join as join22, parse as parse9, resolve as resolve11 } from "path";
49008
+ 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";
49009
+ import { dirname as dirname12, isAbsolute as isAbsolute9, join as join22, parse as parse9, resolve as resolve11 } from "path";
48960
49010
  function stat(path) {
48961
49011
  try {
48962
- return lstatSync14(path, { bigint: true });
49012
+ return lstatSync15(path, { bigint: true });
48963
49013
  } catch (error61) {
48964
49014
  if (missing(error61))
48965
49015
  return null;
@@ -48978,7 +49028,7 @@ function same3(left, right, identityOnly = false) {
48978
49028
  }
48979
49029
  function ancestors(path, create = false) {
48980
49030
  canonical5(path);
48981
- const result = [], parent = dirname11(path), filesystemRoot = parse9(parent).root;
49031
+ const result = [], parent = dirname12(path), filesystemRoot = parse9(parent).root;
48982
49032
  let current = filesystemRoot;
48983
49033
  for (const segment of ["", ...parent.slice(filesystemRoot.length).split("/").filter(Boolean)]) {
48984
49034
  if (segment)
@@ -49028,19 +49078,19 @@ function readBytes(path, maximum, kind) {
49028
49078
  fileShape(before, maximum, kind);
49029
49079
  let fd;
49030
49080
  try {
49031
- fd = openSync10(path, READ_FLAGS);
49032
- const opened = fstatSync10(fd, { bigint: true });
49081
+ fd = openSync11(path, READ_FLAGS);
49082
+ const opened = fstatSync11(fd, { bigint: true });
49033
49083
  same3(before, opened);
49034
49084
  fileShape(opened, maximum, kind);
49035
49085
  const bytes = new Uint8Array(Number(opened.size));
49036
49086
  let offset = 0;
49037
49087
  while (offset < bytes.byteLength) {
49038
- const count = readSync6(fd, bytes, offset, bytes.byteLength - offset, null);
49088
+ const count = readSync7(fd, bytes, offset, bytes.byteLength - offset, null);
49039
49089
  pluginNeed(count > 0, "Plugin file changed while being read");
49040
49090
  offset += count;
49041
49091
  }
49042
- pluginNeed(readSync6(fd, new Uint8Array(1), 0, 1, null) === 0, "Plugin file grew while being read");
49043
- same3(opened, fstatSync10(fd, { bigint: true }));
49092
+ pluginNeed(readSync7(fd, new Uint8Array(1), 0, 1, null) === 0, "Plugin file grew while being read");
49093
+ same3(opened, fstatSync11(fd, { bigint: true }));
49044
49094
  same3(opened, stat(path));
49045
49095
  verifyAncestors(chain);
49046
49096
  return bytes;
@@ -49050,7 +49100,7 @@ function readBytes(path, maximum, kind) {
49050
49100
  return pluginRefusal("Cannot safely read plugin file");
49051
49101
  } finally {
49052
49102
  if (fd !== undefined)
49053
- closeSync10(fd);
49103
+ closeSync11(fd);
49054
49104
  }
49055
49105
  }
49056
49106
  function exactPaths(entries) {
@@ -49173,8 +49223,8 @@ function readPluginJson(path) {
49173
49223
  var READ_FLAGS, WRITE_FLAGS, uid = () => typeof process.getuid === "function" ? BigInt(process.getuid()) : undefined, missing = (error61) => Boolean(error61 && typeof error61 === "object" && "code" in error61 && error61.code === "ENOENT");
49174
49224
  var init_plugin_projection_store = __esm(() => {
49175
49225
  init_plugin_projection();
49176
- READ_FLAGS = constants7.O_RDONLY | constants7.O_NOFOLLOW | constants7.O_NONBLOCK;
49177
- WRITE_FLAGS = constants7.O_WRONLY | constants7.O_CREAT | constants7.O_EXCL | constants7.O_NOFOLLOW | constants7.O_NONBLOCK;
49226
+ READ_FLAGS = constants8.O_RDONLY | constants8.O_NOFOLLOW | constants8.O_NONBLOCK;
49227
+ WRITE_FLAGS = constants8.O_WRONLY | constants8.O_CREAT | constants8.O_EXCL | constants8.O_NOFOLLOW | constants8.O_NONBLOCK;
49178
49228
  });
49179
49229
 
49180
49230
  // src/lib/selected-manifest.ts
@@ -49407,8 +49457,8 @@ var init_plugin_admission = __esm(() => {
49407
49457
  });
49408
49458
 
49409
49459
  // src/lib/plugin-discovery.ts
49410
- import { closeSync as closeSync11, constants as constants8, fstatSync as fstatSync11, lstatSync as lstatSync15, openSync as openSync11, opendirSync as opendirSync3, readSync as readSync7 } from "fs";
49411
- import { basename as basename6, dirname as dirname12, isAbsolute as isAbsolute11, join as join24, resolve as resolve13 } from "path";
49460
+ import { closeSync as closeSync12, constants as constants9, fstatSync as fstatSync12, lstatSync as lstatSync16, openSync as openSync12, opendirSync as opendirSync3, readSync as readSync8 } from "fs";
49461
+ import { basename as basename6, dirname as dirname13, isAbsolute as isAbsolute11, join as join24, resolve as resolve13 } from "path";
49412
49462
  function validateManagedPluginWitnesses(value) {
49413
49463
  pluginNeed(Array.isArray(value) && value.length > 0 && value.length <= PLUGIN_PROJECTION_LIMITS.registrations, "Invalid managed plugin witness collection");
49414
49464
  const seen = new Set;
@@ -49423,29 +49473,29 @@ function validateManagedPluginWitnesses(value) {
49423
49473
  function safe3(path) {
49424
49474
  pluginText(path);
49425
49475
  pluginNeed(isAbsolute11(path) && resolve13(path) === path, "Invalid plugin registry path");
49426
- for (let at = path;; at = dirname12(at)) {
49427
- pluginNeed(!lstatSync15(at, { throwIfNoEntry: false })?.isSymbolicLink(), "Plugin registry path traverses a symlink");
49428
- if (at === dirname12(at))
49476
+ for (let at = path;; at = dirname13(at)) {
49477
+ pluginNeed(!lstatSync16(at, { throwIfNoEntry: false })?.isSymbolicLink(), "Plugin registry path traverses a symlink");
49478
+ if (at === dirname13(at))
49429
49479
  break;
49430
49480
  }
49431
49481
  }
49432
49482
  function readRegistry(path) {
49433
49483
  safe3(path);
49434
- const initial = lstatSync15(path);
49484
+ const initial = lstatSync16(path);
49435
49485
  pluginNeed(initial.isFile() && initial.size <= 1024 * 1024, "Plugin registry is not a bounded regular file");
49436
- const fd = openSync11(path, constants8.O_RDONLY | constants8.O_NOFOLLOW | constants8.O_NONBLOCK);
49486
+ const fd = openSync12(path, constants9.O_RDONLY | constants9.O_NOFOLLOW | constants9.O_NONBLOCK);
49437
49487
  try {
49438
- const opened = fstatSync11(fd);
49488
+ const opened = fstatSync12(fd);
49439
49489
  pluginNeed(opened.isFile() && opened.ino === initial.ino && opened.dev === initial.dev, "Plugin registry changed during open");
49440
49490
  const bytes = Buffer.alloc(1024 * 1024 + 1);
49441
49491
  let length = 0;
49442
49492
  while (length < bytes.length) {
49443
- const count = readSync7(fd, bytes, length, bytes.length - length, null);
49493
+ const count = readSync8(fd, bytes, length, bytes.length - length, null);
49444
49494
  if (!count)
49445
49495
  break;
49446
49496
  length += count;
49447
49497
  }
49448
- const after = fstatSync11(fd), current = lstatSync15(path);
49498
+ const after = fstatSync12(fd), current = lstatSync16(path);
49449
49499
  safe3(path);
49450
49500
  pluginNeed(length <= 1024 * 1024 && length === opened.size && after.size === opened.size && after.mtimeMs === opened.mtimeMs && after.ctimeMs === opened.ctimeMs && current.dev === opened.dev && current.ino === opened.ino && current.mtimeMs === opened.mtimeMs && current.ctimeMs === opened.ctimeMs, "Plugin registry changed during read");
49451
49501
  let value;
@@ -49457,7 +49507,7 @@ function readRegistry(path) {
49457
49507
  pluginNeed(pluginObject(value) && value.version === 2 && pluginObject(value.plugins), "Unsupported native plugin registry schema");
49458
49508
  return { value, rawDigest: pluginHash(bytes.subarray(0, length)) };
49459
49509
  } finally {
49460
- closeSync11(fd);
49510
+ closeSync12(fd);
49461
49511
  }
49462
49512
  }
49463
49513
  function nativeVersionMatches(version2, receipt) {
@@ -49466,7 +49516,7 @@ function nativeVersionMatches(version2, receipt) {
49466
49516
  }
49467
49517
  function hashManagedPluginRegistry(path, managed) {
49468
49518
  validateManagedPluginWitnesses(managed);
49469
- const snapshot = readRegistry(path), plugins = snapshot.value.plugins;
49519
+ const snapshot2 = readRegistry(path), plugins = snapshot2.value.plugins;
49470
49520
  const seen = new Set, verified = new Set;
49471
49521
  let verifiedBytes = 0;
49472
49522
  for (const witness of managed) {
@@ -49475,7 +49525,7 @@ function hashManagedPluginRegistry(path, managed) {
49475
49525
  seen.add(target.pluginId);
49476
49526
  const rows = plugins[target.pluginId];
49477
49527
  pluginNeed(Array.isArray(rows) && rows.length === target.registrations.length, "Managed plugin registration membership changed");
49478
- const [name, market] = target.pluginId.split("@"), cacheRoot = join24(dirname12(path), "cache", market, name);
49528
+ const [name, market] = target.pluginId.split("@"), cacheRoot = join24(dirname13(path), "cache", market, name);
49479
49529
  const scopes = new Set, approvals = new Map, currentFiles = new Map;
49480
49530
  plugins[target.pluginId] = rows.map((row) => {
49481
49531
  pluginNeed(pluginObject(row), "Invalid managed plugin registration");
@@ -49518,7 +49568,7 @@ function hashManagedPluginRegistry(path, managed) {
49518
49568
  return Object.fromEntries(Object.entries(row).filter(([key]) => !["version", "installPath", "sourceProducerPath", "previousProducerPaths", "lastUpdated"].includes(key)));
49519
49569
  });
49520
49570
  safe3(cacheRoot);
49521
- const before = lstatSync15(cacheRoot);
49571
+ const before = lstatSync16(cacheRoot);
49522
49572
  pluginNeed(before.isDirectory(), "Invalid managed plugin cache root");
49523
49573
  const directory = opendirSync3(cacheRoot), names = [];
49524
49574
  try {
@@ -49541,12 +49591,12 @@ function hashManagedPluginRegistry(path, managed) {
49541
49591
  }
49542
49592
  for (const row of rows)
49543
49593
  pluginNeed(names.includes(row.version), "Managed native plugin installation is missing");
49544
- const after = lstatSync15(cacheRoot);
49594
+ const after = lstatSync16(cacheRoot);
49545
49595
  safe3(cacheRoot);
49546
49596
  pluginNeed(before.dev === after.dev && before.ino === after.ino && before.mtimeMs === after.mtimeMs && before.ctimeMs === after.ctimeMs, "Managed cache version membership changed during verification");
49547
49597
  }
49548
- pluginNeed(readRegistry(path).rawDigest === snapshot.rawDigest, "Native plugin registry changed during content verification");
49549
- return pluginHash(JSON.stringify(snapshot.value));
49598
+ pluginNeed(readRegistry(path).rawDigest === snapshot2.rawDigest, "Native plugin registry changed during content verification");
49599
+ return pluginHash(JSON.stringify(snapshot2.value));
49550
49600
  }
49551
49601
  var init_plugin_discovery = __esm(() => {
49552
49602
  init_plugin_admission();
@@ -49555,50 +49605,50 @@ var init_plugin_discovery = __esm(() => {
49555
49605
  });
49556
49606
 
49557
49607
  // src/lib/claude-marketplace-registry.ts
49558
- import { createHash as createHash13 } from "crypto";
49559
- import { closeSync as closeSync12, constants as constants9, fstatSync as fstatSync12, lstatSync as lstatSync16, openSync as openSync12, readSync as readSync8 } from "fs";
49560
- import { basename as basename7, dirname as dirname13, isAbsolute as isAbsolute12, resolve as resolve14 } from "path";
49561
- function need5(value, reason) {
49608
+ import { createHash as createHash14 } from "crypto";
49609
+ import { closeSync as closeSync13, constants as constants10, fstatSync as fstatSync13, lstatSync as lstatSync17, openSync as openSync13, readSync as readSync9 } from "fs";
49610
+ import { basename as basename7, dirname as dirname14, isAbsolute as isAbsolute12, resolve as resolve14 } from "path";
49611
+ function need6(value, reason) {
49562
49612
  if (!value)
49563
49613
  throw new Error(`Claude marketplace registry ${reason}`);
49564
49614
  }
49565
49615
  function absolutePath2(value) {
49566
- need5(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute12(value) && resolve14(value) === value, "requires a normalized absolute path");
49616
+ need6(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute12(value) && resolve14(value) === value, "requires a normalized absolute path");
49567
49617
  }
49568
49618
  function parents2(path) {
49569
49619
  const result = [];
49570
- for (let at = dirname13(path);; at = dirname13(at)) {
49571
- const stat2 = lstatSync16(at, { bigint: true });
49572
- need5(stat2.isDirectory() && !stat2.isSymbolicLink(), "path traverses a symlink or non-directory");
49620
+ for (let at = dirname14(path);; at = dirname14(at)) {
49621
+ const stat2 = lstatSync17(at, { bigint: true });
49622
+ need6(stat2.isDirectory() && !stat2.isSymbolicLink(), "path traverses a symlink or non-directory");
49573
49623
  result.push([at, stat2]);
49574
- if (at === dirname13(at))
49624
+ if (at === dirname14(at))
49575
49625
  return result;
49576
49626
  }
49577
49627
  }
49578
49628
  function readRegistry2(path, budget) {
49579
49629
  absolutePath2(path);
49580
- need5(basename7(path) === "known_marketplaces.json", "requires known_marketplaces.json");
49581
- need5(Number.isSafeInteger(budget.remaining) && budget.remaining >= 0, "has an invalid byte budget");
49582
- const ancestors2 = parents2(path), initial = lstatSync16(path, { bigint: true });
49583
- need5(initial.isFile() && !initial.isSymbolicLink() && initial.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
49584
- need5(initial.size <= BigInt(budget.remaining), "exceeds its aggregate byte limit");
49585
- const fd = openSync12(path, constants9.O_RDONLY | constants9.O_NOFOLLOW | constants9.O_NONBLOCK);
49630
+ need6(basename7(path) === "known_marketplaces.json", "requires known_marketplaces.json");
49631
+ need6(Number.isSafeInteger(budget.remaining) && budget.remaining >= 0, "has an invalid byte budget");
49632
+ const ancestors2 = parents2(path), initial = lstatSync17(path, { bigint: true });
49633
+ need6(initial.isFile() && !initial.isSymbolicLink() && initial.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
49634
+ need6(initial.size <= BigInt(budget.remaining), "exceeds its aggregate byte limit");
49635
+ const fd = openSync13(path, constants10.O_RDONLY | constants10.O_NOFOLLOW | constants10.O_NONBLOCK);
49586
49636
  try {
49587
- const opened = fstatSync12(fd, { bigint: true });
49588
- need5(opened.isFile() && sameFile2(initial, opened), "changed during open");
49637
+ const opened = fstatSync13(fd, { bigint: true });
49638
+ need6(opened.isFile() && sameFile2(initial, opened), "changed during open");
49589
49639
  const bytes = Buffer.alloc(Number(opened.size) + 1);
49590
49640
  let length = 0;
49591
49641
  while (length < bytes.length) {
49592
- const count = readSync8(fd, bytes, length, bytes.length - length, null);
49642
+ const count = readSync9(fd, bytes, length, bytes.length - length, null);
49593
49643
  if (!count)
49594
49644
  break;
49595
49645
  length += count;
49596
49646
  }
49597
- const after = fstatSync12(fd, { bigint: true }), current = lstatSync16(path, { bigint: true });
49598
- need5(current.isFile() && sameFile2(opened, after) && sameFile2(after, current) && BigInt(length) === opened.size, "changed during read");
49647
+ const after = fstatSync13(fd, { bigint: true }), current = lstatSync17(path, { bigint: true });
49648
+ need6(current.isFile() && sameFile2(opened, after) && sameFile2(after, current) && BigInt(length) === opened.size, "changed during read");
49599
49649
  for (const [ancestor, before] of ancestors2) {
49600
- const now = lstatSync16(ancestor, { bigint: true });
49601
- need5(now.isDirectory() && before.dev === now.dev && before.ino === now.ino && before.mode === now.mode, "parent changed during read");
49650
+ const now = lstatSync17(ancestor, { bigint: true });
49651
+ need6(now.isDirectory() && before.dev === now.dev && before.ino === now.ino && before.mode === now.mode, "parent changed during read");
49602
49652
  }
49603
49653
  budget.remaining -= length;
49604
49654
  try {
@@ -49607,7 +49657,7 @@ function readRegistry2(path, budget) {
49607
49657
  throw new Error("Claude marketplace registry is not strict UTF-8");
49608
49658
  }
49609
49659
  } finally {
49610
- closeSync12(fd);
49660
+ closeSync13(fd);
49611
49661
  }
49612
49662
  }
49613
49663
  function parse10(text2) {
@@ -49618,7 +49668,7 @@ function parse10(text2) {
49618
49668
  at++;
49619
49669
  };
49620
49670
  function string5() {
49621
- need5(text2[at] === '"', "contains invalid JSON");
49671
+ need6(text2[at] === '"', "contains invalid JSON");
49622
49672
  const start = at++;
49623
49673
  while (at < text2.length) {
49624
49674
  const character = text2[at++];
@@ -49629,7 +49679,7 @@ function parse10(text2) {
49629
49679
  } catch {
49630
49680
  throw new Error("Claude marketplace registry contains invalid JSON string");
49631
49681
  }
49632
- need5(value2.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.stringCharacters, "exceeds its string limit");
49682
+ need6(value2.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.stringCharacters, "exceeds its string limit");
49633
49683
  return value2;
49634
49684
  }
49635
49685
  if (character === "\\")
@@ -49638,7 +49688,7 @@ function parse10(text2) {
49638
49688
  throw new Error("Claude marketplace registry contains an unterminated JSON string");
49639
49689
  }
49640
49690
  function value(depth) {
49641
- need5(depth <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.depth && ++nodes <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.nodes, "exceeds its nesting or node limit");
49691
+ need6(depth <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.depth && ++nodes <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.nodes, "exceeds its nesting or node limit");
49642
49692
  space();
49643
49693
  const character = text2[at];
49644
49694
  if (character === '"')
@@ -49652,17 +49702,17 @@ function parse10(text2) {
49652
49702
  if (object7) {
49653
49703
  space();
49654
49704
  const key = string5();
49655
- need5(!keys.has(key), "contains a duplicate JSON key");
49705
+ need6(!keys.has(key), "contains a duplicate JSON key");
49656
49706
  keys.add(key);
49657
49707
  space();
49658
- need5(text2[at++] === ":", "contains invalid JSON");
49708
+ need6(text2[at++] === ":", "contains invalid JSON");
49659
49709
  entries.push([key, value(depth + 1)]);
49660
49710
  } else
49661
49711
  items.push(value(depth + 1));
49662
49712
  space();
49663
49713
  if (text2[at] === end)
49664
49714
  break;
49665
- need5(text2[at++] === ",", "contains invalid JSON");
49715
+ need6(text2[at++] === ",", "contains invalid JSON");
49666
49716
  }
49667
49717
  at++;
49668
49718
  return object7 ? { kind: "object", entries } : { kind: "array", items };
@@ -49674,21 +49724,21 @@ function parse10(text2) {
49674
49724
  }
49675
49725
  numberPattern.lastIndex = at;
49676
49726
  const number5 = numberPattern.exec(text2);
49677
- need5(number5, "contains invalid JSON");
49727
+ need6(number5, "contains invalid JSON");
49678
49728
  at += number5[0].length;
49679
49729
  return { kind: "number", value: number5[0] };
49680
49730
  }
49681
49731
  const root = value(0);
49682
49732
  space();
49683
- need5(at === text2.length && root.kind === "object", "requires a JSON object without trailing content");
49684
- need5(root.entries.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.rows, "exceeds its marketplace row limit");
49733
+ need6(at === text2.length && root.kind === "object", "requires a JSON object without trailing content");
49734
+ need6(root.entries.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.rows, "exceeds its marketplace row limit");
49685
49735
  return root;
49686
49736
  }
49687
49737
  function exactKeys(value, keys) {
49688
49738
  return value?.kind === "object" && value.entries.length === keys.length && value.entries.every(([key]) => keys.includes(key));
49689
49739
  }
49690
49740
  function textField(value) {
49691
- need5(value?.kind === "string" && value.value.length > 0 && !/[\x00-\x1f\x7f]/.test(value.value), "contains an invalid recognized field");
49741
+ need6(value?.kind === "string" && value.value.length > 0 && !/[\x00-\x1f\x7f]/.test(value.value), "contains an invalid recognized field");
49692
49742
  return value.value;
49693
49743
  }
49694
49744
  function normalizeRow(row, version2 = 1) {
@@ -49696,7 +49746,7 @@ function normalizeRow(row, version2 = 1) {
49696
49746
  if (version2 !== 2 || !exactKeys(row, ["source", "installLocation", "lastUpdated", "autoUpdate"]))
49697
49747
  return;
49698
49748
  const autoUpdate = field(row, "autoUpdate");
49699
- need5(autoUpdate?.kind === "literal" && (autoUpdate.value === "true" || autoUpdate.value === "false"), "contains an invalid automatic-update preference");
49749
+ need6(autoUpdate?.kind === "literal" && (autoUpdate.value === "true" || autoUpdate.value === "false"), "contains an invalid automatic-update preference");
49700
49750
  }
49701
49751
  const source = field(row, "source");
49702
49752
  if (source?.kind !== "object")
@@ -49712,23 +49762,23 @@ function normalizeRow(row, version2 = 1) {
49712
49762
  absolutePath2(sourceLocation);
49713
49763
  absolutePath2(textField(field(row, "installLocation")));
49714
49764
  const updated = textField(field(row, "lastUpdated"));
49715
- need5(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(updated), "contains an invalid recognized update timestamp");
49765
+ need6(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(updated), "contains an invalid recognized update timestamp");
49716
49766
  const millis = Date.parse(updated);
49717
- need5(Number.isFinite(millis) && new Date(millis).toISOString() === updated, "contains an invalid recognized update timestamp");
49767
+ need6(Number.isFinite(millis) && new Date(millis).toISOString() === updated, "contains an invalid recognized update timestamp");
49718
49768
  row.entries = row.entries.map(([key, value]) => [key, key === "lastUpdated" ? { kind: "validated-update-time" } : value]);
49719
49769
  }
49720
49770
  function captureClaudeMarketplaceRegistry(path, budget = { remaining: 256 * 1024 * 1024 }) {
49721
49771
  const value = parse10(readRegistry2(path, budget));
49722
49772
  for (const [, row] of value.entries)
49723
49773
  normalizeRow(row);
49724
- const sha2562 = createHash13("sha256").update("hasna.skills.claude-marketplace-registry.v1\x00").update(JSON.stringify(value)).digest("hex");
49774
+ const sha2562 = createHash14("sha256").update("hasna.skills.claude-marketplace-registry.v1\x00").update(JSON.stringify(value)).digest("hex");
49725
49775
  return { path, hashMode: "claude-marketplace-registry", sha256: sha2562 };
49726
49776
  }
49727
49777
  function captureClaudeMarketplaceRegistryV2(path, budget = { remaining: 256 * 1024 * 1024 }) {
49728
49778
  const value = parse10(readRegistry2(path, budget));
49729
49779
  for (const [, row] of value.entries)
49730
49780
  normalizeRow(row, 2);
49731
- const sha2562 = createHash13("sha256").update("hasna.skills.claude-marketplace-registry.v2\x00").update(JSON.stringify(value)).digest("hex");
49781
+ const sha2562 = createHash14("sha256").update("hasna.skills.claude-marketplace-registry.v2\x00").update(JSON.stringify(value)).digest("hex");
49732
49782
  return { path, hashMode: "claude-marketplace-registry-v2", sha256: sha2562 };
49733
49783
  }
49734
49784
  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];
@@ -49736,55 +49786,6 @@ var init_claude_marketplace_registry = __esm(() => {
49736
49786
  CLAUDE_MARKETPLACE_REGISTRY_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
49737
49787
  });
49738
49788
 
49739
- // src/lib/codex-hook-trust-files.ts
49740
- import { closeSync as closeSync13, constants as constants10, fstatSync as fstatSync13, fsyncSync as fsyncSync3, lstatSync as lstatSync17, openSync as openSync13, readSync as readSync9, writeFileSync as writeFileSync5 } from "fs";
49741
- import { createHash as createHash14 } from "crypto";
49742
- import { dirname as dirname14 } from "path";
49743
- function need6(value, code) {
49744
- if (!value)
49745
- throw new Error(`CODEX_HOOK_TRUST_${code}`);
49746
- }
49747
- function safeParents(file2) {
49748
- for (let p = dirname14(file2);; p = dirname14(p)) {
49749
- const s = lstatSync17(p);
49750
- need6(s.isDirectory() && !s.isSymbolicLink(), "UNSAFE_PARENT");
49751
- need6((s.mode & 18) === 0 || s.uid === 0 && (s.mode & 512) !== 0, "UNSAFE_PARENT");
49752
- if (dirname14(p) === p)
49753
- break;
49754
- }
49755
- }
49756
- function snapshot(file2, privateFile = false, options = {}) {
49757
- const readOnlyPackage = options.readOnlyPackage === true && !privateFile;
49758
- safeParents(file2);
49759
- const initial = lstatSync17(file2, { bigint: true });
49760
- need6(initial.isFile() && initial.uid === BigInt(process.getuid()) && (initial.nlink === 1n || readOnlyPackage && initial.nlink > 1n) && (initial.mode & 0o022n) === 0n && (!privateFile || (initial.mode & 0o777n) === 0o600n), "UNSAFE_FILE");
49761
- need6(initial.size <= 8n * 1024n * 1024n, "FILE_BOUND");
49762
- const fd = openSync13(file2, constants10.O_RDONLY | constants10.O_NOFOLLOW | constants10.O_NONBLOCK);
49763
- try {
49764
- const before = fstatSync13(fd, { bigint: true });
49765
- need6(sameStat(initial, before), "INPUT_CHANGED");
49766
- const bytes = Buffer.alloc(Number(before.size) + 1);
49767
- let length = 0;
49768
- while (length < bytes.length) {
49769
- const n2 = readSync9(fd, bytes, length, bytes.length - length, null);
49770
- if (!n2)
49771
- break;
49772
- length += n2;
49773
- }
49774
- need6(length === Number(before.size) && sameStat(before, fstatSync13(fd, { bigint: true })) && sameStat(before, lstatSync17(file2, { bigint: true })), "INPUT_CHANGED");
49775
- const content = bytes.subarray(0, length), text2 = new TextDecoder("utf-8", { fatal: true }).decode(content);
49776
- return { file: file2, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before, sha256: createHash14("sha256").update(content).digest("hex") };
49777
- } finally {
49778
- closeSync13(fd);
49779
- }
49780
- }
49781
- function unchanged2(before) {
49782
- const after = snapshot(before.file, before.privateFile, before.readOnlyPackage ? { readOnlyPackage: true } : {});
49783
- need6(sameStat(before.stat, after.stat) && after.sha256 === before.sha256, "INPUT_CHANGED");
49784
- }
49785
- var sameStat = (a, b) => ["dev", "ino", "uid", "nlink", "mode", "size", "mtimeNs", "ctimeNs"].every((key) => a[key] === b[key]);
49786
- var init_codex_hook_trust_files = () => {};
49787
-
49788
49789
  // src/lib/codex-hook-trust-layout.ts
49789
49790
  var init_codex_hook_trust_layout = () => {};
49790
49791
 
@@ -49802,7 +49803,7 @@ var init_codex_hook_additions_review = __esm(() => {
49802
49803
  import { createHash as createHash15 } from "crypto";
49803
49804
  function assertCodexHookDiscoveryRecovery(binding, witness) {
49804
49805
  const proof = proofs2.get(witness);
49805
- need6(!!proof && binding.agent === "codex" && witness.discoverySha256 === sha3(JSON.stringify(binding)), "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
49806
+ need5(!!proof && binding.agent === "codex" && witness.discoverySha256 === sha3(JSON.stringify(binding)), "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
49806
49807
  unchanged2(proof.before);
49807
49808
  unchanged2(proof.current);
49808
49809
  proof.recheckAdditions();
@@ -49811,7 +49812,7 @@ function verifiesCodexHookDiscoverySource(binding, source, currentDigest, witnes
49811
49812
  if (!witness || source.path !== witness.configPath || source.hashMode !== "bytes")
49812
49813
  return false;
49813
49814
  assertCodexHookDiscoveryRecovery(binding, witness);
49814
- need6(source.sha256 === witness.beforeSha256 && currentDigest === witness.currentSha256, "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
49815
+ need5(source.sha256 === witness.beforeSha256 && currentDigest === witness.currentSha256, "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
49815
49816
  return true;
49816
49817
  }
49817
49818
  var sha3 = (text2) => createHash15("sha256").update(text2).digest("hex"), fields, proofs2;
package/bin/migrate.js CHANGED
@@ -7,7 +7,7 @@ import { join as join5 } from "path";
7
7
  // package.json
8
8
  var package_default = {
9
9
  name: "@hasna/skills",
10
- version: "0.10.34",
10
+ version: "0.10.35",
11
11
  description: "Skills library for AI coding agents",
12
12
  type: "module",
13
13
  bin: {
package/bin/server.js CHANGED
@@ -24122,7 +24122,7 @@ var init_dist_es9 = __esm(() => {
24122
24122
  // package.json
24123
24123
  var package_default = {
24124
24124
  name: "@hasna/skills",
24125
- version: "0.10.34",
24125
+ version: "0.10.35",
24126
24126
  description: "Skills library for AI coding agents",
24127
24127
  type: "module",
24128
24128
  bin: {
package/bin/worker.js CHANGED
@@ -24125,7 +24125,7 @@ import { randomUUID as randomUUID6 } from "crypto";
24125
24125
  // package.json
24126
24126
  var package_default = {
24127
24127
  name: "@hasna/skills",
24128
- version: "0.10.34",
24128
+ version: "0.10.35",
24129
24129
  description: "Skills library for AI coding agents",
24130
24130
  type: "module",
24131
24131
  bin: {
package/dist/index.d.ts CHANGED
@@ -60,7 +60,8 @@ export type { SkillSelection, SkillProfile, ResolvedSkillSelection, ResolvedSkil
60
60
  export { buildSkillContext } from "./lib/skill-context.js";
61
61
  export { syncSelectionProfile } from "./lib/selection-resolver.js";
62
62
  export { inspectSkillSession, reconcileSkillSession, type SessionReconciliationInput, type SessionReconciliationOptions } from "./lib/session-reconciliation.js";
63
- export { planAgentIntegration, planClaudeStopHookUpdate, planClaudePreToolUseHookUpdate, planClaudeHookEventsUpdate, planAgentSettingsWitnessUpgrade, applyAgentIntegration, inventoryNativeSkills, archiveNativeSkills } from "./lib/agent-integration.js";
63
+ export { planAgentIntegration, planClaudeStopHookUpdate, planClaudePreToolUseHookUpdate, planClaudeHookEventsUpdate, planClaudeManagedHookProjection, planAgentSettingsWitnessUpgrade, applyAgentIntegration, inventoryNativeSkills, archiveNativeSkills } from "./lib/agent-integration.js";
64
+ export type { ClaudeManagedHookProjection, ClaudeManagedHookProjectionOptions } from "./lib/agent-integration.js";
64
65
  export { captureDiscoveryDirectories, captureDiscoveryByteSources, captureDiscoveryPathSources, type DiscoveryDirectory, type DiscoverySource } from "./lib/agent-discovery.js";
65
66
  export { captureClaudeMarketplaceRegistry, captureClaudeMarketplaceRegistryV2 } from "./lib/claude-marketplace-registry.js";
66
67
  export { captureClaudeSettings, captureClaudeSettingsV2, captureClaudeSettingsV3, upgradeClaudeSettingsWitness } from "./lib/claude-settings-witness.js";