@hasna/skills 0.10.51 → 0.10.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -0
- package/bin/index.js +1795 -1346
- package/bin/mcp.js +702 -457
- package/bin/migrate.js +1 -1
- package/bin/server.js +11 -4
- package/bin/worker.js +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1023 -679
- package/dist/lib/agent-discovery.d.ts +37 -1
- package/dist/lib/agent-integration.d.ts +4 -1
- package/dist/lib/claude-marketplace-entry-witness.d.ts +26 -0
- package/dist/lib/claude-settings-witness.d.ts +25 -1
- package/dist/lib/codex-hook-trust-files.d.ts +17 -0
- package/dist/lib/selection-cache.d.ts +2 -2
- package/dist/lib/session-reconciliation.d.ts +9 -0
- package/dist/sdk/index.js +990 -649
- package/docs/plugin-admission.md +185 -0
- package/package.json +1 -1
|
@@ -7,10 +7,12 @@ export { captureDiscoveryDirectories, type DiscoveryDirectory } from "./agent-di
|
|
|
7
7
|
export interface DiscoverySource {
|
|
8
8
|
path: string;
|
|
9
9
|
sha256: string | null;
|
|
10
|
-
hashMode?: "bytes" | "path-bytes" | "claude-plugin-manifest-v1" | "claude-plugin-registry" | "claude-marketplace-registry" | "claude-settings-v1" | "claude-settings-v2" | "claude-settings-v3" | "claude-settings-v4" | "claude-marketplace-registry-v2" | "codex-settings-v1" | "codex-settings-v2" | "codex-settings-v3" | "codex-settings-v4" | "sumi-settings-v1";
|
|
10
|
+
hashMode?: "bytes" | "path-bytes" | "claude-plugin-manifest-v1" | "claude-plugin-registry" | "claude-marketplace-registry" | "claude-settings-v1" | "claude-settings-v2" | "claude-settings-v3" | "claude-settings-v4" | "claude-marketplace-registry-v2" | "codex-settings-v1" | "codex-settings-v2" | "codex-settings-v3" | "codex-settings-v4" | "sumi-settings-v1" | "claude-marketplace-entry-v1";
|
|
11
11
|
managedPlugins?: ManagedPluginRegistrationWitness[];
|
|
12
12
|
format?: "json" | "toml" | "yaml";
|
|
13
13
|
fields?: string[];
|
|
14
|
+
marketplace?: string;
|
|
15
|
+
plugin?: string;
|
|
14
16
|
}
|
|
15
17
|
export interface AgentDiscoveryBinding {
|
|
16
18
|
agent: IntegrationAgent;
|
|
@@ -34,6 +36,27 @@ export interface AgentDiscoveryBinding {
|
|
|
34
36
|
directories?: DiscoveryDirectory[];
|
|
35
37
|
};
|
|
36
38
|
}
|
|
39
|
+
/** An environment gap, not drift: the runtime a review saw cannot be resolved
|
|
40
|
+
* from this process, so its discovery cannot be re-derived. Callers keep it
|
|
41
|
+
* blocking and must not report it as NATIVE_SKILL_DRIFT. */
|
|
42
|
+
export declare const DISCOVERY_ROOT_UNRESOLVED = "DISCOVERY_ROOT_UNRESOLVED";
|
|
43
|
+
export declare function discoveryRootUnresolved(agent: IntegrationAgent, command: string, detail: string): Error;
|
|
44
|
+
export declare function isDiscoveryRootUnresolved(error: unknown): error is Error;
|
|
45
|
+
/** The runtime executable a discovery review resolved through PATH, with the
|
|
46
|
+
* realpath its launcher led to. The policy stores it beside the binding
|
|
47
|
+
* (bridge.discoveryExecutables), not inside it, so a consumer that compares
|
|
48
|
+
* stored bindings keeps the shape it already knows. */
|
|
49
|
+
export interface DiscoveryExecutable {
|
|
50
|
+
command: string;
|
|
51
|
+
path: string;
|
|
52
|
+
target: string;
|
|
53
|
+
}
|
|
54
|
+
/** Resolve the agent's runtime command through this process's PATH: the
|
|
55
|
+
* executable this process would actually run. */
|
|
56
|
+
export declare function discoveryExecutable(agent: IntegrationAgent): DiscoveryExecutable | null;
|
|
57
|
+
/** Check a recorded executable by its exact path, ignoring PATH. Null when the
|
|
58
|
+
* path no longer resolves (missing, dangling, ENOTDIR, EACCES). */
|
|
59
|
+
export declare function recordedDiscoveryExecutable(agent: IntegrationAgent, recorded: DiscoveryExecutable): DiscoveryExecutable | null;
|
|
37
60
|
export interface ReviewedDiscoveryInputs {
|
|
38
61
|
version: 1;
|
|
39
62
|
agents: Array<{
|
|
@@ -63,10 +86,23 @@ export declare function assertProjectDiscovery(agent: IntegrationAgent, director
|
|
|
63
86
|
/** Resolve configured plugin discovery without starting an agent or loading a plugin.
|
|
64
87
|
* Unknown runtime registrations require explicit reviewed inputs, never a cache guess. */
|
|
65
88
|
export declare function agentDiscoveryConfigPath(home: string, agent: IntegrationAgent): string;
|
|
89
|
+
/** Re-derive an automatic binding and compare it with the stored one. A
|
|
90
|
+
* mismatch is drift, except when the only difference is a runtime this process
|
|
91
|
+
* cannot resolve: then it is DISCOVERY_ROOT_UNRESOLVED, which stays blocking. */
|
|
92
|
+
export declare function verifyAutomaticDiscoveryClosure(binding: AgentDiscoveryBinding, options: {
|
|
93
|
+
home: string;
|
|
94
|
+
canonical: (path: string) => string;
|
|
95
|
+
change: string;
|
|
96
|
+
executable?: DiscoveryExecutable;
|
|
97
|
+
}): void;
|
|
98
|
+
/** `executable` is the agent's runtime: omitted, it is resolved through PATH;
|
|
99
|
+
* a value (or null for none) is used as given, so verification never depends
|
|
100
|
+
* on the caller's PATH. */
|
|
66
101
|
export declare function resolveAgentDiscovery(options: {
|
|
67
102
|
home: string;
|
|
68
103
|
agent: IntegrationAgent;
|
|
69
104
|
reviewed?: ReviewedDiscoveryInputs;
|
|
70
105
|
retainedReview?: AgentDiscoveryBinding;
|
|
71
106
|
canonical?: (path: string) => string;
|
|
107
|
+
executable?: DiscoveryExecutable | null;
|
|
72
108
|
}): AgentDiscoveryBinding;
|
|
@@ -2,7 +2,7 @@ import { type CodexCorpusWriteOptions } from "./codex-corpus-write.js";
|
|
|
2
2
|
import { type ReviewedCodexSkillDenial } from "./codex-plugin-skill-controls.js";
|
|
3
3
|
import { type CodexNativeHookEnvelope, type ProcessInspector, type NativePolicyHelperRunner } from "./codex-native-skill-policy.js";
|
|
4
4
|
import { type CodexNativeSkillCatalog } from "./codex-native-skill-catalog.js";
|
|
5
|
-
import { type AgentDiscoveryBinding, type ReviewedDiscoveryInputs } from "./agent-discovery.js";
|
|
5
|
+
import { type DiscoveryExecutable, type AgentDiscoveryBinding, type ReviewedDiscoveryInputs } from "./agent-discovery.js";
|
|
6
6
|
import { type IntegrationAgent } from "./agent-adapters.js";
|
|
7
7
|
import type { CodexHookDiscoveryRecovery } from "./codex-hook-discovery-recovery.js";
|
|
8
8
|
import { type ClaudeCoordinatedHookEvent } from "./claude-settings-witness.js";
|
|
@@ -85,6 +85,7 @@ export interface AgentIntegrationPlan {
|
|
|
85
85
|
};
|
|
86
86
|
discoveryBefore?: AgentDiscoveryBinding[];
|
|
87
87
|
discoveryAfter?: AgentDiscoveryBinding[];
|
|
88
|
+
discoveryExecutables?: Record<string, DiscoveryExecutable>;
|
|
88
89
|
rootAliases?: AgentRootAlias[];
|
|
89
90
|
managedAgentChecks?: {
|
|
90
91
|
home: string;
|
|
@@ -96,6 +97,8 @@ export interface AgentIntegrationPlan {
|
|
|
96
97
|
agents: IntegrationAgent[];
|
|
97
98
|
};
|
|
98
99
|
}
|
|
100
|
+
/** Normalize only the verified OS prefix, never hide user-controlled links. */
|
|
101
|
+
export declare function canonicalSystemPath(path: string): string;
|
|
99
102
|
/** Parse the reviewed exact-target binding used by native migration. Paths are
|
|
100
103
|
* deliberately project-relative so a manifest cannot silently select another
|
|
101
104
|
* checkout when a project root changes. */
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type ClaudeSettingsWitnessBudget } from "./claude-settings-witness.js";
|
|
2
|
+
export declare const CLAUDE_MARKETPLACE_ENTRY_HASH_MODE: "claude-marketplace-entry-v1";
|
|
3
|
+
export interface ClaudeMarketplaceEntrySelector {
|
|
4
|
+
marketplace: string;
|
|
5
|
+
plugin: string;
|
|
6
|
+
}
|
|
7
|
+
export interface ClaudeMarketplaceEntryWitness {
|
|
8
|
+
path: string;
|
|
9
|
+
hashMode: typeof CLAUDE_MARKETPLACE_ENTRY_HASH_MODE;
|
|
10
|
+
marketplace: string;
|
|
11
|
+
plugin: string;
|
|
12
|
+
sha256: string;
|
|
13
|
+
}
|
|
14
|
+
/** Selector and path checks shared by capture, discovery binding and the stored policy bounds. */
|
|
15
|
+
export declare function claudeMarketplaceEntrySourceValid(source: {
|
|
16
|
+
path?: unknown;
|
|
17
|
+
marketplace?: unknown;
|
|
18
|
+
plugin?: unknown;
|
|
19
|
+
}): boolean;
|
|
20
|
+
/** Digest the reviewed entry from marketplace.json text. Refuses rather than
|
|
21
|
+
* guessing whenever the selected entry or its resolution context is ambiguous. */
|
|
22
|
+
export declare function hashClaudeMarketplaceEntry(text: string, selector: ClaudeMarketplaceEntrySelector): string;
|
|
23
|
+
/** Capture an explicit review witness from a stable regular marketplace.json.
|
|
24
|
+
* Symlinked ancestors, special files, oversized files and concurrent
|
|
25
|
+
* replacement refuse; capture writes nothing. */
|
|
26
|
+
export declare function captureClaudeMarketplaceEntry(path: string, marketplace: string, plugin: string, budget?: ClaudeSettingsWitnessBudget): ClaudeMarketplaceEntryWitness;
|
|
@@ -9,7 +9,30 @@ export declare const CLAUDE_SETTINGS_WITNESS_LIMITS: Readonly<{
|
|
|
9
9
|
export interface ClaudeSettingsWitnessBudget {
|
|
10
10
|
remaining: number;
|
|
11
11
|
}
|
|
12
|
-
export declare function readNativeSettingsWitnessFile(path: string, budget: ClaudeSettingsWitnessBudget, filename?: "settings.json" | "config.toml" | "sumi.json"): string;
|
|
12
|
+
export declare function readNativeSettingsWitnessFile(path: string, budget: ClaudeSettingsWitnessBudget, filename?: "settings.json" | "config.toml" | "sumi.json" | "marketplace.json"): string;
|
|
13
|
+
export type NativeJsonObject = ObjectValue;
|
|
14
|
+
export type NativeJsonValue = Value;
|
|
15
|
+
type ObjectValue = {
|
|
16
|
+
kind: "object";
|
|
17
|
+
entries: Array<[string, Value]>;
|
|
18
|
+
};
|
|
19
|
+
type Value = ObjectValue | {
|
|
20
|
+
kind: "array";
|
|
21
|
+
items: Value[];
|
|
22
|
+
} | {
|
|
23
|
+
kind: "string";
|
|
24
|
+
value: string;
|
|
25
|
+
} | {
|
|
26
|
+
kind: "number";
|
|
27
|
+
value: string;
|
|
28
|
+
} | {
|
|
29
|
+
kind: "literal";
|
|
30
|
+
value: "true" | "false" | "null";
|
|
31
|
+
};
|
|
32
|
+
/** The same strict syntax tree for other bounded native JSON witnesses:
|
|
33
|
+
* duplicate decoded keys refuse, numbers keep their spelling, and the byte,
|
|
34
|
+
* depth, node, string and top-level field limits above apply unchanged. */
|
|
35
|
+
export declare function parseNativeJsonObject(text: string): NativeJsonObject;
|
|
13
36
|
export declare const CLAUDE_BUILTIN_THEMES: readonly ["auto", "dark", "light", "dark-daltonized", "light-daltonized", "dark-ansi", "light-ansi"];
|
|
14
37
|
/** Cooperating installers may replace only their explicitly selected event. Compare the strict syntax
|
|
15
38
|
* trees, not JSON.parse values or the preference-tolerant witness digest: all
|
|
@@ -76,3 +99,4 @@ export declare function hashNativeJsonControls(text: string, excludedMetadata?:
|
|
|
76
99
|
* tree. Unknown fields, permissions, routing and executable inputs stay bound.
|
|
77
100
|
* Only schema/display strings and two presentation-only booleans may vary. */
|
|
78
101
|
export declare function hashSumiNativeJsonControls(text: string): string;
|
|
102
|
+
export {};
|
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
import { type BigIntStats } from "node:fs";
|
|
2
2
|
export declare function need(value: unknown, code: string): asserts value;
|
|
3
|
+
/** The owner of a directory can rename or replace its entries whatever its
|
|
4
|
+
* mode, so an ancestor must belong to root or the current user. There is no
|
|
5
|
+
* allowlist: a prefix such as /opt/homebrew passes only when one of them owns it. */
|
|
6
|
+
export declare function trustedAncestorOwner(uid: number | bigint): boolean;
|
|
7
|
+
/** Every ancestor directory of `file`: a real directory, owned by root or the
|
|
8
|
+
* current user, and writable by neither group nor others unless it is a
|
|
9
|
+
* root-owned sticky directory. Throws CODEX_HOOK_TRUST_UNSAFE_PARENT. */
|
|
10
|
+
export declare function safeParents(file: string): void;
|
|
11
|
+
/** The path a symbolic link names, when that text cannot pass through another
|
|
12
|
+
* link: an absolute text of plain names, or a relative text that leaves the
|
|
13
|
+
* link's own directory only through leading `..` components and then names
|
|
14
|
+
* plain entries. Undefined for any other text. The caller has verified the
|
|
15
|
+
* link's directory chain as real directories, so the leading `..` steps stay
|
|
16
|
+
* on verified directories, and requires the result to equal realpath, which
|
|
17
|
+
* proves that no named component is itself a link: the command leaf is then
|
|
18
|
+
* the only alias in the chain. */
|
|
19
|
+
export declare function directAliasTarget(link: string): string | undefined;
|
|
3
20
|
export declare function snapshot(file: string, privateFile?: boolean, options?: {
|
|
4
21
|
readOnlyPackage?: true;
|
|
5
22
|
}): {
|
|
@@ -2,7 +2,7 @@ import { type SkillBundleEntry } from "./skill-bundle.js";
|
|
|
2
2
|
import type { ResolvedSkillProfile, ResolvedSkillSelection } from "../types/skill-selection.js";
|
|
3
3
|
export declare class SkillSelectionError extends Error {
|
|
4
4
|
readonly code: string;
|
|
5
|
-
constructor(code: string, message: string);
|
|
5
|
+
constructor(code: string, message: string, options?: ErrorOptions);
|
|
6
6
|
}
|
|
7
7
|
export interface SelectionCacheOptions {
|
|
8
8
|
cacheDir?: string;
|
|
@@ -44,7 +44,7 @@ export declare function validateSelection(selection: ResolvedSkillSelection): vo
|
|
|
44
44
|
export declare function validateResolvedProfile(profile: ResolvedSkillProfile, authority?: string): void;
|
|
45
45
|
export declare function selectionBundlePath(selection: ResolvedSkillSelection, options?: SelectionCacheOptions): string;
|
|
46
46
|
export declare function writeSelectionJson(path: string, value: unknown): void;
|
|
47
|
-
export declare function readSelectionJson<T>(path: string): T | null;
|
|
47
|
+
export declare function readSelectionJson<T>(path: string, maximumBytes?: number): T | null;
|
|
48
48
|
export declare function readCachedSelection(selection: ResolvedSkillSelection, options?: SelectionCacheOptions): Promise<SkillBundleEntry[] | null>;
|
|
49
49
|
/** Verify an authenticated exact-version response without changing any cache or receipt. */
|
|
50
50
|
export declare function verifySelectionBundleResponse(selection: ResolvedSkillSelection, response: Response | null, signal?: AbortSignal, deadline?: number): Promise<{
|
|
@@ -32,6 +32,15 @@ export declare function inspectSkillSession(sessionId: string, options?: Selecti
|
|
|
32
32
|
};
|
|
33
33
|
/** Fits inside the managed context child's 6.5-second ceiling, including CLI work. */
|
|
34
34
|
export declare const SESSION_RENEWAL_TIMEOUT_MS = 4000;
|
|
35
|
+
/**
|
|
36
|
+
* A definitive automatic renewal refusal is remembered briefly so the managed
|
|
37
|
+
* hook does not resolve the whole profile again on every prompt. The record
|
|
38
|
+
* only ever repeats that refusal: it never authorizes, renews or writes a pin.
|
|
39
|
+
* It binds the exact receipt bytes, profile, authority, workspace and the
|
|
40
|
+
* locally synced profile revision, and lapses after a fixed window that the
|
|
41
|
+
* file cannot extend. Anything unexpected is ignored and the authority is asked.
|
|
42
|
+
*/
|
|
43
|
+
export declare const SESSION_RENEWAL_REFUSAL_TTL_MS: number;
|
|
35
44
|
/**
|
|
36
45
|
* Renew authorization for the complete immutable pin; never manufacture a
|
|
37
46
|
* profile combining historical loaded versions with current unloaded versions.
|