@hasna/skills 0.9.12 → 0.9.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/index.js +97 -22
- package/bin/maintenance.js +73 -0
- package/bin/mcp.js +63 -18
- package/bin/migrate.js +36 -1
- package/bin/server.js +96 -25
- package/bin/worker.js +74 -8
- package/dist/index.d.ts +4 -3
- package/dist/index.js +142 -40
- package/dist/lib/agent-discovery.d.ts +1 -1
- package/dist/lib/agent-integration.d.ts +9 -1
- package/dist/lib/claude-marketplace-registry.d.ts +6 -0
- package/dist/lib/claude-settings-witness.d.ts +12 -1
- package/dist/sdk/index.js +213 -45
- package/dist/server/rows.d.ts +2 -1
- package/dist/server/sqlite-store.d.ts +2 -1
- package/dist/server/store.d.ts +3 -1
- package/dist/server/types.d.ts +18 -0
- package/docs/plugin-admission.md +60 -0
- package/package.json +1 -1
package/bin/index.js
CHANGED
|
@@ -36868,7 +36868,7 @@ var package_default;
|
|
|
36868
36868
|
var init_package = __esm(() => {
|
|
36869
36869
|
package_default = {
|
|
36870
36870
|
name: "@hasna/skills",
|
|
36871
|
-
version: "0.9.
|
|
36871
|
+
version: "0.9.14",
|
|
36872
36872
|
description: "Skills library for AI coding agents",
|
|
36873
36873
|
type: "module",
|
|
36874
36874
|
bin: {
|
|
@@ -39947,10 +39947,10 @@ function assertAgentPolicyCollections(policy) {
|
|
|
39947
39947
|
text(source.path);
|
|
39948
39948
|
requireBound(source.sha256 === null || typeof source.sha256 === "string" && /^[a-f0-9]{64}$/.test(source.sha256));
|
|
39949
39949
|
if (source.hashMode !== undefined)
|
|
39950
|
-
requireBound(["bytes", "path-bytes", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
|
|
39951
|
-
if (source.hashMode === "claude-settings-v1")
|
|
39950
|
+
requireBound(["bytes", "path-bytes", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1", "claude-settings-v2", "claude-marketplace-registry-v2"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
|
|
39951
|
+
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2")
|
|
39952
39952
|
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute2(source.path) && resolve3(source.path) === source.path && basename2(source.path) === "settings.json");
|
|
39953
|
-
if (source.hashMode === "claude-marketplace-registry")
|
|
39953
|
+
if (source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2")
|
|
39954
39954
|
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute2(source.path) && resolve3(source.path) === source.path && basename2(source.path) === "known_marketplaces.json");
|
|
39955
39955
|
if (source.hashMode === "claude-plugin-registry") {
|
|
39956
39956
|
requireBound(agent === "claude");
|
|
@@ -50545,9 +50545,32 @@ function canonical2(value) {
|
|
|
50545
50545
|
return { kind: "array", items: value.items.map(canonical2) };
|
|
50546
50546
|
return value;
|
|
50547
50547
|
}
|
|
50548
|
-
function
|
|
50548
|
+
function inferencePreference(key, child) {
|
|
50549
|
+
if (key === "skipDangerousModePermissionPrompt") {
|
|
50550
|
+
need2(child.kind === "literal" && (child.value === "true" || child.value === "false"), "contains an invalid dialog acknowledgment");
|
|
50551
|
+
return false;
|
|
50552
|
+
}
|
|
50553
|
+
if (key === "effortLevel") {
|
|
50554
|
+
need2(child.kind === "string" && PERSISTED_EFFORT_LEVELS.has(child.value), "contains an invalid persisted effort level");
|
|
50555
|
+
return true;
|
|
50556
|
+
}
|
|
50557
|
+
if (key !== "modelSettings")
|
|
50558
|
+
return false;
|
|
50559
|
+
need2(child.kind === "object", "requires an object of model preferences");
|
|
50560
|
+
child.entries = child.entries.filter(([model, preferences]) => {
|
|
50561
|
+
if (!BUILTIN_MODEL_SELECTIONS.has(model) || preferences.kind !== "object" || preferences.entries.length !== 1 || preferences.entries[0][0] !== "effortLevel")
|
|
50562
|
+
return true;
|
|
50563
|
+
const effort = preferences.entries[0][1];
|
|
50564
|
+
need2(effort.kind === "string" && PERSISTED_EFFORT_LEVELS.has(effort.value), "contains an invalid persisted model effort level");
|
|
50565
|
+
return false;
|
|
50566
|
+
});
|
|
50567
|
+
return child.entries.length === 0;
|
|
50568
|
+
}
|
|
50569
|
+
function settingsDigest(text2, version = 1) {
|
|
50549
50570
|
const value = parse3(text2);
|
|
50550
50571
|
value.entries = value.entries.filter(([key, child]) => {
|
|
50572
|
+
if (version === 2 && inferencePreference(key, child))
|
|
50573
|
+
return false;
|
|
50551
50574
|
if (key === "model") {
|
|
50552
50575
|
need2(child.kind === "string", "contains an invalid model selection");
|
|
50553
50576
|
return !BUILTIN_MODEL_SELECTIONS.has(child.value);
|
|
@@ -50562,7 +50585,7 @@ function settingsDigest(text2) {
|
|
|
50562
50585
|
}
|
|
50563
50586
|
return true;
|
|
50564
50587
|
});
|
|
50565
|
-
return createHash9("sha256").update(
|
|
50588
|
+
return createHash9("sha256").update(`hasna.skills.claude-settings.v${version}\x00`).update(JSON.stringify(canonical2(value))).digest("hex");
|
|
50566
50589
|
}
|
|
50567
50590
|
function hashClaudeSettingsReplacement(text2, budget) {
|
|
50568
50591
|
need2(typeof text2 === "string", "requires settings text");
|
|
@@ -50574,7 +50597,17 @@ function hashClaudeSettingsReplacement(text2, budget) {
|
|
|
50574
50597
|
function captureClaudeSettings(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
50575
50598
|
return { path, hashMode: "claude-settings-v1", sha256: settingsDigest(readSettings(path, budget)) };
|
|
50576
50599
|
}
|
|
50577
|
-
|
|
50600
|
+
function captureClaudeSettingsV2(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
50601
|
+
return { path, hashMode: "claude-settings-v2", sha256: settingsDigest(readSettings(path, budget), 2) };
|
|
50602
|
+
}
|
|
50603
|
+
function hashClaudeSettingsReplacementV2(text2, budget) {
|
|
50604
|
+
need2(typeof text2 === "string", "requires settings text");
|
|
50605
|
+
const bytes = Buffer.byteLength(text2);
|
|
50606
|
+
need2(bytes <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes && Number.isSafeInteger(budget.remaining) && budget.remaining >= bytes, "exceeds its byte limit");
|
|
50607
|
+
budget.remaining -= bytes;
|
|
50608
|
+
return settingsDigest(text2, 2);
|
|
50609
|
+
}
|
|
50610
|
+
var CLAUDE_SETTINGS_WITNESS_LIMITS, sameFile = (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, BOOLEAN_PREFERENCES, ENUM_PREFERENCES, BUILTIN_MODEL_SELECTIONS, PERSISTED_EFFORT_LEVELS;
|
|
50578
50611
|
var init_claude_settings_witness = __esm(() => {
|
|
50579
50612
|
CLAUDE_SETTINGS_WITNESS_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
|
|
50580
50613
|
BOOLEAN_PREFERENCES = new Set([
|
|
@@ -50628,6 +50661,7 @@ var init_claude_settings_witness = __esm(() => {
|
|
|
50628
50661
|
"claude-opus-4-6[1m]",
|
|
50629
50662
|
"claude-sonnet-4-6[1m]"
|
|
50630
50663
|
]);
|
|
50664
|
+
PERSISTED_EFFORT_LEVELS = new Set(["low", "medium", "high", "xhigh"]);
|
|
50631
50665
|
});
|
|
50632
50666
|
|
|
50633
50667
|
// src/lib/agent-integration.ts
|
|
@@ -51199,6 +51233,20 @@ function planAgentIntegration(options) {
|
|
|
51199
51233
|
recheckRootAliases(aliases);
|
|
51200
51234
|
return { dataDir: dataDir3, profileId, changes, nativeSkills, observedPolicy: { path: policyPath, before: previousPolicy }, discoveryBefore: discoveries, discoveryAfter, ...aliases.length ? { rootAliases: aliases } : {} };
|
|
51201
51235
|
}
|
|
51236
|
+
function verifyCoordinatedDiscovery(binding, home, aliases) {
|
|
51237
|
+
try {
|
|
51238
|
+
if (binding.method !== "automatic" && binding.method !== "reviewed")
|
|
51239
|
+
throw new Error("Invalid managed discovery method");
|
|
51240
|
+
verifyAgentDiscovery(binding);
|
|
51241
|
+
if (binding.method === "automatic") {
|
|
51242
|
+
const current = resolveAgentDiscovery({ home, agent: binding.agent, canonical: (path) => canonicalAgentPath(path, aliases) });
|
|
51243
|
+
if (JSON.stringify(current) !== JSON.stringify(binding))
|
|
51244
|
+
throw new Error("Configured native discovery roots changed during Claude update");
|
|
51245
|
+
}
|
|
51246
|
+
} catch (error) {
|
|
51247
|
+
throw new Error(`NATIVE_SKILL_DRIFT: ${error.message}`);
|
|
51248
|
+
}
|
|
51249
|
+
}
|
|
51202
51250
|
function atomicWrite2(path, content) {
|
|
51203
51251
|
assertSafePath(path);
|
|
51204
51252
|
mkdirSync5(dirname10(path), { recursive: true, mode: 448 });
|
|
@@ -51223,8 +51271,12 @@ function applyAgentIntegration(plan) {
|
|
|
51223
51271
|
recheckRootAliases(aliases);
|
|
51224
51272
|
for (const agent of plan.managedAgentChecks?.agents ?? [])
|
|
51225
51273
|
assertManagedAgentBridge(agent, { home: plan.managedAgentChecks.home, dataDir: plan.dataDir, projectDir: plan.managedAgentChecks.home });
|
|
51226
|
-
for (const binding of plan.discoveryBefore ?? [])
|
|
51227
|
-
|
|
51274
|
+
for (const binding of plan.discoveryBefore ?? []) {
|
|
51275
|
+
if (plan.managedAgentChecks)
|
|
51276
|
+
verifyCoordinatedDiscovery(binding, plan.managedAgentChecks.home, aliases);
|
|
51277
|
+
else
|
|
51278
|
+
verifyAgentDiscovery(binding);
|
|
51279
|
+
}
|
|
51228
51280
|
if (plan.observedPolicy && currentText(plan.observedPolicy.path) !== plan.observedPolicy.before)
|
|
51229
51281
|
throw new Error("Agent policy changed after planning");
|
|
51230
51282
|
for (const change of plan.changes)
|
|
@@ -51256,8 +51308,12 @@ function applyAgentIntegration(plan) {
|
|
|
51256
51308
|
written.push({ path: change.path, before: change.before, after: after2 });
|
|
51257
51309
|
}
|
|
51258
51310
|
recheckRootAliases(aliases);
|
|
51259
|
-
for (const binding of plan.discoveryAfter ?? [])
|
|
51260
|
-
|
|
51311
|
+
for (const binding of plan.discoveryAfter ?? []) {
|
|
51312
|
+
if (plan.managedAgentChecks)
|
|
51313
|
+
verifyCoordinatedDiscovery(binding, plan.managedAgentChecks.home, aliases);
|
|
51314
|
+
else
|
|
51315
|
+
verifyAgentDiscovery(binding);
|
|
51316
|
+
}
|
|
51261
51317
|
for (const agent of plan.managedAgentChecks?.agents ?? [])
|
|
51262
51318
|
assertManagedAgentBridge(agent, { home: plan.managedAgentChecks.home, dataDir: plan.dataDir, projectDir: plan.managedAgentChecks.home });
|
|
51263
51319
|
atomicWrite2(join20(backupRoot, "receipt.json"), JSON.stringify({ version: 1, changes: written.map((change) => ({ path: change.path, beforeHash: change.before === null ? null : sha(change.before), afterHash: sha(change.after) })), backups, ...aliases.length ? { rootAliases: aliases } : {} }) + `
|
|
@@ -54402,9 +54458,13 @@ function textField(value) {
|
|
|
54402
54458
|
need3(value?.kind === "string" && value.value.length > 0 && !/[\x00-\x1f\x7f]/.test(value.value), "contains an invalid recognized field");
|
|
54403
54459
|
return value.value;
|
|
54404
54460
|
}
|
|
54405
|
-
function normalizeRow(row) {
|
|
54406
|
-
if (!exactKeys(row, ["source", "installLocation", "lastUpdated"]))
|
|
54407
|
-
|
|
54461
|
+
function normalizeRow(row, version = 1) {
|
|
54462
|
+
if (!exactKeys(row, ["source", "installLocation", "lastUpdated"])) {
|
|
54463
|
+
if (version !== 2 || !exactKeys(row, ["source", "installLocation", "lastUpdated", "autoUpdate"]))
|
|
54464
|
+
return;
|
|
54465
|
+
const autoUpdate = field(row, "autoUpdate");
|
|
54466
|
+
need3(autoUpdate?.kind === "literal" && (autoUpdate.value === "true" || autoUpdate.value === "false"), "contains an invalid automatic-update preference");
|
|
54467
|
+
}
|
|
54408
54468
|
const source = field(row, "source");
|
|
54409
54469
|
if (source?.kind !== "object")
|
|
54410
54470
|
return;
|
|
@@ -54431,6 +54491,13 @@ function captureClaudeMarketplaceRegistry(path, budget = { remaining: 256 * 1024
|
|
|
54431
54491
|
const sha2562 = createHash13("sha256").update("hasna.skills.claude-marketplace-registry.v1\x00").update(JSON.stringify(value)).digest("hex");
|
|
54432
54492
|
return { path, hashMode: "claude-marketplace-registry", sha256: sha2562 };
|
|
54433
54493
|
}
|
|
54494
|
+
function captureClaudeMarketplaceRegistryV2(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
54495
|
+
const value = parse6(readRegistry2(path, budget));
|
|
54496
|
+
for (const [, row] of value.entries)
|
|
54497
|
+
normalizeRow(row, 2);
|
|
54498
|
+
const sha2562 = createHash13("sha256").update("hasna.skills.claude-marketplace-registry.v2\x00").update(JSON.stringify(value)).digest("hex");
|
|
54499
|
+
return { path, hashMode: "claude-marketplace-registry-v2", sha256: sha2562 };
|
|
54500
|
+
}
|
|
54434
54501
|
var CLAUDE_MARKETPLACE_REGISTRY_LIMITS, sameFile2 = (a, b) => a.dev === b.dev && a.ino === b.ino && a.mode === b.mode && a.uid === b.uid && a.gid === b.gid && a.nlink === b.nlink && a.size === b.size && a.mtimeNs === b.mtimeNs && a.ctimeNs === b.ctimeNs, field = (object4, key) => object4.entries.find(([name]) => name === key)?.[1];
|
|
54435
54502
|
var init_claude_marketplace_registry = __esm(() => {
|
|
54436
54503
|
CLAUDE_MARKETPLACE_REGISTRY_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
|
|
@@ -54714,18 +54781,18 @@ function read2(path, changes) {
|
|
|
54714
54781
|
return readFileSync17(path, "utf8");
|
|
54715
54782
|
}
|
|
54716
54783
|
function projected(source, changes, budget = discoveryByteBudget()) {
|
|
54717
|
-
if (source.hashMode === "claude-settings-v1") {
|
|
54784
|
+
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2") {
|
|
54718
54785
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
54719
54786
|
throw new Error("Claude settings witnesses require exact typed metadata");
|
|
54720
|
-
const current = captureClaudeSettings(source.path, budget).sha256;
|
|
54787
|
+
const current = (source.hashMode === "claude-settings-v2" ? captureClaudeSettingsV2 : captureClaudeSettings)(source.path, budget).sha256;
|
|
54721
54788
|
if (current !== source.sha256)
|
|
54722
54789
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
54723
|
-
return changes?.has(source.path) ? hashClaudeSettingsReplacement(changes.get(source.path), budget) : current;
|
|
54790
|
+
return changes?.has(source.path) ? (source.hashMode === "claude-settings-v2" ? hashClaudeSettingsReplacementV2 : hashClaudeSettingsReplacement)(changes.get(source.path), budget) : current;
|
|
54724
54791
|
}
|
|
54725
|
-
if (source.hashMode === "claude-marketplace-registry") {
|
|
54792
|
+
if (source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2") {
|
|
54726
54793
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256) || changes?.has(source.path))
|
|
54727
54794
|
throw new Error("Claude marketplace witnesses require an exact reviewed registry without synthetic changes");
|
|
54728
|
-
const sha2562 = captureClaudeMarketplaceRegistry(source.path, budget).sha256;
|
|
54795
|
+
const sha2562 = (source.hashMode === "claude-marketplace-registry-v2" ? captureClaudeMarketplaceRegistryV2 : captureClaudeMarketplaceRegistry)(source.path, budget).sha256;
|
|
54729
54796
|
if (sha2562 !== source.sha256)
|
|
54730
54797
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
54731
54798
|
return sha2562;
|
|
@@ -54782,9 +54849,9 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
54782
54849
|
safe4(root2);
|
|
54783
54850
|
}
|
|
54784
54851
|
function assertMarketplaceBinding(binding, source) {
|
|
54785
|
-
if (source.hashMode === "claude-settings-v1" && (binding.agent !== "claude" || binding.method !== "reviewed" || basename8(source.path) !== "settings.json"))
|
|
54852
|
+
if ((source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2") && (binding.agent !== "claude" || binding.method !== "reviewed" || basename8(source.path) !== "settings.json"))
|
|
54786
54853
|
throw new Error("Claude settings witnesses require explicit reviewed Claude configuration");
|
|
54787
|
-
if (source.hashMode === "claude-marketplace-registry" && (binding.agent !== "claude" || binding.method !== "reviewed"))
|
|
54854
|
+
if ((source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2") && (binding.agent !== "claude" || binding.method !== "reviewed"))
|
|
54788
54855
|
throw new Error("Claude marketplace witnesses require explicit reviewed Claude discovery");
|
|
54789
54856
|
}
|
|
54790
54857
|
function rebindAgentDiscovery(binding, changes) {
|
|
@@ -54913,7 +54980,7 @@ function resolveAgentDiscovery(options) {
|
|
|
54913
54980
|
if (review.sources.some((source) => source.format !== undefined || source.fields !== undefined))
|
|
54914
54981
|
throw new Error("Explicit discovery reviews require full source-file hashes");
|
|
54915
54982
|
verifyAgentDiscovery(supplied);
|
|
54916
|
-
if (review.sources.some((source) => source.hashMode === "claude-settings-v1" && source.path !== canonical4(configPath)))
|
|
54983
|
+
if (review.sources.some((source) => (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2") && source.path !== canonical4(configPath)))
|
|
54917
54984
|
throw new Error("Semantic settings witnesses must name the configured Claude configuration source");
|
|
54918
54985
|
if (!review.sources.some((source) => source.path === canonical4(configPath)))
|
|
54919
54986
|
throw new Error("Discovery review must include the agent configuration source");
|
|
@@ -109057,6 +109124,12 @@ function agents(value) {
|
|
|
109057
109124
|
}
|
|
109058
109125
|
function registerAgentIntegration(parent) {
|
|
109059
109126
|
const hook = parent.command("hook").description("Load selected Skills context through agent lifecycle hooks");
|
|
109127
|
+
hook.command("witness").requiredOption("--kind <kind>", "claude-settings-v2 or claude-marketplace-registry-v2").requiredOption("--path <path>", "Canonical absolute path to the reviewed settings or registry file").option("--json", "Output the discovery witness as JSON", false).description("Capture an explicit versioned review witness without installing it").action(async (options) => {
|
|
109128
|
+
const capture2 = options.kind === "claude-settings-v2" ? captureClaudeSettingsV2 : options.kind === "claude-marketplace-registry-v2" ? captureClaudeMarketplaceRegistryV2 : null;
|
|
109129
|
+
if (!capture2)
|
|
109130
|
+
throw new Error("Unsupported witness kind; select claude-settings-v2 or claude-marketplace-registry-v2");
|
|
109131
|
+
await writeCliOutput(JSON.stringify(capture2(options.path), null, 2));
|
|
109132
|
+
});
|
|
109060
109133
|
hook.command("agents").option("--json", "Output the adapter capability inventory", false).description("Show maintained native adapters and explicit coverage limits").action(async () => {
|
|
109061
109134
|
await writeCliOutput(JSON.stringify({ agents: INTEGRATION_AGENTS.map((agent) => ({ agent, bridge: true, ...AGENT_ADAPTERS[agent] })), inventoryOnly: ["codewith", "windsurf", "pi", "amp", "cline", "roo", "copilot"], limitations: ["Cursor prompt hooks gate submission; selected context is injected at session start only.", "Native discovery checks cover known home roots and current project ancestors. External plugin hook injection and arbitrary added directories require separate review.", "Hermes injects selected prompt context, but native pre_llm_call fails open. Exact native hook trust, bundled reseeding opt-out, native payload retirement and a supervised pre-tool guard are required. Child failures block explicitly; native host/supervisor death is not a universal fail-closed guarantee.", "Restart agents and use their normal hook trust controls after installation."] }, null, 2));
|
|
109062
109135
|
});
|
|
@@ -109243,6 +109316,8 @@ var init_agent_integration2 = __esm(() => {
|
|
|
109243
109316
|
init_agent_codex_trust();
|
|
109244
109317
|
init_hook_diagnostics();
|
|
109245
109318
|
init_selection_cache();
|
|
109319
|
+
init_claude_settings_witness();
|
|
109320
|
+
init_claude_marketplace_registry();
|
|
109246
109321
|
RECOVERABLE_CONTEXT_CACHE_ERRORS = new Set(["CACHED_PROFILE_EXPIRED", "CACHED_PROFILE_MISSING", "CACHED_BUNDLE_MISSING"]);
|
|
109247
109322
|
});
|
|
109248
109323
|
|
package/bin/maintenance.js
CHANGED
|
@@ -2737,6 +2737,18 @@ function rowToSkill(row) {
|
|
|
2737
2737
|
...row.replacement_slug ? { replacementSlug: String(row.replacement_slug) } : {}
|
|
2738
2738
|
};
|
|
2739
2739
|
}
|
|
2740
|
+
function rowToPublishedSelectionState(row) {
|
|
2741
|
+
return {
|
|
2742
|
+
slug: String(row.slug),
|
|
2743
|
+
version: String(row.version),
|
|
2744
|
+
current: row.skill_exists ? {
|
|
2745
|
+
lifecycle: row.lifecycle === "archived" ? "archived" : "active",
|
|
2746
|
+
...row.tombstoned_at ? { tombstonedAt: dateString(row.tombstoned_at) } : {}
|
|
2747
|
+
} : null,
|
|
2748
|
+
versionBundleSha256: typeof row.bundle_sha256 === "string" ? row.bundle_sha256 : null,
|
|
2749
|
+
bundleAvailable: Boolean(row.bundle_available)
|
|
2750
|
+
};
|
|
2751
|
+
}
|
|
2740
2752
|
function rowToPin(row) {
|
|
2741
2753
|
return {
|
|
2742
2754
|
orgId: String(row.org_id),
|
|
@@ -2809,6 +2821,13 @@ function rowToSkillVersion(row) {
|
|
|
2809
2821
|
};
|
|
2810
2822
|
}
|
|
2811
2823
|
|
|
2824
|
+
// src/lib/profile-limits.ts
|
|
2825
|
+
var MAX_PROFILE_SELECTIONS = 4096;
|
|
2826
|
+
var MAX_PROFILE_DOCUMENT_BYTES = 8 * 1024 * 1024;
|
|
2827
|
+
var MAX_SKILL_SESSION_ID_CHARS = 256;
|
|
2828
|
+
var PROFILE_SESSION_ENVELOPE_BYTES = MAX_PROFILE_SELECTIONS * 67 + MAX_SKILL_SESSION_ID_CHARS * 12 + 512;
|
|
2829
|
+
var MAX_RESOLVED_PROFILE_BYTES = MAX_PROFILE_DOCUMENT_BYTES - PROFILE_SESSION_ENVELOPE_BYTES;
|
|
2830
|
+
|
|
2812
2831
|
// src/lib/revision.ts
|
|
2813
2832
|
import { createHash as createHash2 } from "crypto";
|
|
2814
2833
|
function revisionIdOf(content) {
|
|
@@ -3495,6 +3514,22 @@ class SqliteSkillsStore {
|
|
|
3495
3514
|
const row = this.get("SELECT * FROM skills_versions WHERE org_id = ? AND slug = ? AND version = ? LIMIT 1", [principal.orgId, slug, version]);
|
|
3496
3515
|
return row ? rowToSkillVersion(row) : null;
|
|
3497
3516
|
}
|
|
3517
|
+
async getPublishedSelectionStates(principal, selections2) {
|
|
3518
|
+
if (selections2.length > MAX_PROFILE_SELECTIONS)
|
|
3519
|
+
throw new RangeError("Published selection lookup exceeds the profile selection limit");
|
|
3520
|
+
if (!selections2.length)
|
|
3521
|
+
return [];
|
|
3522
|
+
const requested = JSON.stringify(selections2.map(({ slug, version }) => ({ slug, version })));
|
|
3523
|
+
return this.all(`SELECT json_extract(q.value, '$.slug') AS slug, json_extract(q.value, '$.version') AS version,
|
|
3524
|
+
r.slug IS NOT NULL AS skill_exists, r.lifecycle, r.tombstoned_at,
|
|
3525
|
+
v.bundle_sha256, b.sha256 IS NOT NULL AS bundle_available
|
|
3526
|
+
FROM json_each(?) q
|
|
3527
|
+
LEFT JOIN skills_registry r ON r.org_id = ? AND r.slug = json_extract(q.value, '$.slug')
|
|
3528
|
+
LEFT JOIN skills_versions v ON v.org_id = ?
|
|
3529
|
+
AND v.slug = json_extract(q.value, '$.slug') AND v.version = json_extract(q.value, '$.version')
|
|
3530
|
+
LEFT JOIN skills_bundles b ON b.org_id = ? AND b.sha256 = v.bundle_sha256
|
|
3531
|
+
ORDER BY CAST(q.key AS INTEGER)`, [requested, principal.orgId, principal.orgId, principal.orgId]).map(rowToPublishedSelectionState);
|
|
3532
|
+
}
|
|
3498
3533
|
async pinSkill(principal, slug, metadata = {}) {
|
|
3499
3534
|
const row = this.get(`INSERT INTO skills_pins (org_id, principal, slug, pinned_at, metadata_json)
|
|
3500
3535
|
VALUES (?, ?, ?, ?, ?)
|
|
@@ -3899,6 +3934,25 @@ class MemorySkillsStore {
|
|
|
3899
3934
|
const found = this.versions.get(versionKey(principal.orgId, slug, version));
|
|
3900
3935
|
return found && found.orgId === principal.orgId ? found : null;
|
|
3901
3936
|
}
|
|
3937
|
+
async getPublishedSelectionStates(principal, selections2) {
|
|
3938
|
+
if (selections2.length > MAX_PROFILE_SELECTIONS)
|
|
3939
|
+
throw new RangeError("Published selection lookup exceeds the profile selection limit");
|
|
3940
|
+
return selections2.map(({ slug, version }) => {
|
|
3941
|
+
const current = this.skills.get(skillKey(principal.orgId, slug));
|
|
3942
|
+
const selectedVersion = this.versions.get(versionKey(principal.orgId, slug, version));
|
|
3943
|
+
const bundle = selectedVersion && this.bundles.get(skillKey(principal.orgId, selectedVersion.bundleSha256));
|
|
3944
|
+
return {
|
|
3945
|
+
slug,
|
|
3946
|
+
version,
|
|
3947
|
+
current: current?.orgId === principal.orgId ? {
|
|
3948
|
+
lifecycle: current.lifecycle,
|
|
3949
|
+
...current.tombstonedAt ? { tombstonedAt: current.tombstonedAt } : {}
|
|
3950
|
+
} : null,
|
|
3951
|
+
versionBundleSha256: selectedVersion?.orgId === principal.orgId ? selectedVersion.bundleSha256 : null,
|
|
3952
|
+
bundleAvailable: bundle?.orgId === principal.orgId
|
|
3953
|
+
};
|
|
3954
|
+
});
|
|
3955
|
+
}
|
|
3902
3956
|
async listSkills(principal) {
|
|
3903
3957
|
return Array.from(this.skills.values()).filter((skill) => skill.orgId === principal.orgId && !skill.tombstonedAt).sort((a, b) => a.slug.localeCompare(b.slug));
|
|
3904
3958
|
}
|
|
@@ -4707,6 +4761,25 @@ class PostgresSkillsStore {
|
|
|
4707
4761
|
`;
|
|
4708
4762
|
return rows[0] ? rowToSkillVersion(rows[0]) : null;
|
|
4709
4763
|
}
|
|
4764
|
+
async getPublishedSelectionStates(principal, selections2) {
|
|
4765
|
+
if (selections2.length > MAX_PROFILE_SELECTIONS)
|
|
4766
|
+
throw new RangeError("Published selection lookup exceeds the profile selection limit");
|
|
4767
|
+
if (!selections2.length)
|
|
4768
|
+
return [];
|
|
4769
|
+
const requested = JSON.stringify(selections2.map(({ slug, version }) => ({ slug, version })));
|
|
4770
|
+
const rows = await this.sql`
|
|
4771
|
+
SELECT q.value->>'slug' AS slug, q.value->>'version' AS version,
|
|
4772
|
+
r.slug IS NOT NULL AS skill_exists, r.lifecycle, r.tombstoned_at,
|
|
4773
|
+
v.bundle_sha256, b.sha256 IS NOT NULL AS bundle_available
|
|
4774
|
+
FROM jsonb_array_elements(${requested}::text::jsonb) WITH ORDINALITY AS q(value, ordinal)
|
|
4775
|
+
LEFT JOIN skills_registry r ON r.org_id = ${principal.orgId} AND r.slug = q.value->>'slug'
|
|
4776
|
+
LEFT JOIN skills_versions v ON v.org_id = ${principal.orgId}
|
|
4777
|
+
AND v.slug = q.value->>'slug' AND v.version = q.value->>'version'
|
|
4778
|
+
LEFT JOIN skills_bundles b ON b.org_id = ${principal.orgId} AND b.sha256 = v.bundle_sha256
|
|
4779
|
+
ORDER BY q.ordinal
|
|
4780
|
+
`;
|
|
4781
|
+
return rows.map(rowToPublishedSelectionState);
|
|
4782
|
+
}
|
|
4710
4783
|
async pinSkill(principal, slug, metadata = {}) {
|
|
4711
4784
|
const rows = await this.sql`
|
|
4712
4785
|
INSERT INTO skills_pins (org_id, principal, slug, pinned_at, metadata_json)
|
package/bin/mcp.js
CHANGED
|
@@ -20019,7 +20019,7 @@ var package_default;
|
|
|
20019
20019
|
var init_package = __esm(() => {
|
|
20020
20020
|
package_default = {
|
|
20021
20021
|
name: "@hasna/skills",
|
|
20022
|
-
version: "0.9.
|
|
20022
|
+
version: "0.9.14",
|
|
20023
20023
|
description: "Skills library for AI coding agents",
|
|
20024
20024
|
type: "module",
|
|
20025
20025
|
bin: {
|
|
@@ -38126,10 +38126,10 @@ function assertAgentPolicyCollections(policy) {
|
|
|
38126
38126
|
text(source.path);
|
|
38127
38127
|
requireBound(source.sha256 === null || typeof source.sha256 === "string" && /^[a-f0-9]{64}$/.test(source.sha256));
|
|
38128
38128
|
if (source.hashMode !== undefined)
|
|
38129
|
-
requireBound(["bytes", "path-bytes", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
|
|
38130
|
-
if (source.hashMode === "claude-settings-v1")
|
|
38129
|
+
requireBound(["bytes", "path-bytes", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1", "claude-settings-v2", "claude-marketplace-registry-v2"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
|
|
38130
|
+
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2")
|
|
38131
38131
|
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute3(source.path) && resolve2(source.path) === source.path && basename3(source.path) === "settings.json");
|
|
38132
|
-
if (source.hashMode === "claude-marketplace-registry")
|
|
38132
|
+
if (source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2")
|
|
38133
38133
|
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute3(source.path) && resolve2(source.path) === source.path && basename3(source.path) === "known_marketplaces.json");
|
|
38134
38134
|
if (source.hashMode === "claude-plugin-registry") {
|
|
38135
38135
|
requireBound(agent === "claude");
|
|
@@ -47080,9 +47080,32 @@ function canonical2(value) {
|
|
|
47080
47080
|
return { kind: "array", items: value.items.map(canonical2) };
|
|
47081
47081
|
return value;
|
|
47082
47082
|
}
|
|
47083
|
-
function
|
|
47083
|
+
function inferencePreference(key, child) {
|
|
47084
|
+
if (key === "skipDangerousModePermissionPrompt") {
|
|
47085
|
+
need2(child.kind === "literal" && (child.value === "true" || child.value === "false"), "contains an invalid dialog acknowledgment");
|
|
47086
|
+
return false;
|
|
47087
|
+
}
|
|
47088
|
+
if (key === "effortLevel") {
|
|
47089
|
+
need2(child.kind === "string" && PERSISTED_EFFORT_LEVELS.has(child.value), "contains an invalid persisted effort level");
|
|
47090
|
+
return true;
|
|
47091
|
+
}
|
|
47092
|
+
if (key !== "modelSettings")
|
|
47093
|
+
return false;
|
|
47094
|
+
need2(child.kind === "object", "requires an object of model preferences");
|
|
47095
|
+
child.entries = child.entries.filter(([model, preferences]) => {
|
|
47096
|
+
if (!BUILTIN_MODEL_SELECTIONS.has(model) || preferences.kind !== "object" || preferences.entries.length !== 1 || preferences.entries[0][0] !== "effortLevel")
|
|
47097
|
+
return true;
|
|
47098
|
+
const effort = preferences.entries[0][1];
|
|
47099
|
+
need2(effort.kind === "string" && PERSISTED_EFFORT_LEVELS.has(effort.value), "contains an invalid persisted model effort level");
|
|
47100
|
+
return false;
|
|
47101
|
+
});
|
|
47102
|
+
return child.entries.length === 0;
|
|
47103
|
+
}
|
|
47104
|
+
function settingsDigest(text2, version2 = 1) {
|
|
47084
47105
|
const value = parse8(text2);
|
|
47085
47106
|
value.entries = value.entries.filter(([key, child]) => {
|
|
47107
|
+
if (version2 === 2 && inferencePreference(key, child))
|
|
47108
|
+
return false;
|
|
47086
47109
|
if (key === "model") {
|
|
47087
47110
|
need2(child.kind === "string", "contains an invalid model selection");
|
|
47088
47111
|
return !BUILTIN_MODEL_SELECTIONS.has(child.value);
|
|
@@ -47097,7 +47120,7 @@ function settingsDigest(text2) {
|
|
|
47097
47120
|
}
|
|
47098
47121
|
return true;
|
|
47099
47122
|
});
|
|
47100
|
-
return createHash9("sha256").update(
|
|
47123
|
+
return createHash9("sha256").update(`hasna.skills.claude-settings.v${version2}\x00`).update(JSON.stringify(canonical2(value))).digest("hex");
|
|
47101
47124
|
}
|
|
47102
47125
|
function hashClaudeSettingsReplacement(text2, budget) {
|
|
47103
47126
|
need2(typeof text2 === "string", "requires settings text");
|
|
@@ -47109,7 +47132,17 @@ function hashClaudeSettingsReplacement(text2, budget) {
|
|
|
47109
47132
|
function captureClaudeSettings(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
47110
47133
|
return { path, hashMode: "claude-settings-v1", sha256: settingsDigest(readSettings(path, budget)) };
|
|
47111
47134
|
}
|
|
47112
|
-
|
|
47135
|
+
function captureClaudeSettingsV2(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
47136
|
+
return { path, hashMode: "claude-settings-v2", sha256: settingsDigest(readSettings(path, budget), 2) };
|
|
47137
|
+
}
|
|
47138
|
+
function hashClaudeSettingsReplacementV2(text2, budget) {
|
|
47139
|
+
need2(typeof text2 === "string", "requires settings text");
|
|
47140
|
+
const bytes = Buffer.byteLength(text2);
|
|
47141
|
+
need2(bytes <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes && Number.isSafeInteger(budget.remaining) && budget.remaining >= bytes, "exceeds its byte limit");
|
|
47142
|
+
budget.remaining -= bytes;
|
|
47143
|
+
return settingsDigest(text2, 2);
|
|
47144
|
+
}
|
|
47145
|
+
var CLAUDE_SETTINGS_WITNESS_LIMITS, sameFile = (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, BOOLEAN_PREFERENCES, ENUM_PREFERENCES, BUILTIN_MODEL_SELECTIONS, PERSISTED_EFFORT_LEVELS;
|
|
47113
47146
|
var init_claude_settings_witness = __esm(() => {
|
|
47114
47147
|
CLAUDE_SETTINGS_WITNESS_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
|
|
47115
47148
|
BOOLEAN_PREFERENCES = new Set([
|
|
@@ -47163,6 +47196,7 @@ var init_claude_settings_witness = __esm(() => {
|
|
|
47163
47196
|
"claude-opus-4-6[1m]",
|
|
47164
47197
|
"claude-sonnet-4-6[1m]"
|
|
47165
47198
|
]);
|
|
47199
|
+
PERSISTED_EFFORT_LEVELS = new Set(["low", "medium", "high", "xhigh"]);
|
|
47166
47200
|
});
|
|
47167
47201
|
|
|
47168
47202
|
// src/lib/agent-integration.ts
|
|
@@ -48665,9 +48699,13 @@ function textField(value) {
|
|
|
48665
48699
|
need3(value?.kind === "string" && value.value.length > 0 && !/[\x00-\x1f\x7f]/.test(value.value), "contains an invalid recognized field");
|
|
48666
48700
|
return value.value;
|
|
48667
48701
|
}
|
|
48668
|
-
function normalizeRow(row) {
|
|
48669
|
-
if (!exactKeys(row, ["source", "installLocation", "lastUpdated"]))
|
|
48670
|
-
|
|
48702
|
+
function normalizeRow(row, version2 = 1) {
|
|
48703
|
+
if (!exactKeys(row, ["source", "installLocation", "lastUpdated"])) {
|
|
48704
|
+
if (version2 !== 2 || !exactKeys(row, ["source", "installLocation", "lastUpdated", "autoUpdate"]))
|
|
48705
|
+
return;
|
|
48706
|
+
const autoUpdate = field(row, "autoUpdate");
|
|
48707
|
+
need3(autoUpdate?.kind === "literal" && (autoUpdate.value === "true" || autoUpdate.value === "false"), "contains an invalid automatic-update preference");
|
|
48708
|
+
}
|
|
48671
48709
|
const source = field(row, "source");
|
|
48672
48710
|
if (source?.kind !== "object")
|
|
48673
48711
|
return;
|
|
@@ -48694,6 +48732,13 @@ function captureClaudeMarketplaceRegistry(path, budget = { remaining: 256 * 1024
|
|
|
48694
48732
|
const sha2562 = createHash11("sha256").update("hasna.skills.claude-marketplace-registry.v1\x00").update(JSON.stringify(value)).digest("hex");
|
|
48695
48733
|
return { path, hashMode: "claude-marketplace-registry", sha256: sha2562 };
|
|
48696
48734
|
}
|
|
48735
|
+
function captureClaudeMarketplaceRegistryV2(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
48736
|
+
const value = parse10(readRegistry2(path, budget));
|
|
48737
|
+
for (const [, row] of value.entries)
|
|
48738
|
+
normalizeRow(row, 2);
|
|
48739
|
+
const sha2562 = createHash11("sha256").update("hasna.skills.claude-marketplace-registry.v2\x00").update(JSON.stringify(value)).digest("hex");
|
|
48740
|
+
return { path, hashMode: "claude-marketplace-registry-v2", sha256: sha2562 };
|
|
48741
|
+
}
|
|
48697
48742
|
var CLAUDE_MARKETPLACE_REGISTRY_LIMITS, sameFile2 = (a, b) => a.dev === b.dev && a.ino === b.ino && a.mode === b.mode && a.uid === b.uid && a.gid === b.gid && a.nlink === b.nlink && a.size === b.size && a.mtimeNs === b.mtimeNs && a.ctimeNs === b.ctimeNs, field = (object7, key) => object7.entries.find(([name]) => name === key)?.[1];
|
|
48698
48743
|
var init_claude_marketplace_registry = __esm(() => {
|
|
48699
48744
|
CLAUDE_MARKETPLACE_REGISTRY_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
|
|
@@ -48809,18 +48854,18 @@ function read(path, changes) {
|
|
|
48809
48854
|
return readFileSync14(path, "utf8");
|
|
48810
48855
|
}
|
|
48811
48856
|
function projected(source, changes, budget = discoveryByteBudget()) {
|
|
48812
|
-
if (source.hashMode === "claude-settings-v1") {
|
|
48857
|
+
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2") {
|
|
48813
48858
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
48814
48859
|
throw new Error("Claude settings witnesses require exact typed metadata");
|
|
48815
|
-
const current = captureClaudeSettings(source.path, budget).sha256;
|
|
48860
|
+
const current = (source.hashMode === "claude-settings-v2" ? captureClaudeSettingsV2 : captureClaudeSettings)(source.path, budget).sha256;
|
|
48816
48861
|
if (current !== source.sha256)
|
|
48817
48862
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
48818
|
-
return changes?.has(source.path) ? hashClaudeSettingsReplacement(changes.get(source.path), budget) : current;
|
|
48863
|
+
return changes?.has(source.path) ? (source.hashMode === "claude-settings-v2" ? hashClaudeSettingsReplacementV2 : hashClaudeSettingsReplacement)(changes.get(source.path), budget) : current;
|
|
48819
48864
|
}
|
|
48820
|
-
if (source.hashMode === "claude-marketplace-registry") {
|
|
48865
|
+
if (source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2") {
|
|
48821
48866
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256) || changes?.has(source.path))
|
|
48822
48867
|
throw new Error("Claude marketplace witnesses require an exact reviewed registry without synthetic changes");
|
|
48823
|
-
const sha2562 = captureClaudeMarketplaceRegistry(source.path, budget).sha256;
|
|
48868
|
+
const sha2562 = (source.hashMode === "claude-marketplace-registry-v2" ? captureClaudeMarketplaceRegistryV2 : captureClaudeMarketplaceRegistry)(source.path, budget).sha256;
|
|
48824
48869
|
if (sha2562 !== source.sha256)
|
|
48825
48870
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
48826
48871
|
return sha2562;
|
|
@@ -48877,9 +48922,9 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
48877
48922
|
safe4(root);
|
|
48878
48923
|
}
|
|
48879
48924
|
function assertMarketplaceBinding(binding, source) {
|
|
48880
|
-
if (source.hashMode === "claude-settings-v1" && (binding.agent !== "claude" || binding.method !== "reviewed" || basename7(source.path) !== "settings.json"))
|
|
48925
|
+
if ((source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2") && (binding.agent !== "claude" || binding.method !== "reviewed" || basename7(source.path) !== "settings.json"))
|
|
48881
48926
|
throw new Error("Claude settings witnesses require explicit reviewed Claude configuration");
|
|
48882
|
-
if (source.hashMode === "claude-marketplace-registry" && (binding.agent !== "claude" || binding.method !== "reviewed"))
|
|
48927
|
+
if ((source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2") && (binding.agent !== "claude" || binding.method !== "reviewed"))
|
|
48883
48928
|
throw new Error("Claude marketplace witnesses require explicit reviewed Claude discovery");
|
|
48884
48929
|
}
|
|
48885
48930
|
function agentDiscoveryConfigPath(home, agent) {
|
|
@@ -48961,7 +49006,7 @@ function resolveAgentDiscovery(options) {
|
|
|
48961
49006
|
if (review.sources.some((source) => source.format !== undefined || source.fields !== undefined))
|
|
48962
49007
|
throw new Error("Explicit discovery reviews require full source-file hashes");
|
|
48963
49008
|
verifyAgentDiscovery(supplied);
|
|
48964
|
-
if (review.sources.some((source) => source.hashMode === "claude-settings-v1" && source.path !== canonical4(configPath)))
|
|
49009
|
+
if (review.sources.some((source) => (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2") && source.path !== canonical4(configPath)))
|
|
48965
49010
|
throw new Error("Semantic settings witnesses must name the configured Claude configuration source");
|
|
48966
49011
|
if (!review.sources.some((source) => source.path === canonical4(configPath)))
|
|
48967
49012
|
throw new Error("Discovery review must include the agent configuration source");
|
package/bin/migrate.js
CHANGED
|
@@ -7,7 +7,7 @@ import { join as join5 } from "path";
|
|
|
7
7
|
// package.json
|
|
8
8
|
var package_default = {
|
|
9
9
|
name: "@hasna/skills",
|
|
10
|
-
version: "0.9.
|
|
10
|
+
version: "0.9.14",
|
|
11
11
|
description: "Skills library for AI coding agents",
|
|
12
12
|
type: "module",
|
|
13
13
|
bin: {
|
|
@@ -985,6 +985,18 @@ function rowToSkill(row) {
|
|
|
985
985
|
...row.replacement_slug ? { replacementSlug: String(row.replacement_slug) } : {}
|
|
986
986
|
};
|
|
987
987
|
}
|
|
988
|
+
function rowToPublishedSelectionState(row) {
|
|
989
|
+
return {
|
|
990
|
+
slug: String(row.slug),
|
|
991
|
+
version: String(row.version),
|
|
992
|
+
current: row.skill_exists ? {
|
|
993
|
+
lifecycle: row.lifecycle === "archived" ? "archived" : "active",
|
|
994
|
+
...row.tombstoned_at ? { tombstonedAt: dateString(row.tombstoned_at) } : {}
|
|
995
|
+
} : null,
|
|
996
|
+
versionBundleSha256: typeof row.bundle_sha256 === "string" ? row.bundle_sha256 : null,
|
|
997
|
+
bundleAvailable: Boolean(row.bundle_available)
|
|
998
|
+
};
|
|
999
|
+
}
|
|
988
1000
|
function rowToPin(row) {
|
|
989
1001
|
return {
|
|
990
1002
|
orgId: String(row.org_id),
|
|
@@ -1057,6 +1069,13 @@ function rowToSkillVersion(row) {
|
|
|
1057
1069
|
};
|
|
1058
1070
|
}
|
|
1059
1071
|
|
|
1072
|
+
// src/lib/profile-limits.ts
|
|
1073
|
+
var MAX_PROFILE_SELECTIONS = 4096;
|
|
1074
|
+
var MAX_PROFILE_DOCUMENT_BYTES = 8 * 1024 * 1024;
|
|
1075
|
+
var MAX_SKILL_SESSION_ID_CHARS = 256;
|
|
1076
|
+
var PROFILE_SESSION_ENVELOPE_BYTES = MAX_PROFILE_SELECTIONS * 67 + MAX_SKILL_SESSION_ID_CHARS * 12 + 512;
|
|
1077
|
+
var MAX_RESOLVED_PROFILE_BYTES = MAX_PROFILE_DOCUMENT_BYTES - PROFILE_SESSION_ENVELOPE_BYTES;
|
|
1078
|
+
|
|
1060
1079
|
// src/server/types.ts
|
|
1061
1080
|
class StaleLeaseGenerationError extends Error {
|
|
1062
1081
|
runId;
|
|
@@ -1758,6 +1777,22 @@ class SqliteSkillsStore {
|
|
|
1758
1777
|
const row = this.get("SELECT * FROM skills_versions WHERE org_id = ? AND slug = ? AND version = ? LIMIT 1", [principal.orgId, slug, version]);
|
|
1759
1778
|
return row ? rowToSkillVersion(row) : null;
|
|
1760
1779
|
}
|
|
1780
|
+
async getPublishedSelectionStates(principal, selections2) {
|
|
1781
|
+
if (selections2.length > MAX_PROFILE_SELECTIONS)
|
|
1782
|
+
throw new RangeError("Published selection lookup exceeds the profile selection limit");
|
|
1783
|
+
if (!selections2.length)
|
|
1784
|
+
return [];
|
|
1785
|
+
const requested = JSON.stringify(selections2.map(({ slug, version }) => ({ slug, version })));
|
|
1786
|
+
return this.all(`SELECT json_extract(q.value, '$.slug') AS slug, json_extract(q.value, '$.version') AS version,
|
|
1787
|
+
r.slug IS NOT NULL AS skill_exists, r.lifecycle, r.tombstoned_at,
|
|
1788
|
+
v.bundle_sha256, b.sha256 IS NOT NULL AS bundle_available
|
|
1789
|
+
FROM json_each(?) q
|
|
1790
|
+
LEFT JOIN skills_registry r ON r.org_id = ? AND r.slug = json_extract(q.value, '$.slug')
|
|
1791
|
+
LEFT JOIN skills_versions v ON v.org_id = ?
|
|
1792
|
+
AND v.slug = json_extract(q.value, '$.slug') AND v.version = json_extract(q.value, '$.version')
|
|
1793
|
+
LEFT JOIN skills_bundles b ON b.org_id = ? AND b.sha256 = v.bundle_sha256
|
|
1794
|
+
ORDER BY CAST(q.key AS INTEGER)`, [requested, principal.orgId, principal.orgId, principal.orgId]).map(rowToPublishedSelectionState);
|
|
1795
|
+
}
|
|
1761
1796
|
async pinSkill(principal, slug, metadata = {}) {
|
|
1762
1797
|
const row = this.get(`INSERT INTO skills_pins (org_id, principal, slug, pinned_at, metadata_json)
|
|
1763
1798
|
VALUES (?, ?, ?, ?, ?)
|