@hasna/skills 0.10.23 → 0.10.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -2
- package/bin/index.js +128 -19
- package/bin/mcp.js +1 -1
- package/bin/migrate.js +1 -1
- package/bin/server.js +1 -1
- package/bin/worker.js +1 -1
- package/dist/index.js +123 -16
- package/dist/sdk/index.js +123 -16
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -431,6 +431,12 @@ directory within your home, add `--allow-root-aliases` to hook installation and
|
|
|
431
431
|
native migration. The plan records and rechecks the exact link and target;
|
|
432
432
|
links inside skill contents or configuration files remain refused.
|
|
433
433
|
|
|
434
|
+
On macOS, the OS-owned `/var`, `/tmp` and `/etc` aliases into `/private` are
|
|
435
|
+
accepted only while their exact targets and protected parent directories verify.
|
|
436
|
+
The protection check refuses extended ACLs and unavailable native ACL inspection.
|
|
437
|
+
Inventory reports canonical paths and deduplicates their alias spellings. This
|
|
438
|
+
does not permit other root-owned links or user-controlled ancestor links.
|
|
439
|
+
|
|
434
440
|
Cooperating installers can use the root package's
|
|
435
441
|
`planClaudeStopHookUpdate({ expectedSettingsSha256, replacement })`, then
|
|
436
442
|
`applyAgentIntegration(plan)`, to write an explicitly authorized Claude settings
|
|
@@ -519,8 +525,12 @@ Only manifest version metadata may vary. Reviewed app declarations use the impli
|
|
|
519
525
|
`id`, optional `category`, and optional boolean `required`. The entire canonical app
|
|
520
526
|
file and its presence stay bound; it preserves existing connector availability and
|
|
521
527
|
native capability hints. Changed or unknown app fields, custom references, native
|
|
522
|
-
hooks, commands and MCP controls refuse.
|
|
523
|
-
|
|
528
|
+
hooks, commands and unsupported MCP controls refuse. Referenced own-root
|
|
529
|
+
`./.mcp.json` declarations may preserve local stdio servers with Codex's typed
|
|
530
|
+
tool, approval, timeout and environment metadata. Their complete fingerprints
|
|
531
|
+
and presence remain bound; review never executes commands or resolves environment
|
|
532
|
+
values. Name controls suppress Skills, not every plugin capability.
|
|
533
|
+
No prompt hook starts an app server to obtain this receipt:
|
|
524
534
|
native startup can maintain caches. The explicit capture starts and closes only its
|
|
525
535
|
own bounded native client; it does not reload an existing agent session.
|
|
526
536
|
Neither a receipt nor a config write proves an existing session adopted new rules;
|
package/bin/index.js
CHANGED
|
@@ -36868,7 +36868,7 @@ var package_default;
|
|
|
36868
36868
|
var init_package = __esm(() => {
|
|
36869
36869
|
package_default = {
|
|
36870
36870
|
name: "@hasna/skills",
|
|
36871
|
-
version: "0.10.
|
|
36871
|
+
version: "0.10.24",
|
|
36872
36872
|
description: "Skills library for AI coding agents",
|
|
36873
36873
|
type: "module",
|
|
36874
36874
|
bin: {
|
|
@@ -51240,27 +51240,62 @@ function mcpControls(path, read2) {
|
|
|
51240
51240
|
const object5 = (v) => Boolean(v && typeof v === "object" && !Array.isArray(v));
|
|
51241
51241
|
const textField = (v, empty = false) => typeof v === "string" && (empty || Boolean(v.trim())) && Buffer.byteLength(v) <= 16384 && !/[\x00-\x1f\x7f]/.test(v);
|
|
51242
51242
|
const envName = (v) => typeof v === "string" && /^[A-Za-z_][A-Za-z0-9_]{0,255}$/.test(v);
|
|
51243
|
+
const optional = (v, valid) => v === undefined || v === null || valid(v);
|
|
51244
|
+
const stringList = (v) => Array.isArray(v) && v.length <= 256 && v.every((item) => textField(item));
|
|
51245
|
+
const approval = (v) => ["auto", "prompt", "writes", "approve"].includes(v);
|
|
51246
|
+
const duration = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0;
|
|
51247
|
+
const positiveInteger = (v) => Number.isSafeInteger(v) && v > 0;
|
|
51248
|
+
const fields = [
|
|
51249
|
+
"command",
|
|
51250
|
+
"args",
|
|
51251
|
+
"cwd",
|
|
51252
|
+
"env",
|
|
51253
|
+
"env_vars",
|
|
51254
|
+
"enabled",
|
|
51255
|
+
"required",
|
|
51256
|
+
"environment_id",
|
|
51257
|
+
"startup_readiness",
|
|
51258
|
+
"supports_parallel_tool_calls",
|
|
51259
|
+
"tool_input_schema_max_bytes",
|
|
51260
|
+
"startup_timeout_sec",
|
|
51261
|
+
"startup_timeout_ms",
|
|
51262
|
+
"tool_timeout_sec",
|
|
51263
|
+
"default_tools_approval_mode",
|
|
51264
|
+
"enabled_tools",
|
|
51265
|
+
"disabled_tools",
|
|
51266
|
+
"omit_tools_from",
|
|
51267
|
+
"tools",
|
|
51268
|
+
"name"
|
|
51269
|
+
];
|
|
51243
51270
|
if (!object5(value) || Object.keys(value).length !== 1 || !object5(value.mcpServers))
|
|
51244
51271
|
refuse2();
|
|
51245
51272
|
const servers = Object.entries(value.mcpServers);
|
|
51246
51273
|
if (!servers.length || servers.length > 256)
|
|
51247
51274
|
refuse2();
|
|
51248
51275
|
for (const [name, server] of servers) {
|
|
51249
|
-
if (!identifier2(name) || !object5(server) || !Object.keys(server).every((key) =>
|
|
51276
|
+
if (!identifier2(name) || !object5(server) || !Object.keys(server).every((key) => fields.includes(key)) || !textField(server.command) || !optional(server.args, (v) => Array.isArray(v) && v.length <= 256 && v.every((arg) => textField(arg, true))) || !optional(server.cwd, textField) || !optional(server.env, (v) => object5(v) && Object.keys(v).length <= 256 && Object.entries(v).every(([key, value2]) => envName(key) && textField(value2, true))) || !["enabled", "required", "supports_parallel_tool_calls"].every((key) => optional(server[key], (v) => typeof v === "boolean")) || !optional(server.environment_id, (v) => v === "local") || !optional(server.startup_readiness, (v) => ["connection", "catalog"].includes(v)) || !optional(server.tool_input_schema_max_bytes, positiveInteger) || !["startup_timeout_sec", "tool_timeout_sec"].every((key) => optional(server[key], duration)) || !optional(server.startup_timeout_ms, (v) => Number.isSafeInteger(v) && v >= 0) || !optional(server.default_tools_approval_mode, approval) || !["enabled_tools", "disabled_tools"].every((key) => optional(server[key], stringList)) || !optional(server.omit_tools_from, (v) => Array.isArray(v) && v.length <= 256 && v.every((item) => ["code_mode", "deferred", "direct"].includes(item))) || !optional(server.name, textField))
|
|
51250
51277
|
refuse2();
|
|
51251
|
-
if (server.env_vars !== undefined) {
|
|
51278
|
+
if (server.env_vars !== undefined && server.env_vars !== null) {
|
|
51252
51279
|
if (!Array.isArray(server.env_vars) || server.env_vars.length > 256)
|
|
51253
51280
|
refuse2();
|
|
51254
51281
|
const names = server.env_vars.map((entry) => {
|
|
51255
51282
|
if (envName(entry))
|
|
51256
51283
|
return entry;
|
|
51257
|
-
if (!object5(entry) || !Object.keys(entry).every((key) => ["name", "source"].includes(key)) || !envName(entry.name) || entry.source
|
|
51284
|
+
if (!object5(entry) || !Object.keys(entry).every((key) => ["name", "source"].includes(key)) || !envName(entry.name) || !optional(entry.source, (v) => v === "local"))
|
|
51258
51285
|
refuse2();
|
|
51259
51286
|
return entry.name;
|
|
51260
51287
|
});
|
|
51261
51288
|
if (new Set(names).size !== names.length)
|
|
51262
51289
|
refuse2();
|
|
51263
51290
|
}
|
|
51291
|
+
if (server.tools !== undefined && server.tools !== null) {
|
|
51292
|
+
if (!object5(server.tools) || Object.keys(server.tools).length > 256)
|
|
51293
|
+
refuse2();
|
|
51294
|
+
for (const [tool, config] of Object.entries(server.tools)) {
|
|
51295
|
+
if (!textField(tool) || !object5(config) || !Object.keys(config).every((key) => ["approval_mode", "output_token_limit"].includes(key)) || !optional(config.approval_mode, approval) || !optional(config.output_token_limit, positiveInteger))
|
|
51296
|
+
refuse2();
|
|
51297
|
+
}
|
|
51298
|
+
}
|
|
51264
51299
|
}
|
|
51265
51300
|
return sha2562;
|
|
51266
51301
|
}
|
|
@@ -52121,10 +52156,75 @@ import { isDeepStrictEqual as isDeepStrictEqual4 } from "util";
|
|
|
52121
52156
|
import { existsSync as existsSync12, lstatSync as lstatSync15, statSync as statSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync13, readdirSync as readdirSync8, opendirSync as opendirSync3, readlinkSync as readlinkSync4, realpathSync as realpathSync6, renameSync as renameSync2, rmdirSync as rmdirSync2, writeFileSync as writeFileSync4, unlinkSync as unlinkSync3, chmodSync, openSync as openSync8, closeSync as closeSync8, fsyncSync as fsyncSync2, fstatSync as fstatSync8, readSync as readSync6, constants as constants8, linkSync } from "fs";
|
|
52122
52157
|
import { dirname as dirname11, join as join21, resolve as resolve11, relative as relative5, isAbsolute as isAbsolute11, sep as sep5 } from "path";
|
|
52123
52158
|
import { homedir as homedir3 } from "os";
|
|
52159
|
+
function hasNoDarwinAcl(fd) {
|
|
52160
|
+
try {
|
|
52161
|
+
const { dlopen, read: read2 } = __require("bun:ffi");
|
|
52162
|
+
const library = dlopen("/usr/lib/libSystem.B.dylib", {
|
|
52163
|
+
acl_get_fd: { args: ["i32"], returns: "ptr" },
|
|
52164
|
+
acl_free: { args: ["ptr"], returns: "i32" },
|
|
52165
|
+
__error: { args: [], returns: "ptr" }
|
|
52166
|
+
});
|
|
52167
|
+
try {
|
|
52168
|
+
const errno = library.symbols.__error();
|
|
52169
|
+
if (!errno)
|
|
52170
|
+
return false;
|
|
52171
|
+
const acl = library.symbols.acl_get_fd(fd);
|
|
52172
|
+
if (acl) {
|
|
52173
|
+
library.symbols.acl_free(acl);
|
|
52174
|
+
return false;
|
|
52175
|
+
}
|
|
52176
|
+
return (acl === null || acl === 0) && read2.i32(errno) === 2;
|
|
52177
|
+
} finally {
|
|
52178
|
+
library.close();
|
|
52179
|
+
}
|
|
52180
|
+
} catch {
|
|
52181
|
+
return false;
|
|
52182
|
+
}
|
|
52183
|
+
}
|
|
52184
|
+
function isSystemRootAlias(path) {
|
|
52185
|
+
if (process.platform !== "darwin" || !["/var", "/tmp", "/etc"].includes(path))
|
|
52186
|
+
return false;
|
|
52187
|
+
const target = `/private${path}`, link2 = `private${path}`;
|
|
52188
|
+
const identity5 = (stat) => `${stat.dev}:${stat.ino}:${stat.ctimeNs}:${stat.uid}:${stat.mode}`;
|
|
52189
|
+
try {
|
|
52190
|
+
const before2 = lstatSync15(path, { bigint: true });
|
|
52191
|
+
if (!before2.isSymbolicLink() || before2.uid !== 0n || readlinkSync4(path) !== link2)
|
|
52192
|
+
return false;
|
|
52193
|
+
const directories = ["/", "/private", target].map((directory) => {
|
|
52194
|
+
const stat = lstatSync15(directory, { bigint: true });
|
|
52195
|
+
if (!stat.isDirectory() || stat.uid !== 0n)
|
|
52196
|
+
throw new Error("Untrusted system alias directory");
|
|
52197
|
+
if (directory !== "/private/tmp") {
|
|
52198
|
+
if ((stat.mode & 0o022n) !== 0n)
|
|
52199
|
+
throw new Error("Writable system alias directory");
|
|
52200
|
+
} else if ((stat.mode & 0o1000n) === 0n)
|
|
52201
|
+
throw new Error("Unprotected system temporary directory");
|
|
52202
|
+
const fd = openSync8(directory, constants8.O_RDONLY | constants8.O_DIRECTORY | constants8.O_NOFOLLOW);
|
|
52203
|
+
try {
|
|
52204
|
+
if (identity5(fstatSync8(fd, { bigint: true })) !== identity5(stat) || !hasNoDarwinAcl(fd) || identity5(fstatSync8(fd, { bigint: true })) !== identity5(stat))
|
|
52205
|
+
throw new Error("Unverified system alias directory ACL");
|
|
52206
|
+
} finally {
|
|
52207
|
+
closeSync8(fd);
|
|
52208
|
+
}
|
|
52209
|
+
return { directory, identity: identity5(stat) };
|
|
52210
|
+
});
|
|
52211
|
+
return realpathSync6(path) === target && readlinkSync4(path) === link2 && identity5(lstatSync15(path, { bigint: true })) === identity5(before2) && directories.every((item) => identity5(lstatSync15(item.directory, { bigint: true })) === item.identity);
|
|
52212
|
+
} catch {
|
|
52213
|
+
return false;
|
|
52214
|
+
}
|
|
52215
|
+
}
|
|
52216
|
+
function canonicalSystemPath(path) {
|
|
52217
|
+
const absolute = resolve11(path), root = `/${absolute.split(sep5)[1]}`;
|
|
52218
|
+
if (process.platform !== "darwin" || !["/var", "/tmp", "/etc"].includes(root) || !lstatSync15(root, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
52219
|
+
return absolute;
|
|
52220
|
+
if (!isSystemRootAlias(root))
|
|
52221
|
+
throw new Error(`Refusing symlink path: ${root}`);
|
|
52222
|
+
return `/private${absolute}`;
|
|
52223
|
+
}
|
|
52124
52224
|
function assertSafePath(path) {
|
|
52125
52225
|
let cursor = resolve11(path);
|
|
52126
52226
|
while (true) {
|
|
52127
|
-
if (lstatSync15(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
52227
|
+
if (lstatSync15(cursor, { throwIfNoEntry: false })?.isSymbolicLink() && !isSystemRootAlias(cursor))
|
|
52128
52228
|
throw new Error(`Refusing symlink path: ${cursor}`);
|
|
52129
52229
|
const parent = dirname11(cursor);
|
|
52130
52230
|
if (parent === cursor)
|
|
@@ -52160,7 +52260,7 @@ function rootAliases(home, allowed = false) {
|
|
|
52160
52260
|
return result2;
|
|
52161
52261
|
}
|
|
52162
52262
|
function canonicalAgentPath(path, aliases) {
|
|
52163
|
-
const absolute =
|
|
52263
|
+
const absolute = canonicalSystemPath(path), binding = aliases.find((item) => absolute === item.alias || absolute.startsWith(item.alias + sep5));
|
|
52164
52264
|
return binding ? join21(binding.target, relative5(binding.alias, absolute)) : absolute;
|
|
52165
52265
|
}
|
|
52166
52266
|
function disabledCodexSkillPaths(config, aliases) {
|
|
@@ -52277,8 +52377,10 @@ function parseNativeMigrationTargetManifest(input) {
|
|
|
52277
52377
|
throw new Error("Invalid native migration target fields");
|
|
52278
52378
|
if (!ROOTS.some(([agent]) => agent === item.agent))
|
|
52279
52379
|
throw new Error(`Unsupported native migration target agent: ${item.agent}`);
|
|
52280
|
-
|
|
52281
|
-
|
|
52380
|
+
if (!isAbsolute11(item.projectRoot) || resolve11(item.projectRoot) !== item.projectRoot)
|
|
52381
|
+
throw new Error(`Native migration target project root must be an existing absolute directory: ${item.projectRoot}`);
|
|
52382
|
+
const projectRoot = canonicalSystemPath(item.projectRoot);
|
|
52383
|
+
if (!existsSync12(projectRoot) || !lstatSync15(projectRoot).isDirectory())
|
|
52282
52384
|
throw new Error(`Native migration target project root must be an existing absolute directory: ${item.projectRoot}`);
|
|
52283
52385
|
assertSafePath(projectRoot);
|
|
52284
52386
|
if (isAbsolute11(item.path) || item.path.includes("\\") || item.path.length === 0 || item.path.includes("\x00"))
|
|
@@ -52288,7 +52390,7 @@ function parseNativeMigrationTargetManifest(input) {
|
|
|
52288
52390
|
throw new Error(`Native migration target path escapes or is not normalized: ${item.path}`);
|
|
52289
52391
|
if (!/^[0-9a-f]{64}$/.test(item.treeSha256))
|
|
52290
52392
|
throw new Error(`Invalid native migration tree digest for ${item.path}`);
|
|
52291
|
-
const identity5 = `${item.agent}\x00${projectRoot}\x00${normalized}`;
|
|
52393
|
+
const identity5 = `${item.agent}\x00${canonicalSystemPath(projectRoot)}\x00${normalized}`;
|
|
52292
52394
|
if (identities.has(identity5))
|
|
52293
52395
|
throw new Error(`Duplicate native migration target: ${item.path}`);
|
|
52294
52396
|
identities.add(identity5);
|
|
@@ -52305,17 +52407,19 @@ function selectNativeMigrationTargets(inventory, manifest) {
|
|
|
52305
52407
|
const identities = new Set;
|
|
52306
52408
|
const selected = [];
|
|
52307
52409
|
for (const target of manifest.targets) {
|
|
52308
|
-
|
|
52309
|
-
|
|
52410
|
+
if (!isAbsolute11(target.projectRoot) || resolve11(target.projectRoot) !== target.projectRoot)
|
|
52411
|
+
throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
|
|
52412
|
+
const projectRoot = canonicalSystemPath(target.projectRoot), normalized = relative5(projectRoot, resolve11(projectRoot, target.path));
|
|
52413
|
+
if (!existsSync12(projectRoot) || !lstatSync15(projectRoot).isDirectory())
|
|
52310
52414
|
throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
|
|
52311
52415
|
assertSafePath(projectRoot);
|
|
52312
52416
|
if (isAbsolute11(target.path) || target.path.includes("\\") || target.path.includes("\x00") || !normalized || normalized === ".." || normalized.startsWith(`..${sep5}`) || normalized !== target.path || !/^[0-9a-f]{64}$/.test(target.treeSha256))
|
|
52313
52417
|
throw new Error(`Invalid native migration target: ${target.path}`);
|
|
52314
|
-
const identity5 = `${target.agent}\x00${projectRoot}\x00${normalized}`;
|
|
52418
|
+
const identity5 = `${target.agent}\x00${canonicalSystemPath(projectRoot)}\x00${normalized}`;
|
|
52315
52419
|
if (identities.has(identity5))
|
|
52316
52420
|
throw new Error(`Duplicate native migration target: ${target.path}`);
|
|
52317
52421
|
identities.add(identity5);
|
|
52318
|
-
const expected = resolve11(target.projectRoot, target.path);
|
|
52422
|
+
const expected = canonicalSystemPath(resolve11(target.projectRoot, target.path));
|
|
52319
52423
|
const matches2 = inventory.filter((entry2) => entry2.agent === target.agent && resolve11(entry2.path) === expected);
|
|
52320
52424
|
if (matches2.length !== 1)
|
|
52321
52425
|
throw new Error(`Native migration target was not found exactly once: ${target.agent} ${target.projectRoot}/${target.path}`);
|
|
@@ -52331,7 +52435,7 @@ function selectNativeMigrationTargets(inventory, manifest) {
|
|
|
52331
52435
|
function projectAncestorDirectories(projects) {
|
|
52332
52436
|
const directories = new Set;
|
|
52333
52437
|
for (const project of projects) {
|
|
52334
|
-
for (let path =
|
|
52438
|
+
for (let path = canonicalSystemPath(project), depth = 0;; depth++) {
|
|
52335
52439
|
if (depth >= 100)
|
|
52336
52440
|
throw new Error("NATIVE_SKILL_DRIFT: project ancestor discovery limit exceeded");
|
|
52337
52441
|
directories.add(path);
|
|
@@ -52344,11 +52448,13 @@ function projectAncestorDirectories(projects) {
|
|
|
52344
52448
|
return [...directories];
|
|
52345
52449
|
}
|
|
52346
52450
|
function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
52451
|
+
home = canonicalSystemPath(home);
|
|
52347
52452
|
if (options.reviewedCacheAlias !== undefined && (!options.includeVendor || !isAbsolute11(options.reviewedCacheAlias) || resolve11(options.reviewedCacheAlias) !== options.reviewedCacheAlias))
|
|
52348
52453
|
throw new Error("A reviewed cache alias requires vendor inventory and an exact absolute path");
|
|
52349
52454
|
if (options.disabledVendorPaths?.some((path) => !isAbsolute11(path) || resolve11(path) !== path))
|
|
52350
52455
|
throw new Error("Disabled vendor paths must be exact absolute paths");
|
|
52351
|
-
const
|
|
52456
|
+
const reviewedCacheAlias = options.reviewedCacheAlias === undefined ? undefined : canonicalSystemPath(options.reviewedCacheAlias);
|
|
52457
|
+
const disabledVendorPaths = new Set((options.disabledVendorPaths ?? []).map(canonicalSystemPath));
|
|
52352
52458
|
const aliases = rootAliases(home, options.allowRootAliases);
|
|
52353
52459
|
const selectedAgents = options.agents ? new Set(options.agents) : undefined;
|
|
52354
52460
|
const includesAgent = (agent) => !selectedAgents || selectedAgents.has(agent);
|
|
@@ -52371,8 +52477,11 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
52371
52477
|
}
|
|
52372
52478
|
let reviewedCacheAliasFound = false;
|
|
52373
52479
|
function verifiedSiblingCacheAlias(agent, path, parent) {
|
|
52374
|
-
const link2 = readlinkSync4(path),
|
|
52375
|
-
if (
|
|
52480
|
+
const link2 = readlinkSync4(path), lexicalTarget = resolve11(parent, link2);
|
|
52481
|
+
if (isAbsolute11(link2) ? link2 !== lexicalTarget : dirname11(link2) !== ".")
|
|
52482
|
+
return false;
|
|
52483
|
+
const target = canonicalSystemPath(lexicalTarget);
|
|
52484
|
+
if (dirname11(target) !== parent)
|
|
52376
52485
|
return false;
|
|
52377
52486
|
if (!lstatSync15(target, { throwIfNoEntry: false })?.isDirectory())
|
|
52378
52487
|
return false;
|
|
@@ -52381,11 +52490,11 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
52381
52490
|
return false;
|
|
52382
52491
|
if (scan.hasSkills) {
|
|
52383
52492
|
const targetSkills = entries.filter((entry) => entry.agent === agent && entry.vendor && (entry.path === target || entry.path.startsWith(target + sep5)));
|
|
52384
|
-
if (path ===
|
|
52493
|
+
if (path === reviewedCacheAlias && targetSkills.length > 0)
|
|
52385
52494
|
reviewedCacheAliasFound = true;
|
|
52386
52495
|
if (agent === "codex" && targetSkills.length > 0 && targetSkills.every((entry) => disabledVendorPaths.has(entry.path) || options.disabledVendorSkill?.(entry) === true))
|
|
52387
52496
|
return true;
|
|
52388
|
-
if (path !==
|
|
52497
|
+
if (path !== reviewedCacheAlias)
|
|
52389
52498
|
return false;
|
|
52390
52499
|
}
|
|
52391
52500
|
return true;
|
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.24",
|
|
20023
20023
|
description: "Skills library for AI coding agents",
|
|
20024
20024
|
type: "module",
|
|
20025
20025
|
bin: {
|
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.24",
|
|
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.24",
|
|
24129
24129
|
description: "Skills library for AI coding agents",
|
|
24130
24130
|
type: "module",
|
|
24131
24131
|
bin: {
|
package/dist/index.js
CHANGED
|
@@ -10881,7 +10881,7 @@ function replaceSkillSession(expected, replacement, plan, options = {}, beforeCo
|
|
|
10881
10881
|
// package.json
|
|
10882
10882
|
var package_default = {
|
|
10883
10883
|
name: "@hasna/skills",
|
|
10884
|
-
version: "0.10.
|
|
10884
|
+
version: "0.10.24",
|
|
10885
10885
|
description: "Skills library for AI coding agents",
|
|
10886
10886
|
type: "module",
|
|
10887
10887
|
bin: {
|
|
@@ -13381,27 +13381,62 @@ function mcpControls(path, read2) {
|
|
|
13381
13381
|
const object5 = (v) => Boolean(v && typeof v === "object" && !Array.isArray(v));
|
|
13382
13382
|
const textField = (v, empty = false) => typeof v === "string" && (empty || Boolean(v.trim())) && Buffer.byteLength(v) <= 16384 && !/[\x00-\x1f\x7f]/.test(v);
|
|
13383
13383
|
const envName = (v) => typeof v === "string" && /^[A-Za-z_][A-Za-z0-9_]{0,255}$/.test(v);
|
|
13384
|
+
const optional = (v, valid) => v === undefined || v === null || valid(v);
|
|
13385
|
+
const stringList = (v) => Array.isArray(v) && v.length <= 256 && v.every((item) => textField(item));
|
|
13386
|
+
const approval = (v) => ["auto", "prompt", "writes", "approve"].includes(v);
|
|
13387
|
+
const duration = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0;
|
|
13388
|
+
const positiveInteger = (v) => Number.isSafeInteger(v) && v > 0;
|
|
13389
|
+
const fields = [
|
|
13390
|
+
"command",
|
|
13391
|
+
"args",
|
|
13392
|
+
"cwd",
|
|
13393
|
+
"env",
|
|
13394
|
+
"env_vars",
|
|
13395
|
+
"enabled",
|
|
13396
|
+
"required",
|
|
13397
|
+
"environment_id",
|
|
13398
|
+
"startup_readiness",
|
|
13399
|
+
"supports_parallel_tool_calls",
|
|
13400
|
+
"tool_input_schema_max_bytes",
|
|
13401
|
+
"startup_timeout_sec",
|
|
13402
|
+
"startup_timeout_ms",
|
|
13403
|
+
"tool_timeout_sec",
|
|
13404
|
+
"default_tools_approval_mode",
|
|
13405
|
+
"enabled_tools",
|
|
13406
|
+
"disabled_tools",
|
|
13407
|
+
"omit_tools_from",
|
|
13408
|
+
"tools",
|
|
13409
|
+
"name"
|
|
13410
|
+
];
|
|
13384
13411
|
if (!object5(value) || Object.keys(value).length !== 1 || !object5(value.mcpServers))
|
|
13385
13412
|
refuse2();
|
|
13386
13413
|
const servers = Object.entries(value.mcpServers);
|
|
13387
13414
|
if (!servers.length || servers.length > 256)
|
|
13388
13415
|
refuse2();
|
|
13389
13416
|
for (const [name, server] of servers) {
|
|
13390
|
-
if (!identifier2(name) || !object5(server) || !Object.keys(server).every((key) =>
|
|
13417
|
+
if (!identifier2(name) || !object5(server) || !Object.keys(server).every((key) => fields.includes(key)) || !textField(server.command) || !optional(server.args, (v) => Array.isArray(v) && v.length <= 256 && v.every((arg) => textField(arg, true))) || !optional(server.cwd, textField) || !optional(server.env, (v) => object5(v) && Object.keys(v).length <= 256 && Object.entries(v).every(([key, value2]) => envName(key) && textField(value2, true))) || !["enabled", "required", "supports_parallel_tool_calls"].every((key) => optional(server[key], (v) => typeof v === "boolean")) || !optional(server.environment_id, (v) => v === "local") || !optional(server.startup_readiness, (v) => ["connection", "catalog"].includes(v)) || !optional(server.tool_input_schema_max_bytes, positiveInteger) || !["startup_timeout_sec", "tool_timeout_sec"].every((key) => optional(server[key], duration)) || !optional(server.startup_timeout_ms, (v) => Number.isSafeInteger(v) && v >= 0) || !optional(server.default_tools_approval_mode, approval) || !["enabled_tools", "disabled_tools"].every((key) => optional(server[key], stringList)) || !optional(server.omit_tools_from, (v) => Array.isArray(v) && v.length <= 256 && v.every((item) => ["code_mode", "deferred", "direct"].includes(item))) || !optional(server.name, textField))
|
|
13391
13418
|
refuse2();
|
|
13392
|
-
if (server.env_vars !== undefined) {
|
|
13419
|
+
if (server.env_vars !== undefined && server.env_vars !== null) {
|
|
13393
13420
|
if (!Array.isArray(server.env_vars) || server.env_vars.length > 256)
|
|
13394
13421
|
refuse2();
|
|
13395
13422
|
const names = server.env_vars.map((entry) => {
|
|
13396
13423
|
if (envName(entry))
|
|
13397
13424
|
return entry;
|
|
13398
|
-
if (!object5(entry) || !Object.keys(entry).every((key) => ["name", "source"].includes(key)) || !envName(entry.name) || entry.source
|
|
13425
|
+
if (!object5(entry) || !Object.keys(entry).every((key) => ["name", "source"].includes(key)) || !envName(entry.name) || !optional(entry.source, (v) => v === "local"))
|
|
13399
13426
|
refuse2();
|
|
13400
13427
|
return entry.name;
|
|
13401
13428
|
});
|
|
13402
13429
|
if (new Set(names).size !== names.length)
|
|
13403
13430
|
refuse2();
|
|
13404
13431
|
}
|
|
13432
|
+
if (server.tools !== undefined && server.tools !== null) {
|
|
13433
|
+
if (!object5(server.tools) || Object.keys(server.tools).length > 256)
|
|
13434
|
+
refuse2();
|
|
13435
|
+
for (const [tool, config] of Object.entries(server.tools)) {
|
|
13436
|
+
if (!textField(tool) || !object5(config) || !Object.keys(config).every((key) => ["approval_mode", "output_token_limit"].includes(key)) || !optional(config.approval_mode, approval) || !optional(config.output_token_limit, positiveInteger))
|
|
13437
|
+
refuse2();
|
|
13438
|
+
}
|
|
13439
|
+
}
|
|
13405
13440
|
}
|
|
13406
13441
|
return sha2562;
|
|
13407
13442
|
}
|
|
@@ -14245,10 +14280,75 @@ function disableCodexBundledSkills(text2) {
|
|
|
14245
14280
|
// src/lib/agent-integration.ts
|
|
14246
14281
|
var sha3 = (data) => createHash12("sha256").update(data).digest("hex");
|
|
14247
14282
|
var ROOTS = NATIVE_SKILL_ROOTS;
|
|
14283
|
+
function hasNoDarwinAcl(fd) {
|
|
14284
|
+
try {
|
|
14285
|
+
const { dlopen, read: read2 } = __require("bun:ffi");
|
|
14286
|
+
const library = dlopen("/usr/lib/libSystem.B.dylib", {
|
|
14287
|
+
acl_get_fd: { args: ["i32"], returns: "ptr" },
|
|
14288
|
+
acl_free: { args: ["ptr"], returns: "i32" },
|
|
14289
|
+
__error: { args: [], returns: "ptr" }
|
|
14290
|
+
});
|
|
14291
|
+
try {
|
|
14292
|
+
const errno = library.symbols.__error();
|
|
14293
|
+
if (!errno)
|
|
14294
|
+
return false;
|
|
14295
|
+
const acl = library.symbols.acl_get_fd(fd);
|
|
14296
|
+
if (acl) {
|
|
14297
|
+
library.symbols.acl_free(acl);
|
|
14298
|
+
return false;
|
|
14299
|
+
}
|
|
14300
|
+
return (acl === null || acl === 0) && read2.i32(errno) === 2;
|
|
14301
|
+
} finally {
|
|
14302
|
+
library.close();
|
|
14303
|
+
}
|
|
14304
|
+
} catch {
|
|
14305
|
+
return false;
|
|
14306
|
+
}
|
|
14307
|
+
}
|
|
14308
|
+
function isSystemRootAlias(path) {
|
|
14309
|
+
if (process.platform !== "darwin" || !["/var", "/tmp", "/etc"].includes(path))
|
|
14310
|
+
return false;
|
|
14311
|
+
const target = `/private${path}`, link = `private${path}`;
|
|
14312
|
+
const identity4 = (stat) => `${stat.dev}:${stat.ino}:${stat.ctimeNs}:${stat.uid}:${stat.mode}`;
|
|
14313
|
+
try {
|
|
14314
|
+
const before = lstatSync15(path, { bigint: true });
|
|
14315
|
+
if (!before.isSymbolicLink() || before.uid !== 0n || readlinkSync4(path) !== link)
|
|
14316
|
+
return false;
|
|
14317
|
+
const directories = ["/", "/private", target].map((directory) => {
|
|
14318
|
+
const stat = lstatSync15(directory, { bigint: true });
|
|
14319
|
+
if (!stat.isDirectory() || stat.uid !== 0n)
|
|
14320
|
+
throw new Error("Untrusted system alias directory");
|
|
14321
|
+
if (directory !== "/private/tmp") {
|
|
14322
|
+
if ((stat.mode & 0o022n) !== 0n)
|
|
14323
|
+
throw new Error("Writable system alias directory");
|
|
14324
|
+
} else if ((stat.mode & 0o1000n) === 0n)
|
|
14325
|
+
throw new Error("Unprotected system temporary directory");
|
|
14326
|
+
const fd = openSync8(directory, constants7.O_RDONLY | constants7.O_DIRECTORY | constants7.O_NOFOLLOW);
|
|
14327
|
+
try {
|
|
14328
|
+
if (identity4(fstatSync8(fd, { bigint: true })) !== identity4(stat) || !hasNoDarwinAcl(fd) || identity4(fstatSync8(fd, { bigint: true })) !== identity4(stat))
|
|
14329
|
+
throw new Error("Unverified system alias directory ACL");
|
|
14330
|
+
} finally {
|
|
14331
|
+
closeSync8(fd);
|
|
14332
|
+
}
|
|
14333
|
+
return { directory, identity: identity4(stat) };
|
|
14334
|
+
});
|
|
14335
|
+
return realpathSync6(path) === target && readlinkSync4(path) === link && identity4(lstatSync15(path, { bigint: true })) === identity4(before) && directories.every((item) => identity4(lstatSync15(item.directory, { bigint: true })) === item.identity);
|
|
14336
|
+
} catch {
|
|
14337
|
+
return false;
|
|
14338
|
+
}
|
|
14339
|
+
}
|
|
14340
|
+
function canonicalSystemPath(path) {
|
|
14341
|
+
const absolute = resolve10(path), root = `/${absolute.split(sep5)[1]}`;
|
|
14342
|
+
if (process.platform !== "darwin" || !["/var", "/tmp", "/etc"].includes(root) || !lstatSync15(root, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
14343
|
+
return absolute;
|
|
14344
|
+
if (!isSystemRootAlias(root))
|
|
14345
|
+
throw new Error(`Refusing symlink path: ${root}`);
|
|
14346
|
+
return `/private${absolute}`;
|
|
14347
|
+
}
|
|
14248
14348
|
function assertSafePath(path) {
|
|
14249
14349
|
let cursor = resolve10(path);
|
|
14250
14350
|
while (true) {
|
|
14251
|
-
if (lstatSync15(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
14351
|
+
if (lstatSync15(cursor, { throwIfNoEntry: false })?.isSymbolicLink() && !isSystemRootAlias(cursor))
|
|
14252
14352
|
throw new Error(`Refusing symlink path: ${cursor}`);
|
|
14253
14353
|
const parent = dirname11(cursor);
|
|
14254
14354
|
if (parent === cursor)
|
|
@@ -14284,7 +14384,7 @@ function rootAliases(home, allowed = false) {
|
|
|
14284
14384
|
return result;
|
|
14285
14385
|
}
|
|
14286
14386
|
function canonicalAgentPath(path, aliases) {
|
|
14287
|
-
const absolute =
|
|
14387
|
+
const absolute = canonicalSystemPath(path), binding = aliases.find((item) => absolute === item.alias || absolute.startsWith(item.alias + sep5));
|
|
14288
14388
|
return binding ? join17(binding.target, relative5(binding.alias, absolute)) : absolute;
|
|
14289
14389
|
}
|
|
14290
14390
|
function disabledCodexSkillPaths(config, aliases) {
|
|
@@ -14382,17 +14482,19 @@ function selectNativeMigrationTargets(inventory, manifest) {
|
|
|
14382
14482
|
const identities = new Set;
|
|
14383
14483
|
const selected = [];
|
|
14384
14484
|
for (const target of manifest.targets) {
|
|
14385
|
-
|
|
14386
|
-
|
|
14485
|
+
if (!isAbsolute11(target.projectRoot) || resolve10(target.projectRoot) !== target.projectRoot)
|
|
14486
|
+
throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
|
|
14487
|
+
const projectRoot = canonicalSystemPath(target.projectRoot), normalized = relative5(projectRoot, resolve10(projectRoot, target.path));
|
|
14488
|
+
if (!existsSync8(projectRoot) || !lstatSync15(projectRoot).isDirectory())
|
|
14387
14489
|
throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
|
|
14388
14490
|
assertSafePath(projectRoot);
|
|
14389
14491
|
if (isAbsolute11(target.path) || target.path.includes("\\") || target.path.includes("\x00") || !normalized || normalized === ".." || normalized.startsWith(`..${sep5}`) || normalized !== target.path || !/^[0-9a-f]{64}$/.test(target.treeSha256))
|
|
14390
14492
|
throw new Error(`Invalid native migration target: ${target.path}`);
|
|
14391
|
-
const identity4 = `${target.agent}\x00${projectRoot}\x00${normalized}`;
|
|
14493
|
+
const identity4 = `${target.agent}\x00${canonicalSystemPath(projectRoot)}\x00${normalized}`;
|
|
14392
14494
|
if (identities.has(identity4))
|
|
14393
14495
|
throw new Error(`Duplicate native migration target: ${target.path}`);
|
|
14394
14496
|
identities.add(identity4);
|
|
14395
|
-
const expected = resolve10(target.projectRoot, target.path);
|
|
14497
|
+
const expected = canonicalSystemPath(resolve10(target.projectRoot, target.path));
|
|
14396
14498
|
const matches = inventory.filter((entry2) => entry2.agent === target.agent && resolve10(entry2.path) === expected);
|
|
14397
14499
|
if (matches.length !== 1)
|
|
14398
14500
|
throw new Error(`Native migration target was not found exactly once: ${target.agent} ${target.projectRoot}/${target.path}`);
|
|
@@ -14408,7 +14510,7 @@ function selectNativeMigrationTargets(inventory, manifest) {
|
|
|
14408
14510
|
function projectAncestorDirectories(projects) {
|
|
14409
14511
|
const directories = new Set;
|
|
14410
14512
|
for (const project of projects) {
|
|
14411
|
-
for (let path =
|
|
14513
|
+
for (let path = canonicalSystemPath(project), depth = 0;; depth++) {
|
|
14412
14514
|
if (depth >= 100)
|
|
14413
14515
|
throw new Error("NATIVE_SKILL_DRIFT: project ancestor discovery limit exceeded");
|
|
14414
14516
|
directories.add(path);
|
|
@@ -14421,11 +14523,13 @@ function projectAncestorDirectories(projects) {
|
|
|
14421
14523
|
return [...directories];
|
|
14422
14524
|
}
|
|
14423
14525
|
function inventoryNativeSkills(home = homedir2(), options = {}) {
|
|
14526
|
+
home = canonicalSystemPath(home);
|
|
14424
14527
|
if (options.reviewedCacheAlias !== undefined && (!options.includeVendor || !isAbsolute11(options.reviewedCacheAlias) || resolve10(options.reviewedCacheAlias) !== options.reviewedCacheAlias))
|
|
14425
14528
|
throw new Error("A reviewed cache alias requires vendor inventory and an exact absolute path");
|
|
14426
14529
|
if (options.disabledVendorPaths?.some((path) => !isAbsolute11(path) || resolve10(path) !== path))
|
|
14427
14530
|
throw new Error("Disabled vendor paths must be exact absolute paths");
|
|
14428
|
-
const
|
|
14531
|
+
const reviewedCacheAlias = options.reviewedCacheAlias === undefined ? undefined : canonicalSystemPath(options.reviewedCacheAlias);
|
|
14532
|
+
const disabledVendorPaths = new Set((options.disabledVendorPaths ?? []).map(canonicalSystemPath));
|
|
14429
14533
|
const aliases = rootAliases(home, options.allowRootAliases);
|
|
14430
14534
|
const selectedAgents = options.agents ? new Set(options.agents) : undefined;
|
|
14431
14535
|
const includesAgent = (agent) => !selectedAgents || selectedAgents.has(agent);
|
|
@@ -14448,8 +14552,11 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
|
|
|
14448
14552
|
}
|
|
14449
14553
|
let reviewedCacheAliasFound = false;
|
|
14450
14554
|
function verifiedSiblingCacheAlias(agent, path, parent) {
|
|
14451
|
-
const link = readlinkSync4(path),
|
|
14452
|
-
if (
|
|
14555
|
+
const link = readlinkSync4(path), lexicalTarget = resolve10(parent, link);
|
|
14556
|
+
if (isAbsolute11(link) ? link !== lexicalTarget : dirname11(link) !== ".")
|
|
14557
|
+
return false;
|
|
14558
|
+
const target = canonicalSystemPath(lexicalTarget);
|
|
14559
|
+
if (dirname11(target) !== parent)
|
|
14453
14560
|
return false;
|
|
14454
14561
|
if (!lstatSync15(target, { throwIfNoEntry: false })?.isDirectory())
|
|
14455
14562
|
return false;
|
|
@@ -14458,11 +14565,11 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
|
|
|
14458
14565
|
return false;
|
|
14459
14566
|
if (scan.hasSkills) {
|
|
14460
14567
|
const targetSkills = entries.filter((entry) => entry.agent === agent && entry.vendor && (entry.path === target || entry.path.startsWith(target + sep5)));
|
|
14461
|
-
if (path ===
|
|
14568
|
+
if (path === reviewedCacheAlias && targetSkills.length > 0)
|
|
14462
14569
|
reviewedCacheAliasFound = true;
|
|
14463
14570
|
if (agent === "codex" && targetSkills.length > 0 && targetSkills.every((entry) => disabledVendorPaths.has(entry.path) || options.disabledVendorSkill?.(entry) === true))
|
|
14464
14571
|
return true;
|
|
14465
|
-
if (path !==
|
|
14572
|
+
if (path !== reviewedCacheAlias)
|
|
14466
14573
|
return false;
|
|
14467
14574
|
}
|
|
14468
14575
|
return true;
|
package/dist/sdk/index.js
CHANGED
|
@@ -32373,7 +32373,7 @@ var init_event_sink = __esm(() => {
|
|
|
32373
32373
|
// package.json
|
|
32374
32374
|
var package_default = {
|
|
32375
32375
|
name: "@hasna/skills",
|
|
32376
|
-
version: "0.10.
|
|
32376
|
+
version: "0.10.24",
|
|
32377
32377
|
description: "Skills library for AI coding agents",
|
|
32378
32378
|
type: "module",
|
|
32379
32379
|
bin: {
|
|
@@ -38359,27 +38359,62 @@ function mcpControls(path, read) {
|
|
|
38359
38359
|
const object3 = (v) => Boolean(v && typeof v === "object" && !Array.isArray(v));
|
|
38360
38360
|
const textField = (v, empty = false) => typeof v === "string" && (empty || Boolean(v.trim())) && Buffer.byteLength(v) <= 16384 && !/[\x00-\x1f\x7f]/.test(v);
|
|
38361
38361
|
const envName = (v) => typeof v === "string" && /^[A-Za-z_][A-Za-z0-9_]{0,255}$/.test(v);
|
|
38362
|
+
const optional = (v, valid) => v === undefined || v === null || valid(v);
|
|
38363
|
+
const stringList = (v) => Array.isArray(v) && v.length <= 256 && v.every((item) => textField(item));
|
|
38364
|
+
const approval = (v) => ["auto", "prompt", "writes", "approve"].includes(v);
|
|
38365
|
+
const duration = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0;
|
|
38366
|
+
const positiveInteger = (v) => Number.isSafeInteger(v) && v > 0;
|
|
38367
|
+
const fields = [
|
|
38368
|
+
"command",
|
|
38369
|
+
"args",
|
|
38370
|
+
"cwd",
|
|
38371
|
+
"env",
|
|
38372
|
+
"env_vars",
|
|
38373
|
+
"enabled",
|
|
38374
|
+
"required",
|
|
38375
|
+
"environment_id",
|
|
38376
|
+
"startup_readiness",
|
|
38377
|
+
"supports_parallel_tool_calls",
|
|
38378
|
+
"tool_input_schema_max_bytes",
|
|
38379
|
+
"startup_timeout_sec",
|
|
38380
|
+
"startup_timeout_ms",
|
|
38381
|
+
"tool_timeout_sec",
|
|
38382
|
+
"default_tools_approval_mode",
|
|
38383
|
+
"enabled_tools",
|
|
38384
|
+
"disabled_tools",
|
|
38385
|
+
"omit_tools_from",
|
|
38386
|
+
"tools",
|
|
38387
|
+
"name"
|
|
38388
|
+
];
|
|
38362
38389
|
if (!object3(value) || Object.keys(value).length !== 1 || !object3(value.mcpServers))
|
|
38363
38390
|
refuse3();
|
|
38364
38391
|
const servers = Object.entries(value.mcpServers);
|
|
38365
38392
|
if (!servers.length || servers.length > 256)
|
|
38366
38393
|
refuse3();
|
|
38367
38394
|
for (const [name, server] of servers) {
|
|
38368
|
-
if (!identifier3(name) || !object3(server) || !Object.keys(server).every((key) =>
|
|
38395
|
+
if (!identifier3(name) || !object3(server) || !Object.keys(server).every((key) => fields.includes(key)) || !textField(server.command) || !optional(server.args, (v) => Array.isArray(v) && v.length <= 256 && v.every((arg) => textField(arg, true))) || !optional(server.cwd, textField) || !optional(server.env, (v) => object3(v) && Object.keys(v).length <= 256 && Object.entries(v).every(([key, value2]) => envName(key) && textField(value2, true))) || !["enabled", "required", "supports_parallel_tool_calls"].every((key) => optional(server[key], (v) => typeof v === "boolean")) || !optional(server.environment_id, (v) => v === "local") || !optional(server.startup_readiness, (v) => ["connection", "catalog"].includes(v)) || !optional(server.tool_input_schema_max_bytes, positiveInteger) || !["startup_timeout_sec", "tool_timeout_sec"].every((key) => optional(server[key], duration)) || !optional(server.startup_timeout_ms, (v) => Number.isSafeInteger(v) && v >= 0) || !optional(server.default_tools_approval_mode, approval) || !["enabled_tools", "disabled_tools"].every((key) => optional(server[key], stringList)) || !optional(server.omit_tools_from, (v) => Array.isArray(v) && v.length <= 256 && v.every((item) => ["code_mode", "deferred", "direct"].includes(item))) || !optional(server.name, textField))
|
|
38369
38396
|
refuse3();
|
|
38370
|
-
if (server.env_vars !== undefined) {
|
|
38397
|
+
if (server.env_vars !== undefined && server.env_vars !== null) {
|
|
38371
38398
|
if (!Array.isArray(server.env_vars) || server.env_vars.length > 256)
|
|
38372
38399
|
refuse3();
|
|
38373
38400
|
const names = server.env_vars.map((entry) => {
|
|
38374
38401
|
if (envName(entry))
|
|
38375
38402
|
return entry;
|
|
38376
|
-
if (!object3(entry) || !Object.keys(entry).every((key) => ["name", "source"].includes(key)) || !envName(entry.name) || entry.source
|
|
38403
|
+
if (!object3(entry) || !Object.keys(entry).every((key) => ["name", "source"].includes(key)) || !envName(entry.name) || !optional(entry.source, (v) => v === "local"))
|
|
38377
38404
|
refuse3();
|
|
38378
38405
|
return entry.name;
|
|
38379
38406
|
});
|
|
38380
38407
|
if (new Set(names).size !== names.length)
|
|
38381
38408
|
refuse3();
|
|
38382
38409
|
}
|
|
38410
|
+
if (server.tools !== undefined && server.tools !== null) {
|
|
38411
|
+
if (!object3(server.tools) || Object.keys(server.tools).length > 256)
|
|
38412
|
+
refuse3();
|
|
38413
|
+
for (const [tool, config] of Object.entries(server.tools)) {
|
|
38414
|
+
if (!textField(tool) || !object3(config) || !Object.keys(config).every((key) => ["approval_mode", "output_token_limit"].includes(key)) || !optional(config.approval_mode, approval) || !optional(config.output_token_limit, positiveInteger))
|
|
38415
|
+
refuse3();
|
|
38416
|
+
}
|
|
38417
|
+
}
|
|
38383
38418
|
}
|
|
38384
38419
|
return sha2562;
|
|
38385
38420
|
}
|
|
@@ -42140,10 +42175,75 @@ function disableCodexBundledSkills(text2) {
|
|
|
42140
42175
|
// src/lib/agent-integration.ts
|
|
42141
42176
|
var sha4 = (data) => createHash18("sha256").update(data).digest("hex");
|
|
42142
42177
|
var ROOTS = NATIVE_SKILL_ROOTS;
|
|
42178
|
+
function hasNoDarwinAcl(fd) {
|
|
42179
|
+
try {
|
|
42180
|
+
const { dlopen, read: read3 } = __require("bun:ffi");
|
|
42181
|
+
const library = dlopen("/usr/lib/libSystem.B.dylib", {
|
|
42182
|
+
acl_get_fd: { args: ["i32"], returns: "ptr" },
|
|
42183
|
+
acl_free: { args: ["ptr"], returns: "i32" },
|
|
42184
|
+
__error: { args: [], returns: "ptr" }
|
|
42185
|
+
});
|
|
42186
|
+
try {
|
|
42187
|
+
const errno = library.symbols.__error();
|
|
42188
|
+
if (!errno)
|
|
42189
|
+
return false;
|
|
42190
|
+
const acl = library.symbols.acl_get_fd(fd);
|
|
42191
|
+
if (acl) {
|
|
42192
|
+
library.symbols.acl_free(acl);
|
|
42193
|
+
return false;
|
|
42194
|
+
}
|
|
42195
|
+
return (acl === null || acl === 0) && read3.i32(errno) === 2;
|
|
42196
|
+
} finally {
|
|
42197
|
+
library.close();
|
|
42198
|
+
}
|
|
42199
|
+
} catch {
|
|
42200
|
+
return false;
|
|
42201
|
+
}
|
|
42202
|
+
}
|
|
42203
|
+
function isSystemRootAlias(path) {
|
|
42204
|
+
if (process.platform !== "darwin" || !["/var", "/tmp", "/etc"].includes(path))
|
|
42205
|
+
return false;
|
|
42206
|
+
const target = `/private${path}`, link = `private${path}`;
|
|
42207
|
+
const identity4 = (stat2) => `${stat2.dev}:${stat2.ino}:${stat2.ctimeNs}:${stat2.uid}:${stat2.mode}`;
|
|
42208
|
+
try {
|
|
42209
|
+
const before = lstatSync19(path, { bigint: true });
|
|
42210
|
+
if (!before.isSymbolicLink() || before.uid !== 0n || readlinkSync4(path) !== link)
|
|
42211
|
+
return false;
|
|
42212
|
+
const directories = ["/", "/private", target].map((directory) => {
|
|
42213
|
+
const stat2 = lstatSync19(directory, { bigint: true });
|
|
42214
|
+
if (!stat2.isDirectory() || stat2.uid !== 0n)
|
|
42215
|
+
throw new Error("Untrusted system alias directory");
|
|
42216
|
+
if (directory !== "/private/tmp") {
|
|
42217
|
+
if ((stat2.mode & 0o022n) !== 0n)
|
|
42218
|
+
throw new Error("Writable system alias directory");
|
|
42219
|
+
} else if ((stat2.mode & 0o1000n) === 0n)
|
|
42220
|
+
throw new Error("Unprotected system temporary directory");
|
|
42221
|
+
const fd = openSync16(directory, constants12.O_RDONLY | constants12.O_DIRECTORY | constants12.O_NOFOLLOW);
|
|
42222
|
+
try {
|
|
42223
|
+
if (identity4(fstatSync16(fd, { bigint: true })) !== identity4(stat2) || !hasNoDarwinAcl(fd) || identity4(fstatSync16(fd, { bigint: true })) !== identity4(stat2))
|
|
42224
|
+
throw new Error("Unverified system alias directory ACL");
|
|
42225
|
+
} finally {
|
|
42226
|
+
closeSync16(fd);
|
|
42227
|
+
}
|
|
42228
|
+
return { directory, identity: identity4(stat2) };
|
|
42229
|
+
});
|
|
42230
|
+
return realpathSync7(path) === target && readlinkSync4(path) === link && identity4(lstatSync19(path, { bigint: true })) === identity4(before) && directories.every((item) => identity4(lstatSync19(item.directory, { bigint: true })) === item.identity);
|
|
42231
|
+
} catch {
|
|
42232
|
+
return false;
|
|
42233
|
+
}
|
|
42234
|
+
}
|
|
42235
|
+
function canonicalSystemPath(path) {
|
|
42236
|
+
const absolute = resolve15(path), root2 = `/${absolute.split(sep5)[1]}`;
|
|
42237
|
+
if (process.platform !== "darwin" || !["/var", "/tmp", "/etc"].includes(root2) || !lstatSync19(root2, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
42238
|
+
return absolute;
|
|
42239
|
+
if (!isSystemRootAlias(root2))
|
|
42240
|
+
throw new Error(`Refusing symlink path: ${root2}`);
|
|
42241
|
+
return `/private${absolute}`;
|
|
42242
|
+
}
|
|
42143
42243
|
function assertSafePath(path) {
|
|
42144
42244
|
let cursor = resolve15(path);
|
|
42145
42245
|
while (true) {
|
|
42146
|
-
if (lstatSync19(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
42246
|
+
if (lstatSync19(cursor, { throwIfNoEntry: false })?.isSymbolicLink() && !isSystemRootAlias(cursor))
|
|
42147
42247
|
throw new Error(`Refusing symlink path: ${cursor}`);
|
|
42148
42248
|
const parent = dirname15(cursor);
|
|
42149
42249
|
if (parent === cursor)
|
|
@@ -42179,7 +42279,7 @@ function rootAliases(home, allowed = false) {
|
|
|
42179
42279
|
return result;
|
|
42180
42280
|
}
|
|
42181
42281
|
function canonicalAgentPath(path, aliases) {
|
|
42182
|
-
const absolute =
|
|
42282
|
+
const absolute = canonicalSystemPath(path), binding = aliases.find((item) => absolute === item.alias || absolute.startsWith(item.alias + sep5));
|
|
42183
42283
|
return binding ? join22(binding.target, relative4(binding.alias, absolute)) : absolute;
|
|
42184
42284
|
}
|
|
42185
42285
|
function disabledCodexSkillPaths(config, aliases) {
|
|
@@ -42277,17 +42377,19 @@ function selectNativeMigrationTargets(inventory, manifest) {
|
|
|
42277
42377
|
const identities = new Set;
|
|
42278
42378
|
const selected = [];
|
|
42279
42379
|
for (const target of manifest.targets) {
|
|
42280
|
-
|
|
42281
|
-
|
|
42380
|
+
if (!isAbsolute17(target.projectRoot) || resolve15(target.projectRoot) !== target.projectRoot)
|
|
42381
|
+
throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
|
|
42382
|
+
const projectRoot = canonicalSystemPath(target.projectRoot), normalized = relative4(projectRoot, resolve15(projectRoot, target.path));
|
|
42383
|
+
if (!existsSync6(projectRoot) || !lstatSync19(projectRoot).isDirectory())
|
|
42282
42384
|
throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
|
|
42283
42385
|
assertSafePath(projectRoot);
|
|
42284
42386
|
if (isAbsolute17(target.path) || target.path.includes("\\") || target.path.includes("\x00") || !normalized || normalized === ".." || normalized.startsWith(`..${sep5}`) || normalized !== target.path || !/^[0-9a-f]{64}$/.test(target.treeSha256))
|
|
42285
42387
|
throw new Error(`Invalid native migration target: ${target.path}`);
|
|
42286
|
-
const identity4 = `${target.agent}\x00${projectRoot}\x00${normalized}`;
|
|
42388
|
+
const identity4 = `${target.agent}\x00${canonicalSystemPath(projectRoot)}\x00${normalized}`;
|
|
42287
42389
|
if (identities.has(identity4))
|
|
42288
42390
|
throw new Error(`Duplicate native migration target: ${target.path}`);
|
|
42289
42391
|
identities.add(identity4);
|
|
42290
|
-
const expected = resolve15(target.projectRoot, target.path);
|
|
42392
|
+
const expected = canonicalSystemPath(resolve15(target.projectRoot, target.path));
|
|
42291
42393
|
const matches = inventory.filter((entry2) => entry2.agent === target.agent && resolve15(entry2.path) === expected);
|
|
42292
42394
|
if (matches.length !== 1)
|
|
42293
42395
|
throw new Error(`Native migration target was not found exactly once: ${target.agent} ${target.projectRoot}/${target.path}`);
|
|
@@ -42303,7 +42405,7 @@ function selectNativeMigrationTargets(inventory, manifest) {
|
|
|
42303
42405
|
function projectAncestorDirectories(projects) {
|
|
42304
42406
|
const directories = new Set;
|
|
42305
42407
|
for (const project of projects) {
|
|
42306
|
-
for (let path =
|
|
42408
|
+
for (let path = canonicalSystemPath(project), depth = 0;; depth++) {
|
|
42307
42409
|
if (depth >= 100)
|
|
42308
42410
|
throw new Error("NATIVE_SKILL_DRIFT: project ancestor discovery limit exceeded");
|
|
42309
42411
|
directories.add(path);
|
|
@@ -42316,11 +42418,13 @@ function projectAncestorDirectories(projects) {
|
|
|
42316
42418
|
return [...directories];
|
|
42317
42419
|
}
|
|
42318
42420
|
function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
42421
|
+
home = canonicalSystemPath(home);
|
|
42319
42422
|
if (options.reviewedCacheAlias !== undefined && (!options.includeVendor || !isAbsolute17(options.reviewedCacheAlias) || resolve15(options.reviewedCacheAlias) !== options.reviewedCacheAlias))
|
|
42320
42423
|
throw new Error("A reviewed cache alias requires vendor inventory and an exact absolute path");
|
|
42321
42424
|
if (options.disabledVendorPaths?.some((path) => !isAbsolute17(path) || resolve15(path) !== path))
|
|
42322
42425
|
throw new Error("Disabled vendor paths must be exact absolute paths");
|
|
42323
|
-
const
|
|
42426
|
+
const reviewedCacheAlias = options.reviewedCacheAlias === undefined ? undefined : canonicalSystemPath(options.reviewedCacheAlias);
|
|
42427
|
+
const disabledVendorPaths = new Set((options.disabledVendorPaths ?? []).map(canonicalSystemPath));
|
|
42324
42428
|
const aliases = rootAliases(home, options.allowRootAliases);
|
|
42325
42429
|
const selectedAgents = options.agents ? new Set(options.agents) : undefined;
|
|
42326
42430
|
const includesAgent = (agent) => !selectedAgents || selectedAgents.has(agent);
|
|
@@ -42343,8 +42447,11 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
42343
42447
|
}
|
|
42344
42448
|
let reviewedCacheAliasFound = false;
|
|
42345
42449
|
function verifiedSiblingCacheAlias(agent, path, parent) {
|
|
42346
|
-
const link = readlinkSync4(path),
|
|
42347
|
-
if (
|
|
42450
|
+
const link = readlinkSync4(path), lexicalTarget = resolve15(parent, link);
|
|
42451
|
+
if (isAbsolute17(link) ? link !== lexicalTarget : dirname15(link) !== ".")
|
|
42452
|
+
return false;
|
|
42453
|
+
const target = canonicalSystemPath(lexicalTarget);
|
|
42454
|
+
if (dirname15(target) !== parent)
|
|
42348
42455
|
return false;
|
|
42349
42456
|
if (!lstatSync19(target, { throwIfNoEntry: false })?.isDirectory())
|
|
42350
42457
|
return false;
|
|
@@ -42353,11 +42460,11 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
42353
42460
|
return false;
|
|
42354
42461
|
if (scan.hasSkills) {
|
|
42355
42462
|
const targetSkills = entries.filter((entry) => entry.agent === agent && entry.vendor && (entry.path === target || entry.path.startsWith(target + sep5)));
|
|
42356
|
-
if (path ===
|
|
42463
|
+
if (path === reviewedCacheAlias && targetSkills.length > 0)
|
|
42357
42464
|
reviewedCacheAliasFound = true;
|
|
42358
42465
|
if (agent === "codex" && targetSkills.length > 0 && targetSkills.every((entry) => disabledVendorPaths.has(entry.path) || options.disabledVendorSkill?.(entry) === true))
|
|
42359
42466
|
return true;
|
|
42360
|
-
if (path !==
|
|
42467
|
+
if (path !== reviewedCacheAlias)
|
|
42361
42468
|
return false;
|
|
42362
42469
|
}
|
|
42363
42470
|
return true;
|