/** * Plugin manifest types and the format-dispatching parse entry point. * * A "plugin" is a directory that bundles agent capabilities (skills, commands, * agents/modes, themes, providers, hooks, MCP servers) behind a single manifest. * Several vendor formats are supported and parsed into one {@link NormalizedPlugin}: * * - `.agents-plugin/plugin.json` — native format (a strict superset) * - `.claude-plugin/plugin.json` — Claude Code compatible format * - `.github/copilot-plugin.json` — GitHub Copilot format (`.github/` layout) * * The per-format detect/parse/emit logic lives in {@link ./formats}, one adapter * per vendor, behind the {@link PluginFormatAdapter} contract — so this module * carries only the shared types and delegates directory parsing to the registry. * When a directory carries more than one format, the highest-precedence one wins * (native > Claude > Copilot; no merge). */ import type { ProviderConfig } from "../types.js"; import type { MarketplacePlatform } from "./formats/types.js"; /** A single shell command invoked by a hook. */ export interface PluginHookCommand { type?: "command"; command: string; /** Timeout in seconds (Claude Code convention). */ timeout?: number; } /** A matcher group: run these commands when `matcher` matches. */ export interface PluginHookMatcherGroup { /** Regex string matched against the tool name. Empty / "*" matches everything. */ matcher?: string; hooks: PluginHookCommand[]; } /** * Hook event map keyed by Claude Code event name * (PreToolUse, PostToolUse, UserPromptSubmit, SessionStart, Stop, ...). */ export type PluginHooksConfig = Record; /** A provider contributed by a native plugin (config-only; uses a built-in API handler). */ export interface PluginProvider { name: string; config: ProviderConfig; } /** One canvas extension shipped inside a plugin: its id and the directory holding `extension.mjs`. */ export interface PluginCanvasExtension { /** Directory name, or the plugin id when the plugin root is itself the extension. */ id: string; /** Absolute path to the extension directory. */ dir: string; } /** Normalized, format-agnostic representation of a plugin. */ export interface NormalizedPlugin { /** Stable identifier (manifest `name`). */ id: string; version?: string; description?: string; author?: string; /** Absolute path to the plugin root directory. */ root: string; /** Absolute path to the parsed manifest file. */ manifestPath: string; /** Which manifest format produced this plugin (the precedence winner). */ format: "agents" | "claude" | "copilot"; /** * Every platform this plugin directory offers. When a directory carries more * than one format manifest (e.g. both `.claude-plugin/` and `.github/`), all * are recorded here — the precedence winner's platform first — rather than * hidden behind the single `format`. Always non-empty (at least `format`'s * platform), mirroring the marketplace's `supportPlatform`. */ supportPlatform: MarketplacePlatform[]; /** Resolved capability directories (only set when they exist on disk). */ skillsDir?: string; commandsDir?: string; agentsDir?: string; themesDir?: string; /** Parsed hooks (from `hooks/hooks.json` or inline `hooks`). */ hooks?: PluginHooksConfig; /** Parsed MCP servers (from `.mcp.json` or inline `mcpServers`); connected via the MCP registry. */ mcpServers?: Record; /** Native-only: providers to register. */ providers?: PluginProvider[]; /** * Canvas extensions this plugin ships, resolved to their directories. * * Unlike every other capability here this one is not loaded into the session: * a canvas has no passive half (see `docs/canvas-extensions-design.md` §5.1), * so the plugin contributes *search roots* that `/canvas` lists and opens on * demand rather than anything that runs at load. Resolving them at parse time * is what lets `ListPlugins`, the install summary and `/canvas` all agree on * what a plugin actually brought. */ canvasExtensions?: PluginCanvasExtension[]; /** * Manifest keys this adapter does not model, preserved verbatim. * * Load-bearing, not diagnostic: an edit re-emits the manifest, so anything not * carried here is silently dropped from a plugin we did not write in full. * Vendor schemas grow independently of ours (Copilot has `extensions` and * `lspServers`; Claude keeps adding component keys), and losing one on a * plugin destined for someone else's ecosystem is worse than failing to read * it. */ unknownFields?: Record; /** * On-disk surfaces present but unhandled, e.g. `[".lsp.json", "monitors/"]`. * Reported rather than implemented: the files stay on disk untouched, and * `ListPlugins` says so, which turns the next round of vendor drift into a * visible signal instead of a silent gap. */ unsupportedSurfaces?: string[]; } /** * Parse and normalize a single plugin directory. * Returns null if no recognized manifest is present or it is invalid. * * Delegates to the format registry; see {@link ./formats/index.ts}. */ export declare function parsePluginDir(root: string, options?: { requireManifest?: boolean; }): NormalizedPlugin | null; //# sourceMappingURL=manifest.d.ts.map