@dsh-cc/plugin-loader 0.5.0
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/LICENSE +201 -0
- package/README.i18n.yaml +6 -0
- package/README.md +68 -0
- package/README.zh.md +68 -0
- package/lib/agents.d.ts +110 -0
- package/lib/agents.d.ts.map +1 -0
- package/lib/agents.js +140 -0
- package/lib/agents.js.map +1 -0
- package/lib/commands.d.ts +119 -0
- package/lib/commands.d.ts.map +1 -0
- package/lib/commands.js +159 -0
- package/lib/commands.js.map +1 -0
- package/lib/discovery.d.ts +49 -0
- package/lib/discovery.d.ts.map +1 -0
- package/lib/discovery.js +223 -0
- package/lib/discovery.js.map +1 -0
- package/lib/hooks.d.ts +44 -0
- package/lib/hooks.d.ts.map +1 -0
- package/lib/hooks.js +89 -0
- package/lib/hooks.js.map +1 -0
- package/lib/index.d.ts +81 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +92 -0
- package/lib/index.js.map +1 -0
- package/lib/manifest.d.ts +29 -0
- package/lib/manifest.d.ts.map +1 -0
- package/lib/manifest.js +120 -0
- package/lib/manifest.js.map +1 -0
- package/lib/mcp.d.ts +41 -0
- package/lib/mcp.d.ts.map +1 -0
- package/lib/mcp.js +64 -0
- package/lib/mcp.js.map +1 -0
- package/lib/resolve-manifest.d.ts +27 -0
- package/lib/resolve-manifest.d.ts.map +1 -0
- package/lib/resolve-manifest.js +85 -0
- package/lib/resolve-manifest.js.map +1 -0
- package/lib/seams.d.ts +59 -0
- package/lib/seams.d.ts.map +1 -0
- package/lib/seams.js +56 -0
- package/lib/seams.js.map +1 -0
- package/lib/settings.d.ts +41 -0
- package/lib/settings.d.ts.map +1 -0
- package/lib/settings.js +44 -0
- package/lib/settings.js.map +1 -0
- package/lib/skill-semantics.d.ts +92 -0
- package/lib/skill-semantics.d.ts.map +1 -0
- package/lib/skill-semantics.js +98 -0
- package/lib/skill-semantics.js.map +1 -0
- package/lib/skills.d.ts +49 -0
- package/lib/skills.d.ts.map +1 -0
- package/lib/skills.js +168 -0
- package/lib/skills.js.map +1 -0
- package/lib/types.d.ts +96 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +12 -0
- package/lib/types.js.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mount a Claude Code plugin's slash commands.
|
|
3
|
+
*
|
|
4
|
+
* Translates manifest `commands` entries (inline content or a source file) into
|
|
5
|
+
* typed command definitions registered on the commands seam. Each handler
|
|
6
|
+
* substitutes `$ARGUMENTS` and dispatches the rendered body as a user prompt
|
|
7
|
+
* on the invoking agent; registration is effect-scoped.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
import type { CcPluginManifest } from './types.ts';
|
|
12
|
+
import { ComponentTally } from './seams.ts';
|
|
13
|
+
/** The commands seam: accepts a typed slash-command definition. */
|
|
14
|
+
export interface CommandsSeam {
|
|
15
|
+
/**
|
|
16
|
+
* Register one command definition.
|
|
17
|
+
* @param definition - the command to register.
|
|
18
|
+
* @returns the exact disposer that removes the command.
|
|
19
|
+
*/
|
|
20
|
+
register(definition: CommandDefinition): () => void;
|
|
21
|
+
}
|
|
22
|
+
/** The minimal typed command definition this loader emits. */
|
|
23
|
+
export interface CommandDefinition {
|
|
24
|
+
/** The bare command name (harness registries reject colon names). */
|
|
25
|
+
readonly name: string;
|
|
26
|
+
/** Human-readable command description. */
|
|
27
|
+
readonly description: string;
|
|
28
|
+
/** Argument placeholder hint, surfaced to the user. */
|
|
29
|
+
readonly input?: {
|
|
30
|
+
hint: string;
|
|
31
|
+
};
|
|
32
|
+
/** Dispatches the rendered command body as a user prompt on the invoking agent. */
|
|
33
|
+
readonly handler: (invocation: CommandInvocationLike) => CommandResult | Promise<CommandResult>;
|
|
34
|
+
}
|
|
35
|
+
/** Result shape the loader's command handlers return. */
|
|
36
|
+
/**
|
|
37
|
+
* Minimal structural view of the upstream command invocation. Duck-typed on
|
|
38
|
+
* purpose: the loader never imports the commands package directly.
|
|
39
|
+
*/
|
|
40
|
+
export interface CommandInvocationLike {
|
|
41
|
+
/** The agent the command was executed against; the prompt injection target. */
|
|
42
|
+
readonly agent: {
|
|
43
|
+
followup(message: unknown): unknown;
|
|
44
|
+
};
|
|
45
|
+
/** Raw argument text following the command name (empty when none given). */
|
|
46
|
+
readonly rawInput: string;
|
|
47
|
+
}
|
|
48
|
+
export type CommandResult = {
|
|
49
|
+
readonly kind: 'success';
|
|
50
|
+
readonly text?: string;
|
|
51
|
+
} | {
|
|
52
|
+
readonly kind: 'error';
|
|
53
|
+
readonly text: string;
|
|
54
|
+
};
|
|
55
|
+
/** A plugin command's public summary, using the `plugin:command` display name. */
|
|
56
|
+
export interface CcPluginCommandInfo {
|
|
57
|
+
/** Display name `plugin:command`, even when both parts are identical. */
|
|
58
|
+
readonly name: string;
|
|
59
|
+
/** The plugin's manifest name. */
|
|
60
|
+
readonly plugin: string;
|
|
61
|
+
/** Human-readable command description. */
|
|
62
|
+
readonly description: string;
|
|
63
|
+
/** Argument placeholder hint, when one is known. */
|
|
64
|
+
readonly argumentHint?: string;
|
|
65
|
+
}
|
|
66
|
+
/** One mounted plugin command: its public summary plus a direct dispatcher. */
|
|
67
|
+
export interface MountedPluginCommand {
|
|
68
|
+
/** Public summary (colon display name; served by the host's own channel). */
|
|
69
|
+
readonly info: CcPluginCommandInfo;
|
|
70
|
+
/**
|
|
71
|
+
* Dispatch the rendered command body as a user prompt on the given agent —
|
|
72
|
+
* the same path the harness-registered bare alias uses.
|
|
73
|
+
*/
|
|
74
|
+
run(invocation: CommandInvocationLike): CommandResult | Promise<CommandResult>;
|
|
75
|
+
}
|
|
76
|
+
/** Commands live under this directory in a plugin root, when present. */
|
|
77
|
+
export declare const STANDARD_COMMANDS_DIR = "commands";
|
|
78
|
+
/** Options for mounting one plugin's commands. */
|
|
79
|
+
export interface MountCommandsOptions {
|
|
80
|
+
/** The plugin root directory; inline `source` paths resolve against it. */
|
|
81
|
+
readonly pluginRoot: string;
|
|
82
|
+
/** The parsed manifest, whose `commands` field drives registration. */
|
|
83
|
+
readonly manifest: CcPluginManifest;
|
|
84
|
+
/** The commands seam (probed; `undefined` to skip commands). */
|
|
85
|
+
readonly commands: CommandsSeam | undefined;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Register a plugin's manifest commands.
|
|
89
|
+
*
|
|
90
|
+
* Only bare command names reach the host commands seam: harness command
|
|
91
|
+
* registries validate names against `/^[a-z][a-z0-9_-]*$/` and reject the
|
|
92
|
+
* `plugin:command` colon form. The colon form stays available through the
|
|
93
|
+
* returned `mounted` list, for hosts that expose plugin commands on their own
|
|
94
|
+
* channel (e.g. cc-shell's `CcPluginsService.runPluginCommand`).
|
|
95
|
+
*
|
|
96
|
+
* A rejected registration (bare name already taken) skips that one command,
|
|
97
|
+
* never the whole plugin mount.
|
|
98
|
+
*
|
|
99
|
+
* @param options - plugin root, manifest, and the commands seam.
|
|
100
|
+
* @returns mounted disposers, per-component counts, and the mounted commands.
|
|
101
|
+
*/
|
|
102
|
+
export declare function mountCommands(options: MountCommandsOptions): {
|
|
103
|
+
disposers: (() => void)[];
|
|
104
|
+
mounted: MountedPluginCommand[];
|
|
105
|
+
tally: ComponentTally;
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Substitute `$ARGUMENTS` with the invocation's raw input and steer the
|
|
109
|
+
* rendered command body into the conversation as a user message — the same
|
|
110
|
+
* cross-plane seam the upstream `/plan` command uses. Returning success
|
|
111
|
+
* without `text` keeps the command plane from echoing the body back as a
|
|
112
|
+
* status row: the injected message itself is the visible artifact.
|
|
113
|
+
*
|
|
114
|
+
* `Agent.followup` is async upstream, so a thenable return is awaited and a
|
|
115
|
+
* rejection is folded into `{ kind: 'error' }` instead of surfacing as an
|
|
116
|
+
* unhandled rejection (a synchronous throw is caught the same way).
|
|
117
|
+
*/
|
|
118
|
+
export declare function dispatchCommandPrompt(invocation: CommandInvocationLike, body: string): CommandResult | Promise<CommandResult>;
|
|
119
|
+
//# sourceMappingURL=commands.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,OAAO,KAAK,EAAE,gBAAgB,EAAa,MAAM,YAAY,CAAA;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAE3C,mEAAmE;AACnE,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,iBAAiB,GAAG,MAAM,IAAI,CAAA;CACpD;AAED,8DAA8D;AAC9D,MAAM,WAAW,iBAAiB;IAChC,qEAAqE;IACrE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,0CAA0C;IAC1C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,uDAAuD;IACvD,QAAQ,CAAC,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;IACjC,mFAAmF;IACnF,QAAQ,CAAC,OAAO,EAAE,CAAC,UAAU,EAAE,qBAAqB,KAAK,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAA;CAChG;AAED,yDAAyD;AACzD;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,+EAA+E;IAC/E,QAAQ,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAA;KAAE,CAAA;IACvD,4EAA4E;IAC5E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAC1B;AAED,MAAM,MAAM,aAAa,GACrB;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GACpD;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAErD,kFAAkF;AAClF,MAAM,WAAW,mBAAmB;IAClC,yEAAyE;IACzE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,kCAAkC;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,0CAA0C;IAC1C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,oDAAoD;IACpD,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAC/B;AAED,+EAA+E;AAC/E,MAAM,WAAW,oBAAoB;IACnC,6EAA6E;IAC7E,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAA;IAClC;;;OAGG;IACH,GAAG,CAAC,UAAU,EAAE,qBAAqB,GAAG,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAA;CAC/E;AAED,yEAAyE;AACzE,eAAO,MAAM,qBAAqB,aAAa,CAAA;AAE/C,kDAAkD;AAClD,MAAM,WAAW,oBAAoB;IACnC,2EAA2E;IAC3E,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAA;IACnC,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,EAAE,YAAY,GAAG,SAAS,CAAA;CAC5C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG;IAC5D,SAAS,EAAE,CAAC,MAAM,IAAI,CAAC,EAAE,CAAA;IACzB,OAAO,EAAE,oBAAoB,EAAE,CAAA;IAC/B,KAAK,EAAE,cAAc,CAAA;CACtB,CA4CA;AAwDD;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,qBAAqB,EAAE,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAkB7H"}
|
package/lib/commands.js
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mount a Claude Code plugin's slash commands.
|
|
3
|
+
*
|
|
4
|
+
* Translates manifest `commands` entries (inline content or a source file) into
|
|
5
|
+
* typed command definitions registered on the commands seam. Each handler
|
|
6
|
+
* substitutes `$ARGUMENTS` and dispatches the rendered body as a user prompt
|
|
7
|
+
* on the invoking agent; registration is effect-scoped.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
import { readdirSync, readFileSync } from 'node:fs';
|
|
12
|
+
import { createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
13
|
+
import { parseCcFrontmatter, parseCcFrontmatterDocument } from '@dsh-cc/skill-loader';
|
|
14
|
+
import { basename, join, resolve } from 'node:path';
|
|
15
|
+
import { ComponentTally } from "./seams.js";
|
|
16
|
+
/** Commands live under this directory in a plugin root, when present. */
|
|
17
|
+
export const STANDARD_COMMANDS_DIR = 'commands';
|
|
18
|
+
/**
|
|
19
|
+
* Register a plugin's manifest commands.
|
|
20
|
+
*
|
|
21
|
+
* Only bare command names reach the host commands seam: harness command
|
|
22
|
+
* registries validate names against `/^[a-z][a-z0-9_-]*$/` and reject the
|
|
23
|
+
* `plugin:command` colon form. The colon form stays available through the
|
|
24
|
+
* returned `mounted` list, for hosts that expose plugin commands on their own
|
|
25
|
+
* channel (e.g. cc-shell's `CcPluginsService.runPluginCommand`).
|
|
26
|
+
*
|
|
27
|
+
* A rejected registration (bare name already taken) skips that one command,
|
|
28
|
+
* never the whole plugin mount.
|
|
29
|
+
*
|
|
30
|
+
* @param options - plugin root, manifest, and the commands seam.
|
|
31
|
+
* @returns mounted disposers, per-component counts, and the mounted commands.
|
|
32
|
+
*/
|
|
33
|
+
export function mountCommands(options) {
|
|
34
|
+
const tally = new ComponentTally('commands');
|
|
35
|
+
const disposers = [];
|
|
36
|
+
const mounted = [];
|
|
37
|
+
if (options.commands === undefined) {
|
|
38
|
+
tally.addSkipped('commands seam "commands" is not mounted');
|
|
39
|
+
return { disposers, mounted, tally };
|
|
40
|
+
}
|
|
41
|
+
const entries = options.manifest.commandsDeclared
|
|
42
|
+
? [...options.manifest.commands]
|
|
43
|
+
: defaultCommandEntries(options.pluginRoot, tally);
|
|
44
|
+
if (entries.length === 0) {
|
|
45
|
+
tally.addSkipped('plugin ships no commands');
|
|
46
|
+
return { disposers, mounted, tally };
|
|
47
|
+
}
|
|
48
|
+
for (const entry of entries) {
|
|
49
|
+
const rendered = renderCommand(options.pluginRoot, entry);
|
|
50
|
+
if (rendered.error !== undefined) {
|
|
51
|
+
tally.addFailed(`command "${entry.name}": ${rendered.error}`);
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
const hint = entry.argumentHint ?? rendered.argumentHint;
|
|
55
|
+
const body = rendered.body ?? '';
|
|
56
|
+
const info = {
|
|
57
|
+
name: `${options.manifest.name}:${entry.name}`,
|
|
58
|
+
plugin: options.manifest.name,
|
|
59
|
+
description: entry.description ?? rendered.description ?? '',
|
|
60
|
+
...hint === undefined ? {} : { argumentHint: hint },
|
|
61
|
+
};
|
|
62
|
+
const run = (invocation) => dispatchCommandPrompt(invocation, body);
|
|
63
|
+
try {
|
|
64
|
+
disposers.push(options.commands.register({
|
|
65
|
+
name: entry.name,
|
|
66
|
+
description: info.description,
|
|
67
|
+
...hint === undefined ? {} : { input: { hint } },
|
|
68
|
+
handler: run,
|
|
69
|
+
}));
|
|
70
|
+
mounted.push({ info, run });
|
|
71
|
+
tally.addLoaded();
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
tally.addSkipped(`bare name "${entry.name}" not registered: ${String(error)}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return { disposers, mounted, tally };
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Scan `commands/*.md` when the manifest omitted `commands`. Nested
|
|
81
|
+
* subdirectories are skipped with a reason (no silent drop, no colon names).
|
|
82
|
+
*/
|
|
83
|
+
function defaultCommandEntries(pluginRoot, tally) {
|
|
84
|
+
const dir = join(pluginRoot, STANDARD_COMMANDS_DIR);
|
|
85
|
+
let entries;
|
|
86
|
+
try {
|
|
87
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return [];
|
|
91
|
+
}
|
|
92
|
+
const found = [];
|
|
93
|
+
for (const entry of entries) {
|
|
94
|
+
if (entry.isDirectory()) {
|
|
95
|
+
tally.addSkipped(`skipped nested commands directory "${entry.name}"`);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (!entry.isFile() && !entry.isSymbolicLink())
|
|
99
|
+
continue;
|
|
100
|
+
if (!entry.name.endsWith('.md'))
|
|
101
|
+
continue;
|
|
102
|
+
found.push({ name: basename(entry.name, '.md'), source: join(STANDARD_COMMANDS_DIR, entry.name) });
|
|
103
|
+
}
|
|
104
|
+
return found;
|
|
105
|
+
}
|
|
106
|
+
/** Resolve a command entry to consumable content, or a failure reason. */
|
|
107
|
+
function renderCommand(pluginRoot, entry) {
|
|
108
|
+
if (entry.content !== undefined) {
|
|
109
|
+
return { body: entry.content };
|
|
110
|
+
}
|
|
111
|
+
if (entry.source !== undefined) {
|
|
112
|
+
const path = resolve(pluginRoot, entry.source);
|
|
113
|
+
try {
|
|
114
|
+
const raw = readFileSync(path, 'utf8');
|
|
115
|
+
const document = parseCcFrontmatterDocument(raw);
|
|
116
|
+
const parsed = parseCcFrontmatter(raw);
|
|
117
|
+
if (document === undefined || parsed === undefined)
|
|
118
|
+
return { body: raw };
|
|
119
|
+
return {
|
|
120
|
+
body: document.body,
|
|
121
|
+
...parsed.description === undefined ? {} : { description: parsed.description },
|
|
122
|
+
...parsed.argumentHint === undefined ? {} : { argumentHint: parsed.argumentHint },
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
return { error: `could not read command file "${entry.source}": ${String(error)}` };
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return { error: 'has neither "content" nor a readable "source"' };
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Substitute `$ARGUMENTS` with the invocation's raw input and steer the
|
|
133
|
+
* rendered command body into the conversation as a user message — the same
|
|
134
|
+
* cross-plane seam the upstream `/plan` command uses. Returning success
|
|
135
|
+
* without `text` keeps the command plane from echoing the body back as a
|
|
136
|
+
* status row: the injected message itself is the visible artifact.
|
|
137
|
+
*
|
|
138
|
+
* `Agent.followup` is async upstream, so a thenable return is awaited and a
|
|
139
|
+
* rejection is folded into `{ kind: 'error' }` instead of surfacing as an
|
|
140
|
+
* unhandled rejection (a synchronous throw is caught the same way).
|
|
141
|
+
*/
|
|
142
|
+
export function dispatchCommandPrompt(invocation, body) {
|
|
143
|
+
const text = body.split('$ARGUMENTS').join(invocation.rawInput);
|
|
144
|
+
let scheduled;
|
|
145
|
+
try {
|
|
146
|
+
scheduled = invocation.agent.followup(createUserMessage({
|
|
147
|
+
content: [{ type: 'text', text }],
|
|
148
|
+
source: { kind: 'user' },
|
|
149
|
+
}));
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
return { kind: 'error', text: `could not dispatch command prompt: ${String(error)}` };
|
|
153
|
+
}
|
|
154
|
+
if (scheduled === null || scheduled === undefined || typeof scheduled.then !== 'function') {
|
|
155
|
+
return { kind: 'success' };
|
|
156
|
+
}
|
|
157
|
+
return Promise.resolve(scheduled).then(() => ({ kind: 'success' }), (error) => ({ kind: 'error', text: `could not dispatch command prompt: ${String(error)}` }));
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discover Claude Code plugin roots the way Claude Code actually installs them.
|
|
3
|
+
*
|
|
4
|
+
* Default (no `pluginDirs`): the intersection of `enabledPlugins` across the
|
|
5
|
+
* user/project/local settings cascade and `installed_plugins.json`. Explicit
|
|
6
|
+
* `pluginDirs` keeps the historical flatten (a root, or its one-level
|
|
7
|
+
* children, that hold `plugin.json` or `.claude-plugin/plugin.json`). Empty
|
|
8
|
+
* or null `pluginDirs` disables discovery. Best-effort: unreadable files and
|
|
9
|
+
* missing install paths skip rather than throw.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
/** One discovered plugin root plus the name used to match marketplace overlays. */
|
|
14
|
+
export interface DiscoveredCcPlugin {
|
|
15
|
+
/** Absolute plugin root (the directory that holds the manifest / components). */
|
|
16
|
+
readonly root: string;
|
|
17
|
+
/** Plugin name without `@marketplace`, used as a marketplace-entry hint. */
|
|
18
|
+
readonly nameHint: string;
|
|
19
|
+
}
|
|
20
|
+
/** Options for one discovery pass. */
|
|
21
|
+
export interface DiscoverCcPluginRootsOptions {
|
|
22
|
+
/**
|
|
23
|
+
* Explicit discovery roots. `undefined` (absent) uses installed ∩ enabled;
|
|
24
|
+
* `[]` or `null` disables discovery; a non-empty list flattens those dirs.
|
|
25
|
+
*/
|
|
26
|
+
readonly pluginDirs?: readonly string[] | null;
|
|
27
|
+
/** Claude config home; defaults to `$CLAUDE_CONFIG_DIR` or `~/.claude`. */
|
|
28
|
+
readonly claudeHome?: string;
|
|
29
|
+
/** Workspace used for project/local `enabledPlugins`; defaults to `process.cwd()`. */
|
|
30
|
+
readonly cwd?: string;
|
|
31
|
+
/** Optional logger for project-scope cwd and skipped bare enablement keys. */
|
|
32
|
+
readonly log?: {
|
|
33
|
+
info(message: string): void;
|
|
34
|
+
warn(message: string): void;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/** Nested Claude Code manifest path, preferred over a top-level `plugin.json`. */
|
|
38
|
+
export declare const NESTED_MANIFEST: string;
|
|
39
|
+
/** Legacy / fixture manifest path at the plugin root. */
|
|
40
|
+
export declare const TOP_LEVEL_MANIFEST = "plugin.json";
|
|
41
|
+
/**
|
|
42
|
+
* Discover plugin roots for the glue to mount.
|
|
43
|
+
* @param options - explicit dirs or the Claude-home / cwd pair for the default path.
|
|
44
|
+
* @returns unique `{ root, nameHint }` entries, in discovery order.
|
|
45
|
+
*/
|
|
46
|
+
export declare function discoverCcPluginRoots(options?: DiscoverCcPluginRootsOptions): DiscoveredCcPlugin[];
|
|
47
|
+
/** `$CLAUDE_CONFIG_DIR` if set, otherwise `~/.claude`. */
|
|
48
|
+
export declare function resolveClaudeHome(explicit?: string): string;
|
|
49
|
+
//# sourceMappingURL=discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,mFAAmF;AACnF,MAAM,WAAW,kBAAkB;IACjC,iFAAiF;IACjF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,4EAA4E;IAC5E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAC1B;AAED,sCAAsC;AACtC,MAAM,WAAW,4BAA4B;IAC3C;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAA;IAC9C,2EAA2E;IAC3E,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,sFAAsF;IACtF,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;IACrB,8EAA8E;IAC9E,QAAQ,CAAC,GAAG,CAAC,EAAE;QAAE,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAA;CAC5E;AAED,kFAAkF;AAClF,eAAO,MAAM,eAAe,QAAwC,CAAA;AAEpE,yDAAyD;AACzD,eAAO,MAAM,kBAAkB,gBAAgB,CAAA;AAE/C;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,4BAAiC,GAAG,kBAAkB,EAAE,CAQtG;AAOD,0DAA0D;AAC1D,wBAAgB,iBAAiB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAK3D"}
|
package/lib/discovery.js
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discover Claude Code plugin roots the way Claude Code actually installs them.
|
|
3
|
+
*
|
|
4
|
+
* Default (no `pluginDirs`): the intersection of `enabledPlugins` across the
|
|
5
|
+
* user/project/local settings cascade and `installed_plugins.json`. Explicit
|
|
6
|
+
* `pluginDirs` keeps the historical flatten (a root, or its one-level
|
|
7
|
+
* children, that hold `plugin.json` or `.claude-plugin/plugin.json`). Empty
|
|
8
|
+
* or null `pluginDirs` disables discovery. Best-effort: unreadable files and
|
|
9
|
+
* missing install paths skip rather than throw.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
import { readdirSync, readFileSync, statSync } from 'node:fs';
|
|
14
|
+
import { homedir } from 'node:os';
|
|
15
|
+
import { basename, join, resolve } from 'node:path';
|
|
16
|
+
import { resolveLocalSettingsDir } from '@dsh-cc/settings-cascade/local-root';
|
|
17
|
+
/** Nested Claude Code manifest path, preferred over a top-level `plugin.json`. */
|
|
18
|
+
export const NESTED_MANIFEST = join('.claude-plugin', 'plugin.json');
|
|
19
|
+
/** Legacy / fixture manifest path at the plugin root. */
|
|
20
|
+
export const TOP_LEVEL_MANIFEST = 'plugin.json';
|
|
21
|
+
/**
|
|
22
|
+
* Discover plugin roots for the glue to mount.
|
|
23
|
+
* @param options - explicit dirs or the Claude-home / cwd pair for the default path.
|
|
24
|
+
* @returns unique `{ root, nameHint }` entries, in discovery order.
|
|
25
|
+
*/
|
|
26
|
+
export function discoverCcPluginRoots(options = {}) {
|
|
27
|
+
if (options.pluginDirs === null || isEmptyList(options.pluginDirs))
|
|
28
|
+
return [];
|
|
29
|
+
if (options.pluginDirs !== undefined)
|
|
30
|
+
return flattenPluginDirs(options.pluginDirs);
|
|
31
|
+
return discoverInstalledEnabled(resolveClaudeHome(options.claudeHome), options.cwd ?? process.cwd(), options.log);
|
|
32
|
+
}
|
|
33
|
+
/** True when an explicit `pluginDirs` list is present and empty. */
|
|
34
|
+
function isEmptyList(value) {
|
|
35
|
+
return value !== undefined && value.length === 0;
|
|
36
|
+
}
|
|
37
|
+
/** `$CLAUDE_CONFIG_DIR` if set, otherwise `~/.claude`. */
|
|
38
|
+
export function resolveClaudeHome(explicit) {
|
|
39
|
+
if (explicit !== undefined)
|
|
40
|
+
return explicit;
|
|
41
|
+
const fromEnv = process.env.CLAUDE_CONFIG_DIR;
|
|
42
|
+
if (fromEnv !== undefined && fromEnv.length > 0)
|
|
43
|
+
return fromEnv;
|
|
44
|
+
return join(homedir(), '.claude');
|
|
45
|
+
}
|
|
46
|
+
/** Flatten configured dirs: the dir itself, or one-level children that look like plugin roots. */
|
|
47
|
+
function flattenPluginDirs(dirs) {
|
|
48
|
+
const found = [];
|
|
49
|
+
const seen = new Set();
|
|
50
|
+
for (const dir of dirs) {
|
|
51
|
+
const hint = nameHintFromRoot(dir);
|
|
52
|
+
if (hint !== undefined) {
|
|
53
|
+
pushUnique(found, seen, dir, hint);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
58
|
+
if (!entry.isDirectory())
|
|
59
|
+
continue;
|
|
60
|
+
const child = join(dir, entry.name);
|
|
61
|
+
const childHint = nameHintFromRoot(child);
|
|
62
|
+
if (childHint !== undefined)
|
|
63
|
+
pushUnique(found, seen, child, childHint);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// Best-effort: an unreadable discovery root contributes nothing.
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return found;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Manifest `name` when a nested or top-level plugin.json is present.
|
|
74
|
+
* Missing files are not a plugin root; unreadable/invalid JSON still is (basename fallback).
|
|
75
|
+
*/
|
|
76
|
+
function nameHintFromRoot(dir) {
|
|
77
|
+
for (const file of [NESTED_MANIFEST, TOP_LEVEL_MANIFEST]) {
|
|
78
|
+
const text = readText(join(dir, file));
|
|
79
|
+
if (text === undefined)
|
|
80
|
+
continue;
|
|
81
|
+
const parsed = parseJson(text);
|
|
82
|
+
if (isRecord(parsed) && typeof parsed['name'] === 'string' && parsed['name'].length > 0)
|
|
83
|
+
return parsed['name'];
|
|
84
|
+
return basename(resolve(dir));
|
|
85
|
+
}
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
/** Default path: enabledPlugins cascade ∩ installed_plugins.json. */
|
|
89
|
+
function discoverInstalledEnabled(claudeHome, cwd, log) {
|
|
90
|
+
const enabled = enabledKeys(claudeHome, cwd, log);
|
|
91
|
+
const installed = readInstalled(join(claudeHome, 'plugins', 'installed_plugins.json'));
|
|
92
|
+
const found = [];
|
|
93
|
+
const seen = new Set();
|
|
94
|
+
for (const key of enabled) {
|
|
95
|
+
const picked = installed[key];
|
|
96
|
+
if (picked === undefined || !isDirectory(picked))
|
|
97
|
+
continue;
|
|
98
|
+
pushUnique(found, seen, picked, key.slice(0, key.indexOf('@')));
|
|
99
|
+
}
|
|
100
|
+
return found;
|
|
101
|
+
}
|
|
102
|
+
/** Keys whose cascaded `enabledPlugins` value is JSON `true`, in first-seen order. */
|
|
103
|
+
function enabledKeys(claudeHome, cwd, log) {
|
|
104
|
+
const cascade = [
|
|
105
|
+
{ path: join(claudeHome, 'settings.json'), scope: 'user' },
|
|
106
|
+
{ path: join(cwd, '.claude', 'settings.json'), scope: 'project' },
|
|
107
|
+
{
|
|
108
|
+
// Claude Code-parity: the *local* settings file is read from the git
|
|
109
|
+
// main checkout root (linked worktree) or git toplevel (subdirectory
|
|
110
|
+
// start); the project settings above stay at the launch cwd.
|
|
111
|
+
path: join(resolveLocalSettingsDir(cwd), '.claude', 'settings.local.json'),
|
|
112
|
+
scope: 'project',
|
|
113
|
+
},
|
|
114
|
+
];
|
|
115
|
+
const state = new Map();
|
|
116
|
+
const order = [];
|
|
117
|
+
let projectScoped = false;
|
|
118
|
+
for (const file of cascade) {
|
|
119
|
+
const parsed = readJson(file.path);
|
|
120
|
+
if (!isRecord(parsed))
|
|
121
|
+
continue;
|
|
122
|
+
const block = parsed['enabledPlugins'];
|
|
123
|
+
if (!isRecord(block))
|
|
124
|
+
continue;
|
|
125
|
+
if (file.scope === 'project' && Object.keys(block).length > 0)
|
|
126
|
+
projectScoped = true;
|
|
127
|
+
for (const [key, value] of Object.entries(block)) {
|
|
128
|
+
if (typeof value !== 'boolean')
|
|
129
|
+
continue;
|
|
130
|
+
if (!state.has(key))
|
|
131
|
+
order.push(key);
|
|
132
|
+
state.set(key, value);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (projectScoped)
|
|
136
|
+
log?.info(`cc-plugin-loader: project-scope enabledPlugins read from cwd ${cwd}`);
|
|
137
|
+
const enabled = [];
|
|
138
|
+
for (const key of order) {
|
|
139
|
+
if (state.get(key) !== true)
|
|
140
|
+
continue;
|
|
141
|
+
if (!key.includes('@')) {
|
|
142
|
+
log?.warn(`cc-plugin-loader: skipping bare enabledPlugins key "${key}" (expected name@marketplace)`);
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
enabled.push(key);
|
|
146
|
+
}
|
|
147
|
+
return enabled;
|
|
148
|
+
}
|
|
149
|
+
/** Winning `installPath` per `name@marketplace` (latest lastUpdated, then later array element). */
|
|
150
|
+
function readInstalled(path) {
|
|
151
|
+
const parsed = readJson(path);
|
|
152
|
+
if (!isRecord(parsed))
|
|
153
|
+
return {};
|
|
154
|
+
const plugins = parsed['plugins'];
|
|
155
|
+
if (!isRecord(plugins))
|
|
156
|
+
return {};
|
|
157
|
+
const out = {};
|
|
158
|
+
for (const [key, raw] of Object.entries(plugins)) {
|
|
159
|
+
if (!Array.isArray(raw))
|
|
160
|
+
continue;
|
|
161
|
+
const picked = pickInstallPath(raw);
|
|
162
|
+
if (picked !== undefined)
|
|
163
|
+
out[key] = picked;
|
|
164
|
+
}
|
|
165
|
+
return out;
|
|
166
|
+
}
|
|
167
|
+
function pickInstallPath(raw) {
|
|
168
|
+
let best;
|
|
169
|
+
for (const [index, item] of raw.entries()) {
|
|
170
|
+
if (!isRecord(item) || typeof item['installPath'] !== 'string')
|
|
171
|
+
continue;
|
|
172
|
+
const candidate = { path: item['installPath'], time: parseTime(item['lastUpdated']), index };
|
|
173
|
+
if (best === undefined || candidate.time > best.time || (candidate.time === best.time && candidate.index > best.index)) {
|
|
174
|
+
best = candidate;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return best?.path;
|
|
178
|
+
}
|
|
179
|
+
function parseTime(value) {
|
|
180
|
+
if (typeof value !== 'string')
|
|
181
|
+
return Number.NEGATIVE_INFINITY;
|
|
182
|
+
const time = Date.parse(value);
|
|
183
|
+
return Number.isNaN(time) ? Number.NEGATIVE_INFINITY : time;
|
|
184
|
+
}
|
|
185
|
+
function pushUnique(found, seen, root, nameHint) {
|
|
186
|
+
const resolved = resolve(root);
|
|
187
|
+
if (seen.has(resolved))
|
|
188
|
+
return;
|
|
189
|
+
seen.add(resolved);
|
|
190
|
+
found.push({ root: resolved, nameHint });
|
|
191
|
+
}
|
|
192
|
+
function isDirectory(path) {
|
|
193
|
+
try {
|
|
194
|
+
return statSync(path).isDirectory();
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function readText(path) {
|
|
201
|
+
try {
|
|
202
|
+
return readFileSync(path, 'utf8');
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
return undefined;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
function parseJson(text) {
|
|
209
|
+
try {
|
|
210
|
+
return JSON.parse(text);
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
return undefined;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
function readJson(path) {
|
|
217
|
+
const text = readText(path);
|
|
218
|
+
return text === undefined ? undefined : parseJson(text);
|
|
219
|
+
}
|
|
220
|
+
function isRecord(value) {
|
|
221
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"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"}
|
package/lib/hooks.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mount a Claude Code plugin's hooks.
|
|
3
|
+
*
|
|
4
|
+
* Reads the plugin's `hooks/hooks.json` (or an inline manifest `hooks`
|
|
5
|
+
* declaration), validates the structure, and injects the hooks into the
|
|
6
|
+
* hooks-claude-code bridge through the optional `hooks` guest seam. When the
|
|
7
|
+
* seam is absent the component is reported skipped, never failed, so a
|
|
8
|
+
* deployment without the bridge keeps loading the rest of the plugin.
|
|
9
|
+
*
|
|
10
|
+
* @module
|
|
11
|
+
*/
|
|
12
|
+
import type { CcPluginManifest } from './types.ts';
|
|
13
|
+
import { ComponentTally } from './seams.ts';
|
|
14
|
+
/** The hooks seam: accepts a plugin's translated per-event hooks. */
|
|
15
|
+
export interface HooksSeam {
|
|
16
|
+
/**
|
|
17
|
+
* Merge a plugin's hooks into the bridge.
|
|
18
|
+
* @param pluginName - the plugin that owns the hooks.
|
|
19
|
+
* @param config - the per-event hook map (`ClaudeCodeHookConfig` shape).
|
|
20
|
+
* @returns the exact disposer that removes the injected hooks.
|
|
21
|
+
*/
|
|
22
|
+
mergePluginHooks(pluginName: string, config: unknown): () => void;
|
|
23
|
+
}
|
|
24
|
+
/** Hooks live under this file in a plugin root, when present. */
|
|
25
|
+
export declare const STANDARD_HOOKS_FILE = "hooks/hooks.json";
|
|
26
|
+
/** Options for mounting one plugin's hooks. */
|
|
27
|
+
export interface MountHooksOptions {
|
|
28
|
+
/** The plugin root directory; the standard hooks file resolves against it. */
|
|
29
|
+
readonly pluginRoot: string;
|
|
30
|
+
/** The parsed manifest; `hooks` supplies an inline or file reference. */
|
|
31
|
+
readonly manifest: CcPluginManifest;
|
|
32
|
+
/** The hooks seam (probed; `undefined` to skip hooks). */
|
|
33
|
+
readonly hooks: HooksSeam | undefined;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Read and inject a plugin's hooks through the optional seam.
|
|
37
|
+
* @param options - plugin root, manifest, and the hooks seam.
|
|
38
|
+
* @returns mounted disposers and per-component counts.
|
|
39
|
+
*/
|
|
40
|
+
export declare function mountHooks(options: MountHooksOptions): {
|
|
41
|
+
disposers: (() => void)[];
|
|
42
|
+
tally: ComponentTally;
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=hooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAE3C,qEAAqE;AACrE,MAAM,WAAW,SAAS;IACxB;;;;;OAKG;IACH,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,IAAI,CAAA;CAClE;AAED,iEAAiE;AACjE,eAAO,MAAM,mBAAmB,qBAAqB,CAAA;AAErD,+CAA+C;AAC/C,MAAM,WAAW,iBAAiB;IAChC,8EAA8E;IAC9E,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAA;IACnC,0DAA0D;IAC1D,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,CAAA;CACtC;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG;IAAE,SAAS,EAAE,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;IAAC,KAAK,EAAE,cAAc,CAAA;CAAE,CAmB3G"}
|