@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/index.js +543 -333
- package/bin/mcp.js +124 -123
- package/bin/migrate.js +1 -1
- package/bin/server.js +1 -1
- package/bin/worker.js +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +398 -214
- package/dist/lib/agent-integration.d.ts +27 -0
- package/dist/sdk/index.js +189 -6
- package/package.json +1 -1
package/bin/mcp.js
CHANGED
|
@@ -20019,7 +20019,7 @@ var package_default;
|
|
|
20019
20019
|
var init_package = __esm(() => {
|
|
20020
20020
|
package_default = {
|
|
20021
20021
|
name: "@hasna/skills",
|
|
20022
|
-
version: "0.10.
|
|
20022
|
+
version: "0.10.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
|
|
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
|
-
|
|
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
|
|
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) =>
|
|
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
|
|
48959
|
-
import { dirname as
|
|
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
|
|
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 =
|
|
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 =
|
|
49032
|
-
const opened =
|
|
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 =
|
|
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(
|
|
49043
|
-
same3(opened,
|
|
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
|
-
|
|
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 =
|
|
49177
|
-
WRITE_FLAGS =
|
|
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
|
|
49411
|
-
import { basename as basename6, dirname as
|
|
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 =
|
|
49427
|
-
pluginNeed(!
|
|
49428
|
-
if (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 =
|
|
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 =
|
|
49486
|
+
const fd = openSync12(path, constants9.O_RDONLY | constants9.O_NOFOLLOW | constants9.O_NONBLOCK);
|
|
49437
49487
|
try {
|
|
49438
|
-
const opened =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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(
|
|
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 =
|
|
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 =
|
|
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 ===
|
|
49549
|
-
return pluginHash(JSON.stringify(
|
|
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
|
|
49559
|
-
import { closeSync as
|
|
49560
|
-
import { basename as basename7, dirname as
|
|
49561
|
-
function
|
|
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
|
-
|
|
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 =
|
|
49571
|
-
const stat2 =
|
|
49572
|
-
|
|
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 ===
|
|
49624
|
+
if (at === dirname14(at))
|
|
49575
49625
|
return result;
|
|
49576
49626
|
}
|
|
49577
49627
|
}
|
|
49578
49628
|
function readRegistry2(path, budget) {
|
|
49579
49629
|
absolutePath2(path);
|
|
49580
|
-
|
|
49581
|
-
|
|
49582
|
-
const ancestors2 = parents2(path), initial =
|
|
49583
|
-
|
|
49584
|
-
|
|
49585
|
-
const fd =
|
|
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 =
|
|
49588
|
-
|
|
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 =
|
|
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 =
|
|
49598
|
-
|
|
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 =
|
|
49601
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
49705
|
+
need6(!keys.has(key), "contains a duplicate JSON key");
|
|
49656
49706
|
keys.add(key);
|
|
49657
49707
|
space();
|
|
49658
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
49684
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
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.
|
|
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.
|
|
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";
|