@hasna/skills 0.10.56 → 0.10.58
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 +697 -109
- package/bin/mcp.js +3 -2
- package/bin/migrate.js +1 -1
- package/bin/server.js +1 -1
- package/bin/worker.js +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +89 -3
- package/dist/lib/agent-integration.d.ts +2 -0
- package/dist/lib/claude-prospective-review.d.ts +140 -0
- package/dist/sdk/index.js +4 -3
- package/docs/plugin-admission.md +59 -0
- package/package.json +1 -1
package/bin/mcp.js
CHANGED
|
@@ -20019,7 +20019,7 @@ var package_default;
|
|
|
20019
20019
|
var init_package = __esm(() => {
|
|
20020
20020
|
package_default = {
|
|
20021
20021
|
name: "@hasna/skills",
|
|
20022
|
-
version: "0.10.
|
|
20022
|
+
version: "0.10.58",
|
|
20023
20023
|
description: "Skills library for AI coding agents",
|
|
20024
20024
|
type: "module",
|
|
20025
20025
|
bin: {
|
|
@@ -38561,7 +38561,8 @@ var init_codex_native_compatibility = __esm(() => {
|
|
|
38561
38561
|
"codex-cli 0.159.2": ["hooks", "qualified-skill-catalog"],
|
|
38562
38562
|
"codex-cli 0.160.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
|
|
38563
38563
|
"codex-cli 0.160.1": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
|
|
38564
|
-
"codex-cli 0.161.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"]
|
|
38564
|
+
"codex-cli 0.161.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
|
|
38565
|
+
"codex-cli 0.162.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"]
|
|
38565
38566
|
};
|
|
38566
38567
|
SUPPORTED_CODEX_HOOK_VERSIONS = Object.freeze(Object.keys(MEASURED_CODEX_CAPABILITIES).filter((version2) => supportsCodexNativeCapability(version2, "hooks")));
|
|
38567
38568
|
});
|
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.58",
|
|
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.58",
|
|
24147
24147
|
description: "Skills library for AI coding agents",
|
|
24148
24148
|
type: "module",
|
|
24149
24149
|
bin: {
|
package/dist/index.d.ts
CHANGED
|
@@ -65,6 +65,8 @@ export type { ClaudeManagedHookProjection, ClaudeManagedHookProjectionOptions }
|
|
|
65
65
|
export { captureDiscoveryDirectories, captureDiscoveryByteSources, captureDiscoveryPathSources, DISCOVERY_ROOT_UNRESOLVED, isDiscoveryRootUnresolved, type DiscoveryDirectory, type DiscoveryExecutable, type DiscoverySource } from "./lib/agent-discovery.js";
|
|
66
66
|
export { captureClaudeMarketplaceRegistry, captureClaudeMarketplaceRegistryV2 } from "./lib/claude-marketplace-registry.js";
|
|
67
67
|
export { captureClaudeMarketplaceEntry, hashClaudeMarketplaceEntry, CLAUDE_MARKETPLACE_ENTRY_HASH_MODE, type ClaudeMarketplaceEntrySelector, type ClaudeMarketplaceEntryWitness } from "./lib/claude-marketplace-entry-witness.js";
|
|
68
|
+
export { captureClaudeProspectiveCandidateClosure } from "./lib/claude-prospective-review.js";
|
|
69
|
+
export { hashClaudePluginManifest } from "./lib/claude-plugin-manifest-witness.js";
|
|
68
70
|
export { captureClaudeSettings, captureClaudeSettingsV2, captureClaudeSettingsV3, captureClaudeSettingsV4, upgradeClaudeSettingsWitness, upgradeClaudeSettingsWitnessV4 } from "./lib/claude-settings-witness.js";
|
|
69
71
|
export { buildPluginProjection, pluginTreeDigest, type PluginProjectionManifest, type PluginPayloadMapping, type PluginFileWitness } from "./lib/plugin-projection.js";
|
|
70
72
|
export { planPluginAdmission, admitPlugin, resolveAdmittedPlugin, pluginResolverCommand, type PluginAdmissionTarget, type PluginAdmissionBinding, type PluginAdmissionPrincipal, type PluginAdmissionPlan, type PluginAdmissionIdentity, type PluginBundleIdentity, type PluginRoutingIdentity, type PluginAdmissionReceipt } from "./lib/plugin-admission.js";
|
package/dist/index.js
CHANGED
|
@@ -9399,7 +9399,8 @@ var MEASURED_CODEX_CAPABILITIES = {
|
|
|
9399
9399
|
"codex-cli 0.159.2": ["hooks", "qualified-skill-catalog"],
|
|
9400
9400
|
"codex-cli 0.160.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
|
|
9401
9401
|
"codex-cli 0.160.1": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
|
|
9402
|
-
"codex-cli 0.161.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"]
|
|
9402
|
+
"codex-cli 0.161.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
|
|
9403
|
+
"codex-cli 0.162.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"]
|
|
9403
9404
|
};
|
|
9404
9405
|
function supportsCodexNativeCapability(version, capability) {
|
|
9405
9406
|
return typeof version === "string" && Object.hasOwn(MEASURED_CODEX_CAPABILITIES, version) && MEASURED_CODEX_CAPABILITIES[version].includes(capability);
|
|
@@ -11833,7 +11834,7 @@ function replaceSkillSession(expected, replacement, plan, options = {}, beforeCo
|
|
|
11833
11834
|
// package.json
|
|
11834
11835
|
var package_default = {
|
|
11835
11836
|
name: "@hasna/skills",
|
|
11836
|
-
version: "0.10.
|
|
11837
|
+
version: "0.10.58",
|
|
11837
11838
|
description: "Skills library for AI coding agents",
|
|
11838
11839
|
type: "module",
|
|
11839
11840
|
bin: {
|
|
@@ -14062,7 +14063,7 @@ async function connectCodexHookRpc(options) {
|
|
|
14062
14063
|
const deadline = setTimeout(() => {
|
|
14063
14064
|
clearTimeout(terminate);
|
|
14064
14065
|
reject(new Error("CODEX_HOOK_TRUST_NATIVE_CLOSE_UNCONFIRMED"));
|
|
14065
|
-
},
|
|
14066
|
+
}, 1e4);
|
|
14066
14067
|
actualClose.then(() => {
|
|
14067
14068
|
clearTimeout(terminate);
|
|
14068
14069
|
clearTimeout(deadline);
|
|
@@ -48343,6 +48344,89 @@ async function reconcileSkillSession(input2, options = {}) {
|
|
|
48343
48344
|
const result = replaceSkillSession(skillSessionSnapshotBinding(snapshot2), replacement, { ...plan, planDigest }, options, () => assertPlanWindow(issuedAt, expiresAt, (options.now ?? Date.now)()));
|
|
48344
48345
|
return { applied: true, plan, planDigest, ...result };
|
|
48345
48346
|
}
|
|
48347
|
+
// src/lib/claude-prospective-review.ts
|
|
48348
|
+
import { createHash as createHash35 } from "crypto";
|
|
48349
|
+
import { lstatSync as lstatSync28, readFileSync as readFileSync30, readdirSync as readdirSync17, realpathSync as realpathSync15 } from "fs";
|
|
48350
|
+
import { basename as basename14, dirname as dirname30, isAbsolute as isAbsolute26, join as join44, relative as relative12, resolve as resolve27, sep as sep15 } from "path";
|
|
48351
|
+
var MAX_CANDIDATE_FILES = 16384;
|
|
48352
|
+
var MAX_CANDIDATE_BYTES = 256 * 1024 * 1024;
|
|
48353
|
+
var sha6 = (data) => createHash35("sha256").update(data).digest("hex");
|
|
48354
|
+
function refuse4(reason2) {
|
|
48355
|
+
throw new Error(`CLAUDE_CANDIDATE_REVIEW_REFUSED: ${reason2}`);
|
|
48356
|
+
}
|
|
48357
|
+
var GENERATED_MARKETPLACE_TIME = Object.freeze({ $generated: "claude-utc-timestamp", field: "known-marketplaces.lastUpdated" });
|
|
48358
|
+
var GENERATED_FRESH_PLUGIN_INSTALLED_AT = Object.freeze({ $generated: "claude-utc-timestamp", field: "installed_plugins.fresh-row.installedAt" });
|
|
48359
|
+
var GENERATED_PLUGIN_UPDATE_TIME = Object.freeze({ $generated: "claude-utc-timestamp", field: "installed_plugins.selected-row.lastUpdated" });
|
|
48360
|
+
function abs(path, name) {
|
|
48361
|
+
if (typeof path !== "string" || !path || path.length > 4096 || /[\x00-\x1f\x7f]/.test(path) || !isAbsolute26(path) || resolve27(path) !== path)
|
|
48362
|
+
refuse4(`${name} must be a normalized absolute path`);
|
|
48363
|
+
}
|
|
48364
|
+
function safeFile(path, name) {
|
|
48365
|
+
abs(path, name);
|
|
48366
|
+
for (let at = dirname30(path);; at = dirname30(at)) {
|
|
48367
|
+
const stat3 = lstatSync28(at, { throwIfNoEntry: false });
|
|
48368
|
+
if (!stat3?.isDirectory() || stat3.isSymbolicLink())
|
|
48369
|
+
refuse4(`${name} traverses a symlink or non-directory`);
|
|
48370
|
+
if (at === dirname30(at))
|
|
48371
|
+
break;
|
|
48372
|
+
}
|
|
48373
|
+
const stat2 = lstatSync28(path, { throwIfNoEntry: false });
|
|
48374
|
+
if (!stat2?.isFile() || stat2.isSymbolicLink() || stat2.size > MAX_CANDIDATE_BYTES)
|
|
48375
|
+
refuse4(`${name} is not a bounded regular file`);
|
|
48376
|
+
return readFileSync30(path);
|
|
48377
|
+
}
|
|
48378
|
+
function canonicalDir(path, name) {
|
|
48379
|
+
abs(path, name);
|
|
48380
|
+
if (realpathSync15(path) !== path || !lstatSync28(path).isDirectory())
|
|
48381
|
+
refuse4(`${name} is not a canonical directory`);
|
|
48382
|
+
for (let at = path;; at = dirname30(at)) {
|
|
48383
|
+
const stat2 = lstatSync28(at);
|
|
48384
|
+
if (!stat2.isDirectory() || stat2.isSymbolicLink())
|
|
48385
|
+
refuse4(`${name} traverses a symlink`);
|
|
48386
|
+
if (at === dirname30(at))
|
|
48387
|
+
break;
|
|
48388
|
+
}
|
|
48389
|
+
}
|
|
48390
|
+
function captureClaudeProspectiveCandidateClosure(root2) {
|
|
48391
|
+
canonicalDir(root2, "candidate root");
|
|
48392
|
+
const entries = [];
|
|
48393
|
+
let bytes = 0;
|
|
48394
|
+
const walk2 = (directory2) => {
|
|
48395
|
+
const beforeDirectory = lstatSync28(directory2);
|
|
48396
|
+
const names = readdirSync17(directory2).sort();
|
|
48397
|
+
if (new Set(names).size !== names.length)
|
|
48398
|
+
refuse4("candidate contains ambiguous directory entries");
|
|
48399
|
+
for (const name of names) {
|
|
48400
|
+
if (!name || name === "." || name === ".." || name.includes("/") || name.includes("\\") || /[\x00-\x1f\x7f]/.test(name))
|
|
48401
|
+
refuse4("candidate contains an unsupported path member");
|
|
48402
|
+
const path = join44(directory2, name), rel = relative12(root2, path).split(sep15).join("/");
|
|
48403
|
+
if (entries.length >= MAX_CANDIDATE_FILES)
|
|
48404
|
+
refuse4("candidate closure exceeds its member limit");
|
|
48405
|
+
const stat2 = lstatSync28(path);
|
|
48406
|
+
if (stat2.isSymbolicLink())
|
|
48407
|
+
refuse4("candidate closure contains a symlink");
|
|
48408
|
+
if (stat2.isDirectory()) {
|
|
48409
|
+
entries.push([rel, "directory", null]);
|
|
48410
|
+
walk2(path);
|
|
48411
|
+
} else if (stat2.isFile()) {
|
|
48412
|
+
bytes += stat2.size;
|
|
48413
|
+
if (bytes > MAX_CANDIDATE_BYTES)
|
|
48414
|
+
refuse4("candidate closure exceeds its byte limit");
|
|
48415
|
+
const content = safeFile(path, "candidate member"), after = lstatSync28(path);
|
|
48416
|
+
if (!after.isFile() || after.dev !== stat2.dev || after.ino !== stat2.ino || after.size !== stat2.size || after.mtimeMs !== stat2.mtimeMs || after.ctimeMs !== stat2.ctimeMs)
|
|
48417
|
+
refuse4("candidate member changed while being read");
|
|
48418
|
+
entries.push([rel, "file", sha6(content)]);
|
|
48419
|
+
} else
|
|
48420
|
+
refuse4("candidate closure contains a special file");
|
|
48421
|
+
}
|
|
48422
|
+
const afterDirectory = lstatSync28(directory2);
|
|
48423
|
+
if (!afterDirectory.isDirectory() || afterDirectory.dev !== beforeDirectory.dev || afterDirectory.ino !== beforeDirectory.ino || afterDirectory.mtimeMs !== beforeDirectory.mtimeMs || afterDirectory.ctimeMs !== beforeDirectory.ctimeMs)
|
|
48424
|
+
refuse4("candidate directory changed while being read");
|
|
48425
|
+
};
|
|
48426
|
+
walk2(root2);
|
|
48427
|
+
entries.sort((a, b) => a[0].localeCompare(b[0]));
|
|
48428
|
+
return sha6(JSON.stringify(entries));
|
|
48429
|
+
}
|
|
48346
48430
|
export {
|
|
48347
48431
|
writeStationSnapshot,
|
|
48348
48432
|
writeStationHydration,
|
|
@@ -48483,6 +48567,7 @@ export {
|
|
|
48483
48567
|
inspectPrivatePublication,
|
|
48484
48568
|
importSkillsLocalSnapshot,
|
|
48485
48569
|
homePathFor,
|
|
48570
|
+
hashClaudePluginManifest,
|
|
48486
48571
|
hashClaudeMarketplaceEntry,
|
|
48487
48572
|
getToolPrimitive,
|
|
48488
48573
|
getStorageStatus,
|
|
@@ -48566,6 +48651,7 @@ export {
|
|
|
48566
48651
|
captureClaudeSettingsV3,
|
|
48567
48652
|
captureClaudeSettingsV2,
|
|
48568
48653
|
captureClaudeSettings,
|
|
48654
|
+
captureClaudeProspectiveCandidateClosure,
|
|
48569
48655
|
captureClaudeMarketplaceRegistryV2,
|
|
48570
48656
|
captureClaudeMarketplaceRegistry,
|
|
48571
48657
|
captureClaudeMarketplaceEntry,
|
|
@@ -99,6 +99,8 @@ export interface AgentIntegrationPlan {
|
|
|
99
99
|
}
|
|
100
100
|
/** Normalize only the verified OS prefix, never hide user-controlled links. */
|
|
101
101
|
export declare function canonicalSystemPath(path: string): string;
|
|
102
|
+
export declare function canonicalAgentPath(path: string, aliases: AgentRootAlias[]): string;
|
|
103
|
+
export declare function recheckRootAliases(aliases: AgentRootAlias[]): void;
|
|
102
104
|
/** Parse the reviewed exact-target binding used by native migration. Paths are
|
|
103
105
|
* deliberately project-relative so a manifest cannot silently select another
|
|
104
106
|
* checkout when a project root changes. */
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { type ReviewedDiscoveryInputs } from "./agent-discovery.js";
|
|
2
|
+
export declare const CLAUDE_PROSPECTIVE_REVIEW_SCHEMA: "skills.claude-plugin-prospective-review/v1";
|
|
3
|
+
export interface ClaudeProspectiveReviewRequest {
|
|
4
|
+
schema: typeof CLAUDE_PROSPECTIVE_REVIEW_SCHEMA;
|
|
5
|
+
scope: {
|
|
6
|
+
kind: "user" | "project";
|
|
7
|
+
projectPath: string;
|
|
8
|
+
};
|
|
9
|
+
native: {
|
|
10
|
+
home: string;
|
|
11
|
+
executable: {
|
|
12
|
+
path: string;
|
|
13
|
+
target: string;
|
|
14
|
+
version: string;
|
|
15
|
+
sha256: string;
|
|
16
|
+
};
|
|
17
|
+
configRoot: string;
|
|
18
|
+
pluginRoot: string;
|
|
19
|
+
};
|
|
20
|
+
skills: {
|
|
21
|
+
dataDir: string;
|
|
22
|
+
policySha256: string;
|
|
23
|
+
discoverySha256: string;
|
|
24
|
+
discoveryInputs: ReviewedDiscoveryInputs;
|
|
25
|
+
};
|
|
26
|
+
candidate: {
|
|
27
|
+
marketplace: string;
|
|
28
|
+
root: string;
|
|
29
|
+
catalogPath: string;
|
|
30
|
+
catalogSha256: string;
|
|
31
|
+
closureSha256: string;
|
|
32
|
+
plugins: Array<{
|
|
33
|
+
plugin: string;
|
|
34
|
+
manifestPath: string;
|
|
35
|
+
manifestSha256: string;
|
|
36
|
+
optionsPatch: Record<string, unknown>;
|
|
37
|
+
}>;
|
|
38
|
+
releaseManifest?: {
|
|
39
|
+
path: string;
|
|
40
|
+
sha256: string;
|
|
41
|
+
};
|
|
42
|
+
functionHooksEnv?: "1";
|
|
43
|
+
};
|
|
44
|
+
preimages: {
|
|
45
|
+
settings: {
|
|
46
|
+
path: string;
|
|
47
|
+
sha256: string | null;
|
|
48
|
+
};
|
|
49
|
+
userSettings: {
|
|
50
|
+
path: string;
|
|
51
|
+
sha256: string | null;
|
|
52
|
+
};
|
|
53
|
+
projectSettings: {
|
|
54
|
+
path: string;
|
|
55
|
+
sha256: string | null;
|
|
56
|
+
};
|
|
57
|
+
projectSettingsLocal: {
|
|
58
|
+
path: string;
|
|
59
|
+
sha256: string | null;
|
|
60
|
+
};
|
|
61
|
+
marketplaces: {
|
|
62
|
+
path: string;
|
|
63
|
+
sha256: string | null;
|
|
64
|
+
};
|
|
65
|
+
installedPlugins: {
|
|
66
|
+
path: string;
|
|
67
|
+
sha256: string | null;
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
/** Complete semantic documents expected after native adoption. The one
|
|
71
|
+
* timestamps generated by Claude for the owned marketplace and registration
|
|
72
|
+
* rows use exact typed field markers documented below; every other field is
|
|
73
|
+
* concrete. */
|
|
74
|
+
delta: {
|
|
75
|
+
settingsAfter: Record<string, unknown>;
|
|
76
|
+
knownMarketplacesAfter: Record<string, unknown>;
|
|
77
|
+
installedPluginsAfter: Record<string, unknown>;
|
|
78
|
+
};
|
|
79
|
+
review: {
|
|
80
|
+
pluginHooks: "reviewed-no-skill-injection";
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
export interface ClaudeProspectiveReviewReceipt {
|
|
84
|
+
schema: typeof CLAUDE_PROSPECTIVE_REVIEW_SCHEMA;
|
|
85
|
+
accepted: true;
|
|
86
|
+
applied: false;
|
|
87
|
+
scope: ClaudeProspectiveReviewRequest["scope"];
|
|
88
|
+
pluginIds: string[];
|
|
89
|
+
native: {
|
|
90
|
+
executablePath: string;
|
|
91
|
+
executableTarget: string;
|
|
92
|
+
executableVersion: string;
|
|
93
|
+
executableSha256: string;
|
|
94
|
+
configRoot: string;
|
|
95
|
+
pluginRoot: string;
|
|
96
|
+
};
|
|
97
|
+
candidate: {
|
|
98
|
+
marketplace: string;
|
|
99
|
+
plugins: Array<{
|
|
100
|
+
plugin: string;
|
|
101
|
+
pluginId: string;
|
|
102
|
+
manifestSha256: string;
|
|
103
|
+
optionsPatchSha256: string;
|
|
104
|
+
}>;
|
|
105
|
+
closureSha256: string;
|
|
106
|
+
catalogSha256: string;
|
|
107
|
+
releaseManifest?: {
|
|
108
|
+
path: string;
|
|
109
|
+
sha256: string;
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
targetSettingsPath: string;
|
|
113
|
+
skillsDiscoverySha256: string;
|
|
114
|
+
requestFileSha256: string;
|
|
115
|
+
semanticDocumentsSha256: string;
|
|
116
|
+
operationSha256: string;
|
|
117
|
+
expectedPostStateSha256: string;
|
|
118
|
+
preimages: Array<{
|
|
119
|
+
name: string;
|
|
120
|
+
path: string;
|
|
121
|
+
sha256: string | null;
|
|
122
|
+
}>;
|
|
123
|
+
ownedDelta: {
|
|
124
|
+
settingsEnabledPlugins: string[];
|
|
125
|
+
selectedPluginOptions: string[];
|
|
126
|
+
functionHooksEnv: string | null;
|
|
127
|
+
knownMarketplace: string;
|
|
128
|
+
installedPlugins: string[];
|
|
129
|
+
unrelatedGraph: "preserved-by-complete-semantic-documents";
|
|
130
|
+
};
|
|
131
|
+
identityPrecondition: "Harnesses must resolve the installed Claude home/config/plugin roots and executable path/version/hash plus the installed Skills data directory through their package-owned consumers, then compare every value before trusting this receipt; this validator checks supplied paths and current bytes only and does not establish actual consumer identity";
|
|
132
|
+
reviewPrecondition: "The caller's no-skill-injection assessment is bound to the raw request hash; structural checks are not semantic hook review, and Harnesses must retain its existing review record and verify the exact candidate binding";
|
|
133
|
+
limitation: "validation-only; native installer atomicity and crash recovery are not established";
|
|
134
|
+
}
|
|
135
|
+
/** Fingerprint every file byte and directory name under the frozen candidate.
|
|
136
|
+
* Symlinks and special files refuse; the digest binds the complete closure. */
|
|
137
|
+
export declare function captureClaudeProspectiveCandidateClosure(root: string): string;
|
|
138
|
+
/** Validate a frozen candidate review against the current filesystem. This is
|
|
139
|
+
* intentionally a planner only: its receipt is not native-install authority. */
|
|
140
|
+
export declare function reviewClaudeProspectiveCandidate(request: ClaudeProspectiveReviewRequest, requestFileSha256: string): ClaudeProspectiveReviewReceipt;
|
package/dist/sdk/index.js
CHANGED
|
@@ -32373,7 +32373,7 @@ var init_event_sink = __esm(() => {
|
|
|
32373
32373
|
// package.json
|
|
32374
32374
|
var package_default = {
|
|
32375
32375
|
name: "@hasna/skills",
|
|
32376
|
-
version: "0.10.
|
|
32376
|
+
version: "0.10.58",
|
|
32377
32377
|
description: "Skills library for AI coding agents",
|
|
32378
32378
|
type: "module",
|
|
32379
32379
|
bin: {
|
|
@@ -38469,7 +38469,8 @@ var MEASURED_CODEX_CAPABILITIES = {
|
|
|
38469
38469
|
"codex-cli 0.159.2": ["hooks", "qualified-skill-catalog"],
|
|
38470
38470
|
"codex-cli 0.160.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
|
|
38471
38471
|
"codex-cli 0.160.1": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
|
|
38472
|
-
"codex-cli 0.161.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"]
|
|
38472
|
+
"codex-cli 0.161.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
|
|
38473
|
+
"codex-cli 0.162.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"]
|
|
38473
38474
|
};
|
|
38474
38475
|
function supportsCodexNativeCapability(version, capability) {
|
|
38475
38476
|
return typeof version === "string" && Object.hasOwn(MEASURED_CODEX_CAPABILITIES, version) && MEASURED_CODEX_CAPABILITIES[version].includes(capability);
|
|
@@ -38611,7 +38612,7 @@ async function connectCodexHookRpc(options) {
|
|
|
38611
38612
|
const deadline = setTimeout(() => {
|
|
38612
38613
|
clearTimeout(terminate);
|
|
38613
38614
|
reject(new Error("CODEX_HOOK_TRUST_NATIVE_CLOSE_UNCONFIRMED"));
|
|
38614
|
-
},
|
|
38615
|
+
}, 1e4);
|
|
38615
38616
|
actualClose.then(() => {
|
|
38616
38617
|
clearTimeout(terminate);
|
|
38617
38618
|
clearTimeout(deadline);
|
package/docs/plugin-admission.md
CHANGED
|
@@ -173,6 +173,65 @@ new loaders still require their dedicated review. API failure refuses an update;
|
|
|
173
173
|
stale projection as synchronized. Claude may retain its previous installation
|
|
174
174
|
after a refused update, whose existing local drift checks continue to apply.
|
|
175
175
|
|
|
176
|
+
## Prospective Claude candidate review
|
|
177
|
+
|
|
178
|
+
Before adding or changing a marketplace, an installer may call
|
|
179
|
+
`skills hook review-claude-candidate --request <absolute-json-path> --json`.
|
|
180
|
+
The `skills.claude-plugin-prospective-review/v1` request binds one frozen
|
|
181
|
+
marketplace/catalog closure and a non-empty `plugins` array. Each selected
|
|
182
|
+
plugin supplies its exact `plugin`, `manifestPath`, `manifestSha256` and bounded
|
|
183
|
+
JSON `optionsPatch`; an optional `releaseManifest` carries the separate
|
|
184
|
+
release.json path and raw-byte SHA-256. The request also binds current Skills
|
|
185
|
+
and Claude preimages, explicit user/project scope, caller assessment and one
|
|
186
|
+
complete expected semantic document set for the whole selected plugin batch.
|
|
187
|
+
The validator checks every selected manifest and source against the same
|
|
188
|
+
closure before returning one receipt. It derives the owned changes and refuses
|
|
189
|
+
any unrelated graph change. Harnesses validates each options patch against its
|
|
190
|
+
release manifest before invoking Claude; Skills does not copy its private
|
|
191
|
+
option allowlists or infer that caller-supplied options are release-approved.
|
|
192
|
+
The supported catalog shape uses relative selected-plugin sources inside that
|
|
193
|
+
closure. Nontrivial `metadata.pluginRoot` values and native catalog or selected
|
|
194
|
+
plugin dependency declarations refuse because this validator does not resolve
|
|
195
|
+
or review unselected external plugins.
|
|
196
|
+
The request may declare `functionHooksEnv: "1"`; without that declaration the
|
|
197
|
+
environment document is preserved unchanged. The validator shallow-merges
|
|
198
|
+
each declared options patch into the selected plugin's existing `options`;
|
|
199
|
+
the patch must explicitly bind `enabled: true`, and the validator enforces that
|
|
200
|
+
value after merging. This preserves all other selected options and unrelated
|
|
201
|
+
plugin configuration. It refuses a selected `enabledPlugins` array shape that
|
|
202
|
+
this schema does not model. Existing target registration rows keep their array
|
|
203
|
+
positions, new rows append, and unrelated rows remain byte-semantically bound.
|
|
204
|
+
Its receipt binds the raw request bytes and the complete projected documents;
|
|
205
|
+
semantic digests use UTF-8 JSON with object keys recursively sorted in
|
|
206
|
+
ECMAScript UTF-16 order, array order retained and JavaScript JSON primitive
|
|
207
|
+
serialization.
|
|
208
|
+
|
|
209
|
+
Native-generated fields use typed markers only in the exact selected rows:
|
|
210
|
+
`{"$generated":"claude-utc-timestamp","field":"<path>"}` requires a valid generated
|
|
211
|
+
UTC timestamp at that field. For a native update that may preserve or refresh
|
|
212
|
+
`lastUpdated`, `{"$allowed":[<exact prior timestamp>,<generated marker>]}` permits
|
|
213
|
+
only those two values. Existing `installedAt` remains exact; a fresh install's
|
|
214
|
+
`installedAt` is generated. No other row fields accept markers.
|
|
215
|
+
|
|
216
|
+
This is a read-only validator. It does not establish that caller-supplied
|
|
217
|
+
`native.home`, config/plugin roots, executable identity or Skills `dataDir` are
|
|
218
|
+
the installed consumers. Harnesses must resolve them through the installed
|
|
219
|
+
package-owned consumers and compare them before trusting the receipt. It must
|
|
220
|
+
also retain its existing review record and bind it to the exact candidate:
|
|
221
|
+
the caller's no-skill-injection assessment is not a semantic hook review, and
|
|
222
|
+
structural refusal checks do not prove hook behavior. Recheck all preimages and
|
|
223
|
+
candidate closure immediately before the first native mutation. The validator
|
|
224
|
+
does not claim native install atomicity or crash recovery.
|
|
225
|
+
|
|
226
|
+
The optional release manifest witness binds the complete supplied release.json
|
|
227
|
+
file bytes, path and SHA-256 in the request/receipt. Harnesses remains
|
|
228
|
+
responsible for verifying that its release options correspond to every
|
|
229
|
+
selected `optionsPatch`; the public Skills validator deliberately does not
|
|
230
|
+
interpret private release schemas.
|
|
231
|
+
Installed consumers can use the public `captureClaudeProspectiveCandidateClosure`
|
|
232
|
+
and `hashClaudePluginManifest` exports to prepare the exact digests without
|
|
233
|
+
copying the package's hashing algorithms.
|
|
234
|
+
|
|
176
235
|
## Reviewed plugin-hook attestation scope
|
|
177
236
|
|
|
178
237
|
A reviewed discovery input carries `pluginHooks: "reviewed-no-skill-injection"`.
|