@hasna/skills 0.10.72 → 0.10.74
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 +347 -2
- package/bin/index.js +2197 -1277
- package/bin/mcp.js +194 -46
- package/bin/migrate.js +1 -1
- package/bin/server.js +1 -1
- package/bin/worker.js +1 -1
- package/dist/cli/commands/provenance.d.ts +18 -0
- package/dist/index.js +1016 -713
- package/dist/lib/agent-discovery.d.ts +36 -0
- package/dist/lib/claude-installer-binding.d.ts +65 -0
- package/dist/lib/codex-node-modules.d.ts +11 -0
- package/dist/lib/codex-settings-witness-v1.d.ts +9 -0
- package/dist/lib/codex-settings-witness.d.ts +18 -0
- package/dist/lib/portable-skills-files.d.ts +10 -0
- package/dist/lib/selected-run.d.ts +45 -0
- package/dist/lib/selection-provenance.d.ts +108 -0
- package/dist/runtime-prerequisites.js +1 -1
- package/dist/sdk/index.js +1174 -842
- package/docs/plugin-admission.md +63 -12
- package/docs/skill-standard.md +18 -4
- package/package.json +1 -1
package/bin/mcp.js
CHANGED
|
@@ -23,7 +23,7 @@ var package_default;
|
|
|
23
23
|
var init_package = __esm(() => {
|
|
24
24
|
package_default = {
|
|
25
25
|
name: "@hasna/skills",
|
|
26
|
-
version: "0.10.
|
|
26
|
+
version: "0.10.74",
|
|
27
27
|
description: "Skills library for AI coding agents",
|
|
28
28
|
type: "module",
|
|
29
29
|
bin: {
|
|
@@ -22021,8 +22021,8 @@ function ensureInstructionSkillFiles(skillPath, manifest) {
|
|
|
22021
22021
|
displayName: manifest.displayName ?? displayName(manifest.name),
|
|
22022
22022
|
category: manifest.category ?? "Development Tools",
|
|
22023
22023
|
tags: manifest.tags?.length ? manifest.tags : ["custom", manifest.name],
|
|
22024
|
-
inputs: [],
|
|
22025
|
-
commands: []
|
|
22024
|
+
inputs: Array.isArray(manifest.inputs) ? manifest.inputs : [],
|
|
22025
|
+
commands: Array.isArray(manifest.commands) ? manifest.commands : []
|
|
22026
22026
|
};
|
|
22027
22027
|
if (!existsSync6(join9(skillPath, "SKILL.md"))) {
|
|
22028
22028
|
writeFileSync2(join9(skillPath, "SKILL.md"), renderSkillMd(next));
|
|
@@ -32219,6 +32219,10 @@ function canonical4(value, depth = 0, budget2 = { remaining: 65536 }) {
|
|
|
32219
32219
|
function hashCodexSettingsReplacement(text2, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
32220
32220
|
need4(Buffer.byteLength(text2) <= 1024 * 1024 && budget2.remaining >= Buffer.byteLength(text2));
|
|
32221
32221
|
budget2.remaining -= Buffer.byteLength(text2);
|
|
32222
|
+
const prepared = prepareCodexSettingsV1(text2);
|
|
32223
|
+
return finishCodexSettingsV1(prepared.config, prepared.tokens);
|
|
32224
|
+
}
|
|
32225
|
+
function prepareCodexSettingsV1(text2) {
|
|
32222
32226
|
let config2;
|
|
32223
32227
|
try {
|
|
32224
32228
|
config2 = Bun.TOML.parse(text2);
|
|
@@ -32226,6 +32230,9 @@ function hashCodexSettingsReplacement(text2, budget2 = { remaining: 256 * 1024 *
|
|
|
32226
32230
|
throw new Error("Invalid Codex settings witness");
|
|
32227
32231
|
}
|
|
32228
32232
|
need4(config2 && typeof config2 === "object" && !Array.isArray(config2));
|
|
32233
|
+
return { config: config2, tokens: numericTokens(text2) };
|
|
32234
|
+
}
|
|
32235
|
+
function finishCodexSettingsV1(config2, tokens) {
|
|
32229
32236
|
if (Object.hasOwn(config2, "model")) {
|
|
32230
32237
|
need4(typeof config2.model === "string" && /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$/.test(config2.model));
|
|
32231
32238
|
delete config2.model;
|
|
@@ -32235,11 +32242,7 @@ function hashCodexSettingsReplacement(text2, budget2 = { remaining: 256 * 1024 *
|
|
|
32235
32242
|
need4(typeof config2[key] === "string" && values.has(config2[key]));
|
|
32236
32243
|
delete config2[key];
|
|
32237
32244
|
}
|
|
32238
|
-
return sha(`hasna.skills.codex-settings.v1\x00${JSON.stringify([canonical4(config2),
|
|
32239
|
-
}
|
|
32240
|
-
function captureCodexSettings(path, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
32241
|
-
const text2 = readNativeSettingsWitnessFile(path, budget2, "config.toml");
|
|
32242
|
-
return { path, hashMode: "codex-settings-v1", sha256: hashCodexSettingsReplacement(text2) };
|
|
32245
|
+
return sha(`hasna.skills.codex-settings.v1\x00${JSON.stringify([canonical4(config2), tokens])}`);
|
|
32243
32246
|
}
|
|
32244
32247
|
var sha = (text2) => createHash11("sha256").update(text2).digest("hex"), EFFORT, VERBOSITY;
|
|
32245
32248
|
var init_codex_settings_witness_v1 = __esm(() => {
|
|
@@ -32953,7 +32956,7 @@ function projectStatusLine(config2) {
|
|
|
32953
32956
|
if (!Object.keys(tui).length)
|
|
32954
32957
|
delete config2.tui;
|
|
32955
32958
|
}
|
|
32956
|
-
function
|
|
32959
|
+
function prepareSettings(text2, version2, dependencies) {
|
|
32957
32960
|
let config2;
|
|
32958
32961
|
try {
|
|
32959
32962
|
config2 = Bun.TOML.parse(text2);
|
|
@@ -32992,51 +32995,106 @@ function settingsDigest2(text2, version2 = 2, dependencies) {
|
|
|
32992
32995
|
delete config2.tui.model_availability_nux;
|
|
32993
32996
|
if (isRecord3(config2.tui) && typeof config2.tui.screen_reader_detection_done === "boolean")
|
|
32994
32997
|
delete config2.tui.screen_reader_detection_done;
|
|
32995
|
-
|
|
32998
|
+
return { config: embedCodexNumericTokens(config2, tokens), numericSource: text2, dependencies };
|
|
32999
|
+
}
|
|
33000
|
+
const mcp = version2 >= 3 ? projectRegularCodexMcp(config2, text2) : { config: config2, numericSource: text2 };
|
|
33001
|
+
return version2 >= 4 ? projectModelAvailabilityNux(mcp.config, mcp.numericSource) : mcp;
|
|
33002
|
+
}
|
|
33003
|
+
function finishSettings(prepared, version2) {
|
|
33004
|
+
const config2 = prepared.config;
|
|
33005
|
+
if (version2 === 6) {
|
|
32996
33006
|
normalize2(config2, 6);
|
|
32997
33007
|
if (isRecord3(config2.tui) && !Object.keys(config2.tui).length)
|
|
32998
33008
|
delete config2.tui;
|
|
32999
|
-
return sha2(`hasna.skills.codex-settings.v6\x00${JSON.stringify([canonical5(config2), canonical5(dependencies)])}`);
|
|
33009
|
+
return sha2(`hasna.skills.codex-settings.v6\x00${JSON.stringify([canonical5(config2), canonical5(prepared.dependencies)])}`);
|
|
33000
33010
|
}
|
|
33001
|
-
|
|
33002
|
-
const
|
|
33003
|
-
normalize2(projected.config, version2);
|
|
33004
|
-
const values = [canonical5(projected.config), numericTokens2(projected.numericSource)];
|
|
33011
|
+
normalize2(config2, version2);
|
|
33012
|
+
const values = [canonical5(config2), numericTokens2(prepared.numericSource)];
|
|
33005
33013
|
return sha2(`hasna.skills.codex-settings.v${version2}\x00${JSON.stringify(values)}`);
|
|
33006
33014
|
}
|
|
33015
|
+
function settingsDigest2(text2, version2 = 2, dependencies) {
|
|
33016
|
+
return finishSettings(prepareSettings(text2, version2, dependencies), version2);
|
|
33017
|
+
}
|
|
33018
|
+
function cloneTree(value) {
|
|
33019
|
+
if (Array.isArray(value))
|
|
33020
|
+
return value.map(cloneTree);
|
|
33021
|
+
if (isRecord3(value) && [Object.prototype, null].includes(Object.getPrototypeOf(value)))
|
|
33022
|
+
return Object.fromEntries(Object.entries(value).map(([key2, child2]) => [key2, cloneTree(child2)]));
|
|
33023
|
+
return value;
|
|
33024
|
+
}
|
|
33025
|
+
function receiptEdits(config2) {
|
|
33026
|
+
const tui = config2.tui;
|
|
33027
|
+
const set2 = (value) => (target) => {
|
|
33028
|
+
if (!isRecord3(target.tui))
|
|
33029
|
+
target.tui = {};
|
|
33030
|
+
target.tui[SCREEN_READER_RECEIPT] = value;
|
|
33031
|
+
};
|
|
33032
|
+
if (tui === undefined || isRecord3(tui) && !Object.hasOwn(tui, SCREEN_READER_RECEIPT))
|
|
33033
|
+
return [set2(true), set2(false)];
|
|
33034
|
+
if (!isRecord3(tui) || typeof tui[SCREEN_READER_RECEIPT] !== "boolean")
|
|
33035
|
+
return [];
|
|
33036
|
+
const remove = (dropEmpty) => (target) => {
|
|
33037
|
+
delete target.tui[SCREEN_READER_RECEIPT];
|
|
33038
|
+
if (dropEmpty && !Object.keys(target.tui).length)
|
|
33039
|
+
delete target.tui;
|
|
33040
|
+
};
|
|
33041
|
+
return [remove(true), ...Object.keys(tui).length === 1 ? [remove(false)] : [], set2(!tui[SCREEN_READER_RECEIPT])];
|
|
33042
|
+
}
|
|
33043
|
+
function codexSettingsToleratesScreenReaderReceipt(text2, hashMode, expected) {
|
|
33044
|
+
try {
|
|
33045
|
+
if (Buffer.byteLength(text2) > 1024 * 1024 || !/^[a-f0-9]{64}$/.test(expected))
|
|
33046
|
+
return false;
|
|
33047
|
+
if (hashMode === "codex-settings-v1") {
|
|
33048
|
+
const prepared2 = prepareCodexSettingsV1(text2);
|
|
33049
|
+
return receiptEdits(prepared2.config).some((edit) => {
|
|
33050
|
+
const candidate = cloneTree(prepared2.config);
|
|
33051
|
+
edit(candidate);
|
|
33052
|
+
return finishCodexSettingsV1(candidate, prepared2.tokens) === expected;
|
|
33053
|
+
});
|
|
33054
|
+
}
|
|
33055
|
+
const version2 = Number(hashMode.slice("codex-settings-v".length));
|
|
33056
|
+
if (![2, 3, 4, 5].includes(version2))
|
|
33057
|
+
return false;
|
|
33058
|
+
const prepared = prepareSettings(text2, version2);
|
|
33059
|
+
return receiptEdits(prepared.config).some((edit) => {
|
|
33060
|
+
const candidate = cloneTree(prepared.config);
|
|
33061
|
+
edit(candidate);
|
|
33062
|
+
if (version2 >= 4 && isRecord3(candidate.tui) && !Object.keys(candidate.tui).length)
|
|
33063
|
+
delete candidate.tui;
|
|
33064
|
+
return finishSettings({ ...prepared, config: candidate }, version2) === expected;
|
|
33065
|
+
});
|
|
33066
|
+
} catch {
|
|
33067
|
+
return false;
|
|
33068
|
+
}
|
|
33069
|
+
}
|
|
33070
|
+
function codexSettingsWitnessMatch(path, hashMode, expected, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
33071
|
+
const text2 = readNativeSettingsWitnessFile(path, budget2, "config.toml");
|
|
33072
|
+
need7(Buffer.byteLength(text2) <= 1024 * 1024);
|
|
33073
|
+
const exact = hashMode === "codex-settings-v1" ? hashCodexSettingsReplacement(text2) : settingsDigest2(text2, Number(hashMode.slice("codex-settings-v".length)));
|
|
33074
|
+
if (exact === expected)
|
|
33075
|
+
return "exact";
|
|
33076
|
+
return codexSettingsToleratesScreenReaderReceipt(text2, hashMode, expected) ? "screen-reader-receipt" : null;
|
|
33077
|
+
}
|
|
33007
33078
|
function hashCodexSettingsReplacementV2(text2, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
33008
33079
|
need7(Buffer.byteLength(text2) <= 1024 * 1024 && budget2.remaining >= Buffer.byteLength(text2));
|
|
33009
33080
|
budget2.remaining -= Buffer.byteLength(text2);
|
|
33010
33081
|
return settingsDigest2(text2);
|
|
33011
33082
|
}
|
|
33012
|
-
function captureCodexSettingsV2(path, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
33013
|
-
const text2 = readNativeSettingsWitnessFile(path, budget2, "config.toml");
|
|
33014
|
-
return { path, hashMode: "codex-settings-v2", sha256: settingsDigest2(text2) };
|
|
33015
|
-
}
|
|
33016
33083
|
function hashCodexSettingsReplacementV3(text2, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
33017
33084
|
need7(Buffer.byteLength(text2) <= 1024 * 1024 && budget2.remaining >= Buffer.byteLength(text2));
|
|
33018
33085
|
budget2.remaining -= Buffer.byteLength(text2);
|
|
33019
33086
|
return settingsDigest2(text2, 3);
|
|
33020
33087
|
}
|
|
33021
|
-
function captureCodexSettingsV3(path, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
33022
|
-
return { path, hashMode: "codex-settings-v3", sha256: settingsDigest2(readNativeSettingsWitnessFile(path, budget2, "config.toml"), 3) };
|
|
33023
|
-
}
|
|
33024
33088
|
function hashCodexSettingsReplacementV4(text2, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
33025
33089
|
need7(Buffer.byteLength(text2) <= 1024 * 1024 && budget2.remaining >= Buffer.byteLength(text2));
|
|
33026
33090
|
budget2.remaining -= Buffer.byteLength(text2);
|
|
33027
33091
|
return settingsDigest2(text2, 4);
|
|
33028
33092
|
}
|
|
33029
|
-
function captureCodexSettingsV4(path, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
33030
|
-
return { path, hashMode: "codex-settings-v4", sha256: settingsDigest2(readNativeSettingsWitnessFile(path, budget2, "config.toml"), 4) };
|
|
33031
|
-
}
|
|
33032
33093
|
function hashCodexSettingsReplacementV5(text2, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
33033
33094
|
need7(Buffer.byteLength(text2) <= 1024 * 1024 && budget2.remaining >= Buffer.byteLength(text2));
|
|
33034
33095
|
budget2.remaining -= Buffer.byteLength(text2);
|
|
33035
33096
|
return settingsDigest2(text2, 5);
|
|
33036
33097
|
}
|
|
33037
|
-
function captureCodexSettingsV5(path, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
33038
|
-
return { path, hashMode: "codex-settings-v5", sha256: settingsDigest2(readNativeSettingsWitnessFile(path, budget2, "config.toml"), 5) };
|
|
33039
|
-
}
|
|
33040
33098
|
function captureCodexSettingsV6(path, reviewedSources, budget2 = { remaining: 256 * 1024 * 1024 }, changes) {
|
|
33041
33099
|
const original = readNativeSettingsWitnessFile(path, budget2, "config.toml");
|
|
33042
33100
|
const text2 = changes?.get(path) ?? original;
|
|
@@ -33046,7 +33104,7 @@ function captureCodexSettingsV6(path, reviewedSources, budget2 = { remaining: 25
|
|
|
33046
33104
|
need7(dependencies.servers.every((server) => !["codex_apps", "_codex_apps"].includes(server) && isCodexLocalStdioMcpServer(server, config2.mcp_servers?.[server])));
|
|
33047
33105
|
return { path, hashMode: "codex-settings-v6", sha256: settingsDigest2(text2, 6, dependencies), hookSources: dependencies.sources };
|
|
33048
33106
|
}
|
|
33049
|
-
var sha2 = (text2) => createHash13("sha256").update(text2).digest("hex"), EFFORT2, VERBOSITY2, MODEL, CODEX_DISCOVERY_PROJECTION_FIELDS, INFERENCE;
|
|
33107
|
+
var sha2 = (text2) => createHash13("sha256").update(text2).digest("hex"), EFFORT2, VERBOSITY2, MODEL, CODEX_DISCOVERY_PROJECTION_FIELDS, INFERENCE, SCREEN_READER_RECEIPT = "screen_reader_detection_done";
|
|
33050
33108
|
var init_codex_settings_witness = __esm(() => {
|
|
33051
33109
|
init_codex_settings_witness_v1();
|
|
33052
33110
|
init_codex_settings_witness_v1();
|
|
@@ -35310,6 +35368,13 @@ var init_codex_semantic_cache_witness = __esm(() => {
|
|
|
35310
35368
|
]);
|
|
35311
35369
|
});
|
|
35312
35370
|
|
|
35371
|
+
// src/lib/codex-node-modules.ts
|
|
35372
|
+
var PLUGIN_MANIFESTS;
|
|
35373
|
+
var init_codex_node_modules = __esm(() => {
|
|
35374
|
+
init_claude_settings_witness();
|
|
35375
|
+
PLUGIN_MANIFESTS = Object.freeze(["plugin.json", ".codex-plugin/plugin.json", ".claude-plugin/plugin.json", ".cursor-plugin/plugin.json"]);
|
|
35376
|
+
});
|
|
35377
|
+
|
|
35313
35378
|
// src/lib/managed-policy.ts
|
|
35314
35379
|
import { closeSync as closeSync14, constants as constants11, fstatSync as fstatSync14, lstatSync as lstatSync17, openSync as openSync14, readSync as readSync8 } from "fs";
|
|
35315
35380
|
import { join as join22 } from "path";
|
|
@@ -35838,6 +35903,7 @@ var init_agent_integration = __esm(() => {
|
|
|
35838
35903
|
init_native_discovery_roots();
|
|
35839
35904
|
init_codex_vendor_refresh();
|
|
35840
35905
|
init_codex_native_skill_catalog();
|
|
35906
|
+
init_codex_node_modules();
|
|
35841
35907
|
init_config();
|
|
35842
35908
|
init_managed_policy();
|
|
35843
35909
|
init_agent_bridge();
|
|
@@ -37313,10 +37379,9 @@ function projected(source, changes, budget2 = discoveryByteBudget()) {
|
|
|
37313
37379
|
if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4" || source.hashMode === "codex-settings-v5")) {
|
|
37314
37380
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
37315
37381
|
throw new Error("Codex settings witnesses require exact typed metadata");
|
|
37316
|
-
|
|
37317
|
-
if (current !== source.sha256)
|
|
37382
|
+
if (codexSettingsWitnessMatch(source.path, source.hashMode, source.sha256, budget2) === null)
|
|
37318
37383
|
throw new NativeDiscoveryWitnessChange("input", source.path, `Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
37319
|
-
return changes?.has(source.path) ? (source.hashMode === "codex-settings-v5" ? hashCodexSettingsReplacementV5 : source.hashMode === "codex-settings-v4" ? hashCodexSettingsReplacementV4 : source.hashMode === "codex-settings-v3" ? hashCodexSettingsReplacementV3 : source.hashMode === "codex-settings-v2" ? hashCodexSettingsReplacementV2 : hashCodexSettingsReplacement)(changes.get(source.path), budget2) :
|
|
37384
|
+
return changes?.has(source.path) ? (source.hashMode === "codex-settings-v5" ? hashCodexSettingsReplacementV5 : source.hashMode === "codex-settings-v4" ? hashCodexSettingsReplacementV4 : source.hashMode === "codex-settings-v3" ? hashCodexSettingsReplacementV3 : source.hashMode === "codex-settings-v2" ? hashCodexSettingsReplacementV2 : hashCodexSettingsReplacement)(changes.get(source.path), budget2) : source.sha256;
|
|
37320
37385
|
}
|
|
37321
37386
|
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4")) {
|
|
37322
37387
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
@@ -37429,10 +37494,22 @@ function retiredCodexRoots(binding, tolerance) {
|
|
|
37429
37494
|
}
|
|
37430
37495
|
return proof.roots;
|
|
37431
37496
|
}
|
|
37432
|
-
function
|
|
37497
|
+
function retainableAbsentWitness(source) {
|
|
37433
37498
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined)
|
|
37434
|
-
return
|
|
37435
|
-
|
|
37499
|
+
return null;
|
|
37500
|
+
if ([undefined, "bytes"].includes(source.hashMode))
|
|
37501
|
+
return "bytes";
|
|
37502
|
+
if (source.hashMode === "claude-plugin-manifest-v1" && source.sha256 !== null && source.path.endsWith(join30(sep11, ".claude-plugin", "plugin.json")))
|
|
37503
|
+
return "claude-plugin-manifest-v1";
|
|
37504
|
+
if (source.hashMode === CLAUDE_ORPHAN_MARKER_MODE && source.sha256 !== null && isClaudePluginCacheOrphanMarker(source.path))
|
|
37505
|
+
return CLAUDE_ORPHAN_MARKER_MODE;
|
|
37506
|
+
return null;
|
|
37507
|
+
}
|
|
37508
|
+
function retainableAbsentSource(source) {
|
|
37509
|
+
return retainableAbsentWitness(source) !== null;
|
|
37510
|
+
}
|
|
37511
|
+
function retainedAbsentRoot(absentRoots, source) {
|
|
37512
|
+
return retainableAbsentSource(source) ? absentRoots.find((root) => source.path.startsWith(root + sep11)) : undefined;
|
|
37436
37513
|
}
|
|
37437
37514
|
function absentRetiredClaudeRoots(binding) {
|
|
37438
37515
|
if (binding.agent !== "claude" || binding.method !== "reviewed")
|
|
@@ -37625,7 +37702,7 @@ function verifyAgentDiscovery(binding, codexRecovery, reviewedRootAliases, witne
|
|
|
37625
37702
|
safe6(source.path);
|
|
37626
37703
|
continue;
|
|
37627
37704
|
}
|
|
37628
|
-
if (absentRoots
|
|
37705
|
+
if (retainedAbsentRoot(absentRoots, source) !== undefined) {
|
|
37629
37706
|
safe6(source.path);
|
|
37630
37707
|
continue;
|
|
37631
37708
|
}
|
|
@@ -37649,6 +37726,12 @@ function verifyAgentDiscovery(binding, codexRecovery, reviewedRootAliases, witne
|
|
|
37649
37726
|
throw new Error("Retired native materialization changed during discovery verification");
|
|
37650
37727
|
}
|
|
37651
37728
|
}
|
|
37729
|
+
function claudeControlSource(source) {
|
|
37730
|
+
return CLAUDE_CONTROL_WITNESS_MODES.has(source.hashMode ?? "") || CLAUDE_CONTROL_FILES.has(basename12(source.path)) && !source.path.includes(`${sep11}.claude${sep11}plugins${sep11}cache${sep11}`);
|
|
37731
|
+
}
|
|
37732
|
+
function retainedAbsentClaudeRoot(absentRoots, source) {
|
|
37733
|
+
return claudeControlSource(source) ? undefined : retainedAbsentRoot(absentRoots, source);
|
|
37734
|
+
}
|
|
37652
37735
|
function codexInstallationRoots(binding) {
|
|
37653
37736
|
const proof = binding.codexInstallationInputs;
|
|
37654
37737
|
if (proof === undefined)
|
|
@@ -37844,7 +37927,10 @@ function resolveAgentDiscovery(options) {
|
|
|
37844
37927
|
if (!review.sources.some((source) => source.path === canonical9(configPath)))
|
|
37845
37928
|
throw new Error("Discovery review must include the agent configuration source");
|
|
37846
37929
|
const reviewedSources = supersedesSettingsProjection(agent, review.sources, canonical9(configPath)) ? sources.filter((source) => !isSupersededSettingsProjection(agent, canonical9(configPath), source)) : sources;
|
|
37930
|
+
const absentRoots = absentRetiredClaudeRoots(supplied);
|
|
37847
37931
|
const reviewedSourcesWithManifestProjection = review.sources.map((source) => {
|
|
37932
|
+
if (retainedAbsentClaudeRoot(absentRoots, source) !== undefined)
|
|
37933
|
+
return source;
|
|
37848
37934
|
if (agent === "claude" && source.format === undefined && source.fields === undefined && source.managedPlugins === undefined && source.reviewArtifact === undefined && [undefined, "bytes", "path-bytes"].includes(source.hashMode) && isClaudePluginCacheOrphanMarker(source.path)) {
|
|
37849
37935
|
return { path: source.path, hashMode: CLAUDE_ORPHAN_MARKER_MODE, sha256: hashClaudePluginCacheOrphanMarker(source.path) };
|
|
37850
37936
|
}
|
|
@@ -37877,6 +37963,11 @@ function resolveAgentDiscovery(options) {
|
|
|
37877
37963
|
});
|
|
37878
37964
|
if (agent === "claude")
|
|
37879
37965
|
assertReviewedClaudeCacheClosures(home, config2, review, canonical9);
|
|
37966
|
+
for (const root of absentRoots) {
|
|
37967
|
+
safe6(root);
|
|
37968
|
+
if (lstatSync23(root, { throwIfNoEntry: false }))
|
|
37969
|
+
throw new Error("Retired native materialization changed during discovery review");
|
|
37970
|
+
}
|
|
37880
37971
|
const combined = [...reviewedSources, ...reviewedSourcesWithManifestProjection];
|
|
37881
37972
|
const unique = combined.filter((source, index) => combined.findIndex((candidate) => isDeepStrictEqual5(candidate, source)) === index);
|
|
37882
37973
|
return { ...supplied, roots: [...new Set([...roots, ...supplied.roots])].sort(), sources: unique, ...agent === "gemini" ? { builtinNames } : {} };
|
|
@@ -37999,7 +38090,7 @@ var DISCOVERY_RUNTIME_COMMANDS, realpathOrNull = (path) => {
|
|
|
37999
38090
|
} catch {
|
|
38000
38091
|
return null;
|
|
38001
38092
|
}
|
|
38002
|
-
}, digest2 = (text2) => createHash24("sha256").update(text2).digest("hex");
|
|
38093
|
+
}, digest2 = (text2) => createHash24("sha256").update(text2).digest("hex"), CLAUDE_CONTROL_WITNESS_MODES, CLAUDE_CONTROL_FILES, ADOPTABLE_SETTINGS_MATCHES, CLAUDE_PROJECT_DISCOVERY_KEYS;
|
|
38003
38094
|
var init_agent_discovery = __esm(() => {
|
|
38004
38095
|
init_sumi_settings_witness();
|
|
38005
38096
|
init_agent_policy_limits();
|
|
@@ -38029,6 +38120,10 @@ var init_agent_discovery = __esm(() => {
|
|
|
38029
38120
|
init_codex_semantic_cache_witness();
|
|
38030
38121
|
init_agent_discovery_directories();
|
|
38031
38122
|
DISCOVERY_RUNTIME_COMMANDS = Object.freeze({ gemini: "gemini" });
|
|
38123
|
+
CLAUDE_CONTROL_WITNESS_MODES = new Set(["claude-settings-v1", "claude-settings-v2", "claude-settings-v3", "claude-settings-v4", "claude-marketplace-registry", "claude-marketplace-registry-v2", "claude-marketplace-entry-v1", "claude-plugin-registry"]);
|
|
38124
|
+
CLAUDE_CONTROL_FILES = new Set(["settings.json", "settings.local.json", "installed_plugins.json", "known_marketplaces.json"]);
|
|
38125
|
+
ADOPTABLE_SETTINGS_MATCHES = Object.freeze(["exact", "screen-reader-receipt"]);
|
|
38126
|
+
CLAUDE_PROJECT_DISCOVERY_KEYS = Object.freeze(["enabledPlugins", "extraKnownMarketplaces", "additionalMarketplaces", "skillOverrides"]);
|
|
38032
38127
|
});
|
|
38033
38128
|
|
|
38034
38129
|
// src/lib/authoring-path.ts
|
|
@@ -46318,7 +46413,11 @@ var exports_selected_run = {};
|
|
|
46318
46413
|
__export(exports_selected_run, {
|
|
46319
46414
|
resolveSelectedRun: () => resolveSelectedRun,
|
|
46320
46415
|
prepareSelectedSecretBindings: () => prepareSelectedSecretBindings,
|
|
46321
|
-
|
|
46416
|
+
instructionRunRefusal: () => instructionRunRefusal,
|
|
46417
|
+
instructionEntrypointMismatch: () => instructionEntrypointMismatch,
|
|
46418
|
+
instructionCommandEntry: () => instructionCommandEntry,
|
|
46419
|
+
executeSelectedLocal: () => executeSelectedLocal,
|
|
46420
|
+
declaredOperation: () => declaredOperation
|
|
46322
46421
|
});
|
|
46323
46422
|
import { createHash as createHash28 } from "crypto";
|
|
46324
46423
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -46331,12 +46430,51 @@ async function resolveSelectedRun(spec, profileId, options = {}) {
|
|
|
46331
46430
|
const entries = await readSelectedEntries(selection2, context2, options);
|
|
46332
46431
|
return { selection: selection2, profileId: context2.receipt.profile.profileId, entries, ...describeEntries(entries), cacheDir: selectionCacheRoot(options) };
|
|
46333
46432
|
}
|
|
46433
|
+
function declaredOperation(manifest) {
|
|
46434
|
+
const entry = instructionCommandEntry(manifest);
|
|
46435
|
+
if (!entry)
|
|
46436
|
+
return null;
|
|
46437
|
+
const runtime = manifest.runtime;
|
|
46438
|
+
if (!runtime || typeof runtime !== "object" || Array.isArray(runtime))
|
|
46439
|
+
return null;
|
|
46440
|
+
if (runtime.runtime !== "bun" && runtime.runtime !== "node" && runtime.runtime !== "python3")
|
|
46441
|
+
return null;
|
|
46442
|
+
if (instructionEntrypointMismatch(manifest))
|
|
46443
|
+
return null;
|
|
46444
|
+
return { entry };
|
|
46445
|
+
}
|
|
46446
|
+
function instructionCommandEntry(manifest) {
|
|
46447
|
+
const commands = Array.isArray(manifest.commands) ? manifest.commands : [];
|
|
46448
|
+
const command = commands[0];
|
|
46449
|
+
if (!command || typeof command !== "object" || typeof command.entry !== "string" || command.entry.length === 0)
|
|
46450
|
+
return null;
|
|
46451
|
+
return command.entry;
|
|
46452
|
+
}
|
|
46453
|
+
function instructionEntrypointMismatch(manifest) {
|
|
46454
|
+
const entry = instructionCommandEntry(manifest);
|
|
46455
|
+
const declared = manifest.runtime;
|
|
46456
|
+
if (!entry || !declared || typeof declared !== "object" || Array.isArray(declared))
|
|
46457
|
+
return null;
|
|
46458
|
+
const runtimeEntrypoint = declared.entrypoint;
|
|
46459
|
+
return typeof runtimeEntrypoint === "string" && runtimeEntrypoint !== entry ? runtimeEntrypoint : null;
|
|
46460
|
+
}
|
|
46461
|
+
function instructionRunRefusal(manifest, isBundledFile) {
|
|
46462
|
+
const declaredEntry = instructionCommandEntry(manifest);
|
|
46463
|
+
if (declaredEntry && !isBundledFile(declaredEntry))
|
|
46464
|
+
return { code: "LOCAL_ENTRYPOINT_MISSING", message: `This selected instruction skill declares its operation entry as ${declaredEntry}, which is not a regular file in the selected bundle; a different runtime.entrypoint never substitutes for it.` };
|
|
46465
|
+
const mismatch = instructionEntrypointMismatch(manifest);
|
|
46466
|
+
if (mismatch)
|
|
46467
|
+
return { code: "LOCAL_ENTRYPOINT_MISMATCH", message: `This selected instruction skill declares its operation entry as ${declaredEntry}, but its runtime.entrypoint is ${mismatch}; the two must agree.` };
|
|
46468
|
+
if (!declaredOperation(manifest))
|
|
46469
|
+
return { code: "INSTRUCTION_SKILL", message: "This selected skill contains instructions. Use skills load instead of skills run." };
|
|
46470
|
+
return null;
|
|
46471
|
+
}
|
|
46334
46472
|
async function prepareSelectedSecretBindings(selected, cwd = process.cwd()) {
|
|
46335
46473
|
const entries = await readCachedSelection(selected.selection, { cacheDir: selected.cacheDir });
|
|
46336
46474
|
if (!entries)
|
|
46337
46475
|
throw new SkillSelectionError("CACHED_BUNDLE_MISSING", "The selected execution bundle is not cached.");
|
|
46338
46476
|
const { kind, manifest } = describeEntries(entries);
|
|
46339
|
-
if (kind !== "executable")
|
|
46477
|
+
if (kind !== "executable" && !declaredOperation(manifest))
|
|
46340
46478
|
throw new SkillSelectionError("INSTRUCTION_SKILL", "Instruction skills do not accept execution secret bindings.");
|
|
46341
46479
|
const names = declaredSecretNames(manifest.runtime?.env);
|
|
46342
46480
|
if (!names.length)
|
|
@@ -46349,8 +46487,12 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
46349
46487
|
if (!entries)
|
|
46350
46488
|
throw new SkillSelectionError("CACHED_BUNDLE_MISSING", "The selected local execution bundle is not cached.");
|
|
46351
46489
|
const { kind, manifest, packageJson } = describeEntries(entries);
|
|
46352
|
-
|
|
46353
|
-
|
|
46490
|
+
const operation = declaredOperation(manifest);
|
|
46491
|
+
if (kind === "instruction") {
|
|
46492
|
+
const refusal3 = instructionRunRefusal(manifest, (path) => entries.some((entry) => entry.path === path));
|
|
46493
|
+
if (refusal3)
|
|
46494
|
+
throw new SkillSelectionError(refusal3.code, refusal3.message);
|
|
46495
|
+
}
|
|
46354
46496
|
const runtime = manifest.runtime ?? {};
|
|
46355
46497
|
if (!runtime || typeof runtime !== "object" || Array.isArray(runtime))
|
|
46356
46498
|
throw new SkillSelectionError("INVALID_SKILL_MANIFEST", "The selected runtime declaration is invalid.");
|
|
@@ -46369,9 +46511,9 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
46369
46511
|
const executable = runtimeName === "bun" ? process.execPath : Bun.which(runtimeName);
|
|
46370
46512
|
if (!executable)
|
|
46371
46513
|
throw new SkillSelectionError("LOCAL_RUNTIME_UNAVAILABLE", "The selected runtime is not installed on this station.");
|
|
46372
|
-
const declaredEntry = runtime.entrypoint ?? (typeof packageJson.bin === "string" ? packageJson.bin : packageJson.bin && typeof packageJson.bin === "object" ? Object.values(packageJson.bin)[0] : undefined);
|
|
46514
|
+
const declaredEntry = (kind === "instruction" ? operation?.entry : undefined) ?? runtime.entrypoint ?? (typeof packageJson.bin === "string" ? packageJson.bin : packageJson.bin && typeof packageJson.bin === "object" ? Object.values(packageJson.bin)[0] : undefined);
|
|
46373
46515
|
if (typeof declaredEntry !== "string" || !entries.some((entry) => entry.path === declaredEntry))
|
|
46374
|
-
throw new SkillSelectionError("LOCAL_ENTRYPOINT_MISSING", "The selected bundle must declare a regular-file entrypoint in its runtime manifest or package bin.");
|
|
46516
|
+
throw new SkillSelectionError("LOCAL_ENTRYPOINT_MISSING", kind === "instruction" ? "The selected instruction skill must declare the operation entrypoint it ships in its manifest, and that declared entry must be a regular file in the selected bundle; a different runtime.entrypoint never substitutes for it." : "The selected bundle must declare a regular-file entrypoint in its runtime manifest or package bin.");
|
|
46375
46517
|
const args = options.args ?? [];
|
|
46376
46518
|
if (args.length > 128 || args.some((arg) => typeof arg !== "string" || arg.length > 16384 || arg.includes("\x00")))
|
|
46377
46519
|
throw new SkillSelectionError("INVALID_RUN_INPUT", "Local skill arguments exceed their limits.");
|
|
@@ -46446,6 +46588,7 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
46446
46588
|
selection: selection2,
|
|
46447
46589
|
target: "local",
|
|
46448
46590
|
runtime: runtimeName,
|
|
46591
|
+
entrypoint: declaredEntry,
|
|
46449
46592
|
inputDigest: `sha256:${createHash28("sha256").update(input2).digest("hex")}`,
|
|
46450
46593
|
runDirectory,
|
|
46451
46594
|
...executionGrant ? { executionGrant } : {},
|
|
@@ -46892,13 +47035,18 @@ function registerOperationTools(server) {
|
|
|
46892
47035
|
return mcpError("CONFLICTING_EXECUTION_MODES", "Use remote for the configured server catalog and quote, or target for selected execution, not both.");
|
|
46893
47036
|
if (managed && !remote) {
|
|
46894
47037
|
try {
|
|
46895
|
-
const { resolveSelectedRun: resolveSelectedRun2, executeSelectedLocal: executeSelectedLocal2 } = await Promise.resolve().then(() => (init_selected_run(), exports_selected_run));
|
|
47038
|
+
const { resolveSelectedRun: resolveSelectedRun2, executeSelectedLocal: executeSelectedLocal2, instructionRunRefusal: instructionRunRefusal2 } = await Promise.resolve().then(() => (init_selected_run(), exports_selected_run));
|
|
46896
47039
|
const resolved = await resolveSelectedRun2(name, selectedProfileId(), { projectDir: process.cwd() });
|
|
46897
|
-
if (resolved.kind === "instruction")
|
|
46898
|
-
|
|
47040
|
+
if (resolved.kind === "instruction") {
|
|
47041
|
+
const refusal3 = instructionRunRefusal2(resolved.manifest, (path) => resolved.entries.some((entry) => entry.path === path));
|
|
47042
|
+
if (refusal3)
|
|
47043
|
+
return mcpError(refusal3.code, refusal3.message);
|
|
47044
|
+
}
|
|
46899
47045
|
if (files?.length)
|
|
46900
47046
|
return mcpError("SELECTED_INPUT_REQUIRED", "Selected executions require their declared JSON input; use the CLI cloud execution input contract for files.");
|
|
46901
47047
|
if (target === "cloud") {
|
|
47048
|
+
if (resolved.kind === "instruction")
|
|
47049
|
+
return mcpError("INSTRUCTION_SKILL", "Cloud execution requires an executable skill version; run the declared operation locally on a managed station, or load the instructions with skills load.");
|
|
46902
47050
|
if (args?.length || quoteReceipt || maxCredits !== undefined || maxCostCents !== undefined)
|
|
46903
47051
|
return mcpError("SELECTED_INPUT_REQUIRED", "The selected cloud execution contract accepts declared JSON input, not legacy run arguments or quote receipts.");
|
|
46904
47052
|
const { CloudExecutionClient: CloudExecutionClient2 } = await Promise.resolve().then(() => (init_cloud_executions(), exports_cloud_executions));
|
package/bin/migrate.js
CHANGED
package/bin/server.js
CHANGED
|
@@ -24140,7 +24140,7 @@ restoreLaunchCwd();
|
|
|
24140
24140
|
// package.json
|
|
24141
24141
|
var package_default = {
|
|
24142
24142
|
name: "@hasna/skills",
|
|
24143
|
-
version: "0.10.
|
|
24143
|
+
version: "0.10.74",
|
|
24144
24144
|
description: "Skills library for AI coding agents",
|
|
24145
24145
|
type: "module",
|
|
24146
24146
|
bin: {
|
package/bin/worker.js
CHANGED
|
@@ -24143,7 +24143,7 @@ import { randomUUID as randomUUID6 } from "crypto";
|
|
|
24143
24143
|
// package.json
|
|
24144
24144
|
var package_default = {
|
|
24145
24145
|
name: "@hasna/skills",
|
|
24146
|
-
version: "0.10.
|
|
24146
|
+
version: "0.10.74",
|
|
24147
24147
|
description: "Skills library for AI coding agents",
|
|
24148
24148
|
type: "module",
|
|
24149
24149
|
bin: {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
import { type SelectionProvenanceReceipt } from "../../lib/selection-provenance.js";
|
|
3
|
+
export interface ProvenanceCommandOptions {
|
|
4
|
+
selectionProfile?: string;
|
|
5
|
+
station?: string;
|
|
6
|
+
session?: string;
|
|
7
|
+
cached?: boolean;
|
|
8
|
+
json?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* One read-only receipt for the selection chain: selected, activated, applied,
|
|
12
|
+
* pinned and consumed are named separately, and every consumer carries its
|
|
13
|
+
* status and reason. An exit code here only reports a bad request: a read that
|
|
14
|
+
* could not be answered is recorded as `unverified`, because that is the fact
|
|
15
|
+
* the caller came for.
|
|
16
|
+
*/
|
|
17
|
+
export declare function provenanceLines(receipt: SelectionProvenanceReceipt): string[];
|
|
18
|
+
export declare function registerProvenance(parent: Command): void;
|