@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.
Files changed (57) hide show
  1. package/LICENSE +201 -0
  2. package/README.i18n.yaml +6 -0
  3. package/README.md +68 -0
  4. package/README.zh.md +68 -0
  5. package/lib/agents.d.ts +110 -0
  6. package/lib/agents.d.ts.map +1 -0
  7. package/lib/agents.js +140 -0
  8. package/lib/agents.js.map +1 -0
  9. package/lib/commands.d.ts +119 -0
  10. package/lib/commands.d.ts.map +1 -0
  11. package/lib/commands.js +159 -0
  12. package/lib/commands.js.map +1 -0
  13. package/lib/discovery.d.ts +49 -0
  14. package/lib/discovery.d.ts.map +1 -0
  15. package/lib/discovery.js +223 -0
  16. package/lib/discovery.js.map +1 -0
  17. package/lib/hooks.d.ts +44 -0
  18. package/lib/hooks.d.ts.map +1 -0
  19. package/lib/hooks.js +89 -0
  20. package/lib/hooks.js.map +1 -0
  21. package/lib/index.d.ts +81 -0
  22. package/lib/index.d.ts.map +1 -0
  23. package/lib/index.js +92 -0
  24. package/lib/index.js.map +1 -0
  25. package/lib/manifest.d.ts +29 -0
  26. package/lib/manifest.d.ts.map +1 -0
  27. package/lib/manifest.js +120 -0
  28. package/lib/manifest.js.map +1 -0
  29. package/lib/mcp.d.ts +41 -0
  30. package/lib/mcp.d.ts.map +1 -0
  31. package/lib/mcp.js +64 -0
  32. package/lib/mcp.js.map +1 -0
  33. package/lib/resolve-manifest.d.ts +27 -0
  34. package/lib/resolve-manifest.d.ts.map +1 -0
  35. package/lib/resolve-manifest.js +85 -0
  36. package/lib/resolve-manifest.js.map +1 -0
  37. package/lib/seams.d.ts +59 -0
  38. package/lib/seams.d.ts.map +1 -0
  39. package/lib/seams.js +56 -0
  40. package/lib/seams.js.map +1 -0
  41. package/lib/settings.d.ts +41 -0
  42. package/lib/settings.d.ts.map +1 -0
  43. package/lib/settings.js +44 -0
  44. package/lib/settings.js.map +1 -0
  45. package/lib/skill-semantics.d.ts +92 -0
  46. package/lib/skill-semantics.d.ts.map +1 -0
  47. package/lib/skill-semantics.js +98 -0
  48. package/lib/skill-semantics.js.map +1 -0
  49. package/lib/skills.d.ts +49 -0
  50. package/lib/skills.d.ts.map +1 -0
  51. package/lib/skills.js +168 -0
  52. package/lib/skills.js.map +1 -0
  53. package/lib/types.d.ts +96 -0
  54. package/lib/types.d.ts.map +1 -0
  55. package/lib/types.js +12 -0
  56. package/lib/types.js.map +1 -0
  57. package/package.json +64 -0
package/lib/hooks.js ADDED
@@ -0,0 +1,89 @@
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 { readFileSync } from 'node:fs';
13
+ import { join, resolve } from 'node:path';
14
+ import { ComponentTally } from "./seams.js";
15
+ /** Hooks live under this file in a plugin root, when present. */
16
+ export const STANDARD_HOOKS_FILE = 'hooks/hooks.json';
17
+ /**
18
+ * Read and inject a plugin's hooks through the optional seam.
19
+ * @param options - plugin root, manifest, and the hooks seam.
20
+ * @returns mounted disposers and per-component counts.
21
+ */
22
+ export function mountHooks(options) {
23
+ const tally = new ComponentTally('hooks');
24
+ const disposers = [];
25
+ if (options.hooks === undefined) {
26
+ tally.addSkipped('hooks seam "hooks" is not mounted');
27
+ return { disposers, tally };
28
+ }
29
+ const hooks = resolveHooks(options.pluginRoot, options.manifest);
30
+ if (hooks.error !== undefined) {
31
+ tally.addFailed(hooks.error);
32
+ return { disposers, tally };
33
+ }
34
+ if (hooks.value === undefined) {
35
+ tally.addSkipped('plugin declares no hooks');
36
+ return { disposers, tally };
37
+ }
38
+ disposers.push(options.hooks.mergePluginHooks(options.manifest.name, hooks.value));
39
+ tally.addLoaded();
40
+ return { disposers, tally };
41
+ }
42
+ /** Resolve the plugin's hooks map, or a failure reason. */
43
+ function resolveHooks(pluginRoot, manifest) {
44
+ const inline = manifest.hooks;
45
+ if (typeof inline === 'string') {
46
+ return readHooksFile(resolve(pluginRoot, inline), `manifest hooks path "${inline}"`);
47
+ }
48
+ if (inline !== undefined) {
49
+ if (!isRecord(inline)) {
50
+ return { error: 'manifest "hooks" must be an object or a hooks file path' };
51
+ }
52
+ const fromInline = inline['hooks'] !== undefined ? inline['hooks'] : inline;
53
+ return validateHooks(fromInline);
54
+ }
55
+ return readHooksFile(join(pluginRoot, STANDARD_HOOKS_FILE), 'hooks/hooks.json');
56
+ }
57
+ /** Read and validate a hooks JSON file (absent file means no hooks). */
58
+ function readHooksFile(path, label) {
59
+ let raw;
60
+ try {
61
+ raw = readFileSync(path, 'utf8');
62
+ }
63
+ catch {
64
+ return { value: undefined }; // absent standard hooks file is valid empty state
65
+ }
66
+ let parsed;
67
+ try {
68
+ parsed = JSON.parse(raw);
69
+ }
70
+ catch {
71
+ return { error: `could not parse ${label}` };
72
+ }
73
+ return validateHooks(parsed);
74
+ }
75
+ /** Validate a hooks value into a per-event map. */
76
+ function validateHooks(value) {
77
+ if (!isRecord(value)) {
78
+ return { error: 'hooks must be an object keyed by event name' };
79
+ }
80
+ const hooks = (value['hooks'] !== undefined ? value['hooks'] : value);
81
+ if (!isRecord(hooks)) {
82
+ return { error: 'hooks "hooks" field must be an object keyed by event name' };
83
+ }
84
+ return { value: hooks };
85
+ }
86
+ function isRecord(value) {
87
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
88
+ }
89
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"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"}
package/lib/index.d.ts ADDED
@@ -0,0 +1,81 @@
1
+ /**
2
+ * A Claude Code `plugin.json` compatibility loader: reads a CC plugin manifest
3
+ * and mounts each component as an in-memory dsh plugin.
4
+ *
5
+ * The loader is peer-style: it parses the manifest subset, translates each
6
+ * component with the pure helpers from `dsh-skill-claude-code` and
7
+ * `dsh-claude-code-agents`, then consults the host seam for that component via
8
+ * `ctx.get(...)`. A component whose seam is absent is reported skipped (never a
9
+ * whole-load failure), matching "misconfiguration fails loud" for the manifest
10
+ * itself but graceful degradation for missing host seams. Every component
11
+ * mount is a Cordis effect, so disabling the plugin recalls all of it.
12
+ *
13
+ * @module @dsh-cc/plugin-loader
14
+ */
15
+ import type { Context } from '@deepseek-ai/cordis';
16
+ import type { HooksSeam } from './hooks.ts';
17
+ import type { McpSeam } from './mcp.ts';
18
+ import type { CommandsSeam } from './commands.ts';
19
+ import type { SettingsSeam } from './settings.ts';
20
+ import type { PluginLoadReport } from './types.ts';
21
+ import { type SkillsSeam } from './skills.ts';
22
+ import { type ResolveModel, type SubagentsSeam } from './agents.ts';
23
+ import { type MountedPluginCommand } from './commands.ts';
24
+ export type { CcPluginManifest, CcCommand, CcSkillRef, CcAgentRef, CcMcpServer, ComponentKind, ComponentResult, PluginLoadReport } from './types.ts';
25
+ export type { CcPluginCommandInfo, MountedPluginCommand } from './commands.ts';
26
+ export { parsePluginManifest } from './manifest.ts';
27
+ export { discoverCcPluginRoots, resolveClaudeHome, NESTED_MANIFEST, TOP_LEVEL_MANIFEST } from './discovery.ts';
28
+ export type { DiscoveredCcPlugin, DiscoverCcPluginRootsOptions } from './discovery.ts';
29
+ export { AgentProvider, STANDARD_AGENTS_DIR } from './agents.ts';
30
+ export type { ResolveModel } from './agents.ts';
31
+ export type { McpSeam, HooksSeam } from './seams.ts';
32
+ export { skillToolRestriction, resolveSkillExecution, forbidsInlineShell, activationFor, registerSkillPathActivator, applySkillRestriction, PROVIDER, type AgentScope, type SkillExecution, type SkillActivation, } from './skill-semantics.ts';
33
+ /** The plugin.json file name at a plugin root (legacy / fixture path). */
34
+ export declare const MANIFEST_FILE = "plugin.json";
35
+ /** The component host seams the loader probes. */
36
+ export interface MountedSeams {
37
+ /** Skill registry seam. */
38
+ skills?: SkillsSeam | undefined;
39
+ /** Subagent registry seam. */
40
+ subagents?: SubagentsSeam | undefined;
41
+ /** Command registry seam. */
42
+ commands?: CommandsSeam | undefined;
43
+ /** Settings seam. */
44
+ settings?: SettingsSeam | undefined;
45
+ /** Hooks bridge seam (guest; absent in the harness today). */
46
+ hooks?: HooksSeam | undefined;
47
+ /** MCP server seam (guest; absent in the harness today). */
48
+ mcp?: McpSeam | undefined;
49
+ }
50
+ /** Options for mounting one Claude Code plugin. */
51
+ export interface MountCcPluginOptions {
52
+ /** The plugin root directory holding `plugin.json` and its components. */
53
+ readonly root: string;
54
+ /** Installed plugin name (no `@marketplace`); matches a marketplace overlay. */
55
+ readonly nameHint?: string;
56
+ /** Optional seam overrides; when omitted the loader probes `ctx.get(...)`. */
57
+ readonly seams?: MountedSeams;
58
+ /** Optional spawn-time model resolver threaded into every mounted agent. */
59
+ readonly resolveModel?: ResolveModel;
60
+ }
61
+ /** The structural report plus a disposer that recalls every mounted component. */
62
+ export interface CcPluginMount {
63
+ /** The structural load report. */
64
+ report: PluginLoadReport;
65
+ /** The plugin's mounted slash commands (colon display names, host-served). */
66
+ commands: MountedPluginCommand[];
67
+ /**
68
+ * Recall every mounted component. Effect-scoped: calling it also releases
69
+ * the Cordis effect, and a context teardown calls it automatically.
70
+ */
71
+ dispose(): void;
72
+ }
73
+ /**
74
+ * Load a Claude Code plugin manifest and mount its components.
75
+ * @param ctx - active context carrying the component host seams.
76
+ * @param options - plugin root and optional seam overrides.
77
+ * @returns the structural report and a disposer that recalls every mount.
78
+ * @throws when the manifest itself is invalid (with the plugin path/name).
79
+ */
80
+ export declare function mountCcPlugin(ctx: Context, options: MountCcPluginOptions): Promise<CcPluginMount>;
81
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/lib/index.js ADDED
@@ -0,0 +1,92 @@
1
+ /**
2
+ * A Claude Code `plugin.json` compatibility loader: reads a CC plugin manifest
3
+ * and mounts each component as an in-memory dsh plugin.
4
+ *
5
+ * The loader is peer-style: it parses the manifest subset, translates each
6
+ * component with the pure helpers from `dsh-skill-claude-code` and
7
+ * `dsh-claude-code-agents`, then consults the host seam for that component via
8
+ * `ctx.get(...)`. A component whose seam is absent is reported skipped (never a
9
+ * whole-load failure), matching "misconfiguration fails loud" for the manifest
10
+ * itself but graceful degradation for missing host seams. Every component
11
+ * mount is a Cordis effect, so disabling the plugin recalls all of it.
12
+ *
13
+ * @module @dsh-cc/plugin-loader
14
+ */
15
+ import { resolve } from 'node:path';
16
+ import { parsePluginManifest } from "./manifest.js";
17
+ import { mountSkills } from "./skills.js";
18
+ import { mountAgents } from "./agents.js";
19
+ import { mountCommands } from "./commands.js";
20
+ import { mountHooks } from "./hooks.js";
21
+ import { mountMcpServers } from "./mcp.js";
22
+ import { mountSettings } from "./settings.js";
23
+ import { resolvePluginManifest } from "./resolve-manifest.js";
24
+ export { parsePluginManifest } from "./manifest.js";
25
+ export { discoverCcPluginRoots, resolveClaudeHome, NESTED_MANIFEST, TOP_LEVEL_MANIFEST } from "./discovery.js";
26
+ export { AgentProvider, STANDARD_AGENTS_DIR } from "./agents.js";
27
+ export { skillToolRestriction, resolveSkillExecution, forbidsInlineShell, activationFor, registerSkillPathActivator, applySkillRestriction, PROVIDER, } from "./skill-semantics.js";
28
+ /** The plugin.json file name at a plugin root (legacy / fixture path). */
29
+ export const MANIFEST_FILE = 'plugin.json';
30
+ /**
31
+ * Load a Claude Code plugin manifest and mount its components.
32
+ * @param ctx - active context carrying the component host seams.
33
+ * @param options - plugin root and optional seam overrides.
34
+ * @returns the structural report and a disposer that recalls every mount.
35
+ * @throws when the manifest itself is invalid (with the plugin path/name).
36
+ */
37
+ export async function mountCcPlugin(ctx, options) {
38
+ const root = resolve(options.root);
39
+ const resolved = resolvePluginManifest(root, options.nameHint);
40
+ const manifest = parsePluginManifest(resolved.raw, root, {
41
+ skillsReplaceDefault: resolved.skillsReplaceDefault,
42
+ });
43
+ const probed = await probeSeams(ctx, options.seams);
44
+ const disposers = [];
45
+ const components = [];
46
+ fold(components, disposers, await mountSkills({
47
+ ctx,
48
+ pluginRoot: root,
49
+ manifest,
50
+ skills: probed.skills,
51
+ subagentsPresent: probed.subagents !== undefined,
52
+ }));
53
+ fold(components, disposers, await mountAgents({
54
+ pluginRoot: root,
55
+ manifest,
56
+ subagents: probed.subagents,
57
+ ...options.resolveModel !== undefined ? { resolveModel: options.resolveModel } : {},
58
+ }));
59
+ const commandMount = mountCommands({ pluginRoot: root, manifest, commands: probed.commands });
60
+ components.push(commandMount.tally.result());
61
+ disposers.push(...commandMount.disposers);
62
+ fold(components, disposers, mountHooks({ pluginRoot: root, manifest, hooks: probed.hooks }));
63
+ fold(components, disposers, mountMcpServers({ pluginRoot: root, manifest, mcp: probed.mcp }));
64
+ fold(components, disposers, mountSettings({ manifest, settings: probed.settings }));
65
+ const tearDown = () => {
66
+ for (const dispose of disposers)
67
+ dispose();
68
+ };
69
+ const effectDisposer = ctx.effect(() => tearDown, 'cc-plugin-loader.mount');
70
+ return {
71
+ report: { name: manifest.name, components },
72
+ commands: commandMount.mounted,
73
+ dispose: () => effectDisposer(),
74
+ };
75
+ }
76
+ /** Probe each component host seam, preferring explicit overrides. */
77
+ async function probeSeams(ctx, overrides) {
78
+ return {
79
+ skills: overrides?.skills ?? ctx.get('skills'),
80
+ subagents: overrides?.subagents ?? ctx.get('subagents'),
81
+ commands: overrides?.commands ?? ctx.get('commands'),
82
+ settings: overrides?.settings ?? ctx.get('settings'),
83
+ hooks: overrides?.hooks ?? ctx.get('hooks'),
84
+ mcp: overrides?.mcp ?? ctx.get('mcp'),
85
+ };
86
+ }
87
+ /** Fold one component mount into the report and disposer list. */
88
+ function fold(components, disposers, mount) {
89
+ components.push(mount.tally.result());
90
+ disposers.push(...mount.disposers);
91
+ }
92
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Parse the Claude Code `plugin.json` manifest subset this loader consumes.
3
+ *
4
+ * Validation happens on the raw manifest object at load time: a malformed
5
+ * manifest (wrong types, a blank or space-containing plugin name, an unreadable
6
+ * file) throws with the plugin name so the failure is actionable. Component
7
+ * fields accept the union shapes Claude Code allows (single path, array, or
8
+ * object map for commands) and are normalized to the loader's typed view.
9
+ * Unknown top-level fields are ignored, matching Claude Code's tolerant
10
+ * top-level handling.
11
+ *
12
+ * @module
13
+ */
14
+ import type { CcPluginManifest } from './types.ts';
15
+ /** Extra flags the resolver threads in (not authored in plugin.json). */
16
+ export interface ParsePluginManifestOptions {
17
+ /** Marketplace-root overlay: listed `skills` replace the default `skills/` scan. */
18
+ readonly skillsReplaceDefault?: boolean;
19
+ }
20
+ /**
21
+ * Validate a raw `plugin.json` object into the loader's typed manifest subset.
22
+ * @param raw - the parsed JSON contents of `plugin.json`.
23
+ * @param source - the plugin name or path used to prefix validation errors.
24
+ * @param options - resolver flags that are not authored in the JSON.
25
+ * @returns the normalized manifest subset.
26
+ * @throws when the manifest is structurally invalid.
27
+ */
28
+ export declare function parsePluginManifest(raw: unknown, source: string, options?: ParsePluginManifestOptions): CcPluginManifest;
29
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAA0B,MAAM,YAAY,CAAA;AAE1E,yEAAyE;AACzE,MAAM,WAAW,0BAA0B;IACzC,oFAAoF;IACpF,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAA;CACxC;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,0BAA+B,GACvC,gBAAgB,CAyBlB"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Parse the Claude Code `plugin.json` manifest subset this loader consumes.
3
+ *
4
+ * Validation happens on the raw manifest object at load time: a malformed
5
+ * manifest (wrong types, a blank or space-containing plugin name, an unreadable
6
+ * file) throws with the plugin name so the failure is actionable. Component
7
+ * fields accept the union shapes Claude Code allows (single path, array, or
8
+ * object map for commands) and are normalized to the loader's typed view.
9
+ * Unknown top-level fields are ignored, matching Claude Code's tolerant
10
+ * top-level handling.
11
+ *
12
+ * @module
13
+ */
14
+ /**
15
+ * Validate a raw `plugin.json` object into the loader's typed manifest subset.
16
+ * @param raw - the parsed JSON contents of `plugin.json`.
17
+ * @param source - the plugin name or path used to prefix validation errors.
18
+ * @param options - resolver flags that are not authored in the JSON.
19
+ * @returns the normalized manifest subset.
20
+ * @throws when the manifest is structurally invalid.
21
+ */
22
+ export function parsePluginManifest(raw, source, options = {}) {
23
+ if (!isRecord(raw)) {
24
+ throw new Error(`plugin ${source}: manifest must be a JSON object`);
25
+ }
26
+ const name = readName(raw['name'], source);
27
+ const commands = normalizeCommands(raw['commands'], name);
28
+ const agents = normalizeStringList(raw['agents'], name, 'agents');
29
+ const skills = normalizeStringList(raw['skills'], name, 'skills');
30
+ const { mcpServers, mcpServersPath } = normalizeMcpServers(raw['mcpServers'], name);
31
+ const settings = isRecord(raw['settings']) ? raw['settings'] : {};
32
+ return {
33
+ name,
34
+ ...typeof raw['version'] === 'string' ? { version: raw['version'] } : {},
35
+ ...typeof raw['description'] === 'string' ? { description: raw['description'] } : {},
36
+ ...raw['author'] !== undefined ? { author: raw['author'] } : {},
37
+ commands,
38
+ commandsDeclared: raw['commands'] !== undefined,
39
+ agents,
40
+ skills,
41
+ skillsReplaceDefault: options.skillsReplaceDefault === true,
42
+ ...raw['hooks'] !== undefined ? { hooks: raw['hooks'] } : {},
43
+ mcpServers,
44
+ ...mcpServersPath !== undefined ? { mcpServersPath } : {},
45
+ settings,
46
+ };
47
+ }
48
+ /** Require and validate the mandatory plugin `name`. */
49
+ function readName(raw, source) {
50
+ if (typeof raw !== 'string' || raw.length === 0) {
51
+ throw new Error(`plugin ${source}: "name" must be a non-empty string`);
52
+ }
53
+ if (raw.includes(' ')) {
54
+ throw new Error(`plugin ${raw}: "name" cannot contain spaces; use kebab-case`);
55
+ }
56
+ return raw;
57
+ }
58
+ function normalizeCommands(raw, name) {
59
+ if (raw === undefined)
60
+ return [];
61
+ if (typeof raw === 'string')
62
+ return [{ name, source: raw }];
63
+ if (isStringArray(raw))
64
+ return raw.map(path => ({ name, source: path }));
65
+ if (isRecord(raw)) {
66
+ return Object.entries(raw).map(([commandName, meta]) => {
67
+ if (!isRecord(meta))
68
+ throw new Error(`plugin ${name}: command "${commandName}" must be an object`);
69
+ const entry = commandEntry(meta, name, commandName);
70
+ return { name: commandName, ...entry };
71
+ });
72
+ }
73
+ throw new Error(`plugin ${name}: "commands" must be a path, a list, or an object map`);
74
+ }
75
+ /** Validate one inline command metadata record; `source` and `content` are exclusive. */
76
+ function commandEntry(meta, name, commandName) {
77
+ const hasSource = typeof meta['source'] === 'string';
78
+ const hasContent = typeof meta['content'] === 'string';
79
+ if (hasSource === hasContent) {
80
+ throw new Error(`plugin ${name}: command "${commandName}" must provide exactly one of "source" (path) or "content" (inline)`);
81
+ }
82
+ const entry = {};
83
+ if (hasSource)
84
+ entry.source = meta['source'];
85
+ if (hasContent)
86
+ entry.content = meta['content'];
87
+ for (const key of ['description', 'argumentHint', 'model']) {
88
+ if (typeof meta[key] === 'string')
89
+ entry[key] = meta[key];
90
+ }
91
+ if (Array.isArray(meta['allowedTools'])) {
92
+ entry.allowedTools = meta['allowedTools'];
93
+ }
94
+ return entry;
95
+ }
96
+ function normalizeStringList(raw, name, field) {
97
+ if (raw === undefined)
98
+ return [];
99
+ if (typeof raw === 'string')
100
+ return [raw];
101
+ if (isStringArray(raw))
102
+ return [...raw];
103
+ throw new Error(`plugin ${name}: "${field}" must be a path or a list of paths`);
104
+ }
105
+ function normalizeMcpServers(raw, name) {
106
+ if (raw === undefined)
107
+ return { mcpServers: {} };
108
+ if (typeof raw === 'string')
109
+ return { mcpServers: {}, mcpServersPath: raw }; // an `.mcp.json` path
110
+ if (isRecord(raw))
111
+ return { mcpServers: raw };
112
+ throw new Error(`plugin ${name}: "mcpServers" must be a path or an object map of server configs`);
113
+ }
114
+ function isRecord(value) {
115
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
116
+ }
117
+ function isStringArray(value) {
118
+ return Array.isArray(value) && value.every(item => typeof item === 'string');
119
+ }
120
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"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"}
package/lib/mcp.d.ts ADDED
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Mount a Claude Code plugin's MCP servers.
3
+ *
4
+ * Collects server definitions from the manifest inline `mcpServers` record or
5
+ * an `.mcp.json` file, then registers each through the optional `mcp` guest
6
+ * seam. Tool naming (`mcp__<server>__<tool>`) is the seam's responsibility.
7
+ * When the seam is absent the component is reported skipped, never failed.
8
+ *
9
+ * @module
10
+ */
11
+ import type { CcPluginManifest } from './types.ts';
12
+ import { ComponentTally } from './seams.ts';
13
+ /** The MCP seam: registers a named server for tool discovery. */
14
+ export interface McpSeam {
15
+ /**
16
+ * Register one MCP server.
17
+ * @param name - unique server name.
18
+ * @param config - server transport configuration.
19
+ * @returns the exact disposer that unregisters the server.
20
+ */
21
+ registerServer(name: string, config: Record<string, unknown>): () => void;
22
+ }
23
+ /** Options for mounting one plugin's MCP servers. */
24
+ export interface MountMcpServersOptions {
25
+ /** The plugin root directory; an `.mcp.json` path resolves against it. */
26
+ readonly pluginRoot: string;
27
+ /** The parsed manifest; `mcpServers` and `mcpServersPath` drive the mount. */
28
+ readonly manifest: CcPluginManifest;
29
+ /** The mcp seam (probed; `undefined` to skip mcpServers). */
30
+ readonly mcp: McpSeam | undefined;
31
+ }
32
+ /**
33
+ * Collect and register a plugin's MCP servers through the optional seam.
34
+ * @param options - plugin root, manifest, and the mcp seam.
35
+ * @returns mounted disposers and per-component counts.
36
+ */
37
+ export declare function mountMcpServers(options: MountMcpServersOptions): {
38
+ disposers: (() => void)[];
39
+ tally: ComponentTally;
40
+ };
41
+ //# sourceMappingURL=mcp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAE3C,iEAAiE;AACjE,MAAM,WAAW,OAAO;IACtB;;;;;OAKG;IACH,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,IAAI,CAAA;CAC1E;AAED,qDAAqD;AACrD,MAAM,WAAW,sBAAsB;IACrC,0EAA0E;IAC1E,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,8EAA8E;IAC9E,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAA;IACnC,6DAA6D;IAC7D,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,SAAS,CAAA;CAClC;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG;IAAE,SAAS,EAAE,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;IAAC,KAAK,EAAE,cAAc,CAAA;CAAE,CAkBrH"}
package/lib/mcp.js ADDED
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Mount a Claude Code plugin's MCP servers.
3
+ *
4
+ * Collects server definitions from the manifest inline `mcpServers` record or
5
+ * an `.mcp.json` file, then registers each through the optional `mcp` guest
6
+ * seam. Tool naming (`mcp__<server>__<tool>`) is the seam's responsibility.
7
+ * When the seam is absent the component is reported skipped, never failed.
8
+ *
9
+ * @module
10
+ */
11
+ import { readFileSync } from 'node:fs';
12
+ import { resolve } from 'node:path';
13
+ import { ComponentTally } from "./seams.js";
14
+ /**
15
+ * Collect and register a plugin's MCP servers through the optional seam.
16
+ * @param options - plugin root, manifest, and the mcp seam.
17
+ * @returns mounted disposers and per-component counts.
18
+ */
19
+ export function mountMcpServers(options) {
20
+ const tally = new ComponentTally('mcpServers');
21
+ const disposers = [];
22
+ if (options.mcp === undefined) {
23
+ tally.addSkipped('mcp seam "mcp" is not mounted');
24
+ return { disposers, tally };
25
+ }
26
+ const servers = collectServers(options.pluginRoot, options.manifest);
27
+ const entries = Object.entries(servers);
28
+ if (entries.length === 0) {
29
+ tally.addSkipped('plugin declares no MCP servers');
30
+ return { disposers, tally };
31
+ }
32
+ for (const [name, config] of entries) {
33
+ disposers.push(options.mcp.registerServer(name, config));
34
+ tally.addLoaded();
35
+ }
36
+ return { disposers, tally };
37
+ }
38
+ /** Combine inline and file-backed MCP server definitions. */
39
+ function collectServers(pluginRoot, manifest) {
40
+ const servers = {};
41
+ if (manifest.mcpServersPath !== undefined) {
42
+ const path = resolve(pluginRoot, manifest.mcpServersPath);
43
+ Object.assign(servers, readMcpJson(path));
44
+ }
45
+ for (const [name, config] of Object.entries(manifest.mcpServers)) {
46
+ servers[name] = config;
47
+ }
48
+ return servers;
49
+ }
50
+ /** Read an `.mcp.json` file's `mcpServers` key (absent/invalid yields none). */
51
+ function readMcpJson(path) {
52
+ try {
53
+ const parsed = JSON.parse(readFileSync(path, 'utf8'));
54
+ const servers = parsed['mcpServers'];
55
+ if (typeof servers === 'object' && servers !== null && !Array.isArray(servers)) {
56
+ return servers;
57
+ }
58
+ return {};
59
+ }
60
+ catch {
61
+ return {};
62
+ }
63
+ }
64
+ //# sourceMappingURL=mcp.js.map
package/lib/mcp.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEnC,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAuB3C;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,OAA+B;IAC7D,MAAM,KAAK,GAAG,IAAI,cAAc,CAAC,YAAY,CAAC,CAAA;IAC9C,MAAM,SAAS,GAAmB,EAAE,CAAA;IACpC,IAAI,OAAO,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;QAC9B,KAAK,CAAC,UAAU,CAAC,+BAA+B,CAAC,CAAA;QACjD,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAA;IAC7B,CAAC;IACD,MAAM,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;IACpE,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IACvC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,KAAK,CAAC,UAAU,CAAC,gCAAgC,CAAC,CAAA;QAClD,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAA;IAC7B,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACrC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;QACxD,KAAK,CAAC,SAAS,EAAE,CAAA;IACnB,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAA;AAC7B,CAAC;AAED,6DAA6D;AAC7D,SAAS,cAAc,CAAC,UAAkB,EAAE,QAA0B;IACpE,MAAM,OAAO,GAA4C,EAAE,CAAA;IAC3D,IAAI,QAAQ,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;QAC1C,MAAM,IAAI,GAAG,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAA;QACzD,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,CAAA;IAC3C,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QACjE,OAAO,CAAC,IAAI,CAAC,GAAG,MAAiC,CAAA;IACnD,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,gFAAgF;AAChF,SAAS,WAAW,CAAC,IAAY;IAC/B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAA4B,CAAA;QAChF,MAAM,OAAO,GAAG,MAAM,CAAC,YAAY,CAAC,CAAA;QACpC,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YAC/E,OAAO,OAAkD,CAAA;QAC3D,CAAC;QACD,OAAO,EAAE,CAAA;IACX,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAA;IACX,CAAC;AACH,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Resolve the raw JSON a plugin root should load as its manifest.
3
+ *
4
+ * Preference: `.claude-plugin/plugin.json`, then top-level `plugin.json`, then
5
+ * a matching `marketplace.json` overlay (requires `nameHint`), then a
6
+ * synthesized `{ name }` so a truly optional manifest still mounts default
7
+ * component dirs. A marketplace file with no matching entry is a hard miss —
8
+ * never fall through to synthesis (that would load the whole skills repo).
9
+ *
10
+ * @module
11
+ */
12
+ /** Resolved raw manifest plus the marketplace replace-default flag. */
13
+ export interface ResolvedPluginManifest {
14
+ /** JSON object to feed `parsePluginManifest`. */
15
+ readonly raw: unknown;
16
+ /** When true, listed `skills` replace the default `skills/` scan. */
17
+ readonly skillsReplaceDefault: boolean;
18
+ }
19
+ /**
20
+ * Locate and return the raw manifest for one plugin root.
21
+ * @param root - plugin root directory.
22
+ * @param nameHint - installed plugin name (no `@marketplace`), for overlays.
23
+ * @returns the raw JSON and whether skills should replace the default dir.
24
+ * @throws when a present file is unreadable/invalid, or a marketplace overlay misses `nameHint`.
25
+ */
26
+ export declare function resolvePluginManifest(root: string, nameHint?: string): ResolvedPluginManifest;
27
+ //# sourceMappingURL=resolve-manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-manifest.d.ts","sourceRoot":"","sources":["../src/resolve-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AASH,uEAAuE;AACvE,MAAM,WAAW,sBAAsB;IACrC,iDAAiD;IACjD,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAA;IACrB,qEAAqE;IACrE,QAAQ,CAAC,oBAAoB,EAAE,OAAO,CAAA;CACvC;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,sBAAsB,CAS7F"}