@hasna/skills 0.10.22 → 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 +175 -22
- package/bin/mcp.js +4 -2
- package/bin/migrate.js +1 -1
- package/bin/server.js +1 -1
- package/bin/worker.js +1 -1
- package/dist/index.js +170 -19
- package/dist/lib/codex-plugin-skill-controls.d.ts +1 -0
- package/dist/sdk/index.js +170 -19
- 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: {
|
|
@@ -39931,7 +39931,7 @@ function assertAgentPolicyCollections(policy) {
|
|
|
39931
39931
|
}
|
|
39932
39932
|
if (bridge.codexPluginSkills !== undefined)
|
|
39933
39933
|
for (const control of array(bridge.codexPluginSkills, 4096)) {
|
|
39934
|
-
requireBound(object(control) && Object.keys(control).every((key) => ["name", "pluginId", "namespace", "pluginParent", "manifestSha256", "appSha256", "remotePluginId"].includes(key)));
|
|
39934
|
+
requireBound(object(control) && Object.keys(control).every((key) => ["name", "pluginId", "namespace", "pluginParent", "manifestSha256", "appSha256", "mcpSha256", "remotePluginId"].includes(key)));
|
|
39935
39935
|
text(control.name, 129);
|
|
39936
39936
|
text(control.pluginId, 1024);
|
|
39937
39937
|
text(control.namespace, 64);
|
|
@@ -39939,6 +39939,8 @@ function assertAgentPolicyCollections(policy) {
|
|
|
39939
39939
|
requireBound(isAbsolute2(control.pluginParent) && resolve3(control.pluginParent) === control.pluginParent && /^[a-f0-9]{64}$/.test(control.manifestSha256));
|
|
39940
39940
|
if (control.remotePluginId !== undefined)
|
|
39941
39941
|
requireBound(typeof control.remotePluginId === "string" && /^[A-Za-z0-9_~-]{1,1024}$/.test(control.remotePluginId));
|
|
39942
|
+
if (control.mcpSha256 !== undefined)
|
|
39943
|
+
requireBound(typeof control.mcpSha256 === "string" && /^[a-f0-9]{64}$/.test(control.mcpSha256));
|
|
39942
39944
|
if (control.appSha256 !== undefined)
|
|
39943
39945
|
requireBound(typeof control.appSha256 === "string" && /^[a-f0-9]{64}$/.test(control.appSha256));
|
|
39944
39946
|
}
|
|
@@ -51226,6 +51228,77 @@ function appControls(path, read2) {
|
|
|
51226
51228
|
}
|
|
51227
51229
|
return sha2562;
|
|
51228
51230
|
}
|
|
51231
|
+
function mcpControls(path, read2) {
|
|
51232
|
+
const text2 = read2(path);
|
|
51233
|
+
let value, sha2562;
|
|
51234
|
+
try {
|
|
51235
|
+
sha2562 = hashNativeJsonControls(text2);
|
|
51236
|
+
value = JSON.parse(text2);
|
|
51237
|
+
} catch {
|
|
51238
|
+
refuse2();
|
|
51239
|
+
}
|
|
51240
|
+
const object5 = (v) => Boolean(v && typeof v === "object" && !Array.isArray(v));
|
|
51241
|
+
const textField = (v, empty = false) => typeof v === "string" && (empty || Boolean(v.trim())) && Buffer.byteLength(v) <= 16384 && !/[\x00-\x1f\x7f]/.test(v);
|
|
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
|
+
];
|
|
51270
|
+
if (!object5(value) || Object.keys(value).length !== 1 || !object5(value.mcpServers))
|
|
51271
|
+
refuse2();
|
|
51272
|
+
const servers = Object.entries(value.mcpServers);
|
|
51273
|
+
if (!servers.length || servers.length > 256)
|
|
51274
|
+
refuse2();
|
|
51275
|
+
for (const [name, server] of servers) {
|
|
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))
|
|
51277
|
+
refuse2();
|
|
51278
|
+
if (server.env_vars !== undefined && server.env_vars !== null) {
|
|
51279
|
+
if (!Array.isArray(server.env_vars) || server.env_vars.length > 256)
|
|
51280
|
+
refuse2();
|
|
51281
|
+
const names = server.env_vars.map((entry) => {
|
|
51282
|
+
if (envName(entry))
|
|
51283
|
+
return entry;
|
|
51284
|
+
if (!object5(entry) || !Object.keys(entry).every((key) => ["name", "source"].includes(key)) || !envName(entry.name) || !optional(entry.source, (v) => v === "local"))
|
|
51285
|
+
refuse2();
|
|
51286
|
+
return entry.name;
|
|
51287
|
+
});
|
|
51288
|
+
if (new Set(names).size !== names.length)
|
|
51289
|
+
refuse2();
|
|
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
|
+
}
|
|
51299
|
+
}
|
|
51300
|
+
return sha2562;
|
|
51301
|
+
}
|
|
51229
51302
|
function rootControls(root, read2) {
|
|
51230
51303
|
const manifestPath = join18(root, ".codex-plugin/plugin.json"), manifestFile = lstatSync12(manifestPath, { throwIfNoEntry: false });
|
|
51231
51304
|
if (!lstatSync12(join18(root, ".codex-plugin"), { throwIfNoEntry: false })?.isDirectory() || !manifestFile?.isFile() || manifestFile.size > 1024 * 1024)
|
|
@@ -51243,15 +51316,21 @@ function rootControls(root, read2) {
|
|
|
51243
51316
|
const cacheVersion = basename5(root), declaredVersion = manifest.version === undefined ? "" : typeof manifest.version === "string" ? manifest.version.trim() : null;
|
|
51244
51317
|
if (declaredVersion === null || (declaredVersion ? declaredVersion !== cacheVersion : cacheVersion !== CODEX_DEFAULT_AGENT_PLUGIN_VERSION))
|
|
51245
51318
|
refuse2();
|
|
51246
|
-
if (manifest.hooks !== undefined || manifest.
|
|
51319
|
+
if (manifest.hooks !== undefined || manifest.commands !== undefined || manifest.mcpServers !== undefined && manifest.mcpServers !== "./.mcp.json" || manifest.apps !== undefined && manifest.apps !== "./.app.json" || lstatSync12(join18(root, "hooks"), { throwIfNoEntry: false }))
|
|
51320
|
+
refuse2();
|
|
51321
|
+
const mcp = join18(root, ".mcp.json"), mcpPresent = lstatSync12(mcp, { throwIfNoEntry: false });
|
|
51322
|
+
if (mcpPresent && (!mcpPresent.isFile() || mcpPresent.isSymbolicLink() || mcpPresent.size > 1024 * 1024 || realpathSync5(mcp) !== mcp))
|
|
51323
|
+
refuse2();
|
|
51324
|
+
if (Boolean(mcpPresent) !== (manifest.mcpServers !== undefined))
|
|
51247
51325
|
refuse2();
|
|
51326
|
+
const mcpSha256 = mcpPresent ? mcpControls(mcp, read2) : undefined;
|
|
51248
51327
|
const app = join18(root, ".app.json"), present = lstatSync12(app, { throwIfNoEntry: false });
|
|
51249
51328
|
if (present && (!present.isFile() || present.isSymbolicLink() || present.size > 1024 * 1024))
|
|
51250
51329
|
refuse2();
|
|
51251
51330
|
if (manifest.apps !== undefined && !present)
|
|
51252
51331
|
refuse2();
|
|
51253
51332
|
const appSha256 = present ? appControls(app, read2) : undefined;
|
|
51254
|
-
return { namespace: manifest.name, manifestSha256, ...appSha256 ? { appSha256 } : {} };
|
|
51333
|
+
return { namespace: manifest.name, manifestSha256, ...appSha256 ? { appSha256 } : {}, ...mcpSha256 ? { mcpSha256 } : {} };
|
|
51255
51334
|
}
|
|
51256
51335
|
function identity4(document3, cache3, read2) {
|
|
51257
51336
|
if (!document3.startsWith(cache3 + sep4) || !document3.endsWith(sep4 + "SKILL.md"))
|
|
@@ -51314,7 +51393,7 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache3, controls, read2) {
|
|
|
51314
51393
|
if (!stat.isDirectory() || ![".codex-plugin/plugin.json", ".app.json", "hooks", ".mcp.json"].some((path) => lstatSync12(join18(root, path), { throwIfNoEntry: false })))
|
|
51315
51394
|
continue;
|
|
51316
51395
|
const parsed = rootControls(root, read2);
|
|
51317
|
-
if (!controls.some((control) => control.pluginParent === parent && control.namespace === parsed.namespace && control.manifestSha256 === parsed.manifestSha256 && control.appSha256 === parsed.appSha256))
|
|
51396
|
+
if (!controls.some((control) => control.pluginParent === parent && control.namespace === parsed.namespace && control.manifestSha256 === parsed.manifestSha256 && control.appSha256 === parsed.appSha256 && control.mcpSha256 === parsed.mcpSha256))
|
|
51318
51397
|
return false;
|
|
51319
51398
|
}
|
|
51320
51399
|
}
|
|
@@ -51374,7 +51453,7 @@ function reviewCodexPluginSkillControls(catalog, documents, cache3, cwd2, read2,
|
|
|
51374
51453
|
}
|
|
51375
51454
|
result2.push({ ...parsed, pluginId: expectedPluginId, ...remotePluginId ? { remotePluginId } : {} });
|
|
51376
51455
|
}
|
|
51377
|
-
if (!result2.length || new Set(result2.map((item) => item.name)).size !== result2.length)
|
|
51456
|
+
if (!result2.length && documents.some((document3) => document3.startsWith(cache3 + sep4)) || new Set(result2.map((item) => item.name)).size !== result2.length)
|
|
51378
51457
|
refuse2();
|
|
51379
51458
|
return result2;
|
|
51380
51459
|
}
|
|
@@ -51387,7 +51466,7 @@ function isReviewedCodexPluginSkillDisabled(document3, cache3, controls, rules,
|
|
|
51387
51466
|
} catch {
|
|
51388
51467
|
return false;
|
|
51389
51468
|
}
|
|
51390
|
-
const reviewed = controls.find((item) => item.name === parsed.name && item.namespace === parsed.namespace && item.pluginParent === parsed.pluginParent && item.manifestSha256 === parsed.manifestSha256 && item.appSha256 === parsed.appSha256);
|
|
51469
|
+
const reviewed = controls.find((item) => item.name === parsed.name && item.namespace === parsed.namespace && item.pluginParent === parsed.pluginParent && item.manifestSha256 === parsed.manifestSha256 && item.appSha256 === parsed.appSha256 && item.mcpSha256 === parsed.mcpSha256);
|
|
51391
51470
|
if (!reviewed || reviewed.remotePluginId !== undefined && !remoteInstallationMatches(reviewed.pluginParent, reviewed.remotePluginId, read2))
|
|
51392
51471
|
return false;
|
|
51393
51472
|
return isCodexNativeSkillDisabled({ name: parsed.name, path: document3, pluginId: reviewed.pluginId, enabled: true }, rules);
|
|
@@ -52077,10 +52156,75 @@ import { isDeepStrictEqual as isDeepStrictEqual4 } from "util";
|
|
|
52077
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";
|
|
52078
52157
|
import { dirname as dirname11, join as join21, resolve as resolve11, relative as relative5, isAbsolute as isAbsolute11, sep as sep5 } from "path";
|
|
52079
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
|
+
}
|
|
52080
52224
|
function assertSafePath(path) {
|
|
52081
52225
|
let cursor = resolve11(path);
|
|
52082
52226
|
while (true) {
|
|
52083
|
-
if (lstatSync15(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
52227
|
+
if (lstatSync15(cursor, { throwIfNoEntry: false })?.isSymbolicLink() && !isSystemRootAlias(cursor))
|
|
52084
52228
|
throw new Error(`Refusing symlink path: ${cursor}`);
|
|
52085
52229
|
const parent = dirname11(cursor);
|
|
52086
52230
|
if (parent === cursor)
|
|
@@ -52116,7 +52260,7 @@ function rootAliases(home, allowed = false) {
|
|
|
52116
52260
|
return result2;
|
|
52117
52261
|
}
|
|
52118
52262
|
function canonicalAgentPath(path, aliases) {
|
|
52119
|
-
const absolute =
|
|
52263
|
+
const absolute = canonicalSystemPath(path), binding = aliases.find((item) => absolute === item.alias || absolute.startsWith(item.alias + sep5));
|
|
52120
52264
|
return binding ? join21(binding.target, relative5(binding.alias, absolute)) : absolute;
|
|
52121
52265
|
}
|
|
52122
52266
|
function disabledCodexSkillPaths(config, aliases) {
|
|
@@ -52233,8 +52377,10 @@ function parseNativeMigrationTargetManifest(input) {
|
|
|
52233
52377
|
throw new Error("Invalid native migration target fields");
|
|
52234
52378
|
if (!ROOTS.some(([agent]) => agent === item.agent))
|
|
52235
52379
|
throw new Error(`Unsupported native migration target agent: ${item.agent}`);
|
|
52236
|
-
|
|
52237
|
-
|
|
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())
|
|
52238
52384
|
throw new Error(`Native migration target project root must be an existing absolute directory: ${item.projectRoot}`);
|
|
52239
52385
|
assertSafePath(projectRoot);
|
|
52240
52386
|
if (isAbsolute11(item.path) || item.path.includes("\\") || item.path.length === 0 || item.path.includes("\x00"))
|
|
@@ -52244,7 +52390,7 @@ function parseNativeMigrationTargetManifest(input) {
|
|
|
52244
52390
|
throw new Error(`Native migration target path escapes or is not normalized: ${item.path}`);
|
|
52245
52391
|
if (!/^[0-9a-f]{64}$/.test(item.treeSha256))
|
|
52246
52392
|
throw new Error(`Invalid native migration tree digest for ${item.path}`);
|
|
52247
|
-
const identity5 = `${item.agent}\x00${projectRoot}\x00${normalized}`;
|
|
52393
|
+
const identity5 = `${item.agent}\x00${canonicalSystemPath(projectRoot)}\x00${normalized}`;
|
|
52248
52394
|
if (identities.has(identity5))
|
|
52249
52395
|
throw new Error(`Duplicate native migration target: ${item.path}`);
|
|
52250
52396
|
identities.add(identity5);
|
|
@@ -52261,17 +52407,19 @@ function selectNativeMigrationTargets(inventory, manifest) {
|
|
|
52261
52407
|
const identities = new Set;
|
|
52262
52408
|
const selected = [];
|
|
52263
52409
|
for (const target of manifest.targets) {
|
|
52264
|
-
|
|
52265
|
-
|
|
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())
|
|
52266
52414
|
throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
|
|
52267
52415
|
assertSafePath(projectRoot);
|
|
52268
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))
|
|
52269
52417
|
throw new Error(`Invalid native migration target: ${target.path}`);
|
|
52270
|
-
const identity5 = `${target.agent}\x00${projectRoot}\x00${normalized}`;
|
|
52418
|
+
const identity5 = `${target.agent}\x00${canonicalSystemPath(projectRoot)}\x00${normalized}`;
|
|
52271
52419
|
if (identities.has(identity5))
|
|
52272
52420
|
throw new Error(`Duplicate native migration target: ${target.path}`);
|
|
52273
52421
|
identities.add(identity5);
|
|
52274
|
-
const expected = resolve11(target.projectRoot, target.path);
|
|
52422
|
+
const expected = canonicalSystemPath(resolve11(target.projectRoot, target.path));
|
|
52275
52423
|
const matches2 = inventory.filter((entry2) => entry2.agent === target.agent && resolve11(entry2.path) === expected);
|
|
52276
52424
|
if (matches2.length !== 1)
|
|
52277
52425
|
throw new Error(`Native migration target was not found exactly once: ${target.agent} ${target.projectRoot}/${target.path}`);
|
|
@@ -52287,7 +52435,7 @@ function selectNativeMigrationTargets(inventory, manifest) {
|
|
|
52287
52435
|
function projectAncestorDirectories(projects) {
|
|
52288
52436
|
const directories = new Set;
|
|
52289
52437
|
for (const project of projects) {
|
|
52290
|
-
for (let path =
|
|
52438
|
+
for (let path = canonicalSystemPath(project), depth = 0;; depth++) {
|
|
52291
52439
|
if (depth >= 100)
|
|
52292
52440
|
throw new Error("NATIVE_SKILL_DRIFT: project ancestor discovery limit exceeded");
|
|
52293
52441
|
directories.add(path);
|
|
@@ -52300,11 +52448,13 @@ function projectAncestorDirectories(projects) {
|
|
|
52300
52448
|
return [...directories];
|
|
52301
52449
|
}
|
|
52302
52450
|
function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
52451
|
+
home = canonicalSystemPath(home);
|
|
52303
52452
|
if (options.reviewedCacheAlias !== undefined && (!options.includeVendor || !isAbsolute11(options.reviewedCacheAlias) || resolve11(options.reviewedCacheAlias) !== options.reviewedCacheAlias))
|
|
52304
52453
|
throw new Error("A reviewed cache alias requires vendor inventory and an exact absolute path");
|
|
52305
52454
|
if (options.disabledVendorPaths?.some((path) => !isAbsolute11(path) || resolve11(path) !== path))
|
|
52306
52455
|
throw new Error("Disabled vendor paths must be exact absolute paths");
|
|
52307
|
-
const
|
|
52456
|
+
const reviewedCacheAlias = options.reviewedCacheAlias === undefined ? undefined : canonicalSystemPath(options.reviewedCacheAlias);
|
|
52457
|
+
const disabledVendorPaths = new Set((options.disabledVendorPaths ?? []).map(canonicalSystemPath));
|
|
52308
52458
|
const aliases = rootAliases(home, options.allowRootAliases);
|
|
52309
52459
|
const selectedAgents = options.agents ? new Set(options.agents) : undefined;
|
|
52310
52460
|
const includesAgent = (agent) => !selectedAgents || selectedAgents.has(agent);
|
|
@@ -52327,8 +52477,11 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
52327
52477
|
}
|
|
52328
52478
|
let reviewedCacheAliasFound = false;
|
|
52329
52479
|
function verifiedSiblingCacheAlias(agent, path, parent) {
|
|
52330
|
-
const link2 = readlinkSync4(path),
|
|
52331
|
-
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)
|
|
52332
52485
|
return false;
|
|
52333
52486
|
if (!lstatSync15(target, { throwIfNoEntry: false })?.isDirectory())
|
|
52334
52487
|
return false;
|
|
@@ -52337,11 +52490,11 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
52337
52490
|
return false;
|
|
52338
52491
|
if (scan.hasSkills) {
|
|
52339
52492
|
const targetSkills = entries.filter((entry) => entry.agent === agent && entry.vendor && (entry.path === target || entry.path.startsWith(target + sep5)));
|
|
52340
|
-
if (path ===
|
|
52493
|
+
if (path === reviewedCacheAlias && targetSkills.length > 0)
|
|
52341
52494
|
reviewedCacheAliasFound = true;
|
|
52342
52495
|
if (agent === "codex" && targetSkills.length > 0 && targetSkills.every((entry) => disabledVendorPaths.has(entry.path) || options.disabledVendorSkill?.(entry) === true))
|
|
52343
52496
|
return true;
|
|
52344
|
-
if (path !==
|
|
52497
|
+
if (path !== reviewedCacheAlias)
|
|
52345
52498
|
return false;
|
|
52346
52499
|
}
|
|
52347
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: {
|
|
@@ -38253,7 +38253,7 @@ function assertAgentPolicyCollections(policy) {
|
|
|
38253
38253
|
}
|
|
38254
38254
|
if (bridge.codexPluginSkills !== undefined)
|
|
38255
38255
|
for (const control of array3(bridge.codexPluginSkills, 4096)) {
|
|
38256
|
-
requireBound(object4(control) && Object.keys(control).every((key) => ["name", "pluginId", "namespace", "pluginParent", "manifestSha256", "appSha256", "remotePluginId"].includes(key)));
|
|
38256
|
+
requireBound(object4(control) && Object.keys(control).every((key) => ["name", "pluginId", "namespace", "pluginParent", "manifestSha256", "appSha256", "mcpSha256", "remotePluginId"].includes(key)));
|
|
38257
38257
|
text(control.name, 129);
|
|
38258
38258
|
text(control.pluginId, 1024);
|
|
38259
38259
|
text(control.namespace, 64);
|
|
@@ -38261,6 +38261,8 @@ function assertAgentPolicyCollections(policy) {
|
|
|
38261
38261
|
requireBound(isAbsolute3(control.pluginParent) && resolve2(control.pluginParent) === control.pluginParent && /^[a-f0-9]{64}$/.test(control.manifestSha256));
|
|
38262
38262
|
if (control.remotePluginId !== undefined)
|
|
38263
38263
|
requireBound(typeof control.remotePluginId === "string" && /^[A-Za-z0-9_~-]{1,1024}$/.test(control.remotePluginId));
|
|
38264
|
+
if (control.mcpSha256 !== undefined)
|
|
38265
|
+
requireBound(typeof control.mcpSha256 === "string" && /^[a-f0-9]{64}$/.test(control.mcpSha256));
|
|
38264
38266
|
if (control.appSha256 !== undefined)
|
|
38265
38267
|
requireBound(typeof control.appSha256 === "string" && /^[a-f0-9]{64}$/.test(control.appSha256));
|
|
38266
38268
|
}
|
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
|
@@ -9038,7 +9038,7 @@ function assertAgentPolicyCollections(policy) {
|
|
|
9038
9038
|
}
|
|
9039
9039
|
if (bridge.codexPluginSkills !== undefined)
|
|
9040
9040
|
for (const control of array(bridge.codexPluginSkills, 4096)) {
|
|
9041
|
-
requireBound(object(control) && Object.keys(control).every((key) => ["name", "pluginId", "namespace", "pluginParent", "manifestSha256", "appSha256", "remotePluginId"].includes(key)));
|
|
9041
|
+
requireBound(object(control) && Object.keys(control).every((key) => ["name", "pluginId", "namespace", "pluginParent", "manifestSha256", "appSha256", "mcpSha256", "remotePluginId"].includes(key)));
|
|
9042
9042
|
text(control.name, 129);
|
|
9043
9043
|
text(control.pluginId, 1024);
|
|
9044
9044
|
text(control.namespace, 64);
|
|
@@ -9046,6 +9046,8 @@ function assertAgentPolicyCollections(policy) {
|
|
|
9046
9046
|
requireBound(isAbsolute2(control.pluginParent) && resolve2(control.pluginParent) === control.pluginParent && /^[a-f0-9]{64}$/.test(control.manifestSha256));
|
|
9047
9047
|
if (control.remotePluginId !== undefined)
|
|
9048
9048
|
requireBound(typeof control.remotePluginId === "string" && /^[A-Za-z0-9_~-]{1,1024}$/.test(control.remotePluginId));
|
|
9049
|
+
if (control.mcpSha256 !== undefined)
|
|
9050
|
+
requireBound(typeof control.mcpSha256 === "string" && /^[a-f0-9]{64}$/.test(control.mcpSha256));
|
|
9049
9051
|
if (control.appSha256 !== undefined)
|
|
9050
9052
|
requireBound(typeof control.appSha256 === "string" && /^[a-f0-9]{64}$/.test(control.appSha256));
|
|
9051
9053
|
}
|
|
@@ -10879,7 +10881,7 @@ function replaceSkillSession(expected, replacement, plan, options = {}, beforeCo
|
|
|
10879
10881
|
// package.json
|
|
10880
10882
|
var package_default = {
|
|
10881
10883
|
name: "@hasna/skills",
|
|
10882
|
-
version: "0.10.
|
|
10884
|
+
version: "0.10.24",
|
|
10883
10885
|
description: "Skills library for AI coding agents",
|
|
10884
10886
|
type: "module",
|
|
10885
10887
|
bin: {
|
|
@@ -13367,6 +13369,77 @@ function appControls(path, read2) {
|
|
|
13367
13369
|
}
|
|
13368
13370
|
return sha2562;
|
|
13369
13371
|
}
|
|
13372
|
+
function mcpControls(path, read2) {
|
|
13373
|
+
const text2 = read2(path);
|
|
13374
|
+
let value, sha2562;
|
|
13375
|
+
try {
|
|
13376
|
+
sha2562 = hashNativeJsonControls(text2);
|
|
13377
|
+
value = JSON.parse(text2);
|
|
13378
|
+
} catch {
|
|
13379
|
+
refuse2();
|
|
13380
|
+
}
|
|
13381
|
+
const object5 = (v) => Boolean(v && typeof v === "object" && !Array.isArray(v));
|
|
13382
|
+
const textField = (v, empty = false) => typeof v === "string" && (empty || Boolean(v.trim())) && Buffer.byteLength(v) <= 16384 && !/[\x00-\x1f\x7f]/.test(v);
|
|
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
|
+
];
|
|
13411
|
+
if (!object5(value) || Object.keys(value).length !== 1 || !object5(value.mcpServers))
|
|
13412
|
+
refuse2();
|
|
13413
|
+
const servers = Object.entries(value.mcpServers);
|
|
13414
|
+
if (!servers.length || servers.length > 256)
|
|
13415
|
+
refuse2();
|
|
13416
|
+
for (const [name, server] of servers) {
|
|
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))
|
|
13418
|
+
refuse2();
|
|
13419
|
+
if (server.env_vars !== undefined && server.env_vars !== null) {
|
|
13420
|
+
if (!Array.isArray(server.env_vars) || server.env_vars.length > 256)
|
|
13421
|
+
refuse2();
|
|
13422
|
+
const names = server.env_vars.map((entry) => {
|
|
13423
|
+
if (envName(entry))
|
|
13424
|
+
return entry;
|
|
13425
|
+
if (!object5(entry) || !Object.keys(entry).every((key) => ["name", "source"].includes(key)) || !envName(entry.name) || !optional(entry.source, (v) => v === "local"))
|
|
13426
|
+
refuse2();
|
|
13427
|
+
return entry.name;
|
|
13428
|
+
});
|
|
13429
|
+
if (new Set(names).size !== names.length)
|
|
13430
|
+
refuse2();
|
|
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
|
+
}
|
|
13440
|
+
}
|
|
13441
|
+
return sha2562;
|
|
13442
|
+
}
|
|
13370
13443
|
function rootControls(root, read2) {
|
|
13371
13444
|
const manifestPath = join14(root, ".codex-plugin/plugin.json"), manifestFile = lstatSync12(manifestPath, { throwIfNoEntry: false });
|
|
13372
13445
|
if (!lstatSync12(join14(root, ".codex-plugin"), { throwIfNoEntry: false })?.isDirectory() || !manifestFile?.isFile() || manifestFile.size > 1024 * 1024)
|
|
@@ -13384,15 +13457,21 @@ function rootControls(root, read2) {
|
|
|
13384
13457
|
const cacheVersion = basename5(root), declaredVersion = manifest.version === undefined ? "" : typeof manifest.version === "string" ? manifest.version.trim() : null;
|
|
13385
13458
|
if (declaredVersion === null || (declaredVersion ? declaredVersion !== cacheVersion : cacheVersion !== CODEX_DEFAULT_AGENT_PLUGIN_VERSION))
|
|
13386
13459
|
refuse2();
|
|
13387
|
-
if (manifest.hooks !== undefined || manifest.
|
|
13460
|
+
if (manifest.hooks !== undefined || manifest.commands !== undefined || manifest.mcpServers !== undefined && manifest.mcpServers !== "./.mcp.json" || manifest.apps !== undefined && manifest.apps !== "./.app.json" || lstatSync12(join14(root, "hooks"), { throwIfNoEntry: false }))
|
|
13461
|
+
refuse2();
|
|
13462
|
+
const mcp = join14(root, ".mcp.json"), mcpPresent = lstatSync12(mcp, { throwIfNoEntry: false });
|
|
13463
|
+
if (mcpPresent && (!mcpPresent.isFile() || mcpPresent.isSymbolicLink() || mcpPresent.size > 1024 * 1024 || realpathSync5(mcp) !== mcp))
|
|
13464
|
+
refuse2();
|
|
13465
|
+
if (Boolean(mcpPresent) !== (manifest.mcpServers !== undefined))
|
|
13388
13466
|
refuse2();
|
|
13467
|
+
const mcpSha256 = mcpPresent ? mcpControls(mcp, read2) : undefined;
|
|
13389
13468
|
const app = join14(root, ".app.json"), present = lstatSync12(app, { throwIfNoEntry: false });
|
|
13390
13469
|
if (present && (!present.isFile() || present.isSymbolicLink() || present.size > 1024 * 1024))
|
|
13391
13470
|
refuse2();
|
|
13392
13471
|
if (manifest.apps !== undefined && !present)
|
|
13393
13472
|
refuse2();
|
|
13394
13473
|
const appSha256 = present ? appControls(app, read2) : undefined;
|
|
13395
|
-
return { namespace: manifest.name, manifestSha256, ...appSha256 ? { appSha256 } : {} };
|
|
13474
|
+
return { namespace: manifest.name, manifestSha256, ...appSha256 ? { appSha256 } : {}, ...mcpSha256 ? { mcpSha256 } : {} };
|
|
13396
13475
|
}
|
|
13397
13476
|
function identity3(document2, cache, read2) {
|
|
13398
13477
|
if (!document2.startsWith(cache + sep4) || !document2.endsWith(sep4 + "SKILL.md"))
|
|
@@ -13455,7 +13534,7 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache, controls, read2) {
|
|
|
13455
13534
|
if (!stat.isDirectory() || ![".codex-plugin/plugin.json", ".app.json", "hooks", ".mcp.json"].some((path) => lstatSync12(join14(root, path), { throwIfNoEntry: false })))
|
|
13456
13535
|
continue;
|
|
13457
13536
|
const parsed = rootControls(root, read2);
|
|
13458
|
-
if (!controls.some((control) => control.pluginParent === parent && control.namespace === parsed.namespace && control.manifestSha256 === parsed.manifestSha256 && control.appSha256 === parsed.appSha256))
|
|
13537
|
+
if (!controls.some((control) => control.pluginParent === parent && control.namespace === parsed.namespace && control.manifestSha256 === parsed.manifestSha256 && control.appSha256 === parsed.appSha256 && control.mcpSha256 === parsed.mcpSha256))
|
|
13459
13538
|
return false;
|
|
13460
13539
|
}
|
|
13461
13540
|
}
|
|
@@ -13515,7 +13594,7 @@ function reviewCodexPluginSkillControls(catalog, documents, cache, cwd, read2, r
|
|
|
13515
13594
|
}
|
|
13516
13595
|
result.push({ ...parsed, pluginId: expectedPluginId, ...remotePluginId ? { remotePluginId } : {} });
|
|
13517
13596
|
}
|
|
13518
|
-
if (!result.length || new Set(result.map((item) => item.name)).size !== result.length)
|
|
13597
|
+
if (!result.length && documents.some((document2) => document2.startsWith(cache + sep4)) || new Set(result.map((item) => item.name)).size !== result.length)
|
|
13519
13598
|
refuse2();
|
|
13520
13599
|
return result;
|
|
13521
13600
|
}
|
|
@@ -13528,7 +13607,7 @@ function isReviewedCodexPluginSkillDisabled(document2, cache, controls, rules, r
|
|
|
13528
13607
|
} catch {
|
|
13529
13608
|
return false;
|
|
13530
13609
|
}
|
|
13531
|
-
const reviewed = controls.find((item) => item.name === parsed.name && item.namespace === parsed.namespace && item.pluginParent === parsed.pluginParent && item.manifestSha256 === parsed.manifestSha256 && item.appSha256 === parsed.appSha256);
|
|
13610
|
+
const reviewed = controls.find((item) => item.name === parsed.name && item.namespace === parsed.namespace && item.pluginParent === parsed.pluginParent && item.manifestSha256 === parsed.manifestSha256 && item.appSha256 === parsed.appSha256 && item.mcpSha256 === parsed.mcpSha256);
|
|
13532
13611
|
if (!reviewed || reviewed.remotePluginId !== undefined && !remoteInstallationMatches(reviewed.pluginParent, reviewed.remotePluginId, read2))
|
|
13533
13612
|
return false;
|
|
13534
13613
|
return isCodexNativeSkillDisabled({ name: parsed.name, path: document2, pluginId: reviewed.pluginId, enabled: true }, rules);
|
|
@@ -14201,10 +14280,75 @@ function disableCodexBundledSkills(text2) {
|
|
|
14201
14280
|
// src/lib/agent-integration.ts
|
|
14202
14281
|
var sha3 = (data) => createHash12("sha256").update(data).digest("hex");
|
|
14203
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
|
+
}
|
|
14204
14348
|
function assertSafePath(path) {
|
|
14205
14349
|
let cursor = resolve10(path);
|
|
14206
14350
|
while (true) {
|
|
14207
|
-
if (lstatSync15(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
14351
|
+
if (lstatSync15(cursor, { throwIfNoEntry: false })?.isSymbolicLink() && !isSystemRootAlias(cursor))
|
|
14208
14352
|
throw new Error(`Refusing symlink path: ${cursor}`);
|
|
14209
14353
|
const parent = dirname11(cursor);
|
|
14210
14354
|
if (parent === cursor)
|
|
@@ -14240,7 +14384,7 @@ function rootAliases(home, allowed = false) {
|
|
|
14240
14384
|
return result;
|
|
14241
14385
|
}
|
|
14242
14386
|
function canonicalAgentPath(path, aliases) {
|
|
14243
|
-
const absolute =
|
|
14387
|
+
const absolute = canonicalSystemPath(path), binding = aliases.find((item) => absolute === item.alias || absolute.startsWith(item.alias + sep5));
|
|
14244
14388
|
return binding ? join17(binding.target, relative5(binding.alias, absolute)) : absolute;
|
|
14245
14389
|
}
|
|
14246
14390
|
function disabledCodexSkillPaths(config, aliases) {
|
|
@@ -14338,17 +14482,19 @@ function selectNativeMigrationTargets(inventory, manifest) {
|
|
|
14338
14482
|
const identities = new Set;
|
|
14339
14483
|
const selected = [];
|
|
14340
14484
|
for (const target of manifest.targets) {
|
|
14341
|
-
|
|
14342
|
-
|
|
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())
|
|
14343
14489
|
throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
|
|
14344
14490
|
assertSafePath(projectRoot);
|
|
14345
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))
|
|
14346
14492
|
throw new Error(`Invalid native migration target: ${target.path}`);
|
|
14347
|
-
const identity4 = `${target.agent}\x00${projectRoot}\x00${normalized}`;
|
|
14493
|
+
const identity4 = `${target.agent}\x00${canonicalSystemPath(projectRoot)}\x00${normalized}`;
|
|
14348
14494
|
if (identities.has(identity4))
|
|
14349
14495
|
throw new Error(`Duplicate native migration target: ${target.path}`);
|
|
14350
14496
|
identities.add(identity4);
|
|
14351
|
-
const expected = resolve10(target.projectRoot, target.path);
|
|
14497
|
+
const expected = canonicalSystemPath(resolve10(target.projectRoot, target.path));
|
|
14352
14498
|
const matches = inventory.filter((entry2) => entry2.agent === target.agent && resolve10(entry2.path) === expected);
|
|
14353
14499
|
if (matches.length !== 1)
|
|
14354
14500
|
throw new Error(`Native migration target was not found exactly once: ${target.agent} ${target.projectRoot}/${target.path}`);
|
|
@@ -14364,7 +14510,7 @@ function selectNativeMigrationTargets(inventory, manifest) {
|
|
|
14364
14510
|
function projectAncestorDirectories(projects) {
|
|
14365
14511
|
const directories = new Set;
|
|
14366
14512
|
for (const project of projects) {
|
|
14367
|
-
for (let path =
|
|
14513
|
+
for (let path = canonicalSystemPath(project), depth = 0;; depth++) {
|
|
14368
14514
|
if (depth >= 100)
|
|
14369
14515
|
throw new Error("NATIVE_SKILL_DRIFT: project ancestor discovery limit exceeded");
|
|
14370
14516
|
directories.add(path);
|
|
@@ -14377,11 +14523,13 @@ function projectAncestorDirectories(projects) {
|
|
|
14377
14523
|
return [...directories];
|
|
14378
14524
|
}
|
|
14379
14525
|
function inventoryNativeSkills(home = homedir2(), options = {}) {
|
|
14526
|
+
home = canonicalSystemPath(home);
|
|
14380
14527
|
if (options.reviewedCacheAlias !== undefined && (!options.includeVendor || !isAbsolute11(options.reviewedCacheAlias) || resolve10(options.reviewedCacheAlias) !== options.reviewedCacheAlias))
|
|
14381
14528
|
throw new Error("A reviewed cache alias requires vendor inventory and an exact absolute path");
|
|
14382
14529
|
if (options.disabledVendorPaths?.some((path) => !isAbsolute11(path) || resolve10(path) !== path))
|
|
14383
14530
|
throw new Error("Disabled vendor paths must be exact absolute paths");
|
|
14384
|
-
const
|
|
14531
|
+
const reviewedCacheAlias = options.reviewedCacheAlias === undefined ? undefined : canonicalSystemPath(options.reviewedCacheAlias);
|
|
14532
|
+
const disabledVendorPaths = new Set((options.disabledVendorPaths ?? []).map(canonicalSystemPath));
|
|
14385
14533
|
const aliases = rootAliases(home, options.allowRootAliases);
|
|
14386
14534
|
const selectedAgents = options.agents ? new Set(options.agents) : undefined;
|
|
14387
14535
|
const includesAgent = (agent) => !selectedAgents || selectedAgents.has(agent);
|
|
@@ -14404,8 +14552,11 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
|
|
|
14404
14552
|
}
|
|
14405
14553
|
let reviewedCacheAliasFound = false;
|
|
14406
14554
|
function verifiedSiblingCacheAlias(agent, path, parent) {
|
|
14407
|
-
const link = readlinkSync4(path),
|
|
14408
|
-
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)
|
|
14409
14560
|
return false;
|
|
14410
14561
|
if (!lstatSync15(target, { throwIfNoEntry: false })?.isDirectory())
|
|
14411
14562
|
return false;
|
|
@@ -14414,11 +14565,11 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
|
|
|
14414
14565
|
return false;
|
|
14415
14566
|
if (scan.hasSkills) {
|
|
14416
14567
|
const targetSkills = entries.filter((entry) => entry.agent === agent && entry.vendor && (entry.path === target || entry.path.startsWith(target + sep5)));
|
|
14417
|
-
if (path ===
|
|
14568
|
+
if (path === reviewedCacheAlias && targetSkills.length > 0)
|
|
14418
14569
|
reviewedCacheAliasFound = true;
|
|
14419
14570
|
if (agent === "codex" && targetSkills.length > 0 && targetSkills.every((entry) => disabledVendorPaths.has(entry.path) || options.disabledVendorSkill?.(entry) === true))
|
|
14420
14571
|
return true;
|
|
14421
|
-
if (path !==
|
|
14572
|
+
if (path !== reviewedCacheAlias)
|
|
14422
14573
|
return false;
|
|
14423
14574
|
}
|
|
14424
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: {
|
|
@@ -38347,6 +38347,77 @@ function appControls(path, read) {
|
|
|
38347
38347
|
}
|
|
38348
38348
|
return sha2562;
|
|
38349
38349
|
}
|
|
38350
|
+
function mcpControls(path, read) {
|
|
38351
|
+
const text = read(path);
|
|
38352
|
+
let value, sha2562;
|
|
38353
|
+
try {
|
|
38354
|
+
sha2562 = hashNativeJsonControls(text);
|
|
38355
|
+
value = JSON.parse(text);
|
|
38356
|
+
} catch {
|
|
38357
|
+
refuse3();
|
|
38358
|
+
}
|
|
38359
|
+
const object3 = (v) => Boolean(v && typeof v === "object" && !Array.isArray(v));
|
|
38360
|
+
const textField = (v, empty = false) => typeof v === "string" && (empty || Boolean(v.trim())) && Buffer.byteLength(v) <= 16384 && !/[\x00-\x1f\x7f]/.test(v);
|
|
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
|
+
];
|
|
38389
|
+
if (!object3(value) || Object.keys(value).length !== 1 || !object3(value.mcpServers))
|
|
38390
|
+
refuse3();
|
|
38391
|
+
const servers = Object.entries(value.mcpServers);
|
|
38392
|
+
if (!servers.length || servers.length > 256)
|
|
38393
|
+
refuse3();
|
|
38394
|
+
for (const [name, server] of servers) {
|
|
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))
|
|
38396
|
+
refuse3();
|
|
38397
|
+
if (server.env_vars !== undefined && server.env_vars !== null) {
|
|
38398
|
+
if (!Array.isArray(server.env_vars) || server.env_vars.length > 256)
|
|
38399
|
+
refuse3();
|
|
38400
|
+
const names = server.env_vars.map((entry) => {
|
|
38401
|
+
if (envName(entry))
|
|
38402
|
+
return entry;
|
|
38403
|
+
if (!object3(entry) || !Object.keys(entry).every((key) => ["name", "source"].includes(key)) || !envName(entry.name) || !optional(entry.source, (v) => v === "local"))
|
|
38404
|
+
refuse3();
|
|
38405
|
+
return entry.name;
|
|
38406
|
+
});
|
|
38407
|
+
if (new Set(names).size !== names.length)
|
|
38408
|
+
refuse3();
|
|
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
|
+
}
|
|
38418
|
+
}
|
|
38419
|
+
return sha2562;
|
|
38420
|
+
}
|
|
38350
38421
|
function rootControls(root, read) {
|
|
38351
38422
|
const manifestPath = join10(root, ".codex-plugin/plugin.json"), manifestFile = lstatSync6(manifestPath, { throwIfNoEntry: false });
|
|
38352
38423
|
if (!lstatSync6(join10(root, ".codex-plugin"), { throwIfNoEntry: false })?.isDirectory() || !manifestFile?.isFile() || manifestFile.size > 1024 * 1024)
|
|
@@ -38364,15 +38435,21 @@ function rootControls(root, read) {
|
|
|
38364
38435
|
const cacheVersion = basename3(root), declaredVersion = manifest.version === undefined ? "" : typeof manifest.version === "string" ? manifest.version.trim() : null;
|
|
38365
38436
|
if (declaredVersion === null || (declaredVersion ? declaredVersion !== cacheVersion : cacheVersion !== CODEX_DEFAULT_AGENT_PLUGIN_VERSION))
|
|
38366
38437
|
refuse3();
|
|
38367
|
-
if (manifest.hooks !== undefined || manifest.
|
|
38438
|
+
if (manifest.hooks !== undefined || manifest.commands !== undefined || manifest.mcpServers !== undefined && manifest.mcpServers !== "./.mcp.json" || manifest.apps !== undefined && manifest.apps !== "./.app.json" || lstatSync6(join10(root, "hooks"), { throwIfNoEntry: false }))
|
|
38439
|
+
refuse3();
|
|
38440
|
+
const mcp = join10(root, ".mcp.json"), mcpPresent = lstatSync6(mcp, { throwIfNoEntry: false });
|
|
38441
|
+
if (mcpPresent && (!mcpPresent.isFile() || mcpPresent.isSymbolicLink() || mcpPresent.size > 1024 * 1024 || realpathSync5(mcp) !== mcp))
|
|
38442
|
+
refuse3();
|
|
38443
|
+
if (Boolean(mcpPresent) !== (manifest.mcpServers !== undefined))
|
|
38368
38444
|
refuse3();
|
|
38445
|
+
const mcpSha256 = mcpPresent ? mcpControls(mcp, read) : undefined;
|
|
38369
38446
|
const app = join10(root, ".app.json"), present = lstatSync6(app, { throwIfNoEntry: false });
|
|
38370
38447
|
if (present && (!present.isFile() || present.isSymbolicLink() || present.size > 1024 * 1024))
|
|
38371
38448
|
refuse3();
|
|
38372
38449
|
if (manifest.apps !== undefined && !present)
|
|
38373
38450
|
refuse3();
|
|
38374
38451
|
const appSha256 = present ? appControls(app, read) : undefined;
|
|
38375
|
-
return { namespace: manifest.name, manifestSha256, ...appSha256 ? { appSha256 } : {} };
|
|
38452
|
+
return { namespace: manifest.name, manifestSha256, ...appSha256 ? { appSha256 } : {}, ...mcpSha256 ? { mcpSha256 } : {} };
|
|
38376
38453
|
}
|
|
38377
38454
|
function identity(document, cache, read) {
|
|
38378
38455
|
if (!document.startsWith(cache + sep2) || !document.endsWith(sep2 + "SKILL.md"))
|
|
@@ -38435,7 +38512,7 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache, controls, read) {
|
|
|
38435
38512
|
if (!stat.isDirectory() || ![".codex-plugin/plugin.json", ".app.json", "hooks", ".mcp.json"].some((path) => lstatSync6(join10(root, path), { throwIfNoEntry: false })))
|
|
38436
38513
|
continue;
|
|
38437
38514
|
const parsed = rootControls(root, read);
|
|
38438
|
-
if (!controls.some((control) => control.pluginParent === parent && control.namespace === parsed.namespace && control.manifestSha256 === parsed.manifestSha256 && control.appSha256 === parsed.appSha256))
|
|
38515
|
+
if (!controls.some((control) => control.pluginParent === parent && control.namespace === parsed.namespace && control.manifestSha256 === parsed.manifestSha256 && control.appSha256 === parsed.appSha256 && control.mcpSha256 === parsed.mcpSha256))
|
|
38439
38516
|
return false;
|
|
38440
38517
|
}
|
|
38441
38518
|
}
|
|
@@ -38495,7 +38572,7 @@ function reviewCodexPluginSkillControls(catalog, documents, cache, cwd, read, ru
|
|
|
38495
38572
|
}
|
|
38496
38573
|
result.push({ ...parsed, pluginId: expectedPluginId, ...remotePluginId ? { remotePluginId } : {} });
|
|
38497
38574
|
}
|
|
38498
|
-
if (!result.length || new Set(result.map((item) => item.name)).size !== result.length)
|
|
38575
|
+
if (!result.length && documents.some((document) => document.startsWith(cache + sep2)) || new Set(result.map((item) => item.name)).size !== result.length)
|
|
38499
38576
|
refuse3();
|
|
38500
38577
|
return result;
|
|
38501
38578
|
}
|
|
@@ -38508,7 +38585,7 @@ function isReviewedCodexPluginSkillDisabled(document, cache, controls, rules, re
|
|
|
38508
38585
|
} catch {
|
|
38509
38586
|
return false;
|
|
38510
38587
|
}
|
|
38511
|
-
const reviewed = controls.find((item) => item.name === parsed.name && item.namespace === parsed.namespace && item.pluginParent === parsed.pluginParent && item.manifestSha256 === parsed.manifestSha256 && item.appSha256 === parsed.appSha256);
|
|
38588
|
+
const reviewed = controls.find((item) => item.name === parsed.name && item.namespace === parsed.namespace && item.pluginParent === parsed.pluginParent && item.manifestSha256 === parsed.manifestSha256 && item.appSha256 === parsed.appSha256 && item.mcpSha256 === parsed.mcpSha256);
|
|
38512
38589
|
if (!reviewed || reviewed.remotePluginId !== undefined && !remoteInstallationMatches(reviewed.pluginParent, reviewed.remotePluginId, read))
|
|
38513
38590
|
return false;
|
|
38514
38591
|
return isCodexNativeSkillDisabled({ name: parsed.name, path: document, pluginId: reviewed.pluginId, enabled: true }, rules);
|
|
@@ -38860,7 +38937,7 @@ function assertAgentPolicyCollections(policy) {
|
|
|
38860
38937
|
}
|
|
38861
38938
|
if (bridge.codexPluginSkills !== undefined)
|
|
38862
38939
|
for (const control of array(bridge.codexPluginSkills, 4096)) {
|
|
38863
|
-
requireBound(object3(control) && Object.keys(control).every((key) => ["name", "pluginId", "namespace", "pluginParent", "manifestSha256", "appSha256", "remotePluginId"].includes(key)));
|
|
38940
|
+
requireBound(object3(control) && Object.keys(control).every((key) => ["name", "pluginId", "namespace", "pluginParent", "manifestSha256", "appSha256", "mcpSha256", "remotePluginId"].includes(key)));
|
|
38864
38941
|
text(control.name, 129);
|
|
38865
38942
|
text(control.pluginId, 1024);
|
|
38866
38943
|
text(control.namespace, 64);
|
|
@@ -38868,6 +38945,8 @@ function assertAgentPolicyCollections(policy) {
|
|
|
38868
38945
|
requireBound(isAbsolute6(control.pluginParent) && resolve5(control.pluginParent) === control.pluginParent && /^[a-f0-9]{64}$/.test(control.manifestSha256));
|
|
38869
38946
|
if (control.remotePluginId !== undefined)
|
|
38870
38947
|
requireBound(typeof control.remotePluginId === "string" && /^[A-Za-z0-9_~-]{1,1024}$/.test(control.remotePluginId));
|
|
38948
|
+
if (control.mcpSha256 !== undefined)
|
|
38949
|
+
requireBound(typeof control.mcpSha256 === "string" && /^[a-f0-9]{64}$/.test(control.mcpSha256));
|
|
38871
38950
|
if (control.appSha256 !== undefined)
|
|
38872
38951
|
requireBound(typeof control.appSha256 === "string" && /^[a-f0-9]{64}$/.test(control.appSha256));
|
|
38873
38952
|
}
|
|
@@ -42096,10 +42175,75 @@ function disableCodexBundledSkills(text2) {
|
|
|
42096
42175
|
// src/lib/agent-integration.ts
|
|
42097
42176
|
var sha4 = (data) => createHash18("sha256").update(data).digest("hex");
|
|
42098
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
|
+
}
|
|
42099
42243
|
function assertSafePath(path) {
|
|
42100
42244
|
let cursor = resolve15(path);
|
|
42101
42245
|
while (true) {
|
|
42102
|
-
if (lstatSync19(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
42246
|
+
if (lstatSync19(cursor, { throwIfNoEntry: false })?.isSymbolicLink() && !isSystemRootAlias(cursor))
|
|
42103
42247
|
throw new Error(`Refusing symlink path: ${cursor}`);
|
|
42104
42248
|
const parent = dirname15(cursor);
|
|
42105
42249
|
if (parent === cursor)
|
|
@@ -42135,7 +42279,7 @@ function rootAliases(home, allowed = false) {
|
|
|
42135
42279
|
return result;
|
|
42136
42280
|
}
|
|
42137
42281
|
function canonicalAgentPath(path, aliases) {
|
|
42138
|
-
const absolute =
|
|
42282
|
+
const absolute = canonicalSystemPath(path), binding = aliases.find((item) => absolute === item.alias || absolute.startsWith(item.alias + sep5));
|
|
42139
42283
|
return binding ? join22(binding.target, relative4(binding.alias, absolute)) : absolute;
|
|
42140
42284
|
}
|
|
42141
42285
|
function disabledCodexSkillPaths(config, aliases) {
|
|
@@ -42233,17 +42377,19 @@ function selectNativeMigrationTargets(inventory, manifest) {
|
|
|
42233
42377
|
const identities = new Set;
|
|
42234
42378
|
const selected = [];
|
|
42235
42379
|
for (const target of manifest.targets) {
|
|
42236
|
-
|
|
42237
|
-
|
|
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())
|
|
42238
42384
|
throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
|
|
42239
42385
|
assertSafePath(projectRoot);
|
|
42240
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))
|
|
42241
42387
|
throw new Error(`Invalid native migration target: ${target.path}`);
|
|
42242
|
-
const identity4 = `${target.agent}\x00${projectRoot}\x00${normalized}`;
|
|
42388
|
+
const identity4 = `${target.agent}\x00${canonicalSystemPath(projectRoot)}\x00${normalized}`;
|
|
42243
42389
|
if (identities.has(identity4))
|
|
42244
42390
|
throw new Error(`Duplicate native migration target: ${target.path}`);
|
|
42245
42391
|
identities.add(identity4);
|
|
42246
|
-
const expected = resolve15(target.projectRoot, target.path);
|
|
42392
|
+
const expected = canonicalSystemPath(resolve15(target.projectRoot, target.path));
|
|
42247
42393
|
const matches = inventory.filter((entry2) => entry2.agent === target.agent && resolve15(entry2.path) === expected);
|
|
42248
42394
|
if (matches.length !== 1)
|
|
42249
42395
|
throw new Error(`Native migration target was not found exactly once: ${target.agent} ${target.projectRoot}/${target.path}`);
|
|
@@ -42259,7 +42405,7 @@ function selectNativeMigrationTargets(inventory, manifest) {
|
|
|
42259
42405
|
function projectAncestorDirectories(projects) {
|
|
42260
42406
|
const directories = new Set;
|
|
42261
42407
|
for (const project of projects) {
|
|
42262
|
-
for (let path =
|
|
42408
|
+
for (let path = canonicalSystemPath(project), depth = 0;; depth++) {
|
|
42263
42409
|
if (depth >= 100)
|
|
42264
42410
|
throw new Error("NATIVE_SKILL_DRIFT: project ancestor discovery limit exceeded");
|
|
42265
42411
|
directories.add(path);
|
|
@@ -42272,11 +42418,13 @@ function projectAncestorDirectories(projects) {
|
|
|
42272
42418
|
return [...directories];
|
|
42273
42419
|
}
|
|
42274
42420
|
function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
42421
|
+
home = canonicalSystemPath(home);
|
|
42275
42422
|
if (options.reviewedCacheAlias !== undefined && (!options.includeVendor || !isAbsolute17(options.reviewedCacheAlias) || resolve15(options.reviewedCacheAlias) !== options.reviewedCacheAlias))
|
|
42276
42423
|
throw new Error("A reviewed cache alias requires vendor inventory and an exact absolute path");
|
|
42277
42424
|
if (options.disabledVendorPaths?.some((path) => !isAbsolute17(path) || resolve15(path) !== path))
|
|
42278
42425
|
throw new Error("Disabled vendor paths must be exact absolute paths");
|
|
42279
|
-
const
|
|
42426
|
+
const reviewedCacheAlias = options.reviewedCacheAlias === undefined ? undefined : canonicalSystemPath(options.reviewedCacheAlias);
|
|
42427
|
+
const disabledVendorPaths = new Set((options.disabledVendorPaths ?? []).map(canonicalSystemPath));
|
|
42280
42428
|
const aliases = rootAliases(home, options.allowRootAliases);
|
|
42281
42429
|
const selectedAgents = options.agents ? new Set(options.agents) : undefined;
|
|
42282
42430
|
const includesAgent = (agent) => !selectedAgents || selectedAgents.has(agent);
|
|
@@ -42299,8 +42447,11 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
42299
42447
|
}
|
|
42300
42448
|
let reviewedCacheAliasFound = false;
|
|
42301
42449
|
function verifiedSiblingCacheAlias(agent, path, parent) {
|
|
42302
|
-
const link = readlinkSync4(path),
|
|
42303
|
-
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)
|
|
42304
42455
|
return false;
|
|
42305
42456
|
if (!lstatSync19(target, { throwIfNoEntry: false })?.isDirectory())
|
|
42306
42457
|
return false;
|
|
@@ -42309,11 +42460,11 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
42309
42460
|
return false;
|
|
42310
42461
|
if (scan.hasSkills) {
|
|
42311
42462
|
const targetSkills = entries.filter((entry) => entry.agent === agent && entry.vendor && (entry.path === target || entry.path.startsWith(target + sep5)));
|
|
42312
|
-
if (path ===
|
|
42463
|
+
if (path === reviewedCacheAlias && targetSkills.length > 0)
|
|
42313
42464
|
reviewedCacheAliasFound = true;
|
|
42314
42465
|
if (agent === "codex" && targetSkills.length > 0 && targetSkills.every((entry) => disabledVendorPaths.has(entry.path) || options.disabledVendorSkill?.(entry) === true))
|
|
42315
42466
|
return true;
|
|
42316
|
-
if (path !==
|
|
42467
|
+
if (path !== reviewedCacheAlias)
|
|
42317
42468
|
return false;
|
|
42318
42469
|
}
|
|
42319
42470
|
return true;
|