@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.
@@ -1,6 +1,7 @@
1
1
  import type { IntegrationAgent } from "./agent-adapters.js";
2
2
  import { type DiscoveryDirectory } from "./agent-discovery-directories.js";
3
3
  import { type CodexReviewedHookSource } from "./codex-hook-mcp-dependencies.js";
4
+ import { CLAUDE_ORPHAN_MARKER_MODE } from "./claude-plugin-cache-marker.js";
4
5
  import { type NativeDiscoveryWitnessTolerance } from "./native-discovery-witness-change.js";
5
6
  import { type ManagedPluginRegistrationWitness } from "./plugin-discovery.js";
6
7
  import { type CodexHookDiscoveryRecovery } from "./codex-hook-discovery-recovery.js";
@@ -95,6 +96,11 @@ export declare function projectNativeDiscoveryFields(text: string, format: "json
95
96
  /** Called only after the owning planner validated discovery and capabilities.
96
97
  * New roots must already be body-free; absent roots need the prior typed proof. */
97
98
  export declare function captureRetiredCodexDiscovery(binding: AgentDiscoveryBinding, controls: CodexPluginSkillControl[], rules: unknown): AgentDiscoveryBinding;
99
+ /** The witness class that may keep its reviewed digest beneath a positively
100
+ * verified absent root: a full byte witness, the installer's full manifest
101
+ * projection or a present version-root orphan marker. Null for every other
102
+ * source, which must stay current. */
103
+ export type RetainedAbsentWitness = "bytes" | "claude-plugin-manifest-v1" | typeof CLAUDE_ORPHAN_MARKER_MODE;
98
104
  /** Only native capability locations covered by the complete typed cache census
99
105
  * qualify. Historical sources remain stored; arbitrary missing files do not. */
100
106
  export declare function codexSemanticCacheSourceRole(source: DiscoverySource, cacheRoot: string, parents: readonly string[], hookParents?: readonly string[]): boolean;
@@ -109,6 +115,25 @@ export declare function verifyAgentDiscovery(binding: AgentDiscoveryBinding, cod
109
115
  alias: string;
110
116
  target: string;
111
117
  }[], witnessTolerance?: NativeDiscoveryWitnessTolerance): void;
118
+ /** One stored Claude discovery source as an installer sees it. */
119
+ export type ClaudeDiscoverySourceVerdict = {
120
+ status: "current";
121
+ } | {
122
+ status: "retained-absent";
123
+ root: string;
124
+ witness: RetainedAbsentWitness;
125
+ } | {
126
+ status: "drift";
127
+ reason: "MISSING" | "APPEARED" | "CHANGED" | "MARKER_INVALID" | "REFUSED";
128
+ };
129
+ /** Read-only, per-source report on a stored Claude discovery binding, in
130
+ * stored order. A source is retained only through the same absent retired
131
+ * version rule and predicate verifyAgentDiscovery applies; a refused rule
132
+ * retains nothing. Every other source is checked by its own witness, exactly
133
+ * as verification checks it (a typed orphan marker by the marker predicate).
134
+ * This report never accepts a binding by itself: a caller must also require
135
+ * verifyAgentDiscovery to accept the same binding. */
136
+ export declare function classifyClaudeDiscoverySources(binding: AgentDiscoveryBinding): ClaudeDiscoverySourceVerdict[];
112
137
  export declare function rebindAgentDiscovery(binding: AgentDiscoveryBinding, changes: Map<string, string>): AgentDiscoveryBinding;
113
138
  /** Explicit streaming integrity witness. Never read an executable as text or execute it. */
114
139
  export declare function captureDiscoveryExecutableSources(paths: string[]): DiscoverySource[];
@@ -116,6 +141,11 @@ export declare function captureDiscoveryExecutableSources(paths: string[]): Disc
116
141
  export declare function captureDiscoveryByteSources(paths: string[]): DiscoverySource[];
117
142
  /** Capture executable/source path identity, including links and absent targets. */
118
143
  export declare function captureDiscoveryPathSources(paths: string[]): DiscoverySource[];
144
+ /** Top-level keys whose presence, at any value, makes a project Claude settings
145
+ * file a higher-precedence discovery source that needs review. Claude 2.1.300
146
+ * rewrites `additionalMarketplaces` into `extraKnownMarketplaces` on every
147
+ * settings read, including local settings, so the alias counts as well. */
148
+ export declare const CLAUDE_PROJECT_DISCOVERY_KEYS: readonly ["enabledPlugins", "extraKnownMarketplaces", "additionalMarketplaces", "skillOverrides"];
119
149
  /** Project settings can introduce a higher-precedence discovery source. Until
120
150
  * its native merge format is supported, refuse that layer rather than certify
121
151
  * the home-only inventory. Ordinary unrelated project settings remain usable. */
@@ -143,6 +173,12 @@ export declare function verifyAutomaticDiscoveryClosure(binding: AgentDiscoveryB
143
173
  * the stored digest. Witness modes
144
174
  * without a replacement digest (V6, artifacts, managed registries) stay strict. */
145
175
  export declare function codexVendorConfigChangeOnly(source: DiscoverySource, cache: string): boolean;
176
+ /** Whether replacing `path` with `text` leaves every recorded witness of it
177
+ * satisfied, judged by each source's own digest mode without touching the file,
178
+ * with the same screen-reader receipt tolerance typed V1-V5 verification applies.
179
+ * Fails closed: a review artifact, managed-plugin or hook-source witness, a
180
+ * semantic cache binding of the file, or an unsupported mode counts as changed. */
181
+ export declare function discoveryTextKeepsWitness(binding: Pick<AgentDiscoveryBinding, "sources" | "codexSemanticCache">, path: string, text: string): boolean;
146
182
  /** `executable` is the agent's runtime: omitted, it is resolved through PATH;
147
183
  * a value (or null for none) is used as given, so verification never depends
148
184
  * on the caller's PATH. */
@@ -0,0 +1,65 @@
1
+ import { type RetainedAbsentWitness } from "./agent-discovery.js";
2
+ export declare const CLAUDE_DISCOVERY_BINDING_VERIFICATION_SCHEMA: "skills.claude-discovery-binding-verification/v1";
3
+ /** The rule that lets a stored witness stay unverified because Claude removed
4
+ * its whole retired plugin-cache version while unchanged settings and
5
+ * registrations select a current sibling version. */
6
+ export declare const ABSENT_RETIRED_CLAUDE_VERSION_RULE: "absent-retired-claude-version";
7
+ export type ClaudeDiscoveryBindingRefusalCode = "POLICY_PATH_MISMATCH" | "POLICY_UNAVAILABLE" | "POLICY_UNREADABLE" | "BINDING_UNAVAILABLE" | "BINDING_INVALID" | "POLICY_CHANGED";
8
+ /** A request, policy or stored-binding read/parse failure: no verdict. */
9
+ export declare class ClaudeDiscoveryBindingRefusal extends Error {
10
+ readonly code: ClaudeDiscoveryBindingRefusalCode;
11
+ constructor(code: ClaudeDiscoveryBindingRefusalCode);
12
+ }
13
+ export type ClaudeBindingSourceFailure = "MISSING" | "APPEARED" | "CHANGED" | "MARKER_INVALID" | "REFUSED";
14
+ export type ClaudeBindingDirectoryFailure = "MEMBERSHIP_CHANGED" | "REFUSED";
15
+ export interface ClaudeBindingSourceReport {
16
+ index: number;
17
+ path: string;
18
+ hashMode: string | null;
19
+ format: string | null;
20
+ sha256: string | null;
21
+ status: "current" | "retained-absent" | "drift";
22
+ retention?: {
23
+ rule: typeof ABSENT_RETIRED_CLAUDE_VERSION_RULE;
24
+ root: string;
25
+ witness: RetainedAbsentWitness;
26
+ };
27
+ reason?: ClaudeBindingSourceFailure;
28
+ }
29
+ export interface ClaudeBindingDirectoryReport {
30
+ index: number;
31
+ path: string;
32
+ status: "current" | "drift";
33
+ reason?: ClaudeBindingDirectoryFailure;
34
+ }
35
+ export type ClaudeBindingFailure = {
36
+ kind: "source";
37
+ index: number;
38
+ path: string;
39
+ reason: ClaudeBindingSourceFailure;
40
+ } | {
41
+ kind: "directory";
42
+ index: number;
43
+ path: string;
44
+ reason: ClaudeBindingDirectoryFailure;
45
+ } | {
46
+ kind: "binding";
47
+ reason: "DISCOVERY_REFUSED";
48
+ };
49
+ export interface ClaudeDiscoveryBindingVerification {
50
+ schema: typeof CLAUDE_DISCOVERY_BINDING_VERIFICATION_SCHEMA;
51
+ ok: boolean;
52
+ policySha256: string;
53
+ discoverySha256: string;
54
+ agent: "claude";
55
+ method: "reviewed" | "automatic";
56
+ rootCount: number;
57
+ sources: ClaudeBindingSourceReport[];
58
+ directories: ClaudeBindingDirectoryReport[];
59
+ failures: ClaudeBindingFailure[];
60
+ }
61
+ /** Verify the stored `bridge.discovery.claude` binding of the package-owned
62
+ * Skills policy. `ok` is true only when the hook's own discovery verification
63
+ * accepts the binding and every source is current or retained under the
64
+ * absent retired version rule, and every directory witness is current. */
65
+ export declare function verifyClaudeInstallerDiscoveryBinding(policyPath: string): ClaudeDiscoveryBindingVerification;
@@ -0,0 +1,11 @@
1
+ /** Whether Codex can load a skill below `path`, a `node_modules` directory
2
+ * `depth` levels below its plugin cache. A marketplace, plugin or version
3
+ * directory is an identity, so one named `node_modules` is always walked.
4
+ * Inside a version, the directory is walked when it lies in, or leads to, a
5
+ * manifest-declared skills path or the default `skills` root. Codex replaces
6
+ * the default with a declared path; Skills keeps walking it, as it walks every
7
+ * other visible directory in the cache. A manifest that cannot be read exactly
8
+ * (a link or special file, oversized, invalid UTF-8 or JSON, duplicate keys, an
9
+ * unsupported skills shape or an escaping path) walks it too, so an unreadable
10
+ * declaration never hides a loaded skill. */
11
+ export declare function codexPluginCacheSkillTree(path: string, depth: number): boolean;
@@ -1,5 +1,14 @@
1
1
  import { type ClaudeSettingsWitnessBudget } from "./claude-settings-witness.js";
2
2
  export declare function hashCodexSettingsReplacement(text: string, budget?: ClaudeSettingsWitnessBudget): string;
3
+ /** The parsed document and numeric spellings a V1 digest binds, before the
4
+ * documented inference fields are removed. Callers that edit the structure
5
+ * (codexSettingsToleratesScreenReaderReceipt) finish each edited copy separately. */
6
+ export declare function prepareCodexSettingsV1(text: string): {
7
+ config: Record<string, any>;
8
+ tokens: string[];
9
+ };
10
+ /** The V1 digest of a prepared structure. Mutates `config`. */
11
+ export declare function finishCodexSettingsV1(config: Record<string, any>, tokens: string[]): string;
3
12
  export declare function captureCodexSettings(path: string, budget?: ClaudeSettingsWitnessBudget): {
4
13
  path: string;
5
14
  hashMode: "codex-settings-v1";
@@ -5,6 +5,24 @@ import { type ClaudeSettingsWitnessBudget } from "./claude-settings-witness.js";
5
5
  * `codex-settings-v2` witness binds strictly more of the same file, so it
6
6
  * supersedes this projection instead of coexisting with it. */
7
7
  export declare const CODEX_DISCOVERY_PROJECTION_FIELDS: readonly ["plugins", "marketplaces", "skills"];
8
+ /** Typed modes whose digests bind the receipt. */
9
+ export type CodexReceiptSettingsMode = "codex-settings-v1" | "codex-settings-v2" | "codex-settings-v3" | "codex-settings-v4" | "codex-settings-v5";
10
+ /** How a current document relates to a typed V1-V5 witness's reviewed digest.
11
+ * `screen-reader-receipt` is the only tolerated difference. */
12
+ export type CodexSettingsWitnessMatch = "exact" | "screen-reader-receipt";
13
+ /** True when `text` differs from the document a typed V1-V5 witness reviewed
14
+ * only by the boolean screen-reader receipt, proven by reproducing `expected`
15
+ * under the witness's own unchanged digest from the current document with the
16
+ * receipt edited back. The text-bound projections (local MCP rows, V4 counts,
17
+ * numeric spelling) run once on the current text; a receipt line holds no
18
+ * numeric token. Digest values never change and nothing is recorded. Any other
19
+ * TUI key, a non-boolean value and every other difference stay bound.
20
+ * Fail-closed: errors return false. */
21
+ export declare function codexSettingsToleratesScreenReaderReceipt(text: string, hashMode: CodexReceiptSettingsMode, expected: string): boolean;
22
+ /** Read a typed V1-V5 settings witness file once and classify it against the
23
+ * reviewed digest: `exact`, `screen-reader-receipt` (the only tolerated
24
+ * difference), or null (drift). */
25
+ export declare function codexSettingsWitnessMatch(path: string, hashMode: CodexReceiptSettingsMode, expected: string, budget?: ClaudeSettingsWitnessBudget): CodexSettingsWitnessMatch | null;
8
26
  export declare function hashCodexSettingsReplacementV2(text: string, budget?: ClaudeSettingsWitnessBudget): string;
9
27
  export declare function captureCodexSettingsV2(path: string, budget?: ClaudeSettingsWitnessBudget): {
10
28
  path: string;
@@ -52,6 +52,16 @@ export declare function ensurePortableSkillFiles(skillPath: string, manifest: Po
52
52
  * locally, so `port` must never fabricate executable stubs (package.json, bin,
53
53
  * src/index.ts, tsconfig.json, AGENTS.md). Apart from aligning declared names
54
54
  * after an import rename, it preserves the copied prose and metadata.
55
+ *
56
+ * "Metadata" includes what the candidate declared in skill.json. An instruction
57
+ * skill may legitimately bundle a helper command (and inputs for it) — the
58
+ * validator permits a package.json bin on an instruction skill for exactly that
59
+ * reason — so declared `commands` and `inputs` are carried through verbatim and
60
+ * only an absent declaration becomes an explicit empty array. Forcing them to []
61
+ * here silently erased the declaration on disk: writeSkillJsonWithHash() merges
62
+ * the rebuilt manifest over the copied candidate skill.json, so the candidate's
63
+ * own array was destroyed and the manifest was left self-inconsistent
64
+ * (runtime.entrypoint still naming an entry no command declared).
55
65
  */
56
66
  export declare function ensureInstructionSkillFiles(skillPath: string, manifest: PortableSkillManifest): PortableSkillManifest;
57
67
  export declare function copySkillDirectory(source: string, destination: string): void;
@@ -13,6 +13,50 @@ export interface ResolvedSelectedRun {
13
13
  cacheDir: string;
14
14
  }
15
15
  export declare function resolveSelectedRun(spec: string, profileId: string, options?: SelectionResolverOptions): Promise<ResolvedSelectedRun>;
16
+ /**
17
+ * The operation an instruction skill declares, if it declares one.
18
+ *
19
+ * An instruction skill is prose-first: agents follow SKILL.md, and `skills run`
20
+ * refuses it. Its manifest may still declare the one operation it ships — the
21
+ * first `commands` entry, naming the helper — together with an explicit runtime
22
+ * contract in `runtime` (`runtime` plus its `version`/`timeout` policy). Such a
23
+ * skill is runnable through that declared operation, and only through it: the
24
+ * executed file is exactly the entry the selected command declares, it must be a
25
+ * regular file in the selected bundle, and a `runtime.entrypoint` that disagrees
26
+ * with it is an inconsistent declaration that refuses (see
27
+ * {@link instructionEntrypointMismatch}) rather than quietly running the other
28
+ * file. An instruction skill that declares no operation — no command, a
29
+ * non-string or empty entry, or no runtime contract — keeps the prose-only
30
+ * refusal (`skills load`, never `skills run`), so an instruction bundle is never
31
+ * mistaken for a runnable stub.
32
+ */
33
+ export declare function declaredOperation(manifest: Record<string, any>): {
34
+ entry: string;
35
+ } | null;
36
+ /**
37
+ * The entry the instruction skill's declared command names, when it names one.
38
+ * The first `commands` entry is the operation: nothing else in the manifest
39
+ * selects what an instruction skill runs.
40
+ */
41
+ export declare function instructionCommandEntry(manifest: Record<string, any>): string | null;
42
+ /**
43
+ * A declared `runtime.entrypoint` that disagrees with the declared command entry,
44
+ * for an instruction skill. The command entry is the authority, so a disagreement
45
+ * is an inconsistent declaration: it refuses, and the disagreeing file never runs.
46
+ */
47
+ export declare function instructionEntrypointMismatch(manifest: Record<string, any>): string | null;
48
+ /**
49
+ * Why an instruction skill cannot run locally, if it cannot. `isBundledFile` says
50
+ * whether a path is a regular file in the selected bundle, so a declared command
51
+ * entry that is not there is refused by name instead of being substituted. The
52
+ * CLI, the MCP tool and the local executor all ask this one function, so the
53
+ * reason and the code cannot drift between them. A runnable instruction skill
54
+ * (declared command, agreeing runtime, entry present in the bundle) returns null.
55
+ */
56
+ export declare function instructionRunRefusal(manifest: Record<string, any>, isBundledFile: (path: string) => boolean): {
57
+ code: string;
58
+ message: string;
59
+ } | null;
16
60
  export interface SelectedLocalRunOptions {
17
61
  args?: string[];
18
62
  input?: unknown;
@@ -54,6 +98,7 @@ export declare function executeSelectedLocal(selected: ResolvedSelectedRun, opti
54
98
  selection: ResolvedSkillSelection;
55
99
  target: "local";
56
100
  runtime: any;
101
+ entrypoint: string;
57
102
  inputDigest: string;
58
103
  runDirectory: string;
59
104
  }>;
@@ -0,0 +1,108 @@
1
+ import { type SelectionCacheOptions } from "./selection-cache.js";
2
+ /** Bounded so one receipt can never carry an unbounded drift list. */
3
+ export declare const PROVENANCE_DRIFT_LIMIT = 200;
4
+ export type SelectionProvenanceStatus = "current" | "behind" | "pinned" | "unverified";
5
+ export type SelectionProvenanceSource = "local-receipt" | "authority-receipt" | "session-receipt";
6
+ export type SelectionProvenanceReference = "authority" | "synced-snapshot" | "unavailable";
7
+ /**
8
+ * The fixed diagnostic vocabulary. A reader's exception text is never carried,
9
+ * only one of these codes, so a foreign body or a credential inside an error
10
+ * string cannot reach a receipt that may be shared.
11
+ */
12
+ export type SelectionProvenanceReason = "CURRENT_SCHEMA_MATCH" | "REVISION_BEHIND" | "PINNED_BY_DESIGN" | "IDENTITY_MISMATCH" | "INCOMPLETE_RECEIPT" | "DIFFERENT_PROFILE" | "NO_LOCAL_RECEIPT" | "NO_SESSION_NAMED" | "NO_SESSION_RECEIPT" | "NO_STATION_RECEIPT" | "READ_REFUSED" | "REFERENCE_FROM_AUTHORITY" | "REFERENCE_NOT_AUTHORITY" | "REFERENCE_UNAVAILABLE" | "NO_STATION_REPORTED";
13
+ export interface SelectionProvenanceVersion {
14
+ slug: string;
15
+ version: string;
16
+ bundleDigest?: string;
17
+ }
18
+ export interface SelectionProvenanceConsumer {
19
+ kind: "station" | "session";
20
+ source: SelectionProvenanceSource;
21
+ /** The local host for a local receipt, the requested station only for the authority receipt. */
22
+ id: string;
23
+ /** Whether `id` names the host running this command or a station named on the command line. */
24
+ idKind: "local-host" | "requested-station";
25
+ profileId?: string;
26
+ profileRevision?: string;
27
+ /** Compared, never assumed: a matching revision under another identity is not current. */
28
+ authority?: string;
29
+ workspaceId?: string;
30
+ observedAt?: string;
31
+ selectionCount?: number;
32
+ /** Only for a session: how many of its selections it really loaded. */
33
+ loadedCount?: number;
34
+ /** Only for a session: the exact versions it really loaded. */
35
+ consumed?: SelectionProvenanceVersion[];
36
+ status: SelectionProvenanceStatus;
37
+ reasonCode: SelectionProvenanceReason;
38
+ reason: string;
39
+ }
40
+ export interface SelectionProvenanceDrift {
41
+ source: SelectionProvenanceSource;
42
+ id: string;
43
+ slug: string;
44
+ selectedVersion: string;
45
+ observedVersion: string;
46
+ }
47
+ export interface SelectionProvenanceReceipt {
48
+ schemaVersion: 1;
49
+ readOnly: true;
50
+ selectionProfile: string;
51
+ selected: {
52
+ profileId: string;
53
+ profileRevision?: string;
54
+ selectionCount?: number;
55
+ authority?: string;
56
+ workspaceId?: string;
57
+ source: SelectionProvenanceReference;
58
+ observedAt?: string;
59
+ reasonCode: SelectionProvenanceReason;
60
+ reason: string;
61
+ };
62
+ consumers: SelectionProvenanceConsumer[];
63
+ drift: SelectionProvenanceDrift[];
64
+ driftTruncated: boolean;
65
+ /**
66
+ * What this receipt deliberately does not attest. Version and digest evidence
67
+ * for published payloads, native discovery, native locks and live consumer
68
+ * adoption are outside this command and stay unverified here rather than being
69
+ * implied by a clean-looking result.
70
+ */
71
+ notAttested: string[];
72
+ }
73
+ export interface SelectionProvenanceInput {
74
+ profileId: string;
75
+ /** The station whose authority-held sync receipt is read. */
76
+ stationId: string;
77
+ /** The host this command runs on. Never conflated with `stationId`. */
78
+ localStationId: string;
79
+ sessionId?: string;
80
+ /** Read the reference from the locally synced snapshot; never ask the authority. */
81
+ cached?: boolean;
82
+ }
83
+ /** A station receipt reduced to what this receipt compares. */
84
+ export interface ProvenanceStationObservation {
85
+ profileId: string;
86
+ profileRevision: string;
87
+ appliedAt: string;
88
+ workspaceId?: string;
89
+ selections: readonly {
90
+ slug: string;
91
+ version: string;
92
+ }[];
93
+ }
94
+ export interface SelectionProvenanceOptions extends SelectionCacheOptions {
95
+ /** Injected by the SDK and tests; defaults to the authenticated reads. */
96
+ readSelected?: (profileId: string) => Promise<{
97
+ profileId: string;
98
+ profileRevision: string;
99
+ authority?: string;
100
+ workspaceId?: string;
101
+ selections: readonly {
102
+ slug: string;
103
+ version: string;
104
+ }[];
105
+ }>;
106
+ readStation?: (stationId: string) => Promise<ProvenanceStationObservation>;
107
+ }
108
+ export declare function readSelectionProvenance(input: SelectionProvenanceInput, options?: SelectionProvenanceOptions): Promise<SelectionProvenanceReceipt>;
@@ -49,7 +49,7 @@ var __require = import.meta.require;
49
49
  // src/runtime-prerequisites.ts
50
50
  import { isAbsolute as isAbsolute7 } from "path";
51
51
  // package.json
52
- var version = "0.10.72";
52
+ var version = "0.10.74";
53
53
  var package_default = {
54
54
  name: "@hasna/skills",
55
55
  version,