@hasna/skills 0.10.20 → 0.10.23
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 +39 -8
- package/bin/index.js +652 -354
- package/bin/mcp.js +310 -119
- package/bin/migrate.js +1 -1
- package/bin/server.js +1 -1
- package/bin/worker.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +466 -177
- package/dist/lib/agent-discovery.d.ts +4 -1
- package/dist/lib/agent-integration.d.ts +4 -0
- package/dist/lib/codex-hook-rpc.d.ts +1 -1
- package/dist/lib/codex-native-compatibility.d.ts +3 -0
- package/dist/lib/codex-native-skill-catalog.d.ts +4 -0
- package/dist/lib/codex-plugin-skill-controls.d.ts +2 -0
- package/dist/lib/codex-settings-witness-v1.d.ts +12 -0
- package/dist/lib/codex-settings-witness.d.ts +13 -5
- package/dist/sdk/index.js +537 -249
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7262,7 +7262,7 @@ import {
|
|
|
7262
7262
|
statSync as statSync10,
|
|
7263
7263
|
writeFileSync as writeFileSync8
|
|
7264
7264
|
} from "fs";
|
|
7265
|
-
import { basename as basename11, dirname as dirname19, isAbsolute as isAbsolute17, join as join29, normalize as
|
|
7265
|
+
import { basename as basename11, dirname as dirname19, isAbsolute as isAbsolute17, join as join29, normalize as normalize4, relative as relative6, resolve as resolve17, sep as sep8 } from "path";
|
|
7266
7266
|
|
|
7267
7267
|
// src/lib/registry-data/index.ts
|
|
7268
7268
|
var SKILLS = [];
|
|
@@ -9038,12 +9038,16 @@ 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"].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);
|
|
9045
9045
|
text(control.pluginParent);
|
|
9046
9046
|
requireBound(isAbsolute2(control.pluginParent) && resolve2(control.pluginParent) === control.pluginParent && /^[a-f0-9]{64}$/.test(control.manifestSha256));
|
|
9047
|
+
if (control.remotePluginId !== undefined)
|
|
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));
|
|
9047
9051
|
if (control.appSha256 !== undefined)
|
|
9048
9052
|
requireBound(typeof control.appSha256 === "string" && /^[a-f0-9]{64}$/.test(control.appSha256));
|
|
9049
9053
|
}
|
|
@@ -9066,8 +9070,8 @@ function assertAgentPolicyCollections(policy) {
|
|
|
9066
9070
|
text(source.path);
|
|
9067
9071
|
requireBound(source.sha256 === null || typeof source.sha256 === "string" && /^[a-f0-9]{64}$/.test(source.sha256));
|
|
9068
9072
|
if (source.hashMode !== undefined)
|
|
9069
|
-
requireBound(["bytes", "path-bytes", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1", "claude-settings-v2", "claude-settings-v3", "claude-marketplace-registry-v2", "codex-settings-v1"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
|
|
9070
|
-
if (source.hashMode === "codex-settings-v1")
|
|
9073
|
+
requireBound(["bytes", "path-bytes", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1", "claude-settings-v2", "claude-settings-v3", "claude-marketplace-registry-v2", "codex-settings-v1", "codex-settings-v2"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
|
|
9074
|
+
if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2")
|
|
9071
9075
|
requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute2(source.path) && resolve2(source.path) === source.path && basename2(source.path) === "config.toml");
|
|
9072
9076
|
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3")
|
|
9073
9077
|
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute2(source.path) && resolve2(source.path) === source.path && basename2(source.path) === "settings.json");
|
|
@@ -9103,10 +9107,10 @@ function assertAgentPolicyCollections(policy) {
|
|
|
9103
9107
|
}
|
|
9104
9108
|
|
|
9105
9109
|
// src/lib/agent-discovery.ts
|
|
9106
|
-
import { createHash as
|
|
9110
|
+
import { createHash as createHash18 } from "crypto";
|
|
9107
9111
|
import { lstatSync as lstatSync21, readFileSync as readFileSync17, readdirSync as readdirSync10, realpathSync as realpathSync7 } from "fs";
|
|
9108
9112
|
import { basename as basename9, dirname as dirname17, isAbsolute as isAbsolute16, join as join27, resolve as resolve15, sep as sep6 } from "path";
|
|
9109
|
-
import { isDeepStrictEqual as
|
|
9113
|
+
import { isDeepStrictEqual as isDeepStrictEqual4 } from "util";
|
|
9110
9114
|
|
|
9111
9115
|
// node_modules/yaml/dist/index.js
|
|
9112
9116
|
var composer = require_composer();
|
|
@@ -10877,7 +10881,7 @@ function replaceSkillSession(expected, replacement, plan, options = {}, beforeCo
|
|
|
10877
10881
|
// package.json
|
|
10878
10882
|
var package_default = {
|
|
10879
10883
|
name: "@hasna/skills",
|
|
10880
|
-
version: "0.10.
|
|
10884
|
+
version: "0.10.23",
|
|
10881
10885
|
description: "Skills library for AI coding agents",
|
|
10882
10886
|
type: "module",
|
|
10883
10887
|
bin: {
|
|
@@ -13027,6 +13031,25 @@ function hashNativeJsonControls(text2, excludedMetadata) {
|
|
|
13027
13031
|
import { basename as basename5, dirname as dirname10, join as join14, relative as relative4, resolve as resolve9, sep as sep4 } from "path";
|
|
13028
13032
|
import { lstatSync as lstatSync12, readdirSync as readdirSync6, readlinkSync as readlinkSync3, realpathSync as realpathSync5 } from "fs";
|
|
13029
13033
|
|
|
13034
|
+
// src/lib/codex-native-compatibility.ts
|
|
13035
|
+
var MEASURED_CODEX_CAPABILITIES = {
|
|
13036
|
+
"codex-cli 0.153.0": ["hooks"],
|
|
13037
|
+
"codex-cli 0.154.0": ["hooks"],
|
|
13038
|
+
"codex-cli 0.155.0": ["hooks"],
|
|
13039
|
+
"codex-cli 0.155.1": ["hooks"],
|
|
13040
|
+
"codex-cli 0.156.1": ["hooks"],
|
|
13041
|
+
"codex-cli 0.157.0": ["hooks"],
|
|
13042
|
+
"codex-cli 0.157.1": ["hooks"],
|
|
13043
|
+
"codex-cli 0.158.0": ["hooks"],
|
|
13044
|
+
"codex-cli 0.159.0": ["hooks"],
|
|
13045
|
+
"codex-cli 0.159.2": ["hooks", "qualified-skill-catalog"],
|
|
13046
|
+
"codex-cli 0.160.0": ["hooks", "qualified-skill-catalog"]
|
|
13047
|
+
};
|
|
13048
|
+
function supportsCodexNativeCapability(version, capability) {
|
|
13049
|
+
return typeof version === "string" && Object.hasOwn(MEASURED_CODEX_CAPABILITIES, version) && MEASURED_CODEX_CAPABILITIES[version].includes(capability);
|
|
13050
|
+
}
|
|
13051
|
+
var SUPPORTED_CODEX_HOOK_VERSIONS = Object.freeze(Object.keys(MEASURED_CODEX_CAPABILITIES).filter((version) => supportsCodexNativeCapability(version, "hooks")));
|
|
13052
|
+
|
|
13030
13053
|
// src/lib/codex-native-skill-catalog.ts
|
|
13031
13054
|
import { realpathSync as realpathSync4 } from "fs";
|
|
13032
13055
|
import { isAbsolute as isAbsolute10, normalize as normalize2 } from "path";
|
|
@@ -13036,7 +13059,6 @@ import { execFile, spawn } from "child_process";
|
|
|
13036
13059
|
import { realpathSync as realpathSync3, statSync as statSync7 } from "fs";
|
|
13037
13060
|
import { isAbsolute as isAbsolute9 } from "path";
|
|
13038
13061
|
import { promisify } from "util";
|
|
13039
|
-
var SUPPORTED_CODEX_HOOK_VERSIONS = ["codex-cli 0.153.0", "codex-cli 0.154.0", "codex-cli 0.155.0", "codex-cli 0.155.1", "codex-cli 0.156.1", "codex-cli 0.157.0", "codex-cli 0.157.1", "codex-cli 0.158.0", "codex-cli 0.159.0", "codex-cli 0.159.2"];
|
|
13040
13062
|
async function connectCodexHookRpc(options) {
|
|
13041
13063
|
const timeoutMs = options.timeoutMs ?? 20000;
|
|
13042
13064
|
if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 100 || timeoutMs > 20000)
|
|
@@ -13054,7 +13076,7 @@ async function connectCodexHookRpc(options) {
|
|
|
13054
13076
|
} catch {
|
|
13055
13077
|
throw new Error("CODEX_HOOK_TRUST_NATIVE_UNAVAILABLE");
|
|
13056
13078
|
}
|
|
13057
|
-
if (!
|
|
13079
|
+
if (!supportsCodexNativeCapability(version, "hooks"))
|
|
13058
13080
|
throw new Error("CODEX_HOOK_TRUST_NATIVE_UNSUPPORTED_VERSION");
|
|
13059
13081
|
const current = statSync7(binary);
|
|
13060
13082
|
if (realpathSync3(found) !== binary || ["dev", "ino", "size", "mtimeMs", "ctimeMs"].some((k) => stat[k] !== current[k]))
|
|
@@ -13179,12 +13201,12 @@ var MAX_SKILLS = 4096;
|
|
|
13179
13201
|
var MAX_NAME_BYTES = 1024;
|
|
13180
13202
|
var MAX_PATH_BYTES = 16384;
|
|
13181
13203
|
var MAX_PLUGIN_ID_BYTES = 1024;
|
|
13182
|
-
var SUPPORTED_NAME_CONTROL_VERSIONS = new Set(["codex-cli 0.159.2"]);
|
|
13183
13204
|
function refuse() {
|
|
13184
13205
|
throw new Error("CODEX_NATIVE_SKILL_CATALOG_INVALID");
|
|
13185
13206
|
}
|
|
13186
13207
|
var object4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
13187
13208
|
var scalar = (value, max) => typeof value === "string" && value.length > 0 && value.trim() === value && Buffer.byteLength(value, "utf8") <= max && !/[\u0000-\u001f\u007f]/u.test(value);
|
|
13209
|
+
var remotePluginIdentifier = (value) => typeof value === "string" && /^[A-Za-z0-9_~-]{1,1024}$/.test(value);
|
|
13188
13210
|
var absolutePath2 = (value) => scalar(value, MAX_PATH_BYTES) && isAbsolute10(value);
|
|
13189
13211
|
function projectCodexNativeSkillCatalog(response, cwd) {
|
|
13190
13212
|
if (!absolutePath2(cwd) || !object4(response) || !Array.isArray(response.data) || response.data.length !== 1)
|
|
@@ -13212,7 +13234,11 @@ function projectCodexInstalledPlugins(response) {
|
|
|
13212
13234
|
for (const value of marketplace.plugins) {
|
|
13213
13235
|
if (!object4(value) || !scalar(value.id, MAX_PLUGIN_ID_BYTES) || !scalar(value.name, MAX_NAME_BYTES) || value.id !== `${value.name}@${marketplace.name}`)
|
|
13214
13236
|
refuse();
|
|
13215
|
-
plugins.push({
|
|
13237
|
+
plugins.push({
|
|
13238
|
+
...value,
|
|
13239
|
+
marketplace: marketplace.name,
|
|
13240
|
+
sourceType: object4(value.source) && value.source.type === "remote" ? "remote" : undefined
|
|
13241
|
+
});
|
|
13216
13242
|
}
|
|
13217
13243
|
}
|
|
13218
13244
|
return projectCodexInstalledPluginEntries(plugins);
|
|
@@ -13222,13 +13248,21 @@ function projectCodexInstalledPluginEntries(value) {
|
|
|
13222
13248
|
refuse();
|
|
13223
13249
|
const ids = new Set;
|
|
13224
13250
|
return value.map((item) => {
|
|
13225
|
-
if (!object4(item) || !scalar(item.id, MAX_PLUGIN_ID_BYTES) || !scalar(item.name, MAX_NAME_BYTES) || typeof item.installed !== "boolean" || typeof item.enabled !== "boolean" || item.localVersion !== null && !scalar(item.localVersion, MAX_NAME_BYTES))
|
|
13251
|
+
if (!object4(item) || !scalar(item.id, MAX_PLUGIN_ID_BYTES) || !scalar(item.name, MAX_NAME_BYTES) || typeof item.installed !== "boolean" || typeof item.enabled !== "boolean" || item.localVersion !== null && !scalar(item.localVersion, MAX_NAME_BYTES) || item.remotePluginId !== undefined && item.remotePluginId !== null && !remotePluginIdentifier(item.remotePluginId) || item.sourceType !== undefined && item.sourceType !== "remote")
|
|
13226
13252
|
refuse();
|
|
13227
13253
|
const at = item.id.lastIndexOf("@");
|
|
13228
13254
|
if (at < 1 || item.id.slice(0, at) !== item.name || at === item.id.length - 1 || ids.has(item.id))
|
|
13229
13255
|
refuse();
|
|
13230
13256
|
ids.add(item.id);
|
|
13231
|
-
return {
|
|
13257
|
+
return {
|
|
13258
|
+
id: item.id,
|
|
13259
|
+
name: item.name,
|
|
13260
|
+
installed: item.installed,
|
|
13261
|
+
enabled: item.enabled,
|
|
13262
|
+
localVersion: item.localVersion ?? null,
|
|
13263
|
+
...item.sourceType === "remote" ? { sourceType: "remote" } : {},
|
|
13264
|
+
...item.remotePluginId == null ? {} : { remotePluginId: item.remotePluginId }
|
|
13265
|
+
};
|
|
13232
13266
|
});
|
|
13233
13267
|
}
|
|
13234
13268
|
async function captureCodexNativeSkillCatalog(options, connect = connectCodexHookRpc) {
|
|
@@ -13241,7 +13275,7 @@ async function captureCodexNativeSkillCatalog(options, connect = connectCodexHoo
|
|
|
13241
13275
|
...options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }
|
|
13242
13276
|
});
|
|
13243
13277
|
try {
|
|
13244
|
-
if (!
|
|
13278
|
+
if (!supportsCodexNativeCapability(rpc.version, "qualified-skill-catalog"))
|
|
13245
13279
|
throw new Error("CODEX_NATIVE_SKILL_CATALOG_UNSUPPORTED_VERSION");
|
|
13246
13280
|
const response = await rpc.request("skills/list", { cwds: [options.cwd], forceReload: true });
|
|
13247
13281
|
const installed = await rpc.request("plugin/installed", { cwds: [options.cwd] });
|
|
@@ -13299,6 +13333,21 @@ var CODEX_DEFAULT_AGENT_PLUGIN_VERSION = "1.0.0";
|
|
|
13299
13333
|
function refuse2() {
|
|
13300
13334
|
throw new Error("CODEX_NATIVE_SKILL_IDENTITY_UNSUPPORTED: review native plugin names and hook controls");
|
|
13301
13335
|
}
|
|
13336
|
+
function remoteInstallationMatches(parent, remotePluginId, read2) {
|
|
13337
|
+
try {
|
|
13338
|
+
if (!remotePluginIdentifier(remotePluginId) || !lstatSync12(parent).isDirectory() || realpathSync5(parent) !== parent)
|
|
13339
|
+
return false;
|
|
13340
|
+
const path = join14(parent, ".codex-remote-plugin-install.json"), stat = lstatSync12(path, { throwIfNoEntry: false });
|
|
13341
|
+
if (!stat?.isFile() || stat.isSymbolicLink() || stat.size > 16384)
|
|
13342
|
+
return false;
|
|
13343
|
+
const text2 = read2(path);
|
|
13344
|
+
hashNativeJsonControls(text2);
|
|
13345
|
+
const value = JSON.parse(text2);
|
|
13346
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 2 && value.schema_version === 1 && value.remote_plugin_id === remotePluginId);
|
|
13347
|
+
} catch {
|
|
13348
|
+
return false;
|
|
13349
|
+
}
|
|
13350
|
+
}
|
|
13302
13351
|
function appControls(path, read2) {
|
|
13303
13352
|
const text2 = read2(path);
|
|
13304
13353
|
let value, sha2562;
|
|
@@ -13320,6 +13369,42 @@ function appControls(path, read2) {
|
|
|
13320
13369
|
}
|
|
13321
13370
|
return sha2562;
|
|
13322
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
|
+
if (!object5(value) || Object.keys(value).length !== 1 || !object5(value.mcpServers))
|
|
13385
|
+
refuse2();
|
|
13386
|
+
const servers = Object.entries(value.mcpServers);
|
|
13387
|
+
if (!servers.length || servers.length > 256)
|
|
13388
|
+
refuse2();
|
|
13389
|
+
for (const [name, server] of servers) {
|
|
13390
|
+
if (!identifier2(name) || !object5(server) || !Object.keys(server).every((key) => ["command", "args", "cwd", "env_vars"].includes(key)) || !textField(server.command) || server.args !== undefined && (!Array.isArray(server.args) || server.args.length > 256 || !server.args.every((arg) => textField(arg, true))) || server.cwd !== undefined && !textField(server.cwd))
|
|
13391
|
+
refuse2();
|
|
13392
|
+
if (server.env_vars !== undefined) {
|
|
13393
|
+
if (!Array.isArray(server.env_vars) || server.env_vars.length > 256)
|
|
13394
|
+
refuse2();
|
|
13395
|
+
const names = server.env_vars.map((entry) => {
|
|
13396
|
+
if (envName(entry))
|
|
13397
|
+
return entry;
|
|
13398
|
+
if (!object5(entry) || !Object.keys(entry).every((key) => ["name", "source"].includes(key)) || !envName(entry.name) || entry.source !== undefined && entry.source !== "local")
|
|
13399
|
+
refuse2();
|
|
13400
|
+
return entry.name;
|
|
13401
|
+
});
|
|
13402
|
+
if (new Set(names).size !== names.length)
|
|
13403
|
+
refuse2();
|
|
13404
|
+
}
|
|
13405
|
+
}
|
|
13406
|
+
return sha2562;
|
|
13407
|
+
}
|
|
13323
13408
|
function rootControls(root, read2) {
|
|
13324
13409
|
const manifestPath = join14(root, ".codex-plugin/plugin.json"), manifestFile = lstatSync12(manifestPath, { throwIfNoEntry: false });
|
|
13325
13410
|
if (!lstatSync12(join14(root, ".codex-plugin"), { throwIfNoEntry: false })?.isDirectory() || !manifestFile?.isFile() || manifestFile.size > 1024 * 1024)
|
|
@@ -13337,15 +13422,21 @@ function rootControls(root, read2) {
|
|
|
13337
13422
|
const cacheVersion = basename5(root), declaredVersion = manifest.version === undefined ? "" : typeof manifest.version === "string" ? manifest.version.trim() : null;
|
|
13338
13423
|
if (declaredVersion === null || (declaredVersion ? declaredVersion !== cacheVersion : cacheVersion !== CODEX_DEFAULT_AGENT_PLUGIN_VERSION))
|
|
13339
13424
|
refuse2();
|
|
13340
|
-
if (manifest.hooks !== undefined || manifest.
|
|
13425
|
+
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 }))
|
|
13426
|
+
refuse2();
|
|
13427
|
+
const mcp = join14(root, ".mcp.json"), mcpPresent = lstatSync12(mcp, { throwIfNoEntry: false });
|
|
13428
|
+
if (mcpPresent && (!mcpPresent.isFile() || mcpPresent.isSymbolicLink() || mcpPresent.size > 1024 * 1024 || realpathSync5(mcp) !== mcp))
|
|
13341
13429
|
refuse2();
|
|
13430
|
+
if (Boolean(mcpPresent) !== (manifest.mcpServers !== undefined))
|
|
13431
|
+
refuse2();
|
|
13432
|
+
const mcpSha256 = mcpPresent ? mcpControls(mcp, read2) : undefined;
|
|
13342
13433
|
const app = join14(root, ".app.json"), present = lstatSync12(app, { throwIfNoEntry: false });
|
|
13343
13434
|
if (present && (!present.isFile() || present.isSymbolicLink() || present.size > 1024 * 1024))
|
|
13344
13435
|
refuse2();
|
|
13345
13436
|
if (manifest.apps !== undefined && !present)
|
|
13346
13437
|
refuse2();
|
|
13347
13438
|
const appSha256 = present ? appControls(app, read2) : undefined;
|
|
13348
|
-
return { namespace: manifest.name, manifestSha256, ...appSha256 ? { appSha256 } : {} };
|
|
13439
|
+
return { namespace: manifest.name, manifestSha256, ...appSha256 ? { appSha256 } : {}, ...mcpSha256 ? { mcpSha256 } : {} };
|
|
13349
13440
|
}
|
|
13350
13441
|
function identity3(document2, cache, read2) {
|
|
13351
13442
|
if (!document2.startsWith(cache + sep4) || !document2.endsWith(sep4 + "SKILL.md"))
|
|
@@ -13388,6 +13479,10 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache, controls, read2) {
|
|
|
13388
13479
|
for (const parent of new Set(controls.map((control) => control.pluginParent))) {
|
|
13389
13480
|
if (!parent.startsWith(cache + sep4) || !lstatSync12(parent, { throwIfNoEntry: false })?.isDirectory())
|
|
13390
13481
|
return false;
|
|
13482
|
+
for (const control of controls.filter((control2) => control2.pluginParent === parent)) {
|
|
13483
|
+
if (control.remotePluginId !== undefined && !remoteInstallationMatches(parent, control.remotePluginId, read2))
|
|
13484
|
+
return false;
|
|
13485
|
+
}
|
|
13391
13486
|
const names = readdirSync6(parent);
|
|
13392
13487
|
entries += names.length;
|
|
13393
13488
|
if (entries > 4096)
|
|
@@ -13404,7 +13499,7 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache, controls, read2) {
|
|
|
13404
13499
|
if (!stat.isDirectory() || ![".codex-plugin/plugin.json", ".app.json", "hooks", ".mcp.json"].some((path) => lstatSync12(join14(root, path), { throwIfNoEntry: false })))
|
|
13405
13500
|
continue;
|
|
13406
13501
|
const parsed = rootControls(root, read2);
|
|
13407
|
-
if (!controls.some((control) => control.pluginParent === parent && control.namespace === parsed.namespace && control.manifestSha256 === parsed.manifestSha256 && control.appSha256 === parsed.appSha256))
|
|
13502
|
+
if (!controls.some((control) => control.pluginParent === parent && control.namespace === parsed.namespace && control.manifestSha256 === parsed.manifestSha256 && control.appSha256 === parsed.appSha256 && control.mcpSha256 === parsed.mcpSha256))
|
|
13408
13503
|
return false;
|
|
13409
13504
|
}
|
|
13410
13505
|
}
|
|
@@ -13414,7 +13509,7 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache, controls, read2) {
|
|
|
13414
13509
|
}
|
|
13415
13510
|
}
|
|
13416
13511
|
function reviewCodexPluginSkillControls(catalog, documents, cache, cwd, read2, rules) {
|
|
13417
|
-
if (catalog?.version
|
|
13512
|
+
if (!supportsCodexNativeCapability(catalog?.version, "qualified-skill-catalog") || catalog.cwd !== cwd)
|
|
13418
13513
|
refuse2();
|
|
13419
13514
|
const skills = projectCodexNativeSkillCatalog({ data: [{ cwd, errors: [], skills: catalog.skills }] }, cwd);
|
|
13420
13515
|
const allowed = new Set(documents), result = [];
|
|
@@ -13441,22 +13536,30 @@ function reviewCodexPluginSkillControls(catalog, documents, cache, cwd, read2, r
|
|
|
13441
13536
|
const listed = skills.filter((skill) => skill.path === document2);
|
|
13442
13537
|
if (listed.length > 1)
|
|
13443
13538
|
refuse2();
|
|
13539
|
+
let remotePluginId;
|
|
13444
13540
|
if (listed.length === 1) {
|
|
13445
13541
|
if (listed[0].name !== parsed.name || listed[0].pluginId !== expectedPluginId)
|
|
13446
13542
|
refuse2();
|
|
13447
13543
|
} else {
|
|
13448
|
-
const installed = installedPlugins.filter((
|
|
13449
|
-
if (installed.length !== 1 || !installed[0].installed || !installed[0].enabled
|
|
13544
|
+
const installed = installedPlugins.filter((plugin2) => plugin2.id === expectedPluginId && plugin2.name === pluginName);
|
|
13545
|
+
if (installed.length !== 1 || !installed[0].installed || !installed[0].enabled)
|
|
13450
13546
|
refuse2();
|
|
13451
|
-
|
|
13452
|
-
|
|
13547
|
+
const plugin = installed[0];
|
|
13548
|
+
if (plugin.localVersion !== null) {
|
|
13549
|
+
if (plugin.localVersion !== basename5(dirname10(dirname10(dirname10(document2)))))
|
|
13550
|
+
continue;
|
|
13551
|
+
} else {
|
|
13552
|
+
if (plugin.sourceType !== "remote" || !plugin.remotePluginId || !remoteInstallationMatches(parsed.pluginParent, plugin.remotePluginId, read2) || !lstatSync12(document2).isFile() || realpathSync5(document2) !== document2)
|
|
13553
|
+
refuse2();
|
|
13554
|
+
remotePluginId = plugin.remotePluginId;
|
|
13555
|
+
}
|
|
13453
13556
|
const exactPathDeny = Array.isArray(rules) && rules.some((rule) => rule?.path === document2 && rule?.enabled === false);
|
|
13454
13557
|
if (!exactPathDeny || !isCodexNativeSkillDisabled({ name: parsed.name, path: document2, pluginId: expectedPluginId, enabled: true }, rules))
|
|
13455
13558
|
refuse2();
|
|
13456
13559
|
}
|
|
13457
|
-
result.push({ ...parsed, pluginId: expectedPluginId });
|
|
13560
|
+
result.push({ ...parsed, pluginId: expectedPluginId, ...remotePluginId ? { remotePluginId } : {} });
|
|
13458
13561
|
}
|
|
13459
|
-
if (!result.length || new Set(result.map((item) => item.name)).size !== result.length)
|
|
13562
|
+
if (!result.length && documents.some((document2) => document2.startsWith(cache + sep4)) || new Set(result.map((item) => item.name)).size !== result.length)
|
|
13460
13563
|
refuse2();
|
|
13461
13564
|
return result;
|
|
13462
13565
|
}
|
|
@@ -13469,8 +13572,8 @@ function isReviewedCodexPluginSkillDisabled(document2, cache, controls, rules, r
|
|
|
13469
13572
|
} catch {
|
|
13470
13573
|
return false;
|
|
13471
13574
|
}
|
|
13472
|
-
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);
|
|
13473
|
-
if (!reviewed)
|
|
13575
|
+
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);
|
|
13576
|
+
if (!reviewed || reviewed.remotePluginId !== undefined && !remoteInstallationMatches(reviewed.pluginParent, reviewed.remotePluginId, read2))
|
|
13474
13577
|
return false;
|
|
13475
13578
|
return isCodexNativeSkillDisabled({ name: parsed.name, path: document2, pluginId: reviewed.pluginId, enabled: true }, rules);
|
|
13476
13579
|
}
|
|
@@ -13489,7 +13592,7 @@ enabled = false
|
|
|
13489
13592
|
return text2;
|
|
13490
13593
|
}
|
|
13491
13594
|
|
|
13492
|
-
// src/lib/codex-settings-witness.ts
|
|
13595
|
+
// src/lib/codex-settings-witness-v1.ts
|
|
13493
13596
|
import { createHash as createHash9 } from "crypto";
|
|
13494
13597
|
var sha = (text2) => createHash9("sha256").update(text2).digest("hex");
|
|
13495
13598
|
var EFFORT = new Set(["none", "minimal", "low", "medium", "high", "xhigh"]);
|
|
@@ -13583,19 +13686,167 @@ function captureCodexSettings(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
|
13583
13686
|
const text2 = readNativeSettingsWitnessFile(path, budget, "config.toml");
|
|
13584
13687
|
return { path, hashMode: "codex-settings-v1", sha256: hashCodexSettingsReplacement(text2) };
|
|
13585
13688
|
}
|
|
13689
|
+
|
|
13690
|
+
// src/lib/codex-settings-witness.ts
|
|
13691
|
+
import { createHash as createHash10 } from "crypto";
|
|
13692
|
+
var sha2 = (text2) => createHash10("sha256").update(text2).digest("hex");
|
|
13693
|
+
var EFFORT2 = new Set(["none", "minimal", "low", "medium", "high", "xhigh"]);
|
|
13694
|
+
var VERBOSITY2 = new Set(["low", "medium", "high"]);
|
|
13695
|
+
var MODEL = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$/;
|
|
13696
|
+
var CODEX_DISCOVERY_PROJECTION_FIELDS = ["plugins", "marketplaces", "skills"];
|
|
13697
|
+
var INFERENCE = ["model", "model_reasoning_effort", "model_verbosity"];
|
|
13698
|
+
function need4(value) {
|
|
13699
|
+
if (!value)
|
|
13700
|
+
throw new Error("Invalid Codex settings witness");
|
|
13701
|
+
}
|
|
13702
|
+
function isRecord3(value) {
|
|
13703
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
13704
|
+
}
|
|
13705
|
+
function isDate(value) {
|
|
13706
|
+
return value instanceof Date;
|
|
13707
|
+
}
|
|
13708
|
+
function numericTokens2(text2) {
|
|
13709
|
+
const result = [];
|
|
13710
|
+
for (let at = 0;at < text2.length; ) {
|
|
13711
|
+
const char = text2[at];
|
|
13712
|
+
if (char === "#") {
|
|
13713
|
+
while (at < text2.length && text2[at] !== `
|
|
13714
|
+
`)
|
|
13715
|
+
at++;
|
|
13716
|
+
continue;
|
|
13717
|
+
}
|
|
13718
|
+
if (char === '"' || char === "'") {
|
|
13719
|
+
const quote = char, triple = text2.slice(at, at + 3) === quote.repeat(3);
|
|
13720
|
+
at += triple ? 3 : 1;
|
|
13721
|
+
while (at < text2.length) {
|
|
13722
|
+
if (quote === '"' && text2[at] === "\\") {
|
|
13723
|
+
at += 2;
|
|
13724
|
+
continue;
|
|
13725
|
+
}
|
|
13726
|
+
if (text2.slice(at, at + (triple ? 3 : 1)) === quote.repeat(triple ? 3 : 1)) {
|
|
13727
|
+
at += triple ? 3 : 1;
|
|
13728
|
+
break;
|
|
13729
|
+
}
|
|
13730
|
+
at++;
|
|
13731
|
+
}
|
|
13732
|
+
continue;
|
|
13733
|
+
}
|
|
13734
|
+
if (/[0-9+-]/.test(char)) {
|
|
13735
|
+
const start = at;
|
|
13736
|
+
while (at < text2.length && !/[\s,\]{}#=]/.test(text2[at]))
|
|
13737
|
+
at++;
|
|
13738
|
+
if (at > start) {
|
|
13739
|
+
result.push(text2.slice(start, at));
|
|
13740
|
+
continue;
|
|
13741
|
+
}
|
|
13742
|
+
}
|
|
13743
|
+
at++;
|
|
13744
|
+
}
|
|
13745
|
+
return result.sort();
|
|
13746
|
+
}
|
|
13747
|
+
function canonical4(value, depth = 0, budget = { remaining: 65536 }) {
|
|
13748
|
+
need4(depth <= 32 && --budget.remaining >= 0);
|
|
13749
|
+
if (value === null)
|
|
13750
|
+
return ["null"];
|
|
13751
|
+
if (typeof value === "string")
|
|
13752
|
+
return ["string", value];
|
|
13753
|
+
if (typeof value === "boolean")
|
|
13754
|
+
return ["boolean", value];
|
|
13755
|
+
if (typeof value === "number") {
|
|
13756
|
+
need4(Number.isFinite(value));
|
|
13757
|
+
return ["number", String(value)];
|
|
13758
|
+
}
|
|
13759
|
+
if (isDate(value)) {
|
|
13760
|
+
need4(Number.isFinite(value.getTime()));
|
|
13761
|
+
return ["date", value.toISOString()];
|
|
13762
|
+
}
|
|
13763
|
+
if (Array.isArray(value))
|
|
13764
|
+
return ["array", value.map((child) => canonical4(child, depth + 1, budget))];
|
|
13765
|
+
need4(isRecord3(value));
|
|
13766
|
+
return ["object", Object.entries(value).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, child]) => [key, canonical4(child, depth + 1, budget)])];
|
|
13767
|
+
}
|
|
13768
|
+
function normalize3(config) {
|
|
13769
|
+
if (isRecord3(config.hooks)) {
|
|
13770
|
+
delete config.hooks.state;
|
|
13771
|
+
if (!Object.keys(config.hooks).length)
|
|
13772
|
+
delete config.hooks;
|
|
13773
|
+
}
|
|
13774
|
+
if (isRecord3(config.skills) && Array.isArray(config.skills.config)) {
|
|
13775
|
+
const skills = config.skills;
|
|
13776
|
+
const retained = skills.config.filter((entry) => !disablesOneSkill(entry));
|
|
13777
|
+
if (retained.length !== skills.config.length) {
|
|
13778
|
+
if (retained.length)
|
|
13779
|
+
skills.config = retained;
|
|
13780
|
+
else
|
|
13781
|
+
delete skills.config;
|
|
13782
|
+
}
|
|
13783
|
+
if (!Object.keys(skills).length)
|
|
13784
|
+
delete config.skills;
|
|
13785
|
+
}
|
|
13786
|
+
inference(config);
|
|
13787
|
+
if (isRecord3(config.profiles)) {
|
|
13788
|
+
for (const profile of Object.values(config.profiles))
|
|
13789
|
+
if (isRecord3(profile))
|
|
13790
|
+
inference(profile);
|
|
13791
|
+
}
|
|
13792
|
+
}
|
|
13793
|
+
function disablesOneSkill(entry) {
|
|
13794
|
+
if (!isRecord3(entry) || entry.enabled !== false)
|
|
13795
|
+
return false;
|
|
13796
|
+
const keys = Object.keys(entry);
|
|
13797
|
+
if (!keys.every((key) => key === "path" || key === "name" || key === "enabled"))
|
|
13798
|
+
return false;
|
|
13799
|
+
const selector = ["path", "name"].filter((key) => Object.hasOwn(entry, key));
|
|
13800
|
+
return selector.length === 1 && typeof entry[selector[0]] === "string" && entry[selector[0]].length > 0;
|
|
13801
|
+
}
|
|
13802
|
+
function inference(target) {
|
|
13803
|
+
for (const key of INFERENCE)
|
|
13804
|
+
if (Object.hasOwn(target, key)) {
|
|
13805
|
+
const value = target[key];
|
|
13806
|
+
if (key === "model")
|
|
13807
|
+
need4(typeof value === "string" && MODEL.test(value));
|
|
13808
|
+
else
|
|
13809
|
+
need4(typeof value === "string" && (key === "model_reasoning_effort" ? EFFORT2.has(value) : VERBOSITY2.has(value)));
|
|
13810
|
+
delete target[key];
|
|
13811
|
+
}
|
|
13812
|
+
}
|
|
13813
|
+
function settingsDigest2(text2) {
|
|
13814
|
+
let config;
|
|
13815
|
+
try {
|
|
13816
|
+
config = Bun.TOML.parse(text2);
|
|
13817
|
+
} catch {
|
|
13818
|
+
throw new Error("Invalid Codex settings witness");
|
|
13819
|
+
}
|
|
13820
|
+
need4(isRecord3(config));
|
|
13821
|
+
normalize3(config);
|
|
13822
|
+
return sha2(`hasna.skills.codex-settings.v2\x00${JSON.stringify([canonical4(config), numericTokens2(text2)])}`);
|
|
13823
|
+
}
|
|
13824
|
+
function hashCodexSettingsReplacementV2(text2, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
13825
|
+
need4(Buffer.byteLength(text2) <= 1024 * 1024 && budget.remaining >= Buffer.byteLength(text2));
|
|
13826
|
+
budget.remaining -= Buffer.byteLength(text2);
|
|
13827
|
+
return settingsDigest2(text2);
|
|
13828
|
+
}
|
|
13829
|
+
function captureCodexSettingsV2(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
13830
|
+
const text2 = readNativeSettingsWitnessFile(path, budget, "config.toml");
|
|
13831
|
+
return { path, hashMode: "codex-settings-v2", sha256: settingsDigest2(text2) };
|
|
13832
|
+
}
|
|
13833
|
+
function readCodexSettingsPreimage(path, budget = { remaining: 2 * 1024 * 1024 }) {
|
|
13834
|
+
return readNativeSettingsWitnessFile(path, budget, "config.toml");
|
|
13835
|
+
}
|
|
13586
13836
|
function upgradeCodexSettingsWitness(previous, reviewedSettingsPath) {
|
|
13587
|
-
|
|
13837
|
+
need4(previous && Object.keys(previous).every((key) => ["path", "hashMode", "sha256"].includes(key)) && (previous.hashMode === undefined || previous.hashMode === "bytes" || previous.hashMode === "codex-settings-v1") && /^[a-f0-9]{64}$/.test(previous.sha256));
|
|
13588
13838
|
const budget = { remaining: 2 * 1024 * 1024 };
|
|
13589
13839
|
const before = readNativeSettingsWitnessFile(reviewedSettingsPath, budget, "config.toml"), current = readNativeSettingsWitnessFile(previous.path, budget, "config.toml");
|
|
13590
|
-
|
|
13591
|
-
const sha2562 =
|
|
13592
|
-
if (
|
|
13840
|
+
need4((previous.hashMode === "codex-settings-v1" ? hashCodexSettingsReplacement(before) : sha2(before)) === previous.sha256);
|
|
13841
|
+
const sha2562 = settingsDigest2(current);
|
|
13842
|
+
if (settingsDigest2(before) !== sha2562)
|
|
13593
13843
|
throw new Error("Codex non-preference settings changed; explicit discovery review required");
|
|
13594
|
-
return { path: previous.path, hashMode: "codex-settings-
|
|
13844
|
+
return { path: previous.path, hashMode: "codex-settings-v2", sha256: sha2562 };
|
|
13595
13845
|
}
|
|
13596
13846
|
|
|
13597
13847
|
// src/lib/agent-integration.ts
|
|
13598
|
-
import { createHash as
|
|
13848
|
+
import { createHash as createHash12, randomUUID as randomUUID2 } from "crypto";
|
|
13849
|
+
import { isDeepStrictEqual as isDeepStrictEqual3 } from "util";
|
|
13599
13850
|
import { existsSync as existsSync8, lstatSync as lstatSync15, statSync as statSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync12, 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 constants7, linkSync } from "fs";
|
|
13600
13851
|
import { dirname as dirname11, join as join17, resolve as resolve10, relative as relative5, isAbsolute as isAbsolute11, sep as sep5 } from "path";
|
|
13601
13852
|
import { homedir as homedir2 } from "os";
|
|
@@ -13681,7 +13932,7 @@ function requiresCliSkillLoading(dataDir2 = getDataDirReadOnly()) {
|
|
|
13681
13932
|
}
|
|
13682
13933
|
|
|
13683
13934
|
// src/lib/agent-bridge.ts
|
|
13684
|
-
import { createHash as
|
|
13935
|
+
import { createHash as createHash11 } from "crypto";
|
|
13685
13936
|
import { lstatSync as lstatSync14, readFileSync as readFileSync11, readdirSync as readdirSync7 } from "fs";
|
|
13686
13937
|
import { join as join16 } from "path";
|
|
13687
13938
|
var CLI_BRIDGE_NAME = "skills-cli";
|
|
@@ -13700,7 +13951,7 @@ Use the Skills CLI as the skill authority for this station.
|
|
|
13700
13951
|
|
|
13701
13952
|
This bridge contains no skill payloads. Do not copy skill content into agent-native skill directories or load other native skill copies. If a Skills command refuses authority, selection, integrity, or native drift, report that refusal and use its repair guidance; do not substitute bundled or stale local content. Explicit local draft authoring remains available.
|
|
13702
13953
|
`;
|
|
13703
|
-
var CLI_BRIDGE_DIGEST =
|
|
13954
|
+
var CLI_BRIDGE_DIGEST = createHash11("sha256").update(markdown).digest("hex");
|
|
13704
13955
|
var CLI_BRIDGE_FILES = Object.freeze({
|
|
13705
13956
|
"SKILL.md": markdown,
|
|
13706
13957
|
".hasna-skills.json": `${JSON.stringify({ managedBy: "@hasna/skills", kind: "cli-bridge", version: CLI_BRIDGE_VERSION, protocol: "selection-v1", contentSha256: CLI_BRIDGE_DIGEST }, null, 2)}
|
|
@@ -13992,7 +14243,7 @@ function disableCodexBundledSkills(text2) {
|
|
|
13992
14243
|
}
|
|
13993
14244
|
|
|
13994
14245
|
// src/lib/agent-integration.ts
|
|
13995
|
-
var
|
|
14246
|
+
var sha3 = (data) => createHash12("sha256").update(data).digest("hex");
|
|
13996
14247
|
var ROOTS = NATIVE_SKILL_ROOTS;
|
|
13997
14248
|
function assertSafePath(path) {
|
|
13998
14249
|
let cursor = resolve10(path);
|
|
@@ -14099,7 +14350,7 @@ function readNativeBytes(path, maximum = 64 * 1024 * 1024) {
|
|
|
14099
14350
|
}
|
|
14100
14351
|
}
|
|
14101
14352
|
function treeHash(root) {
|
|
14102
|
-
const hash2 =
|
|
14353
|
+
const hash2 = createHash12("sha256");
|
|
14103
14354
|
let bytes = 0, files = 0;
|
|
14104
14355
|
function visit2(path) {
|
|
14105
14356
|
const stat = lstatSync15(path);
|
|
@@ -14484,7 +14735,7 @@ function planAgentIntegration(options) {
|
|
|
14484
14735
|
const observedNativeSources = [];
|
|
14485
14736
|
const codexPluginSkills = options.codexNativeCatalog ? reviewCodexPluginSkillControls(options.codexNativeCatalog, nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor).map((entry) => join17(entry.path, "SKILL.md")), canonicalAgentPath(join17(home, ".codex/plugins/cache"), aliases), resolve10(options.projectDir ?? home), (path) => {
|
|
14486
14737
|
const bytes = readNativeBytes(path, 1024 * 1024);
|
|
14487
|
-
observedNativeSources.push({ path, sha256:
|
|
14738
|
+
observedNativeSources.push({ path, sha256: sha3(bytes) });
|
|
14488
14739
|
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
14489
14740
|
}, codexConfig.skills?.config ?? []) : policy.bridge?.codexPluginSkills ?? [];
|
|
14490
14741
|
const changes = [];
|
|
@@ -14512,7 +14763,7 @@ function planAgentIntegration(options) {
|
|
|
14512
14763
|
throw new Error("Refusing to overwrite an unrecognized Hermes supervisor");
|
|
14513
14764
|
if (supervisorBefore !== supervisorAfter)
|
|
14514
14765
|
changes.push({ path: supervisorPath, before: supervisorBefore, after: supervisorAfter });
|
|
14515
|
-
const supervisor = { path: supervisorPath, runtime: process.execPath, sha256:
|
|
14766
|
+
const supervisor = { path: supervisorPath, runtime: process.execPath, sha256: sha3(supervisorAfter) };
|
|
14516
14767
|
const after2 = configureHermesHooks(before, supervisor, previous);
|
|
14517
14768
|
if (before !== after2)
|
|
14518
14769
|
changes.push({ path, before, after: after2 });
|
|
@@ -14559,12 +14810,12 @@ function planAgentIntegration(options) {
|
|
|
14559
14810
|
agents: [...new Set([...priorAgents, ...options.agents])].sort(),
|
|
14560
14811
|
home: resolve10(home),
|
|
14561
14812
|
includeVendor: true,
|
|
14562
|
-
...options.agents.includes("hermes") ? { supervisors: { ...policy.bridge?.supervisors, hermes: { path: join17(dataDir2, "agent-hooks", "hermes.js"), runtime: process.execPath, sha256:
|
|
14813
|
+
...options.agents.includes("hermes") ? { supervisors: { ...policy.bridge?.supervisors, hermes: { path: join17(dataDir2, "agent-hooks", "hermes.js"), runtime: process.execPath, sha256: sha3(renderHermesSupervisor(bindings.get("hermes").command, bindings.get("hermes").profileId)) } } } : {},
|
|
14563
14814
|
commands: { ...policy.bridge?.commands, ...Object.fromEntries([...bindings].map(([agent, binding]) => [agent, binding.command])) },
|
|
14564
14815
|
profiles: Object.fromEntries([...new Set([...priorAgents, ...options.agents])].sort().map((agent) => [agent, bindings.get(agent)?.profileId ?? policy.bridge?.profiles?.[agent] ?? policy.profileId])),
|
|
14565
14816
|
disabledBuiltins: options.agents.includes("codex") ? nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor && entry.path.startsWith(canonicalAgentPath(join17(home, ".codex", "skills", ".system"), aliases) + sep5)).map((entry) => ({ path: entry.path, hash: entry.hash })) : policy.bridge?.disabledBuiltins ?? [],
|
|
14566
14817
|
rootAliases: aliases,
|
|
14567
|
-
...codexPluginSkills.length ? { codexPluginSkills, codexPluginSkillReview: options.codexNativeCatalog ? { version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, catalogSha256:
|
|
14818
|
+
...codexPluginSkills.length ? { codexPluginSkills, codexPluginSkillReview: options.codexNativeCatalog ? { version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, catalogSha256: sha3(JSON.stringify({ version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, skills: projectCodexNativeSkillCatalog({ data: [{ cwd: options.codexNativeCatalog.cwd, errors: [], skills: options.codexNativeCatalog.skills }] }, options.codexNativeCatalog.cwd), ...options.codexNativeCatalog.plugins === undefined ? {} : { plugins: projectCodexInstalledPluginEntries(options.codexNativeCatalog.plugins) } })), configSha256: changes.find((change) => change.path === canonicalAgentPath(join17(home, ".codex/config.toml"), aliases))?.before === null ? null : sha3(readOptional(canonicalAgentPath(join17(home, ".codex/config.toml"), aliases)) ?? "") } : policy.bridge?.codexPluginSkillReview } : {},
|
|
14568
14819
|
discovery: { ...policy.bridge?.discovery, ...Object.fromEntries(discoveryAfter.map((binding) => [binding.agent, binding])) }
|
|
14569
14820
|
} };
|
|
14570
14821
|
const serializedPolicy = serializeManagedSkillPolicy(nextPolicy);
|
|
@@ -14580,12 +14831,12 @@ function planClaudePreToolUseHookUpdate(options) {
|
|
|
14580
14831
|
return planClaudeHookEventsUpdate({ ...options, events: ["PreToolUse"] });
|
|
14581
14832
|
}
|
|
14582
14833
|
function claudeSettingsConsumers(home, path, discoveries, aliases) {
|
|
14583
|
-
const
|
|
14834
|
+
const canonical5 = (value) => canonicalAgentPath(value, aliases);
|
|
14584
14835
|
const containsSettings = (root) => {
|
|
14585
|
-
const distance = relative5(
|
|
14836
|
+
const distance = relative5(canonical5(root), path);
|
|
14586
14837
|
return distance === "" || distance !== ".." && !distance.startsWith(`..${sep5}`) && !isAbsolute11(distance);
|
|
14587
14838
|
};
|
|
14588
|
-
return discoveries.filter((binding) => binding.agent === "claude" || binding.agent === "opencode" ||
|
|
14839
|
+
return discoveries.filter((binding) => binding.agent === "claude" || binding.agent === "opencode" || canonical5(join17(home, AGENT_ADAPTERS[binding.agent].config)) === path || binding.sources.some((source) => canonical5(source.path) === path) || binding.roots.some(containsSettings) || binding.directories?.some((directory) => containsSettings(directory.path))).map((binding) => binding.agent);
|
|
14589
14840
|
}
|
|
14590
14841
|
function verifyCoordinatedDiscovery(binding, home, aliases) {
|
|
14591
14842
|
try {
|
|
@@ -14617,7 +14868,7 @@ function planClaudeHookEventsUpdate(options) {
|
|
|
14617
14868
|
const path = canonicalAgentPath(join17(home, ".claude", "settings.json"), aliases);
|
|
14618
14869
|
assertSafePath(path);
|
|
14619
14870
|
const before = lstatSync15(path, { throwIfNoEntry: false }) ? new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(readNativeBytes(path, 1024 * 1024)) : null;
|
|
14620
|
-
if ((before === null ? "absent" :
|
|
14871
|
+
if ((before === null ? "absent" : sha3(before)) !== options.expectedSettingsSha256)
|
|
14621
14872
|
throw new Error("Claude settings preimage changed");
|
|
14622
14873
|
assertClaudeHookEventsReplacement(before, options.replacement, options.events);
|
|
14623
14874
|
const agents = bridge.agents;
|
|
@@ -14683,7 +14934,7 @@ function atomicWrite2(path, content) {
|
|
|
14683
14934
|
function planAgentSettingsWitnessUpgrade(options) {
|
|
14684
14935
|
const home = resolve10(options.home ?? homedir2()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
|
|
14685
14936
|
const snapshot = readManagedSkillPolicySnapshot(dataDir2);
|
|
14686
|
-
if (!snapshot ||
|
|
14937
|
+
if (!snapshot || sha3(snapshot.text) !== options.expectedPolicySha256)
|
|
14687
14938
|
throw new Error("Managed policy preimage changed");
|
|
14688
14939
|
const policy = snapshot.value, aliases = policy.bridge?.rootAliases ?? [];
|
|
14689
14940
|
recheckRootAliases(aliases);
|
|
@@ -14692,7 +14943,7 @@ function planAgentSettingsWitnessUpgrade(options) {
|
|
|
14692
14943
|
throw new Error("Settings witness upgrade requires an existing reviewed native binding");
|
|
14693
14944
|
const configPath = canonicalAgentPath(join17(home, options.agent === "claude" ? ".claude/settings.json" : ".codex/config.toml"), aliases);
|
|
14694
14945
|
const settings = readOptional(configPath);
|
|
14695
|
-
if (settings === null ||
|
|
14946
|
+
if (settings === null || sha3(settings) !== options.expectedSettingsSha256)
|
|
14696
14947
|
throw new Error("Native settings preimage changed");
|
|
14697
14948
|
const sources = binding.sources.filter((source) => source.path === configPath && source.format === undefined && source.fields === undefined);
|
|
14698
14949
|
if (sources.length !== 1)
|
|
@@ -14700,15 +14951,40 @@ function planAgentSettingsWitnessUpgrade(options) {
|
|
|
14700
14951
|
const previous = sources[0];
|
|
14701
14952
|
if (typeof previous.sha256 !== "string")
|
|
14702
14953
|
throw new Error("Settings witness upgrade requires a preserved settings preimage");
|
|
14954
|
+
const replaced = [previous];
|
|
14955
|
+
if (options.agent === "codex") {
|
|
14956
|
+
if (previous.hashMode !== undefined && previous.hashMode !== "bytes" && previous.hashMode !== "codex-settings-v1")
|
|
14957
|
+
throw new Error("Codex settings witness upgrade requires a preserved raw or codex-settings-v1 configuration witness");
|
|
14958
|
+
const preimage = readCodexSettingsPreimage(options.reviewedPreimage);
|
|
14959
|
+
for (const source of binding.sources) {
|
|
14960
|
+
if (source === previous || source.path !== configPath)
|
|
14961
|
+
continue;
|
|
14962
|
+
const fields = source.fields;
|
|
14963
|
+
if (source.hashMode !== undefined || source.format !== "toml" || !Array.isArray(fields) || !isDeepStrictEqual3(fields, [...CODEX_DISCOVERY_PROJECTION_FIELDS]) || typeof source.sha256 !== "string")
|
|
14964
|
+
throw new Error("Codex settings witness upgrade found an unrecognized configuration witness");
|
|
14965
|
+
if (projectNativeDiscoveryFields(preimage, "toml", fields, configPath) !== source.sha256)
|
|
14966
|
+
throw new Error("Reviewed preimage does not explain the Codex discovery projection witness");
|
|
14967
|
+
replaced.push(source);
|
|
14968
|
+
}
|
|
14969
|
+
}
|
|
14703
14970
|
const next = options.agent === "claude" ? upgradeClaudeSettingsWitness(previous, options.reviewedPreimage) : upgradeCodexSettingsWitness(previous, options.reviewedPreimage);
|
|
14704
|
-
const
|
|
14971
|
+
const rebound = [];
|
|
14972
|
+
for (const source of binding.sources) {
|
|
14973
|
+
if (!replaced.includes(source)) {
|
|
14974
|
+
rebound.push(source);
|
|
14975
|
+
continue;
|
|
14976
|
+
}
|
|
14977
|
+
if (source === replaced[0])
|
|
14978
|
+
rebound.push(next);
|
|
14979
|
+
}
|
|
14980
|
+
const replacement = { ...binding, sources: rebound };
|
|
14705
14981
|
verifyAgentDiscovery(replacement);
|
|
14706
14982
|
const after = serializeManagedSkillPolicy({ ...policy, bridge: { ...policy.bridge, discovery: { ...policy.bridge.discovery, [options.agent]: replacement } } });
|
|
14707
|
-
return { dataDir: dataDir2, profileId: policy.profileId, changes: [{ path: join17(dataDir2, "agent-policy.json"), before: snapshot.text, after }], nativeSkills: [], observedPolicy: { path: join17(dataDir2, "agent-policy.json"), before: snapshot.text }, observedSettings: { path: configPath, before: settings }, discoveryBefore: [replacement], discoveryAfter: [replacement], rootAliases: aliases, managedAgentChecks: { home, agents: [options.agent] }, settingsWitnessUpgrade: { agent: options.agent, path: configPath, fromHashMode: previous.hashMode ?? "bytes", fromSha256: previous.sha256, toHashMode: next.hashMode, toSha256: next.sha256, reviewedPreimage: options.reviewedPreimage, currentSettingsSha256: options.expectedSettingsSha256 } };
|
|
14983
|
+
return { dataDir: dataDir2, profileId: policy.profileId, changes: [{ path: join17(dataDir2, "agent-policy.json"), before: snapshot.text, after }], nativeSkills: [], observedPolicy: { path: join17(dataDir2, "agent-policy.json"), before: snapshot.text }, observedSettings: { path: configPath, before: settings }, discoveryBefore: [replacement], discoveryAfter: [replacement], rootAliases: aliases, managedAgentChecks: { home, agents: [options.agent] }, settingsWitnessUpgrade: { agent: options.agent, path: configPath, fromHashMode: previous.hashMode ?? "bytes", fromSha256: previous.sha256, toHashMode: next.hashMode, toSha256: next.sha256, reviewedPreimage: options.reviewedPreimage, currentSettingsSha256: options.expectedSettingsSha256, replacedWitnesses: replaced.map((source) => ({ hashMode: source.hashMode ?? "bytes", sha256: source.sha256 })) } };
|
|
14708
14984
|
}
|
|
14709
14985
|
function applyAgentIntegration(plan) {
|
|
14710
14986
|
for (const source of plan.observedNativeSources ?? [])
|
|
14711
|
-
if (
|
|
14987
|
+
if (sha3(readNativeBytes(source.path, 1024 * 1024)) !== source.sha256)
|
|
14712
14988
|
throw new Error("Native identity source changed after planning");
|
|
14713
14989
|
if (plan.observedSettings && readOptional(plan.observedSettings.path) !== plan.observedSettings.before)
|
|
14714
14990
|
throw new Error("Native settings changed after witness planning");
|
|
@@ -14728,7 +15004,7 @@ function applyAgentIntegration(plan) {
|
|
|
14728
15004
|
const upgrade = plan.settingsWitnessUpgrade;
|
|
14729
15005
|
if (!plan.managedAgentChecks || !plan.observedPolicy?.before)
|
|
14730
15006
|
throw new Error("Invalid settings witness upgrade plan");
|
|
14731
|
-
const verified = planAgentSettingsWitnessUpgrade({ agent: upgrade.agent, reviewedPreimage: upgrade.reviewedPreimage, home: plan.managedAgentChecks.home, dataDir: plan.dataDir, expectedPolicySha256:
|
|
15007
|
+
const verified = planAgentSettingsWitnessUpgrade({ agent: upgrade.agent, reviewedPreimage: upgrade.reviewedPreimage, home: plan.managedAgentChecks.home, dataDir: plan.dataDir, expectedPolicySha256: sha3(plan.observedPolicy.before), expectedSettingsSha256: upgrade.currentSettingsSha256 });
|
|
14732
15008
|
if (JSON.stringify(verified.changes) !== JSON.stringify(plan.changes) || JSON.stringify(verified.settingsWitnessUpgrade) !== JSON.stringify(upgrade))
|
|
14733
15009
|
throw new Error("Settings witness upgrade plan changed");
|
|
14734
15010
|
provenDiscovery = verified.discoveryBefore[0];
|
|
@@ -14756,7 +15032,7 @@ function applyAgentIntegration(plan) {
|
|
|
14756
15032
|
chmodSync(backupRoot, 448);
|
|
14757
15033
|
for (const [index, change] of plan.changes.entries())
|
|
14758
15034
|
if (change.before !== null) {
|
|
14759
|
-
const backup = join17(backupRoot, `${index}-${
|
|
15035
|
+
const backup = join17(backupRoot, `${index}-${sha3(change.path).slice(0, 12)}.backup`);
|
|
14760
15036
|
writeFileSync4(backup, change.before, { mode: 384, flag: "wx" });
|
|
14761
15037
|
if (readFileSync12(backup, "utf8") !== change.before)
|
|
14762
15038
|
throw new Error("Native configuration preservation readback failed");
|
|
@@ -14775,7 +15051,7 @@ function applyAgentIntegration(plan) {
|
|
|
14775
15051
|
}
|
|
14776
15052
|
recheckRootAliases(aliases);
|
|
14777
15053
|
for (const source of plan.observedNativeSources ?? [])
|
|
14778
|
-
if (
|
|
15054
|
+
if (sha3(readNativeBytes(source.path, 1024 * 1024)) !== source.sha256)
|
|
14779
15055
|
throw new Error("Native identity source changed during application");
|
|
14780
15056
|
if (plan.observedSettings && readOptional(plan.observedSettings.path) !== plan.observedSettings.before)
|
|
14781
15057
|
throw new Error("Native settings changed during witness application");
|
|
@@ -14787,7 +15063,7 @@ function applyAgentIntegration(plan) {
|
|
|
14787
15063
|
}
|
|
14788
15064
|
for (const agent of plan.managedAgentChecks?.agents ?? [])
|
|
14789
15065
|
assertManagedAgentBridge(agent, { home: plan.managedAgentChecks.home, dataDir: plan.dataDir, projectDir: plan.managedAgentChecks.home });
|
|
14790
|
-
atomicWrite2(join17(backupRoot, "receipt.json"), JSON.stringify({ version: 1, changes: written.map((change) => ({ path: change.path, beforeHash: change.before === null ? null :
|
|
15066
|
+
atomicWrite2(join17(backupRoot, "receipt.json"), JSON.stringify({ version: 1, changes: written.map((change) => ({ path: change.path, beforeHash: change.before === null ? null : sha3(change.before), afterHash: sha3(change.after) })), backups, ...aliases.length ? { rootAliases: aliases } : {} }) + `
|
|
14791
15067
|
`);
|
|
14792
15068
|
} catch (error) {
|
|
14793
15069
|
for (const change of written.reverse()) {
|
|
@@ -14866,8 +15142,8 @@ function archiveNativeSkills(inventory, options) {
|
|
|
14866
15142
|
const operationId = randomUUID2(), archiveRoot = join17(options.dataDir ?? getDataDir(), "migration", operationId, "native"), receiptPath = join17(archiveRoot, "receipt.json");
|
|
14867
15143
|
const entries = selected.map((entry, index) => ({
|
|
14868
15144
|
source: entry.vendor ? join17(entry.path, "SKILL.md") : entry.path,
|
|
14869
|
-
archive: join17(archiveRoot, `${index}-${
|
|
14870
|
-
hash: entry.vendor ?
|
|
15145
|
+
archive: join17(archiveRoot, `${index}-${sha3(entry.path).slice(0, 12)}`),
|
|
15146
|
+
hash: entry.vendor ? sha3(readNativeBytes(join17(entry.path, "SKILL.md"))) : entry.hash,
|
|
14871
15147
|
...entry.vendor ? { discoveryOnly: true } : {},
|
|
14872
15148
|
status: "planned"
|
|
14873
15149
|
}));
|
|
@@ -14878,7 +15154,7 @@ function archiveNativeSkills(inventory, options) {
|
|
|
14878
15154
|
const stat = lstatSync15(entry.archive);
|
|
14879
15155
|
if (entry.discoveryOnly ? !stat.isFile() : !stat.isDirectory())
|
|
14880
15156
|
throw new Error("Archive type changed");
|
|
14881
|
-
if ((entry.discoveryOnly ?
|
|
15157
|
+
if ((entry.discoveryOnly ? sha3(readNativeBytes(entry.archive)) : treeHash(entry.archive)) !== entry.hash)
|
|
14882
15158
|
throw new Error("Archive bytes changed");
|
|
14883
15159
|
};
|
|
14884
15160
|
assertSafePath(archiveRoot);
|
|
@@ -14998,7 +15274,7 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
|
|
|
14998
15274
|
throw new Error("NATIVE_SKILL_DRIFT: the hook selection profile differs from its managed binding; restart the native client after reviewing skills hook install");
|
|
14999
15275
|
if (agent === "hermes") {
|
|
15000
15276
|
const supervisor = binding.supervisors?.hermes;
|
|
15001
|
-
if (supervisor?.path !== join17(dataDir2, "agent-hooks", "hermes.js") || supervisor?.sha256 !==
|
|
15277
|
+
if (supervisor?.path !== join17(dataDir2, "agent-hooks", "hermes.js") || supervisor?.sha256 !== sha3(renderHermesSupervisor(command, profile)))
|
|
15002
15278
|
throw new Error("NATIVE_SKILL_DRIFT: Hermes supervisor binding changed; run skills hook install");
|
|
15003
15279
|
assertHermesProtection(home, config, command, profile, supervisor);
|
|
15004
15280
|
} else if (agent === "opencode") {
|
|
@@ -16296,7 +16572,7 @@ function exactProfileSelection(spec, profile) {
|
|
|
16296
16572
|
}
|
|
16297
16573
|
|
|
16298
16574
|
// src/lib/plugin-projection.ts
|
|
16299
|
-
import { createHash as
|
|
16575
|
+
import { createHash as createHash13 } from "crypto";
|
|
16300
16576
|
import { posix } from "path";
|
|
16301
16577
|
var PLUGIN_PROJECTION_MANIFEST = "plugin-projection.json";
|
|
16302
16578
|
var PLUGIN_PROJECTION_LIMITS = Object.freeze({ files: 1024, bytes: 64 * 1024 * 1024, fileBytes: 16 * 1024 * 1024, metadataBytes: 512 * 1024, registrations: 64, history: 128 });
|
|
@@ -16307,7 +16583,7 @@ function pluginNeed(value, message) {
|
|
|
16307
16583
|
if (!value)
|
|
16308
16584
|
pluginRefusal(message);
|
|
16309
16585
|
}
|
|
16310
|
-
var pluginHash = (bytes) =>
|
|
16586
|
+
var pluginHash = (bytes) => createHash13("sha256").update(bytes).digest("hex");
|
|
16311
16587
|
function pluginObject(value) {
|
|
16312
16588
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
16313
16589
|
}
|
|
@@ -16495,7 +16771,7 @@ function buildPluginProjection(entries) {
|
|
|
16495
16771
|
}
|
|
16496
16772
|
|
|
16497
16773
|
// src/lib/plugin-projection-store.ts
|
|
16498
|
-
import { createHash as
|
|
16774
|
+
import { createHash as createHash14, randomUUID as randomUUID3 } from "crypto";
|
|
16499
16775
|
import { constants as constants8, closeSync as closeSync9, fchmodSync, fstatSync as fstatSync9, fsyncSync as fsyncSync3, linkSync as linkSync2, lstatSync as lstatSync17, mkdirSync as mkdirSync8, openSync as openSync9, opendirSync as opendirSync4, readSync as readSync7, renameSync as renameSync4, rmdirSync as rmdirSync3, rmSync as rmSync3, unlinkSync as unlinkSync4, writeSync as writeSync2 } from "fs";
|
|
16500
16776
|
import { dirname as dirname13, isAbsolute as isAbsolute12, join as join23, parse as parse5, resolve as resolve11 } from "path";
|
|
16501
16777
|
var READ_FLAGS = constants8.O_RDONLY | constants8.O_NOFOLLOW | constants8.O_NONBLOCK;
|
|
@@ -16511,7 +16787,7 @@ function stat(path) {
|
|
|
16511
16787
|
return pluginRefusal("Cannot inspect plugin filesystem entry");
|
|
16512
16788
|
}
|
|
16513
16789
|
}
|
|
16514
|
-
function
|
|
16790
|
+
function canonical5(path) {
|
|
16515
16791
|
pluginNeed(typeof path === "string" && path.length <= 8192 && isAbsolute12(path) && resolve11(path) === path && !/[\x00-\x1f\x7f]/.test(path), "Plugin storage paths must be canonical absolute paths");
|
|
16516
16792
|
}
|
|
16517
16793
|
function owner(stats, system = false) {
|
|
@@ -16522,7 +16798,7 @@ function same3(left, right, identityOnly = false) {
|
|
|
16522
16798
|
pluginNeed(right && left.dev === right.dev && left.ino === right.ino && left.mode === right.mode && left.uid === right.uid && left.gid === right.gid && (identityOnly || left.size === right.size && left.nlink === right.nlink && left.mtimeNs === right.mtimeNs && left.ctimeNs === right.ctimeNs), "Plugin filesystem entry changed during access");
|
|
16523
16799
|
}
|
|
16524
16800
|
function ancestors(path, create = false) {
|
|
16525
|
-
|
|
16801
|
+
canonical5(path);
|
|
16526
16802
|
const result = [], parent = dirname13(path), filesystemRoot = parse5(parent).root;
|
|
16527
16803
|
let current = filesystemRoot;
|
|
16528
16804
|
for (const segment of ["", ...parent.slice(filesystemRoot.length).split("/").filter(Boolean)]) {
|
|
@@ -16837,7 +17113,7 @@ function pluginExecutableDigest(path) {
|
|
|
16837
17113
|
const opened = fstatSync9(fd, { bigint: true });
|
|
16838
17114
|
same3(before, opened);
|
|
16839
17115
|
fileShape(opened, maximum, "executable");
|
|
16840
|
-
const hash2 =
|
|
17116
|
+
const hash2 = createHash14("sha256"), buffer = new Uint8Array(64 * 1024);
|
|
16841
17117
|
let remaining = Number(opened.size);
|
|
16842
17118
|
while (remaining > 0) {
|
|
16843
17119
|
const count = readSync7(fd, buffer, 0, Math.min(buffer.byteLength, remaining), null);
|
|
@@ -17396,23 +17672,23 @@ function captureManagedPluginRegistry(path, managedPlugins) {
|
|
|
17396
17672
|
}
|
|
17397
17673
|
|
|
17398
17674
|
// src/lib/claude-marketplace-registry.ts
|
|
17399
|
-
import { createHash as
|
|
17675
|
+
import { createHash as createHash15 } from "crypto";
|
|
17400
17676
|
import { closeSync as closeSync11, constants as constants10, fstatSync as fstatSync11, lstatSync as lstatSync19, openSync as openSync11, readSync as readSync9 } from "fs";
|
|
17401
17677
|
import { basename as basename8, dirname as dirname15, isAbsolute as isAbsolute15, resolve as resolve14 } from "path";
|
|
17402
17678
|
var CLAUDE_MARKETPLACE_REGISTRY_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
|
|
17403
|
-
function
|
|
17679
|
+
function need5(value, reason) {
|
|
17404
17680
|
if (!value)
|
|
17405
17681
|
throw new Error(`Claude marketplace registry ${reason}`);
|
|
17406
17682
|
}
|
|
17407
17683
|
function absolutePath3(value) {
|
|
17408
|
-
|
|
17684
|
+
need5(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute15(value) && resolve14(value) === value, "requires a normalized absolute path");
|
|
17409
17685
|
}
|
|
17410
17686
|
var sameFile2 = (a, b) => a.dev === b.dev && a.ino === b.ino && a.mode === b.mode && a.uid === b.uid && a.gid === b.gid && a.nlink === b.nlink && a.size === b.size && a.mtimeNs === b.mtimeNs && a.ctimeNs === b.ctimeNs;
|
|
17411
17687
|
function parents2(path) {
|
|
17412
17688
|
const result = [];
|
|
17413
17689
|
for (let at = dirname15(path);; at = dirname15(at)) {
|
|
17414
17690
|
const stat2 = lstatSync19(at, { bigint: true });
|
|
17415
|
-
|
|
17691
|
+
need5(stat2.isDirectory() && !stat2.isSymbolicLink(), "path traverses a symlink or non-directory");
|
|
17416
17692
|
result.push([at, stat2]);
|
|
17417
17693
|
if (at === dirname15(at))
|
|
17418
17694
|
return result;
|
|
@@ -17420,15 +17696,15 @@ function parents2(path) {
|
|
|
17420
17696
|
}
|
|
17421
17697
|
function readRegistry2(path, budget) {
|
|
17422
17698
|
absolutePath3(path);
|
|
17423
|
-
|
|
17424
|
-
|
|
17699
|
+
need5(basename8(path) === "known_marketplaces.json", "requires known_marketplaces.json");
|
|
17700
|
+
need5(Number.isSafeInteger(budget.remaining) && budget.remaining >= 0, "has an invalid byte budget");
|
|
17425
17701
|
const ancestors2 = parents2(path), initial = lstatSync19(path, { bigint: true });
|
|
17426
|
-
|
|
17427
|
-
|
|
17702
|
+
need5(initial.isFile() && !initial.isSymbolicLink() && initial.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
|
|
17703
|
+
need5(initial.size <= BigInt(budget.remaining), "exceeds its aggregate byte limit");
|
|
17428
17704
|
const fd = openSync11(path, constants10.O_RDONLY | constants10.O_NOFOLLOW | constants10.O_NONBLOCK);
|
|
17429
17705
|
try {
|
|
17430
17706
|
const opened = fstatSync11(fd, { bigint: true });
|
|
17431
|
-
|
|
17707
|
+
need5(opened.isFile() && sameFile2(initial, opened), "changed during open");
|
|
17432
17708
|
const bytes = Buffer.alloc(Number(opened.size) + 1);
|
|
17433
17709
|
let length = 0;
|
|
17434
17710
|
while (length < bytes.length) {
|
|
@@ -17438,10 +17714,10 @@ function readRegistry2(path, budget) {
|
|
|
17438
17714
|
length += count;
|
|
17439
17715
|
}
|
|
17440
17716
|
const after = fstatSync11(fd, { bigint: true }), current = lstatSync19(path, { bigint: true });
|
|
17441
|
-
|
|
17717
|
+
need5(current.isFile() && sameFile2(opened, after) && sameFile2(after, current) && BigInt(length) === opened.size, "changed during read");
|
|
17442
17718
|
for (const [ancestor, before] of ancestors2) {
|
|
17443
17719
|
const now = lstatSync19(ancestor, { bigint: true });
|
|
17444
|
-
|
|
17720
|
+
need5(now.isDirectory() && before.dev === now.dev && before.ino === now.ino && before.mode === now.mode, "parent changed during read");
|
|
17445
17721
|
}
|
|
17446
17722
|
budget.remaining -= length;
|
|
17447
17723
|
try {
|
|
@@ -17461,7 +17737,7 @@ function parse6(text2) {
|
|
|
17461
17737
|
at++;
|
|
17462
17738
|
};
|
|
17463
17739
|
function string() {
|
|
17464
|
-
|
|
17740
|
+
need5(text2[at] === '"', "contains invalid JSON");
|
|
17465
17741
|
const start = at++;
|
|
17466
17742
|
while (at < text2.length) {
|
|
17467
17743
|
const character = text2[at++];
|
|
@@ -17472,7 +17748,7 @@ function parse6(text2) {
|
|
|
17472
17748
|
} catch {
|
|
17473
17749
|
throw new Error("Claude marketplace registry contains invalid JSON string");
|
|
17474
17750
|
}
|
|
17475
|
-
|
|
17751
|
+
need5(value2.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.stringCharacters, "exceeds its string limit");
|
|
17476
17752
|
return value2;
|
|
17477
17753
|
}
|
|
17478
17754
|
if (character === "\\")
|
|
@@ -17481,7 +17757,7 @@ function parse6(text2) {
|
|
|
17481
17757
|
throw new Error("Claude marketplace registry contains an unterminated JSON string");
|
|
17482
17758
|
}
|
|
17483
17759
|
function value(depth) {
|
|
17484
|
-
|
|
17760
|
+
need5(depth <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.depth && ++nodes <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.nodes, "exceeds its nesting or node limit");
|
|
17485
17761
|
space();
|
|
17486
17762
|
const character = text2[at];
|
|
17487
17763
|
if (character === '"')
|
|
@@ -17495,17 +17771,17 @@ function parse6(text2) {
|
|
|
17495
17771
|
if (object5) {
|
|
17496
17772
|
space();
|
|
17497
17773
|
const key = string();
|
|
17498
|
-
|
|
17774
|
+
need5(!keys.has(key), "contains a duplicate JSON key");
|
|
17499
17775
|
keys.add(key);
|
|
17500
17776
|
space();
|
|
17501
|
-
|
|
17777
|
+
need5(text2[at++] === ":", "contains invalid JSON");
|
|
17502
17778
|
entries.push([key, value(depth + 1)]);
|
|
17503
17779
|
} else
|
|
17504
17780
|
items.push(value(depth + 1));
|
|
17505
17781
|
space();
|
|
17506
17782
|
if (text2[at] === end)
|
|
17507
17783
|
break;
|
|
17508
|
-
|
|
17784
|
+
need5(text2[at++] === ",", "contains invalid JSON");
|
|
17509
17785
|
}
|
|
17510
17786
|
at++;
|
|
17511
17787
|
return object5 ? { kind: "object", entries } : { kind: "array", items };
|
|
@@ -17517,14 +17793,14 @@ function parse6(text2) {
|
|
|
17517
17793
|
}
|
|
17518
17794
|
numberPattern.lastIndex = at;
|
|
17519
17795
|
const number = numberPattern.exec(text2);
|
|
17520
|
-
|
|
17796
|
+
need5(number, "contains invalid JSON");
|
|
17521
17797
|
at += number[0].length;
|
|
17522
17798
|
return { kind: "number", value: number[0] };
|
|
17523
17799
|
}
|
|
17524
17800
|
const root2 = value(0);
|
|
17525
17801
|
space();
|
|
17526
|
-
|
|
17527
|
-
|
|
17802
|
+
need5(at === text2.length && root2.kind === "object", "requires a JSON object without trailing content");
|
|
17803
|
+
need5(root2.entries.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.rows, "exceeds its marketplace row limit");
|
|
17528
17804
|
return root2;
|
|
17529
17805
|
}
|
|
17530
17806
|
function exactKeys(value, keys) {
|
|
@@ -17532,7 +17808,7 @@ function exactKeys(value, keys) {
|
|
|
17532
17808
|
}
|
|
17533
17809
|
var field = (object5, key) => object5.entries.find(([name]) => name === key)?.[1];
|
|
17534
17810
|
function textField(value) {
|
|
17535
|
-
|
|
17811
|
+
need5(value?.kind === "string" && value.value.length > 0 && !/[\x00-\x1f\x7f]/.test(value.value), "contains an invalid recognized field");
|
|
17536
17812
|
return value.value;
|
|
17537
17813
|
}
|
|
17538
17814
|
function normalizeRow(row, version = 1) {
|
|
@@ -17540,7 +17816,7 @@ function normalizeRow(row, version = 1) {
|
|
|
17540
17816
|
if (version !== 2 || !exactKeys(row, ["source", "installLocation", "lastUpdated", "autoUpdate"]))
|
|
17541
17817
|
return;
|
|
17542
17818
|
const autoUpdate = field(row, "autoUpdate");
|
|
17543
|
-
|
|
17819
|
+
need5(autoUpdate?.kind === "literal" && (autoUpdate.value === "true" || autoUpdate.value === "false"), "contains an invalid automatic-update preference");
|
|
17544
17820
|
}
|
|
17545
17821
|
const source = field(row, "source");
|
|
17546
17822
|
if (source?.kind !== "object")
|
|
@@ -17556,34 +17832,34 @@ function normalizeRow(row, version = 1) {
|
|
|
17556
17832
|
absolutePath3(sourceLocation);
|
|
17557
17833
|
absolutePath3(textField(field(row, "installLocation")));
|
|
17558
17834
|
const updated = textField(field(row, "lastUpdated"));
|
|
17559
|
-
|
|
17835
|
+
need5(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(updated), "contains an invalid recognized update timestamp");
|
|
17560
17836
|
const millis = Date.parse(updated);
|
|
17561
|
-
|
|
17837
|
+
need5(Number.isFinite(millis) && new Date(millis).toISOString() === updated, "contains an invalid recognized update timestamp");
|
|
17562
17838
|
row.entries = row.entries.map(([key, value]) => [key, key === "lastUpdated" ? { kind: "validated-update-time" } : value]);
|
|
17563
17839
|
}
|
|
17564
17840
|
function captureClaudeMarketplaceRegistry(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
17565
17841
|
const value = parse6(readRegistry2(path, budget));
|
|
17566
17842
|
for (const [, row] of value.entries)
|
|
17567
17843
|
normalizeRow(row);
|
|
17568
|
-
const sha2562 =
|
|
17844
|
+
const sha2562 = createHash15("sha256").update("hasna.skills.claude-marketplace-registry.v1\x00").update(JSON.stringify(value)).digest("hex");
|
|
17569
17845
|
return { path, hashMode: "claude-marketplace-registry", sha256: sha2562 };
|
|
17570
17846
|
}
|
|
17571
17847
|
function captureClaudeMarketplaceRegistryV2(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
17572
17848
|
const value = parse6(readRegistry2(path, budget));
|
|
17573
17849
|
for (const [, row] of value.entries)
|
|
17574
17850
|
normalizeRow(row, 2);
|
|
17575
|
-
const sha2562 =
|
|
17851
|
+
const sha2562 = createHash15("sha256").update("hasna.skills.claude-marketplace-registry.v2\x00").update(JSON.stringify(value)).digest("hex");
|
|
17576
17852
|
return { path, hashMode: "claude-marketplace-registry-v2", sha256: sha2562 };
|
|
17577
17853
|
}
|
|
17578
17854
|
|
|
17579
17855
|
// src/lib/codex-hook-discovery-recovery.ts
|
|
17580
|
-
import { createHash as
|
|
17856
|
+
import { createHash as createHash17 } from "crypto";
|
|
17581
17857
|
|
|
17582
17858
|
// src/lib/codex-hook-trust-files.ts
|
|
17583
17859
|
import { closeSync as closeSync12, constants as constants11, fstatSync as fstatSync12, fsyncSync as fsyncSync4, lstatSync as lstatSync20, openSync as openSync12, readSync as readSync10, writeFileSync as writeFileSync7 } from "fs";
|
|
17584
|
-
import { createHash as
|
|
17860
|
+
import { createHash as createHash16 } from "crypto";
|
|
17585
17861
|
import { dirname as dirname16 } from "path";
|
|
17586
|
-
function
|
|
17862
|
+
function need6(value, code) {
|
|
17587
17863
|
if (!value)
|
|
17588
17864
|
throw new Error(`CODEX_HOOK_TRUST_${code}`);
|
|
17589
17865
|
}
|
|
@@ -17591,8 +17867,8 @@ var sameStat = (a, b) => ["dev", "ino", "uid", "nlink", "mode", "size", "mtimeNs
|
|
|
17591
17867
|
function safeParents(file) {
|
|
17592
17868
|
for (let p = dirname16(file);; p = dirname16(p)) {
|
|
17593
17869
|
const s = lstatSync20(p);
|
|
17594
|
-
|
|
17595
|
-
|
|
17870
|
+
need6(s.isDirectory() && !s.isSymbolicLink(), "UNSAFE_PARENT");
|
|
17871
|
+
need6((s.mode & 18) === 0 || s.uid === 0 && (s.mode & 512) !== 0, "UNSAFE_PARENT");
|
|
17596
17872
|
if (dirname16(p) === p)
|
|
17597
17873
|
break;
|
|
17598
17874
|
}
|
|
@@ -17601,12 +17877,12 @@ function snapshot(file, privateFile = false, options = {}) {
|
|
|
17601
17877
|
const readOnlyPackage = options.readOnlyPackage === true && !privateFile;
|
|
17602
17878
|
safeParents(file);
|
|
17603
17879
|
const initial = lstatSync20(file, { bigint: true });
|
|
17604
|
-
|
|
17605
|
-
|
|
17880
|
+
need6(initial.isFile() && initial.uid === BigInt(process.getuid()) && (initial.nlink === 1n || readOnlyPackage && initial.nlink > 1n) && (initial.mode & 0o022n) === 0n && (!privateFile || (initial.mode & 0o777n) === 0o600n), "UNSAFE_FILE");
|
|
17881
|
+
need6(initial.size <= 8n * 1024n * 1024n, "FILE_BOUND");
|
|
17606
17882
|
const fd = openSync12(file, constants11.O_RDONLY | constants11.O_NOFOLLOW | constants11.O_NONBLOCK);
|
|
17607
17883
|
try {
|
|
17608
17884
|
const before = fstatSync12(fd, { bigint: true });
|
|
17609
|
-
|
|
17885
|
+
need6(sameStat(initial, before), "INPUT_CHANGED");
|
|
17610
17886
|
const bytes = Buffer.alloc(Number(before.size) + 1);
|
|
17611
17887
|
let length = 0;
|
|
17612
17888
|
while (length < bytes.length) {
|
|
@@ -17615,16 +17891,16 @@ function snapshot(file, privateFile = false, options = {}) {
|
|
|
17615
17891
|
break;
|
|
17616
17892
|
length += n2;
|
|
17617
17893
|
}
|
|
17618
|
-
|
|
17894
|
+
need6(length === Number(before.size) && sameStat(before, fstatSync12(fd, { bigint: true })) && sameStat(before, lstatSync20(file, { bigint: true })), "INPUT_CHANGED");
|
|
17619
17895
|
const content = bytes.subarray(0, length), text2 = new TextDecoder("utf-8", { fatal: true }).decode(content);
|
|
17620
|
-
return { file, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before, sha256:
|
|
17896
|
+
return { file, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before, sha256: createHash16("sha256").update(content).digest("hex") };
|
|
17621
17897
|
} finally {
|
|
17622
17898
|
closeSync12(fd);
|
|
17623
17899
|
}
|
|
17624
17900
|
}
|
|
17625
17901
|
function unchanged2(before) {
|
|
17626
17902
|
const after = snapshot(before.file, before.privateFile, before.readOnlyPackage ? { readOnlyPackage: true } : {});
|
|
17627
|
-
|
|
17903
|
+
need6(sameStat(before.stat, after.stat) && after.sha256 === before.sha256, "INPUT_CHANGED");
|
|
17628
17904
|
}
|
|
17629
17905
|
|
|
17630
17906
|
// src/lib/codex-hook-additions-review.ts
|
|
@@ -17633,11 +17909,12 @@ var matchedEvents = { ...events, PreToolUse: ["preToolUse", "pre_tool_use"] };
|
|
|
17633
17909
|
var proofs = new WeakMap;
|
|
17634
17910
|
|
|
17635
17911
|
// src/lib/codex-hook-discovery-recovery.ts
|
|
17636
|
-
var
|
|
17912
|
+
var sha4 = (text2) => createHash17("sha256").update(text2).digest("hex");
|
|
17913
|
+
var fields = [...CODEX_DISCOVERY_PROJECTION_FIELDS];
|
|
17637
17914
|
var proofs2 = new WeakMap;
|
|
17638
17915
|
function assertCodexHookDiscoveryRecovery(binding, witness) {
|
|
17639
17916
|
const proof = proofs2.get(witness);
|
|
17640
|
-
|
|
17917
|
+
need6(!!proof && binding.agent === "codex" && witness.discoverySha256 === sha4(JSON.stringify(binding)), "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
|
|
17641
17918
|
unchanged2(proof.before);
|
|
17642
17919
|
unchanged2(proof.current);
|
|
17643
17920
|
proof.recheckAdditions();
|
|
@@ -17646,12 +17923,12 @@ function verifiesCodexHookDiscoverySource(binding, source, currentDigest, witnes
|
|
|
17646
17923
|
if (!witness || source.path !== witness.configPath || source.hashMode !== "bytes")
|
|
17647
17924
|
return false;
|
|
17648
17925
|
assertCodexHookDiscoveryRecovery(binding, witness);
|
|
17649
|
-
|
|
17926
|
+
need6(source.sha256 === witness.beforeSha256 && currentDigest === witness.currentSha256, "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
|
|
17650
17927
|
return true;
|
|
17651
17928
|
}
|
|
17652
17929
|
|
|
17653
17930
|
// src/lib/agent-discovery.ts
|
|
17654
|
-
var digest = (text2) =>
|
|
17931
|
+
var digest = (text2) => createHash18("sha256").update(text2).digest("hex");
|
|
17655
17932
|
function parseConfig(text2, path, toml = false) {
|
|
17656
17933
|
try {
|
|
17657
17934
|
const value = toml ? Bun.TOML.parse(text2) : JSON.parse(text2);
|
|
@@ -17683,14 +17960,26 @@ function read2(path, changes) {
|
|
|
17683
17960
|
throw new Error(`Unsupported or oversized native discovery input: ${path}`);
|
|
17684
17961
|
return readFileSync17(path, "utf8");
|
|
17685
17962
|
}
|
|
17963
|
+
function projectNativeDiscoveryFields(text2, format, fields2, path) {
|
|
17964
|
+
const object5 = format === "yaml" ? parseHermesConfig(text2) : parseConfig(text2, path, format === "toml");
|
|
17965
|
+
if (!object5 || typeof object5 !== "object" || Array.isArray(object5))
|
|
17966
|
+
throw new Error("Expected native discovery configuration object");
|
|
17967
|
+
return digest(JSON.stringify(Object.fromEntries(fields2.map((field2) => [field2, object5[field2] ?? null]))));
|
|
17968
|
+
}
|
|
17969
|
+
function isSupersededCodexProjection(agent, configPath, source) {
|
|
17970
|
+
return agent === "codex" && source.path === configPath && source.format === "toml" && isDeepStrictEqual4(source.fields, [...CODEX_DISCOVERY_PROJECTION_FIELDS]);
|
|
17971
|
+
}
|
|
17972
|
+
function supersedesCodexProjection(sources, configPath) {
|
|
17973
|
+
return sources.some((source) => source.path === configPath && source.hashMode === "codex-settings-v2");
|
|
17974
|
+
}
|
|
17686
17975
|
function projected(source, changes, budget = discoveryByteBudget()) {
|
|
17687
|
-
if (source.hashMode === "codex-settings-v1") {
|
|
17976
|
+
if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2") {
|
|
17688
17977
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
17689
17978
|
throw new Error("Codex settings witnesses require exact typed metadata");
|
|
17690
|
-
const current = captureCodexSettings(source.path, budget).sha256;
|
|
17979
|
+
const current = (source.hashMode === "codex-settings-v2" ? captureCodexSettingsV2 : captureCodexSettings)(source.path, budget).sha256;
|
|
17691
17980
|
if (current !== source.sha256)
|
|
17692
17981
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
17693
|
-
return changes?.has(source.path) ? hashCodexSettingsReplacement(changes.get(source.path), budget) : current;
|
|
17982
|
+
return changes?.has(source.path) ? (source.hashMode === "codex-settings-v2" ? hashCodexSettingsReplacementV2 : hashCodexSettingsReplacement)(changes.get(source.path), budget) : current;
|
|
17694
17983
|
}
|
|
17695
17984
|
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") {
|
|
17696
17985
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
@@ -17729,10 +18018,7 @@ function projected(source, changes, budget = discoveryByteBudget()) {
|
|
|
17729
18018
|
return null;
|
|
17730
18019
|
if (!source.format)
|
|
17731
18020
|
return digest(text2);
|
|
17732
|
-
|
|
17733
|
-
if (!object5 || typeof object5 !== "object" || Array.isArray(object5))
|
|
17734
|
-
throw new Error("Expected native discovery configuration object");
|
|
17735
|
-
return digest(JSON.stringify(Object.fromEntries((source.fields ?? []).map((field2) => [field2, object5[field2] ?? null]))));
|
|
18021
|
+
return projectNativeDiscoveryFields(text2, source.format, source.fields ?? [], source.path);
|
|
17736
18022
|
}
|
|
17737
18023
|
function verifyAgentDiscovery(binding, codexRecovery) {
|
|
17738
18024
|
if (codexRecovery)
|
|
@@ -17760,7 +18046,7 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
17760
18046
|
safe4(root2);
|
|
17761
18047
|
}
|
|
17762
18048
|
function assertMarketplaceBinding(binding, source) {
|
|
17763
|
-
if (source.hashMode === "codex-settings-v1" && (binding.agent !== "codex" || binding.method !== "reviewed" || basename9(source.path) !== "config.toml"))
|
|
18049
|
+
if ((source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2") && (binding.agent !== "codex" || binding.method !== "reviewed" || basename9(source.path) !== "config.toml"))
|
|
17764
18050
|
throw new Error("Codex settings witnesses require explicit reviewed Codex configuration");
|
|
17765
18051
|
if ((source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") && (binding.agent !== "claude" || binding.method !== "reviewed" || basename9(source.path) !== "settings.json"))
|
|
17766
18052
|
throw new Error("Claude settings witnesses require explicit reviewed Claude configuration");
|
|
@@ -17789,8 +18075,8 @@ function captureDiscoveryPathSources(paths) {
|
|
|
17789
18075
|
const budget = discoveryByteBudget();
|
|
17790
18076
|
return paths.map((path) => ({ path, hashMode: "path-bytes", sha256: hashDiscoveryPathFile(path, budget) }));
|
|
17791
18077
|
}
|
|
17792
|
-
function assertProjectDiscovery(agent, directories, home,
|
|
17793
|
-
const homeConfigPath =
|
|
18078
|
+
function assertProjectDiscovery(agent, directories, home, canonical6 = resolve15, reviewed) {
|
|
18079
|
+
const homeConfigPath = canonical6(agentDiscoveryConfigPath(home, agent));
|
|
17794
18080
|
for (const directory of directories) {
|
|
17795
18081
|
const isHome = resolve15(directory) === resolve15(home);
|
|
17796
18082
|
if (agent === "hermes") {
|
|
@@ -17801,7 +18087,7 @@ function assertProjectDiscovery(agent, directories, home, canonical5 = resolve15
|
|
|
17801
18087
|
continue;
|
|
17802
18088
|
const paths = agent === "claude" ? [...isHome ? [] : [".claude/settings.json"], ".claude/settings.local.json"] : agent === "codex" ? [".codex/config.toml"] : agent === "gemini" ? [".gemini/settings.json"] : agent === "opencode" ? ["opencode.json", "opencode.jsonc", ".opencode/opencode.json", ".opencode/opencode.jsonc"] : [".cursor/hooks.json"];
|
|
17803
18089
|
for (const suffix of paths) {
|
|
17804
|
-
const path =
|
|
18090
|
+
const path = canonical6(join27(directory, suffix)), raw = read2(path);
|
|
17805
18091
|
if (raw === null)
|
|
17806
18092
|
continue;
|
|
17807
18093
|
const isRootAliasedHomeConfig = agent === "claude" && suffix === ".claude/settings.json" || agent === "codex" && suffix === ".codex/config.toml";
|
|
@@ -17817,14 +18103,14 @@ function assertProjectDiscovery(agent, directories, home, canonical5 = resolve15
|
|
|
17817
18103
|
const managed = reviewed.sources.flatMap((source) => source.hashMode === "claude-plugin-registry" ? source.managedPlugins ?? [] : []);
|
|
17818
18104
|
if (exact && projected(exact) === exact.sha256 && managed.length) {
|
|
17819
18105
|
const bindings = managed.map((item) => readPluginBinding(item.storeRoot, item.bindingId));
|
|
17820
|
-
admittedPlugins = Object.entries(config.enabledPlugins).every(([id, enabled]) => typeof enabled === "boolean" && bindings.some((binding) => binding.target.pluginId === id && binding.target.registrations.some((scope) => scope.scope === "project" && scope.projectPath ===
|
|
18106
|
+
admittedPlugins = Object.entries(config.enabledPlugins).every(([id, enabled]) => typeof enabled === "boolean" && bindings.some((binding) => binding.target.pluginId === id && binding.target.registrations.some((scope) => scope.scope === "project" && scope.projectPath === canonical6(directory))));
|
|
17821
18107
|
}
|
|
17822
18108
|
}
|
|
17823
18109
|
if (keys.some((key) => config[key] !== undefined && !(key === "enabledPlugins" && admittedPlugins)) || config.disableAllHooks === true || config.disableBundledSkills === false || config.hooksConfig?.enabled === false || config.permission?.skill !== undefined || config.permissions?.deny?.some((rule) => typeof rule === "string" && /^Skill(?:\(|$)/.test(rule)))
|
|
17824
18110
|
throw new Error(`NATIVE_SKILL_DRIFT: higher-precedence project skill or hook configuration requires review: ${path}`);
|
|
17825
18111
|
}
|
|
17826
18112
|
if (agent === "claude") {
|
|
17827
|
-
const commands =
|
|
18113
|
+
const commands = canonical6(join27(directory, ".claude/commands"));
|
|
17828
18114
|
safe4(commands);
|
|
17829
18115
|
if (lstatSync21(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync10(commands).length)
|
|
17830
18116
|
throw new Error("NATIVE_SKILL_DRIFT: legacy project command discovery requires a dedicated format adapter");
|
|
@@ -17835,10 +18121,10 @@ function agentDiscoveryConfigPath(home, agent) {
|
|
|
17835
18121
|
return join27(home, agent === "hermes" ? ".hermes/config.yaml" : agent === "opencode" ? ".config/opencode/opencode.json" : `.${agent}/${agent === "codex" ? "config.toml" : agent === "cursor" ? "hooks.json" : "settings.json"}`);
|
|
17836
18122
|
}
|
|
17837
18123
|
function resolveAgentDiscovery(options) {
|
|
17838
|
-
const
|
|
18124
|
+
const canonical6 = options.canonical ?? resolve15, home = resolve15(options.home), agent = options.agent;
|
|
17839
18125
|
const sources = [], roots = new Set, builtinNames = [];
|
|
17840
|
-
const witness = (path, format,
|
|
17841
|
-
const source = { path:
|
|
18126
|
+
const witness = (path, format, fields2) => {
|
|
18127
|
+
const source = { path: canonical6(path), sha256: null, ...format ? { format, fields: fields2 } : {} };
|
|
17842
18128
|
source.sha256 = projected(source);
|
|
17843
18129
|
sources.push(source);
|
|
17844
18130
|
return read2(source.path);
|
|
@@ -17846,7 +18132,7 @@ function resolveAgentDiscovery(options) {
|
|
|
17846
18132
|
if (agent === "hermes")
|
|
17847
18133
|
assertHermesEnvironment(home);
|
|
17848
18134
|
const configPath = agentDiscoveryConfigPath(home, agent);
|
|
17849
|
-
const configText = witness(configPath, agent === "hermes" ? "yaml" : agent === "codex" ? "toml" : "json", agent === "hermes" ? ["skills", "plugins", "hooks"] : agent === "claude" ? ["enabledPlugins", "extraKnownMarketplaces"] : agent === "codex" ? [
|
|
18135
|
+
const configText = witness(configPath, agent === "hermes" ? "yaml" : agent === "codex" ? "toml" : "json", agent === "hermes" ? ["skills", "plugins", "hooks"] : agent === "claude" ? ["enabledPlugins", "extraKnownMarketplaces"] : agent === "codex" ? [...CODEX_DISCOVERY_PROJECTION_FIELDS] : agent === "gemini" ? ["skills", "extensions", "security"] : agent === "opencode" ? ["plugin", "skills"] : ["version"]);
|
|
17850
18136
|
const config = configText === null ? {} : agent === "hermes" ? parseHermesConfig(configText) : parseConfig(configText, configPath, agent === "codex");
|
|
17851
18137
|
const unresolved = (detail) => {
|
|
17852
18138
|
throw new Error(`Native discovery is unresolved (${agent}: ${detail}); provide a reviewed --discovery-inputs file`);
|
|
@@ -17905,11 +18191,12 @@ function resolveAgentDiscovery(options) {
|
|
|
17905
18191
|
if (retained.agent !== agent || retained.method !== "reviewed")
|
|
17906
18192
|
unresolved("invalid retained review");
|
|
17907
18193
|
verifyAgentDiscovery(retained);
|
|
17908
|
-
if (!retained.sources.some((source) => source.path ===
|
|
18194
|
+
if (!retained.sources.some((source) => source.path === canonical6(configPath) && source.format === undefined && source.fields === undefined))
|
|
17909
18195
|
unresolved("retained review is missing the full agent configuration source");
|
|
17910
|
-
if (retained.sources.some((source) => (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "codex-settings-v1")) && source.path !==
|
|
18196
|
+
if (retained.sources.some((source) => (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2"))) && source.path !== canonical6(configPath)))
|
|
17911
18197
|
unresolved("retained settings witness names another configuration source");
|
|
17912
|
-
|
|
18198
|
+
const covered = supersedesCodexProjection(retained.sources, canonical6(configPath)) ? sources.filter((source) => !isSupersededCodexProjection(agent, canonical6(configPath), source)) : sources;
|
|
18199
|
+
if (covered.some((source) => !retained.sources.some((saved) => isDeepStrictEqual4(saved, source))) || [...roots].some((root2) => !retained.roots.includes(root2)) || agent === "gemini" && JSON.stringify(retained.builtinNames) !== JSON.stringify(builtinNames))
|
|
17913
18200
|
unresolved("retained review is missing current runtime discovery coverage");
|
|
17914
18201
|
return retained;
|
|
17915
18202
|
}
|
|
@@ -17923,14 +18210,15 @@ function resolveAgentDiscovery(options) {
|
|
|
17923
18210
|
if (review.sources.some((source) => source.format !== undefined || source.fields !== undefined))
|
|
17924
18211
|
throw new Error("Explicit discovery reviews require full source-file hashes");
|
|
17925
18212
|
verifyAgentDiscovery(supplied);
|
|
17926
|
-
if (review.sources.some((source) => (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "codex-settings-v1")) && source.path !==
|
|
18213
|
+
if (review.sources.some((source) => (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2"))) && source.path !== canonical6(configPath)))
|
|
17927
18214
|
throw new Error("Semantic settings witnesses must name the configured Claude configuration source");
|
|
17928
|
-
if (!review.sources.some((source) => source.path ===
|
|
18215
|
+
if (!review.sources.some((source) => source.path === canonical6(configPath)))
|
|
17929
18216
|
throw new Error("Discovery review must include the agent configuration source");
|
|
17930
|
-
|
|
18217
|
+
const reviewedSources = supersedesCodexProjection(review.sources, canonical6(configPath)) ? sources.filter((source) => !isSupersededCodexProjection(agent, canonical6(configPath), source)) : sources;
|
|
18218
|
+
return { ...supplied, roots: [...new Set([...roots, ...supplied.roots])].sort(), sources: [...reviewedSources, ...review.sources], ...agent === "gemini" ? { builtinNames } : {} };
|
|
17931
18219
|
}
|
|
17932
18220
|
function plugin(root2) {
|
|
17933
|
-
root2 =
|
|
18221
|
+
root2 = canonical6(root2);
|
|
17934
18222
|
safe4(root2);
|
|
17935
18223
|
const manifestPath = join27(root2, agent === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json");
|
|
17936
18224
|
const raw = witness(manifestPath);
|
|
@@ -17962,7 +18250,7 @@ function resolveAgentDiscovery(options) {
|
|
|
17962
18250
|
if (agent === "claude") {
|
|
17963
18251
|
const registrations = witness(join27(home, ".claude/plugins/installed_plugins.json"));
|
|
17964
18252
|
const installed = registrations === null ? {} : parseConfig(registrations, join27(home, ".claude/plugins/installed_plugins.json")).plugins;
|
|
17965
|
-
const commands =
|
|
18253
|
+
const commands = canonical6(join27(home, ".claude/commands"));
|
|
17966
18254
|
safe4(commands);
|
|
17967
18255
|
if (lstatSync21(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync10(commands).length)
|
|
17968
18256
|
unresolved("legacy home command discovery requires a dedicated format adapter");
|
|
@@ -18036,7 +18324,7 @@ function resolveAgentDiscovery(options) {
|
|
|
18036
18324
|
roots.add(join27(root2, "skills"));
|
|
18037
18325
|
}
|
|
18038
18326
|
}
|
|
18039
|
-
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join27(home, ".hermes/plugins"), join27(home, ".hermes/hermes-agent")].map((path) =>
|
|
18327
|
+
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join27(home, ".hermes/plugins"), join27(home, ".hermes/hermes-agent")].map((path) => canonical6(path))) } : {} };
|
|
18040
18328
|
}
|
|
18041
18329
|
|
|
18042
18330
|
// src/lib/authoring-path.ts
|
|
@@ -18228,7 +18516,7 @@ function scaffoldPortableSkill(name, options = {}) {
|
|
|
18228
18516
|
return { name: skillName, path: skillPath, manifest, created: true };
|
|
18229
18517
|
}
|
|
18230
18518
|
function portPortableSkillDirectory(sourceDir, options = {}) {
|
|
18231
|
-
const absoluteSource =
|
|
18519
|
+
const absoluteSource = normalize4(sourceDir);
|
|
18232
18520
|
if (!existsSync13(absoluteSource) || !statSync10(absoluteSource).isDirectory()) {
|
|
18233
18521
|
throw new Error(`Import directory not found: ${sourceDir}`);
|
|
18234
18522
|
}
|
|
@@ -18295,7 +18583,7 @@ function assertDisjointImportPaths(source, destination) {
|
|
|
18295
18583
|
}
|
|
18296
18584
|
}
|
|
18297
18585
|
function portPortableSkill(sourcePath, options = {}) {
|
|
18298
|
-
const absoluteSource =
|
|
18586
|
+
const absoluteSource = normalize4(sourcePath);
|
|
18299
18587
|
if (!existsSync13(absoluteSource) || !statSync10(absoluteSource).isDirectory()) {
|
|
18300
18588
|
throw new Error(`Skill source directory not found: ${sourcePath}`);
|
|
18301
18589
|
}
|
|
@@ -18571,7 +18859,7 @@ function safeIsDirectory(path) {
|
|
|
18571
18859
|
function isSafeRelativePath2(value) {
|
|
18572
18860
|
if (!value.trim() || isAbsolute17(value))
|
|
18573
18861
|
return false;
|
|
18574
|
-
const normalized =
|
|
18862
|
+
const normalized = normalize4(value).replace(/\\/g, "/");
|
|
18575
18863
|
return normalized !== ".." && !normalized.startsWith("../") && !normalized.includes("/../");
|
|
18576
18864
|
}
|
|
18577
18865
|
function add3(target, code, message) {
|
|
@@ -18885,7 +19173,7 @@ function getAllTags() {
|
|
|
18885
19173
|
return Array.from(tagSet).sort();
|
|
18886
19174
|
}
|
|
18887
19175
|
// src/lib/run-state.ts
|
|
18888
|
-
import { createHash as
|
|
19176
|
+
import { createHash as createHash19, randomBytes } from "crypto";
|
|
18889
19177
|
import { existsSync as existsSync15, mkdirSync as mkdirSync10, readFileSync as readFileSync19, readdirSync as readdirSync13, statSync as statSync11, writeFileSync as writeFileSync9 } from "fs";
|
|
18890
19178
|
import { extname, join as join31, relative as relative7 } from "path";
|
|
18891
19179
|
function createSkillRun(params, targetDir = process.cwd()) {
|
|
@@ -19012,7 +19300,7 @@ function collectRunArtifacts(context) {
|
|
|
19012
19300
|
artifacts.push({
|
|
19013
19301
|
path: toProjectRelative(context.targetDir, path),
|
|
19014
19302
|
mime: mimeForPath(path),
|
|
19015
|
-
sha256:
|
|
19303
|
+
sha256: createHash19("sha256").update(bytes).digest("hex"),
|
|
19016
19304
|
sizeBytes: stat2.size
|
|
19017
19305
|
});
|
|
19018
19306
|
}
|
|
@@ -22370,15 +22658,15 @@ var $ZodDate = /* @__PURE__ */ $constructor("$ZodDate", (inst, def) => {
|
|
|
22370
22658
|
} catch (_err) {}
|
|
22371
22659
|
}
|
|
22372
22660
|
const input = payload.value;
|
|
22373
|
-
const
|
|
22374
|
-
const isValidDate =
|
|
22661
|
+
const isDate2 = input instanceof Date;
|
|
22662
|
+
const isValidDate = isDate2 && !Number.isNaN(input.getTime());
|
|
22375
22663
|
if (isValidDate)
|
|
22376
22664
|
return payload;
|
|
22377
22665
|
payload.issues.push({
|
|
22378
22666
|
expected: "date",
|
|
22379
22667
|
code: "invalid_type",
|
|
22380
22668
|
input,
|
|
22381
|
-
...
|
|
22669
|
+
...isDate2 ? { received: "Invalid Date" } : {},
|
|
22382
22670
|
inst
|
|
22383
22671
|
});
|
|
22384
22672
|
return payload;
|
|
@@ -38431,7 +38719,7 @@ function clone2(value) {
|
|
|
38431
38719
|
return value === undefined ? undefined : JSON.parse(JSON.stringify(value));
|
|
38432
38720
|
}
|
|
38433
38721
|
// src/lib/canonical-json.ts
|
|
38434
|
-
import { createHash as
|
|
38722
|
+
import { createHash as createHash20 } from "crypto";
|
|
38435
38723
|
function canonicalJson2(value, maximumBytes = 2 * 1024 * 1024) {
|
|
38436
38724
|
return canonicalJsonAtDepth(value, maximumBytes, 64);
|
|
38437
38725
|
}
|
|
@@ -38475,7 +38763,7 @@ function canonicalJsonAtDepth(value, maximumBytes, maximumDepth) {
|
|
|
38475
38763
|
return visit3(value, 0);
|
|
38476
38764
|
}
|
|
38477
38765
|
function canonicalJsonSha256(value, maximumBytes) {
|
|
38478
|
-
return
|
|
38766
|
+
return createHash20("sha256").update(canonicalJson2(value, maximumBytes)).digest("hex");
|
|
38479
38767
|
}
|
|
38480
38768
|
|
|
38481
38769
|
// src/lib/remote-recurring-contract.ts
|
|
@@ -39231,7 +39519,7 @@ function getApiUrl(action, env = process.env, options = {}) {
|
|
|
39231
39519
|
// src/lib/remote-run-contract.ts
|
|
39232
39520
|
var REMOTE_SKILL_RUN_CONTRACT_VERSION = 1;
|
|
39233
39521
|
function normalizeRemoteSkillRunContract(payload, fallbackSkill) {
|
|
39234
|
-
const record6 =
|
|
39522
|
+
const record6 = isRecord4(payload) ? payload : {};
|
|
39235
39523
|
return {
|
|
39236
39524
|
contractVersion: REMOTE_SKILL_RUN_CONTRACT_VERSION,
|
|
39237
39525
|
...pickString(record6, "id"),
|
|
@@ -39253,7 +39541,7 @@ function normalizeRemoteSkillRunContract(payload, fallbackSkill) {
|
|
|
39253
39541
|
...hasOwn(record6, "details") ? { details: record6.details } : {}
|
|
39254
39542
|
};
|
|
39255
39543
|
}
|
|
39256
|
-
function
|
|
39544
|
+
function isRecord4(value) {
|
|
39257
39545
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
39258
39546
|
}
|
|
39259
39547
|
function hasOwn(record6, key) {
|
|
@@ -39385,7 +39673,7 @@ function creditCheckoutFailure(value, status, key) {
|
|
|
39385
39673
|
|
|
39386
39674
|
// src/lib/remote-profile.ts
|
|
39387
39675
|
function customerNamePatch(input2, field2) {
|
|
39388
|
-
if (!
|
|
39676
|
+
if (!isRecord5(input2) || Object.keys(input2).length !== 1 || !Object.hasOwn(input2, field2))
|
|
39389
39677
|
throw new Error("Provide only the requested name field.");
|
|
39390
39678
|
const value = input2[field2];
|
|
39391
39679
|
if (typeof value !== "string" || /[\p{Cc}\p{Cs}\u2028\u2029]/u.test(value) || !value.trim() || [...value.trim()].length > 100) {
|
|
@@ -39393,22 +39681,22 @@ function customerNamePatch(input2, field2) {
|
|
|
39393
39681
|
}
|
|
39394
39682
|
return { [field2]: value.trim() };
|
|
39395
39683
|
}
|
|
39396
|
-
function
|
|
39684
|
+
function isRecord5(value) {
|
|
39397
39685
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
39398
39686
|
}
|
|
39399
39687
|
function string4(value) {
|
|
39400
39688
|
return typeof value === "string" && value.length > 0;
|
|
39401
39689
|
}
|
|
39402
39690
|
function parseUpdatedProfile(value) {
|
|
39403
|
-
const user =
|
|
39404
|
-
if (!
|
|
39691
|
+
const user = isRecord5(value) && value.user;
|
|
39692
|
+
if (!isRecord5(user) || !string4(user.id) || !string4(user.email) || !(user.displayName === null || typeof user.displayName === "string") || typeof user.role !== "string" || !["owner", "admin", "member", "viewer"].includes(user.role)) {
|
|
39405
39693
|
throw new Error("The server returned an invalid account profile.");
|
|
39406
39694
|
}
|
|
39407
39695
|
return { user: { id: user.id, email: user.email, displayName: user.displayName, role: user.role } };
|
|
39408
39696
|
}
|
|
39409
39697
|
function parseUpdatedWorkspace(value) {
|
|
39410
|
-
const organization2 =
|
|
39411
|
-
if (!
|
|
39698
|
+
const organization2 = isRecord5(value) && value.organization;
|
|
39699
|
+
if (!isRecord5(organization2) || !string4(organization2.id) || !string4(organization2.slug) || !string4(organization2.name)) {
|
|
39412
39700
|
throw new Error("The server returned an invalid workspace.");
|
|
39413
39701
|
}
|
|
39414
39702
|
return { organization: { id: organization2.id, slug: organization2.slug, name: organization2.name } };
|
|
@@ -40597,11 +40885,11 @@ function validateCronField(expr, min, max, label) {
|
|
|
40597
40885
|
return { valid: true };
|
|
40598
40886
|
}
|
|
40599
40887
|
function validateCron(expr) {
|
|
40600
|
-
const
|
|
40601
|
-
if (
|
|
40602
|
-
return { valid: false, error: `Expected 5 fields, got ${
|
|
40888
|
+
const fields2 = expr.trim().split(/\s+/);
|
|
40889
|
+
if (fields2.length !== 5) {
|
|
40890
|
+
return { valid: false, error: `Expected 5 fields, got ${fields2.length}. Format: "minute hour day-of-month month day-of-week"` };
|
|
40603
40891
|
}
|
|
40604
|
-
const [minuteF, hourF, domF, monthF, dowF] =
|
|
40892
|
+
const [minuteF, hourF, domF, monthF, dowF] = fields2;
|
|
40605
40893
|
const checks3 = [
|
|
40606
40894
|
{ expr: minuteF, min: 0, max: 59, label: "minute" },
|
|
40607
40895
|
{ expr: hourF, min: 0, max: 23, label: "hour" },
|
|
@@ -40742,7 +41030,7 @@ function recordScheduleRun(id, status, targetDir) {
|
|
|
40742
41030
|
saveSchedules(data, targetDir);
|
|
40743
41031
|
}
|
|
40744
41032
|
// src/lib/revision.ts
|
|
40745
|
-
import { createHash as
|
|
41033
|
+
import { createHash as createHash21 } from "crypto";
|
|
40746
41034
|
var REVISION_ID_PATTERN = /^[0-9a-f]{64}$/;
|
|
40747
41035
|
function revisionIdOf(content) {
|
|
40748
41036
|
const canonicalContent = {
|
|
@@ -40763,8 +41051,8 @@ function revisionIdOf(content) {
|
|
|
40763
41051
|
canonicalContent.archiveReason = content.archiveReason ?? null;
|
|
40764
41052
|
canonicalContent.replacementSlug = content.replacementSlug ?? null;
|
|
40765
41053
|
}
|
|
40766
|
-
const
|
|
40767
|
-
return
|
|
41054
|
+
const canonical6 = JSON.stringify(canonicalContent);
|
|
41055
|
+
return createHash21("sha256").update(canonical6).digest("hex");
|
|
40768
41056
|
}
|
|
40769
41057
|
function revisionIdOfRecord(record7) {
|
|
40770
41058
|
return revisionIdOf(record7);
|
|
@@ -41305,7 +41593,7 @@ async function requestInvitationEmail(origin, action, input2) {
|
|
|
41305
41593
|
}
|
|
41306
41594
|
|
|
41307
41595
|
// src/lib/remote-private-publications.ts
|
|
41308
|
-
import { createHash as
|
|
41596
|
+
import { createHash as createHash22 } from "crypto";
|
|
41309
41597
|
var PRIVATE_PUBLICATION_MAX_BYTES = 16 * 1024 * 1024;
|
|
41310
41598
|
var failures2 = {
|
|
41311
41599
|
INVALID_REQUEST: [400, "The publication request is invalid."],
|
|
@@ -41352,7 +41640,7 @@ var hash3 = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v);
|
|
|
41352
41640
|
var record8 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
41353
41641
|
var exact = (v, keys) => record8(v) && Object.keys(v).sort().join(",") === keys.sort().join(",");
|
|
41354
41642
|
var date5 = (v) => typeof v === "string" && /^\d{4}-\d\d-\d\dT[0-9:.]+(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/.test(v) && Number.isFinite(Date.parse(v));
|
|
41355
|
-
var publicationSha256 = (bytes) =>
|
|
41643
|
+
var publicationSha256 = (bytes) => createHash22("sha256").update(bytes).digest("hex");
|
|
41356
41644
|
function checkedPublicationDeclaration(value) {
|
|
41357
41645
|
if (!exact(value, ["idempotencyKey", "version", "expectedCurrentVersionId", "manifestText", "archiveSha256", "archiveByteSize"]) || !publicationUuid(value.idempotencyKey) || !(value.expectedCurrentVersionId === null || publicationUuid(value.expectedCurrentVersionId)) || typeof value.version !== "string" || !value.version || value.version.length > 128 || /[\p{Cc}\p{Cs}]/u.test(value.version) || typeof value.manifestText !== "string" || Buffer.byteLength(value.manifestText) > 16384 || !hash3(value.archiveSha256) || !Number.isSafeInteger(value.archiveByteSize) || Number(value.archiveByteSize) < 1 || Number(value.archiveByteSize) > PRIVATE_PUBLICATION_MAX_BYTES)
|
|
41358
41646
|
return bad();
|
|
@@ -41651,7 +41939,7 @@ async function requestAuthApi(instance, path, options) {
|
|
|
41651
41939
|
const text3 = await res.text();
|
|
41652
41940
|
const body = text3 ? parseJsonBody(text3) : {};
|
|
41653
41941
|
if (!res.ok) {
|
|
41654
|
-
const record9 =
|
|
41942
|
+
const record9 = isRecord6(body) ? body : {};
|
|
41655
41943
|
const detail = typeof record9.detail === "string" ? record9.detail : undefined;
|
|
41656
41944
|
const error61 = typeof record9.error === "string" ? record9.error : undefined;
|
|
41657
41945
|
const code = typeof record9.code === "string" ? record9.code : undefined;
|
|
@@ -41679,7 +41967,7 @@ function condenseErrorBody(text3) {
|
|
|
41679
41967
|
return collapsed;
|
|
41680
41968
|
return `${collapsed.slice(0, MAX_ERROR_DETAIL_LENGTH - 1).trimEnd()}\u2026`;
|
|
41681
41969
|
}
|
|
41682
|
-
function
|
|
41970
|
+
function isRecord6(value) {
|
|
41683
41971
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
41684
41972
|
}
|
|
41685
41973
|
|
|
@@ -41836,7 +42124,7 @@ class RemoteSkillsAuthClient {
|
|
|
41836
42124
|
|
|
41837
42125
|
// src/lib/recurring-recovery.ts
|
|
41838
42126
|
var uuid12 = exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/);
|
|
41839
|
-
var
|
|
42127
|
+
var sha5 = exports_external.string().regex(/^[a-f0-9]{64}$/);
|
|
41840
42128
|
var common = exports_external.object({
|
|
41841
42129
|
contractVersion: exports_external.literal(1),
|
|
41842
42130
|
apiOrigin: exports_external.string().min(1).max(4096),
|
|
@@ -41849,7 +42137,7 @@ var intentSchema = exports_external.discriminatedUnion("operation", [
|
|
|
41849
42137
|
common.extend({
|
|
41850
42138
|
operation: exports_external.literal("activate"),
|
|
41851
42139
|
draftId: uuid12,
|
|
41852
|
-
termsSha256:
|
|
42140
|
+
termsSha256: sha5,
|
|
41853
42141
|
approvalDeadline: exports_external.string().datetime(),
|
|
41854
42142
|
approval: recurringActivationSchema
|
|
41855
42143
|
}).strict(),
|
|
@@ -41857,7 +42145,7 @@ var intentSchema = exports_external.discriminatedUnion("operation", [
|
|
|
41857
42145
|
]);
|
|
41858
42146
|
var stateSchema = exports_external.object({
|
|
41859
42147
|
contractVersion: exports_external.literal(1),
|
|
41860
|
-
intentSha256:
|
|
42148
|
+
intentSha256: sha5,
|
|
41861
42149
|
phase: exports_external.enum(["prepared", "pending", "observed"]),
|
|
41862
42150
|
consentId: uuid12.nullable()
|
|
41863
42151
|
}).strict();
|
|
@@ -43218,7 +43506,7 @@ function isApiMode(env = process.env) {
|
|
|
43218
43506
|
}
|
|
43219
43507
|
}
|
|
43220
43508
|
// src/lib/native-storage.ts
|
|
43221
|
-
import { createHash as
|
|
43509
|
+
import { createHash as createHash23, createHmac as createHmac2 } from "crypto";
|
|
43222
43510
|
import {
|
|
43223
43511
|
existsSync as existsSync19,
|
|
43224
43512
|
mkdirSync as mkdirSync15,
|
|
@@ -43227,7 +43515,7 @@ import {
|
|
|
43227
43515
|
statSync as statSync12,
|
|
43228
43516
|
writeFileSync as writeFileSync13
|
|
43229
43517
|
} from "fs";
|
|
43230
|
-
import { dirname as dirname23, join as join35, normalize as
|
|
43518
|
+
import { dirname as dirname23, join as join35, normalize as normalize5, relative as relative9, sep as sep9 } from "path";
|
|
43231
43519
|
var SKILLS_STORAGE_TABLES = [
|
|
43232
43520
|
"skills_sync_records",
|
|
43233
43521
|
"skills_sync_cursors"
|
|
@@ -43394,7 +43682,7 @@ function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
|
|
|
43394
43682
|
files.push({
|
|
43395
43683
|
path: relativePath,
|
|
43396
43684
|
sizeBytes: bytes.byteLength,
|
|
43397
|
-
sha256:
|
|
43685
|
+
sha256: createHash23("sha256").update(bytes).digest("hex"),
|
|
43398
43686
|
...options.includeFileContents ? { contentBase64: Buffer.from(bytes).toString("base64") } : {}
|
|
43399
43687
|
});
|
|
43400
43688
|
}
|
|
@@ -43419,7 +43707,7 @@ function importSkillsLocalSnapshot(snapshot2, targetDir = process.cwd(), options
|
|
|
43419
43707
|
continue;
|
|
43420
43708
|
}
|
|
43421
43709
|
const bytes = Buffer.from(file2.contentBase64, "base64");
|
|
43422
|
-
const hash4 =
|
|
43710
|
+
const hash4 = createHash23("sha256").update(bytes).digest("hex");
|
|
43423
43711
|
if (hash4 !== file2.sha256) {
|
|
43424
43712
|
throw new Error(`Snapshot file checksum mismatch: ${file2.path}`);
|
|
43425
43713
|
}
|
|
@@ -43731,7 +44019,7 @@ function walkFiles2(dir) {
|
|
|
43731
44019
|
return files;
|
|
43732
44020
|
}
|
|
43733
44021
|
function resolveSnapshotPath(targetDir, snapshotPath) {
|
|
43734
|
-
const normalizedPath =
|
|
44022
|
+
const normalizedPath = normalize5(snapshotPath);
|
|
43735
44023
|
if (normalizedPath.startsWith("..") || normalizedPath.includes(`${sep9}..${sep9}`) || normalizedPath.startsWith(sep9)) {
|
|
43736
44024
|
throw new Error(`Unsafe snapshot path: ${snapshotPath}`);
|
|
43737
44025
|
}
|
|
@@ -43751,7 +44039,7 @@ function toIsoString(value) {
|
|
|
43751
44039
|
return Number.isNaN(date6.getTime()) ? value : date6.toISOString();
|
|
43752
44040
|
}
|
|
43753
44041
|
function sha256Hex2(value) {
|
|
43754
|
-
return
|
|
44042
|
+
return createHash23("sha256").update(value).digest("hex");
|
|
43755
44043
|
}
|
|
43756
44044
|
function normalizeHeaders(headers) {
|
|
43757
44045
|
const result = {};
|
|
@@ -43803,7 +44091,7 @@ function toArrayBuffer(bytes) {
|
|
|
43803
44091
|
return buffer;
|
|
43804
44092
|
}
|
|
43805
44093
|
// src/lib/station-snapshot.ts
|
|
43806
|
-
import { createHash as
|
|
44094
|
+
import { createHash as createHash24 } from "crypto";
|
|
43807
44095
|
import {
|
|
43808
44096
|
copyFileSync,
|
|
43809
44097
|
mkdirSync as mkdirSync16,
|
|
@@ -43978,7 +44266,7 @@ function validateStationId(stationId) {
|
|
|
43978
44266
|
}
|
|
43979
44267
|
}
|
|
43980
44268
|
function sha256File(filePath) {
|
|
43981
|
-
return
|
|
44269
|
+
return createHash24("sha256").update(readFileSync25(filePath)).digest("hex");
|
|
43982
44270
|
}
|
|
43983
44271
|
function scanHome(definition, homesRoot) {
|
|
43984
44272
|
const homePath = homePathFor(definition, homesRoot);
|
|
@@ -44129,7 +44417,7 @@ function writeStationSnapshot(options) {
|
|
|
44129
44417
|
};
|
|
44130
44418
|
}
|
|
44131
44419
|
// src/lib/station-hydrate.ts
|
|
44132
|
-
import { createHash as
|
|
44420
|
+
import { createHash as createHash25 } from "crypto";
|
|
44133
44421
|
import {
|
|
44134
44422
|
copyFileSync as copyFileSync2,
|
|
44135
44423
|
mkdirSync as mkdirSync17,
|
|
@@ -44335,7 +44623,7 @@ function skillSha256(skill) {
|
|
|
44335
44623
|
return sha256File(skill.files[0].winner.fullPath);
|
|
44336
44624
|
}
|
|
44337
44625
|
const joined = skill.files.map((file2) => sha256File(file2.winner.fullPath));
|
|
44338
|
-
return
|
|
44626
|
+
return createHash25("sha256").update(joined.sort().join(`
|
|
44339
44627
|
`)).digest("hex");
|
|
44340
44628
|
}
|
|
44341
44629
|
function writeStationHydration(options) {
|
|
@@ -44663,7 +44951,7 @@ async function inspectLocked(client2, directory2, cancel) {
|
|
|
44663
44951
|
return privatePublicationResult(directory2, receipt);
|
|
44664
44952
|
}
|
|
44665
44953
|
// src/lib/skill-context.ts
|
|
44666
|
-
import { createHash as
|
|
44954
|
+
import { createHash as createHash26 } from "crypto";
|
|
44667
44955
|
import { resolve as resolve21 } from "path";
|
|
44668
44956
|
function words(value) {
|
|
44669
44957
|
return new Set(value.toLowerCase().match(/[a-z0-9]+/g) ?? []);
|
|
@@ -44752,7 +45040,7 @@ ${content}`;
|
|
|
44752
45040
|
`);
|
|
44753
45041
|
const receipt = {
|
|
44754
45042
|
schemaVersion: 1,
|
|
44755
|
-
id:
|
|
45043
|
+
id: createHash26("sha256").update(JSON.stringify({ profile: profile.profileRevision, sessionId, selections, omitted })).digest("hex"),
|
|
44756
45044
|
profileId: profile.profileId,
|
|
44757
45045
|
profileRevision: profile.profileRevision,
|
|
44758
45046
|
authority: profile.authority,
|
|
@@ -44768,9 +45056,9 @@ ${content}`;
|
|
|
44768
45056
|
return { context: context2, selections, omitted, receipt };
|
|
44769
45057
|
}
|
|
44770
45058
|
// src/lib/session-reconciliation.ts
|
|
44771
|
-
import { createHash as
|
|
45059
|
+
import { createHash as createHash27 } from "crypto";
|
|
44772
45060
|
var SESSION_RECONCILIATION_PLAN_TTL_MS = 5 * 60 * 1000;
|
|
44773
|
-
var digest3 = (value) =>
|
|
45061
|
+
var digest3 = (value) => createHash27("sha256").update(JSON.stringify(value)).digest("hex");
|
|
44774
45062
|
function exactTimestamp(value) {
|
|
44775
45063
|
const parsed = value === undefined ? Number.NaN : Date.parse(value);
|
|
44776
45064
|
if (!Number.isFinite(parsed) || new Date(parsed).toISOString() !== value) {
|
|
@@ -45069,6 +45357,7 @@ export {
|
|
|
45069
45357
|
captureDiscoveryPathSources,
|
|
45070
45358
|
captureDiscoveryDirectories,
|
|
45071
45359
|
captureDiscoveryByteSources,
|
|
45360
|
+
captureCodexSettingsV2,
|
|
45072
45361
|
captureCodexSettings,
|
|
45073
45362
|
captureCodexNativeSkillCatalog,
|
|
45074
45363
|
captureClaudeSettingsV3,
|