zidane 7.0.32 → 7.1.3
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 +19 -0
- package/dist/{acp-bBDF-dhy.js → acp-B5UfEhMd.js} +4 -4
- package/dist/{acp-bBDF-dhy.js.map → acp-B5UfEhMd.js.map} +1 -1
- package/dist/acp-cli.js +6 -6
- package/dist/acp.d.ts +2 -2
- package/dist/acp.js +1 -1
- package/dist/{agent-BCG9JcZl.js → agent-_xxElOgH.js} +162 -18
- package/dist/agent-_xxElOgH.js.map +1 -0
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +1 -1
- package/dist/{anthropic-B4UmPm4H.js → anthropic-DPPs3wjJ.js} +111 -7
- package/dist/anthropic-DPPs3wjJ.js.map +1 -0
- package/dist/{approvals-DkwGBMZ9.js → approvals-u2T19Dc-.js} +275 -88
- package/dist/approvals-u2T19Dc-.js.map +1 -0
- package/dist/{auth-D0BHBb02.js → auth-HRKkOErn.js} +3 -3
- package/dist/{auth-D0BHBb02.js.map → auth-HRKkOErn.js.map} +1 -1
- package/dist/chat/pure.d.ts +3 -3
- package/dist/chat/pure.js +1 -1
- package/dist/chat.d.ts +6 -6
- package/dist/chat.js +8 -8
- package/dist/contexts/daytona.d.ts +3 -3
- package/dist/contexts/docker.d.ts +1 -1
- package/dist/contexts/e2b.d.ts +2 -2
- package/dist/contexts/sandbox.d.ts +1 -1
- package/dist/{contexts-BSFQVclW.js → contexts-CRE9pw07.js} +544 -17
- package/dist/contexts-CRE9pw07.js.map +1 -0
- package/dist/contexts.d.ts +4 -4
- package/dist/contexts.js +2 -2
- package/dist/daemon-cli.js +1 -1
- package/dist/eval.d.ts +1 -1
- package/dist/eval.js +3 -3
- package/dist/extensions.d.ts +1 -1
- package/dist/extensions.js +1 -1
- package/dist/headless.d.ts +1 -1
- package/dist/headless.js +3 -3
- package/dist/{index-B6FkK6ZN.d.ts → index-C37_ppWv.d.ts} +2 -2
- package/dist/index-C37_ppWv.d.ts.map +1 -0
- package/dist/{index-Ogi2CeHf.d.ts → index-D3TTaaQ5.d.ts} +20 -7
- package/dist/index-D3TTaaQ5.d.ts.map +1 -0
- package/dist/{index-CCB05-JZ.d.ts → index-DZhrTn-v.d.ts} +259 -12
- package/dist/index-DZhrTn-v.d.ts.map +1 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.js +8 -8
- package/dist/{ipc-C10lnS-a.js → ipc-ChQeueur.js} +3 -3
- package/dist/{ipc-C10lnS-a.js.map → ipc-ChQeueur.js.map} +1 -1
- package/dist/ipc.d.ts +5 -5
- package/dist/ipc.js +3 -3
- package/dist/{types-U-rIVUDw.d.ts → isolation-Kfoof0MM.d.ts} +93 -2
- package/dist/isolation-Kfoof0MM.d.ts.map +1 -0
- package/dist/mcp.d.ts +1 -1
- package/dist/output/stream-json.d.ts +1 -1
- package/dist/output/terminal.d.ts +1 -1
- package/dist/{plugins-B531Tz5b.js → plugins-gbI7SBA6.js} +3 -3
- package/dist/{plugins-B531Tz5b.js.map → plugins-gbI7SBA6.js.map} +1 -1
- package/dist/plugins.d.ts +1 -1
- package/dist/plugins.js +1 -1
- package/dist/presets.d.ts +1 -1
- package/dist/presets.js +1 -1
- package/dist/providers/anthropic.d.ts +2 -2
- package/dist/providers/anthropic.js +2 -2
- package/dist/providers/arcee.d.ts +1 -1
- package/dist/providers/baseten.d.ts +1 -1
- package/dist/providers/cerebras.d.ts +1 -1
- package/dist/providers/local.d.ts +1 -1
- package/dist/providers/openai-compat.d.ts +1 -1
- package/dist/providers/openai.d.ts +1 -1
- package/dist/providers/openrouter.d.ts +1 -1
- package/dist/providers/xai.d.ts +1 -1
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +1 -1
- package/dist/restate.d.ts +2 -2
- package/dist/restate.js +1 -1
- package/dist/{sandbox-CDl9tfTo.d.ts → sandbox-BH0WQkXn.d.ts} +2 -2
- package/dist/{sandbox-CDl9tfTo.d.ts.map → sandbox-BH0WQkXn.d.ts.map} +1 -1
- package/dist/{server--mwNA7oC.js → server-CTUpOdh3.js} +8 -8
- package/dist/{server--mwNA7oC.js.map → server-CTUpOdh3.js.map} +1 -1
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/session/sqlite.d.ts.map +1 -1
- package/dist/session/sqlite.js +7 -0
- package/dist/session/sqlite.js.map +1 -1
- package/dist/{session-CVy-2mAy.js → session-BqRP1hS7.js} +33 -3
- package/dist/session-BqRP1hS7.js.map +1 -0
- package/dist/session.d.ts +1 -1
- package/dist/session.js +1 -1
- package/dist/{skills-PJyiSRCp.js → skills-BC3dodWp.js} +2 -2
- package/dist/{skills-PJyiSRCp.js.map → skills-BC3dodWp.js.map} +1 -1
- package/dist/skills.d.ts +1 -1
- package/dist/skills.js +1 -1
- package/dist/{src-CjkY6fBj.js → src-CkNQKFKr.js} +3 -3
- package/dist/{src-CjkY6fBj.js.map → src-CkNQKFKr.js.map} +1 -1
- package/dist/{tool-formatters-Bu4repDJ.d.ts → tool-formatters-C5s88MUd.d.ts} +2 -2
- package/dist/{tool-formatters-Bu4repDJ.d.ts.map → tool-formatters-C5s88MUd.d.ts.map} +1 -1
- package/dist/tools/fetch-url.d.ts +1 -1
- package/dist/tools/web-search.d.ts +1 -1
- package/dist/tools.d.ts +1 -1
- package/dist/tools.js +1 -1
- package/dist/{transcript-anchors-CJCxyVE-.d.ts → transcript-anchors-DxofXw_y.d.ts} +3 -3
- package/dist/transcript-anchors-DxofXw_y.d.ts.map +1 -0
- package/dist/tui.d.ts +21 -28
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +163 -69
- package/dist/tui.js.map +1 -1
- package/dist/{turn-operations-HX3g3XIc.js → turn-operations-6JDu2ewy.js} +14 -2
- package/dist/{turn-operations-HX3g3XIc.js.map → turn-operations-6JDu2ewy.js.map} +1 -1
- package/dist/{turn-operations-qcv9UFcL.d.ts → turn-operations-BaQnxzhr.d.ts} +14 -4
- package/dist/{turn-operations-qcv9UFcL.d.ts.map → turn-operations-BaQnxzhr.d.ts.map} +1 -1
- package/dist/types-CWgENVLY.js.map +1 -1
- package/dist/types.d.ts +3 -3
- package/docs/ARCHITECTURE.md +2 -1
- package/docs/CHAT.md +9 -1
- package/docs/EXECUTION_CONTEXT.md +64 -3
- package/docs/SKILL.md +28 -0
- package/docs/TUI.md +6 -5
- package/package.json +1 -1
- package/dist/agent-BCG9JcZl.js.map +0 -1
- package/dist/anthropic-B4UmPm4H.js.map +0 -1
- package/dist/approvals-DkwGBMZ9.js.map +0 -1
- package/dist/contexts-BSFQVclW.js.map +0 -1
- package/dist/index-B6FkK6ZN.d.ts.map +0 -1
- package/dist/index-CCB05-JZ.d.ts.map +0 -1
- package/dist/index-Ogi2CeHf.d.ts.map +0 -1
- package/dist/session-CVy-2mAy.js.map +0 -1
- package/dist/transcript-anchors-CJCxyVE-.d.ts.map +0 -1
- package/dist/types-U-rIVUDw.d.ts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugins-B531Tz5b.js","names":[],"sources":["../src/chat/xdg.ts","../src/plugins/boundary.ts","../src/plugins/types.ts","../src/plugins/manifest.ts","../src/plugins/mcp.ts","../src/plugins/skills.ts","../src/plugins/load.ts"],"sourcesContent":["/**\n * XDG Base Directory resolution for zidane.\n *\n * The user's storage spreads across four logical slots:\n *\n * - **config** — credentials, mcp-credentials, keybindings, config.json,\n * mcps.json, skills (user-editable surface).\n * - **data** — sessions.db (long-lived chat history).\n * - **state** — state.json (per-machine UI bookkeeping: last provider,\n * last model, last agent, settings).\n * - **cache** — persisted tool results, background-task logs,\n * auto-update registry cache (regenerable, safe to wipe).\n *\n * Historically all four collapsed to `~/.zidane/`. This module adds\n * XDG-Base-Directory-aware defaults so a Linux user with no existing\n * `~/.zidane/` lands in the conventional `~/.config/zidane/`,\n * `~/.local/share/zidane/`, `~/.local/state/zidane/`, `~/.cache/zidane/`\n * trio. Existing setups (anyone with a `~/.zidane/` directory or\n * `ZIDANE_STORAGE_DIR` set) keep the single-dir layout unchanged.\n *\n * Resolution flow — applied in this order:\n *\n * 1. Caller passed an explicit `storageDir` (`ChatOptions.storageDir`)\n * OR `ZIDANE_STORAGE_DIR` is set → **legacy-explicit** single-dir\n * layout under `<storageDir>/<prefix>`. The four slots collapse to\n * the same directory.\n * 2. `~/<prefix>/` already exists on disk → **legacy-existing**\n * single-dir layout under that directory. Upgrades never silently\n * shift files around.\n * 3. Any `XDG_*_HOME` env var is set OR `process.platform === 'linux'`\n * → **XDG split**. Each slot lands in its own dir. Per-slot\n * `ZIDANE_{CONFIG,DATA,CACHE,STATE}_DIR` overrides beat the XDG\n * vars for surgical tweaks.\n * 4. Otherwise (macOS/Windows, no XDG signal, no existing dir) →\n * **default** single-dir layout at `~/<prefix>/`. Day-one behavior\n * on these platforms is unchanged.\n *\n * The `userDir` legacy alias always equals `configDir` so existing code\n * that still references `paths.userDir` keeps reading credentials, mcps,\n * etc. from the right place.\n */\n\nimport { existsSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { resolve } from 'node:path'\n\n/** The four slot kinds we resolve. Names match the XDG spec. */\nexport type StorageSlot = 'config' | 'data' | 'state' | 'cache'\n\n/** Which resolution branch produced the layout — surfaced for debugging + tests. */\nexport type StorageMode = 'legacy-explicit' | 'legacy-existing' | 'xdg' | 'default'\n\n/**\n * Per-slot directories. In legacy / default modes the four fields all\n * point at the same path; in XDG mode they fan out into their\n * spec-conventional locations.\n *\n * `mode` carries the resolution branch so a host that wants to print\n * a startup banner (\"zidane is using XDG paths\") can detect the\n * layout without re-running the logic.\n */\nexport interface StorageDirs {\n configDir: string\n dataDir: string\n stateDir: string\n cacheDir: string\n mode: StorageMode\n}\n\nexport interface ResolveStorageDirsOptions {\n /** Storage prefix. Leading dot tolerated. Default: `'.zidane'`. */\n prefix?: string\n /**\n * Explicit storage root (`ChatOptions.storageDir`). When set, forces\n * legacy-explicit mode regardless of the platform / XDG signals.\n */\n storageDir?: string\n /** Override `os.homedir()` for tests. */\n home?: string\n /** Override `process.platform` for tests. */\n platform?: NodeJS.Platform\n /** Override `process.env` for tests. */\n env?: Readonly<Record<string, string | undefined>>\n}\n\n/**\n * Resolve the four storage slots according to the precedence above.\n *\n * Pure aside from one filesystem probe (`existsSync(home/<prefix>)`)\n * — the same probe `resolveStoragePaths` would do anyway when\n * computing `paths.userDir`. No directories are created here; the\n * relevant write paths (state store, credentials writer, persist\n * dir) handle their own lazy `mkdirSync` already.\n */\nexport function resolveStorageDirs(opts: ResolveStorageDirsOptions = {}): StorageDirs {\n const env = opts.env ?? process.env\n const home = opts.home ?? homedir()\n const platform = opts.platform ?? process.platform\n // Two prefix forms — legacy mode preserves whatever the caller\n // passed (no implicit dot insertion, so `prefix: 'myapp'` lands at\n // `<storageDir>/myapp` not `<storageDir>/.myapp` — matches the\n // pre-XDG behavior tests already rely on). XDG mode uses the de-\n // dotted form (`'.zidane'` → `'zidane'`) because the XDG dir itself\n // is already the dotfile container — `~/.config/.zidane/` would be\n // a double-dot offense.\n const rawPrefix = opts.prefix ?? '.zidane'\n const prefixBare = rawPrefix.replace(/^\\./, '')\n\n // Branch 1 — explicit storage root → legacy-explicit.\n // Host-supplied `storageDir` beats env so SDK callers can pin a\n // location for embedded usage; otherwise `ZIDANE_STORAGE_DIR` wins.\n const explicitStorageDir = opts.storageDir ?? env.ZIDANE_STORAGE_DIR\n if (explicitStorageDir) {\n const base = resolve(explicitStorageDir, rawPrefix)\n return single(base, 'legacy-explicit')\n }\n\n // Branch 2 — `~/<prefix>/` already exists → legacy-existing.\n // Detect ANY of the legacy locations the user might have:\n // - `~/.zidane/` (default prefix)\n // - `~/.<prefix>/` (custom prefix)\n // The probe is a single existsSync (cheap) and skipping it for a\n // user with a customized prefix would leak their data into XDG dirs\n // on next launch.\n const legacyHomeDir = resolve(home, rawPrefix)\n if (existsSync(legacyHomeDir))\n return single(legacyHomeDir, 'legacy-existing')\n\n // Branch 3 — XDG signals present → split layout.\n // The signal is generous: Linux always qualifies, any platform\n // where the user has set any `XDG_*_HOME` var opts in (a savvy\n // mac user can put zidane in their XDG hierarchy too), AND any\n // `ZIDANE_{CONFIG,DATA,STATE,CACHE}_DIR` per-slot override also\n // opts in — otherwise a user pinning JUST `ZIDANE_CACHE_DIR` on\n // macOS would have it silently ignored because none of the\n // `XDG_*_HOME` vars are set.\n const hasXdgSignal = platform === 'linux'\n || !!env.XDG_CONFIG_HOME\n || !!env.XDG_DATA_HOME\n || !!env.XDG_CACHE_HOME\n || !!env.XDG_STATE_HOME\n || !!env.ZIDANE_CONFIG_DIR\n || !!env.ZIDANE_DATA_DIR\n || !!env.ZIDANE_STATE_DIR\n || !!env.ZIDANE_CACHE_DIR\n\n if (hasXdgSignal) {\n return {\n configDir: env.ZIDANE_CONFIG_DIR\n ?? resolve(env.XDG_CONFIG_HOME || resolve(home, '.config'), prefixBare),\n dataDir: env.ZIDANE_DATA_DIR\n ?? resolve(env.XDG_DATA_HOME || resolve(home, '.local', 'share'), prefixBare),\n stateDir: env.ZIDANE_STATE_DIR\n ?? resolve(env.XDG_STATE_HOME || resolve(home, '.local', 'state'), prefixBare),\n cacheDir: env.ZIDANE_CACHE_DIR\n ?? resolve(env.XDG_CACHE_HOME || resolve(home, '.cache'), prefixBare),\n mode: 'xdg',\n }\n }\n\n // Branch 4 — default (mac/windows, no XDG signal, no existing dir).\n // Same as the day-one experience: everything under `~/<prefix>/`.\n return single(legacyHomeDir, 'default')\n}\n\nfunction single(base: string, mode: StorageMode): StorageDirs {\n return {\n configDir: base,\n dataDir: base,\n stateDir: base,\n cacheDir: base,\n mode,\n }\n}\n","/**\n * The Agent Plugins package boundary.\n *\n * The spec's central filesystem rule: \"Every package file a client\n * discovers, reads, or executes must remain inside the filesystem-resolved\n * root after resolving symlinks, junctions, reparse points, and equivalent\n * mechanisms.\"\n *\n * Lexical containment (`../skills/validate.ts`'s `validateResourcePath`) is\n * NOT sufficient here — a `skills` symlink pointing at `~/.ssh` passes every\n * lexical check. So each package path is resolved through `realpath` and\n * re-tested against the realpath-resolved root, and the required filesystem\n * kind is asserted with a symlink-FOLLOWING `stat` (the spec wants\n * `SKILL.md` to be a regular file, not a fifo or a directory wearing the\n * name).\n *\n * Containment is tested with `path.relative` rather than a string prefix so\n * `/plugin-root` vs `/plugin-root-evil` can't be confused and Windows\n * separators are handled by the platform.\n */\n\nimport { realpath, stat } from 'node:fs/promises'\nimport { isAbsolute, relative, resolve } from 'node:path'\n\n/**\n * A resolved plugin root. Hold one of these for the lifetime of a load and\n * pass it to every path check, so `realpath(root)` is paid once rather than\n * per package file.\n */\nexport interface PluginBoundary {\n /** Plugin root as requested, made absolute (symlinks NOT resolved). */\n dir: string\n /** Symlink-resolved plugin root. The boundary every package path is tested against. */\n root: string\n}\n\n/**\n * Why a package path is unusable.\n *\n * - `missing` the path does not exist. Often benign (a missing fixed\n * location is valid per spec), so callers decide severity.\n * - `escaped` the path resolved outside the plugin root.\n * - `wrong-kind` the path exists but is not the required filesystem kind.\n */\nexport type PackagePathFailure = 'missing' | 'escaped' | 'wrong-kind'\n\nexport type PackagePathResult\n = | { ok: true, real: string }\n | { ok: false, reason: PackagePathFailure }\n\n/** Filesystem kind a package path is required to have. */\nexport type PackagePathKind = 'file' | 'directory'\n\n/**\n * Resolve the plugin root itself. Returns `null` when the root does not\n * exist or is not a directory — the caller turns that into a plugin-level\n * rejection, since there is nothing to load.\n */\nexport async function resolvePluginBoundary(dir: string): Promise<PluginBoundary | null> {\n const absolute = resolve(dir)\n try {\n const root = await realpath(absolute)\n if (!(await stat(root)).isDirectory())\n return null\n return { dir: absolute, root }\n }\n catch {\n return null\n }\n}\n\n/**\n * True when `real` (an already symlink-resolved path) lives at or under\n * `root` (likewise resolved).\n */\nexport function isWithin(root: string, real: string): boolean {\n const rel = relative(root, real)\n // `''` is the root itself; a `..` lead or an absolute result means the\n // target sits outside (the latter happens across Windows drives).\n return rel === '' || (!rel.startsWith('..') && !isAbsolute(rel))\n}\n\n/**\n * Symlink-resolve `target` and confirm it stays inside the boundary.\n *\n * Use this for paths whose filesystem kind doesn't matter or that may not\n * exist yet (Phase 3's `cwd` handling); otherwise prefer\n * {@link resolvePackagePath}, which also asserts the kind.\n */\nexport async function realPathWithin(\n boundary: PluginBoundary,\n target: string,\n): Promise<PackagePathResult> {\n let real: string\n try {\n real = await realpath(target)\n }\n catch {\n return { ok: false, reason: 'missing' }\n }\n if (!isWithin(boundary.root, real))\n return { ok: false, reason: 'escaped' }\n return { ok: true, real }\n}\n\n/**\n * Resolve a package path and assert its filesystem kind.\n *\n * `stat` (not `lstat`) is deliberate: a symlink to a regular file INSIDE the\n * root is legitimate packaging, and containment is already enforced against\n * the resolved target. What we reject is the kind mismatch the spec calls\n * out — `skills` as a regular file, `SKILL.md` as a directory or a fifo.\n */\nexport async function resolvePackagePath(\n boundary: PluginBoundary,\n target: string,\n kind: PackagePathKind,\n): Promise<PackagePathResult> {\n const within = await realPathWithin(boundary, target)\n if (!within.ok)\n return within\n try {\n const info = await stat(within.real)\n const matches = kind === 'directory' ? info.isDirectory() : info.isFile()\n if (!matches)\n return { ok: false, reason: 'wrong-kind' }\n }\n catch {\n // Raced away between realpath and stat.\n return { ok: false, reason: 'missing' }\n }\n return within\n}\n","/**\n * Types for the Agent Plugins loader.\n *\n * Implements the Agent Plugins open standard (agent-plugins.org) — a\n * portable package format that places reusable agent components at fixed\n * locations inside a plugin root:\n *\n * plugin.json the closed manifest (identity + metadata)\n * skills/ immediate child dirs holding an Agent Skills `SKILL.md`\n * mcp.json one MCP server configuration document\n *\n * Agent Plugins deliberately does NOT redefine either component format —\n * skills are Agent Skills, MCP config is MCP config. So this module owns\n * only the packaging contract: manifest validation, the filesystem\n * boundary, fixed-location discovery, and the failure-isolation ladder.\n * The component formats themselves route through the existing loaders\n * (`../skills/discovery`, `../mcp`), which is why `LoadedPlugin` hands\n * back plain `SkillConfig` / `McpServerConfig` values that every\n * downstream consumer already understands.\n *\n * Validation here is STRICT, unlike `../skills/discovery` (lenient by\n * design) and `normalizeMcpServers` (heuristic by design). The spec\n * mandates closed schemas with narrow failure boundaries; a plugin is a\n * third-party package, so \"guess what the author meant\" is the wrong\n * default. Leniency is reserved for the two violations the spec\n * explicitly marks non-fatal (see `./manifest`).\n */\n\nimport type { McpServerConfig } from '../mcp'\nimport type { SkillConfig, SkillSource } from '../skills'\n\n// ---------------------------------------------------------------------------\n// Spec versions\n// ---------------------------------------------------------------------------\n\n/**\n * Agent Plugins spec versions this loader implements, newest first.\n *\n * The spec requires clients to select validation rules from the manifest's\n * `$schema` WITHOUT retrieving it, and to let plugins keep targeting older\n * versions under a locally supported compatibility policy. Our policy: a\n * version is supported iff it appears in this list. Adding `1.1.0` later\n * means adding it here plus any rule deltas in `./manifest` — never\n * reinterpreting an already-published identifier, which the spec forbids.\n */\nexport const SUPPORTED_AGENT_PLUGINS_VERSIONS = ['1.0.0'] as const\n\nexport type AgentPluginsVersion = typeof SUPPORTED_AGENT_PLUGINS_VERSIONS[number]\n\n/** Which canonical schema a `$schema` identifier selects. */\nexport type PluginSchemaKind = 'plugin' | 'mcp'\n\n/**\n * Canonical schema identifier for a given document kind + version. Built\n * rather than hardcoded so the two call sites (manifest, mcp.json) can't\n * drift, and so the version cross-check the spec requires between\n * `plugin.json` and `mcp.json` is a plain string comparison.\n */\nexport function agentPluginsSchemaId(kind: PluginSchemaKind, version: string): string {\n return `https://agent-plugins.org/schemas/${version}/${kind}.schema.json`\n}\n\n/**\n * Canonical schema identifier grammar. Anchored and exact — a `$schema`\n * that merely looks similar (http, a trailing slash, a different host) is\n * not the canonical identifier and must not select the contract.\n */\nconst SCHEMA_ID_RE = /^https:\\/\\/agent-plugins\\.org\\/schemas\\/([^/]+)\\/(plugin|mcp)\\.schema\\.json$/\n\n/**\n * Split a canonical `$schema` identifier into its document kind + version.\n * Returns `null` for anything that isn't a canonical identifier; the caller\n * decides whether that's fatal (manifest) or component-scoped (mcp.json).\n *\n * Purely syntactic: it never fetches. The spec forbids retrieving a schema\n * during load, so version support is a lookup against\n * {@link SUPPORTED_AGENT_PLUGINS_VERSIONS}, not a download.\n */\nexport function parseSchemaId(value: string): { kind: PluginSchemaKind, version: string } | null {\n const match = SCHEMA_ID_RE.exec(value)\n if (!match)\n return null\n return { kind: match[2] as PluginSchemaKind, version: match[1]! }\n}\n\n/** True when this loader implements the given Agent Plugins version. */\nexport function isSupportedAgentPluginsVersion(version: string): version is AgentPluginsVersion {\n return (SUPPORTED_AGENT_PLUGINS_VERSIONS as readonly string[]).includes(version)\n}\n\n/**\n * Type label for a rejected JSON value, for diagnostic messages.\n *\n * `typeof` alone is useless in a validator that has to tell an author what\n * they got wrong: `null` and `[]` both report `'object'`, and those are two of\n * the most common mistakes in a hand-written manifest. Shared by the manifest\n * and `mcp.json` validators, which produce the same class of message.\n *\n * Internal — not re-exported from the module barrel.\n */\nexport function describeJsonType(value: unknown): string {\n if (value === null)\n return 'null'\n if (Array.isArray(value))\n return 'array'\n return typeof value\n}\n\n// ---------------------------------------------------------------------------\n// Manifest\n// ---------------------------------------------------------------------------\n\n/** Optional author block. Closed: only these three keys, all strings. */\nexport interface PluginAuthor {\n name?: string\n email?: string\n url?: string\n}\n\n/**\n * A validated `plugin.json`. Only spec fields survive validation —\n * unknown top-level keys are reported and dropped, so consumers can\n * never accidentally depend on a non-portable field.\n *\n * `version` here is the PLUGIN's own version string; the spec version\n * selected by `$schema` lands on {@link PluginManifest.specVersion}.\n */\nexport interface PluginManifest {\n /** Agent Plugins version selected by the manifest's `$schema`. */\n specVersion: AgentPluginsVersion\n /** Plugin name + package identifier (1-64 chars, see `./manifest`). */\n name: string\n version?: string\n description?: string\n author?: PluginAuthor\n homepage?: string\n repository?: string\n license?: string\n keywords?: string[]\n /**\n * Client-owned data keyed by reverse-domain namespace. Values are\n * deliberately `unknown`: the spec says to ignore namespaces the client\n * does not implement WITHOUT validating their contents, so this loader\n * never inspects a member it doesn't own.\n */\n extensions?: Record<string, unknown>\n}\n\n// ---------------------------------------------------------------------------\n// Diagnostics\n// ---------------------------------------------------------------------------\n\n/**\n * A load-time finding. Mirrors `SkillDiagnostic`'s shape (severity + stable\n * code + message) so host UIs already rendering skill diagnostics can\n * render these with no new plumbing.\n *\n * `severity: 'error'` on a returned plugin means a narrow boundary fired\n * (a component type disabled, a skill skipped) — NOT that the whole plugin\n * failed. Plugin-level rejection is signalled by `LoadedPlugin.ok === false`.\n */\nexport interface PluginDiagnostic {\n severity: 'warning' | 'error'\n /** Stable machine-readable code (e.g. `manifest-unknown-field`). */\n code: string\n message: string\n /** Manifest field the finding relates to, when applicable. */\n field?: string\n /** Filesystem path the finding relates to, when applicable. */\n path?: string\n}\n\n// ---------------------------------------------------------------------------\n// Component status\n// ---------------------------------------------------------------------------\n\n/**\n * Per-component-type outcome. The spec insists a missing fixed location is\n * NOT an error, and that an invalid one disables only its own component\n * type — so these four states are load-bearing, not cosmetic:\n *\n * - `absent` fixed location not present. Valid.\n * - `loaded` discovered (possibly zero entries, e.g. an empty `skills/`).\n * - `invalid` wrong filesystem kind, or the location escaped the root.\n * - `unsupported` never discovered — not implemented by this client,\n * disabled by the caller, or the plugin was rejected\n * before component discovery ran.\n */\nexport type PluginComponentStatus = 'absent' | 'loaded' | 'invalid' | 'unsupported'\n\n// ---------------------------------------------------------------------------\n// Loaded plugin\n// ---------------------------------------------------------------------------\n\n/**\n * Result of {@link loadAgentPlugin}. Never thrown — a rejected plugin comes\n * back as `ok: false` with the reason in `diagnostics`, because one bad\n * plugin must not take down a host that's loading several.\n */\nexport interface LoadedPlugin {\n /**\n * `false` when a fatal manifest or boundary violation rejected the whole\n * plugin. Components are empty in that case and were never discovered —\n * the spec requires rejection to happen BEFORE component discovery.\n */\n ok: boolean\n /** Plugin root as requested, resolved to an absolute path. */\n dir: string\n /**\n * Symlink-resolved plugin root. Every package path a caller touches must\n * stay under this — it's the boundary the spec defines. Falls back to\n * `dir` when the root itself could not be resolved.\n */\n root: string\n /** Validated manifest. Absent iff `ok === false`. */\n manifest?: PluginManifest\n /** Skills discovered under `skills/`. */\n skills: SkillConfig[]\n /** MCP servers declared by `mcp.json`. */\n mcpServers: McpServerConfig[]\n /** Per-component-type outcome — see {@link PluginComponentStatus}. */\n components: {\n skills: PluginComponentStatus\n mcp: PluginComponentStatus\n }\n /** Everything worth reporting: rejections, disabled components, skipped skills. */\n diagnostics: PluginDiagnostic[]\n}\n\n// ---------------------------------------------------------------------------\n// Load options\n// ---------------------------------------------------------------------------\n\nexport interface LoadAgentPluginOptions {\n /**\n * Source tag stamped onto every discovered skill, driving collision\n * precedence and the `trustProjectSkills` gate downstream. Defaults to\n * `'project'` — the conservative choice, since a plugin sitting in a\n * repo is exactly the untrusted-input case that gate exists for.\n */\n source?: SkillSource\n /**\n * Prefix applied to discovered skill names as `<prefix>-<name>`.\n *\n * Agent Plugins leaves naming to the client, and zidane's skill catalog\n * is a single flat namespace (`discoverSkills` dedupes by name), so two\n * plugins shipping a `deploy` skill would silently shadow one another.\n * Opt in to prefixing when loading untrusted or multiple plugins.\n */\n namePrefix?: string\n /** Discover `skills/`. Default `true`. */\n skills?: boolean\n /** Discover `mcp.json`. Default `true`. */\n mcp?: boolean\n /**\n * Exact directory exposed to MCP servers as `${PLUGIN_DATA}`.\n *\n * Must live outside the plugin root: the spec requires this directory to\n * persist across plugin updates, and an update replaces the package tree.\n * Prefer {@link LoadAgentPluginOptions.dataRoot} unless you need to pin one\n * specific plugin's directory.\n */\n dataDir?: string\n /**\n * Parent directory under which `${PLUGIN_DATA}` is created as\n * `<dataRoot>/<plugin-name>/`.\n *\n * Exists because the plugin name comes from the manifest, which the caller\n * hasn't read yet — a host that wants its own namespace (the extensions\n * seam puts plugin data inside the loading extension's storage root) can\n * supply the parent and let the loader append the name.\n *\n * Defaults to `<dataDir>/plugin-data` from `resolveStorageDirs`. Ignored\n * when {@link LoadAgentPluginOptions.dataDir} is set.\n */\n dataRoot?: string\n}\n","/**\n * `plugin.json` validation.\n *\n * The manifest schema is CLOSED and validated locally — the spec is explicit\n * that a client selects its rules from `$schema` and must not retrieve a\n * schema while loading. So the 1.0.0 contract is encoded here as code rather\n * than fetched or bundled as JSON Schema (the repo has no schema validator,\n * and the document is small and closed enough that hand-rolling it stays\n * honest — same call as the hand-rolled frontmatter parser in\n * `../skills/discovery.ts`).\n *\n * Exactly two violations are non-fatal, per spec:\n *\n * 1. an unknown top-level field → report, ignore, continue\n * 2. a non-object `extensions` → report, ignore, continue\n *\n * Every other schema violation rejects the whole plugin, and rejection\n * happens BEFORE component discovery — a plugin with a broken manifest never\n * gets its skills read or its MCP servers spawned.\n */\n\nimport type { PluginAuthor, PluginDiagnostic, PluginManifest } from './types'\nimport {\n agentPluginsSchemaId,\n describeJsonType,\n isSupportedAgentPluginsVersion,\n parseSchemaId,\n SUPPORTED_AGENT_PLUGINS_VERSIONS,\n} from './types'\n\n/**\n * Plugin name grammar, lifted from the canonical schema: 1-64 chars,\n * lowercase alphanumerics plus `-` and `.`, alphanumeric at both ends, and\n * no `--` or `..` anywhere (the negative lookahead).\n *\n * Length is checked separately so an over-long name gets a message about\n * length instead of a generic \"doesn't match the grammar\".\n */\nconst PLUGIN_NAME_RE = /^(?!.*(?:--|\\.\\.))[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$/\n\nconst NAME_MAX = 64\n\n/** Top-level fields the 1.0.0 manifest permits. Anything else is unknown. */\nconst KNOWN_FIELDS = new Set([\n '$schema',\n 'name',\n 'version',\n 'description',\n 'author',\n 'homepage',\n 'repository',\n 'license',\n 'keywords',\n 'extensions',\n])\n\n/** Optional top-level fields whose value must be a string when present. */\nconst STRING_FIELDS = ['version', 'description', 'homepage', 'repository', 'license'] as const\n\n/** Keys the closed `author` object permits. */\nconst AUTHOR_FIELDS = new Set(['name', 'email', 'url'])\n\nexport type ManifestValidation\n = | { ok: true, manifest: PluginManifest, diagnostics: PluginDiagnostic[] }\n | { ok: false, diagnostics: PluginDiagnostic[] }\n\n/**\n * Parse manifest text, then validate it.\n *\n * A JSON syntax error is fatal — unlike `mcps.json` (where\n * `parseJsonTolerant` repairs copy-paste whitespace artifacts), a plugin\n * manifest is a package file produced by a build or an author's editor, not\n * pasted into a settings box. Repairing it would mean guessing at the\n * contents of a third-party package.\n */\nexport function parsePluginManifest(text: string): ManifestValidation {\n let raw: unknown\n try {\n raw = JSON.parse(text)\n }\n catch (err) {\n return {\n ok: false,\n diagnostics: [{\n severity: 'error',\n code: 'manifest-invalid-json',\n message: `plugin.json is not valid JSON: ${err instanceof Error ? err.message : String(err)}`,\n }],\n }\n }\n return validatePluginManifest(raw)\n}\n\n/**\n * Validate an already-parsed manifest value against the closed 1.0.0 schema.\n *\n * Fatal violations short-circuit: `$schema` and `name` are checked first\n * because without them there is no contract to validate against and no\n * identity to report problems under.\n */\nexport function validatePluginManifest(raw: unknown): ManifestValidation {\n const diagnostics: PluginDiagnostic[] = []\n\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {\n return {\n ok: false,\n diagnostics: [{\n severity: 'error',\n code: 'manifest-not-object',\n message: `plugin.json must be a JSON object (got ${Array.isArray(raw) ? 'array' : typeof raw}).`,\n }],\n }\n }\n\n const obj = raw as Record<string, unknown>\n\n // --- $schema: selects the contract. No contract, no plugin. ------------\n const schema = obj.$schema\n if (typeof schema !== 'string' || schema.length === 0) {\n return fatal(diagnostics, {\n code: 'manifest-schema-missing',\n message: `plugin.json is missing the required \"$schema\" field. Expected \"${agentPluginsSchemaId('plugin', SUPPORTED_AGENT_PLUGINS_VERSIONS[0])}\".`,\n field: '$schema',\n })\n }\n const parsed = parseSchemaId(schema)\n if (!parsed || parsed.kind !== 'plugin') {\n return fatal(diagnostics, {\n code: 'manifest-schema-unsupported',\n message: `plugin.json \"$schema\" is not a canonical Agent Plugins manifest schema identifier: \"${schema}\".`,\n field: '$schema',\n })\n }\n if (!isSupportedAgentPluginsVersion(parsed.version)) {\n return fatal(diagnostics, {\n code: 'manifest-schema-unsupported',\n message: `plugin.json targets Agent Plugins ${parsed.version}, which this client does not support (supported: ${SUPPORTED_AGENT_PLUGINS_VERSIONS.join(', ')}).`,\n field: '$schema',\n })\n }\n\n // --- name: identity. --------------------------------------------------\n const name = obj.name\n if (typeof name !== 'string') {\n return fatal(diagnostics, {\n code: 'manifest-name-missing',\n message: `plugin.json is missing the required \"name\" field${name === undefined ? '' : ` (got ${typeof name})`}.`,\n field: 'name',\n })\n }\n if (name.length === 0 || name.length > NAME_MAX) {\n return fatal(diagnostics, {\n code: 'manifest-name-invalid',\n message: `Plugin name must be 1-${NAME_MAX} characters (got ${name.length}).`,\n field: 'name',\n })\n }\n if (!PLUGIN_NAME_RE.test(name)) {\n return fatal(diagnostics, {\n code: 'manifest-name-invalid',\n message: `Plugin name \"${name}\" is invalid — use lowercase letters, digits, hyphens and periods, starting and ending alphanumeric, with no \"--\" or \"..\".`,\n field: 'name',\n })\n }\n\n const manifest: PluginManifest = { specVersion: parsed.version, name }\n\n // --- optional strings -------------------------------------------------\n for (const field of STRING_FIELDS) {\n const value = obj[field]\n if (value === undefined)\n continue\n if (typeof value !== 'string') {\n return fatal(diagnostics, {\n code: 'manifest-field-wrong-type',\n message: `plugin.json \"${field}\" must be a string (got ${describeJsonType(value)}).`,\n field,\n })\n }\n manifest[field] = value\n }\n\n // --- keywords ---------------------------------------------------------\n if (obj.keywords !== undefined) {\n if (!Array.isArray(obj.keywords)) {\n return fatal(diagnostics, {\n code: 'manifest-field-wrong-type',\n message: `plugin.json \"keywords\" must be an array of strings (got ${describeJsonType(obj.keywords)}).`,\n field: 'keywords',\n })\n }\n const bad = obj.keywords.findIndex(entry => typeof entry !== 'string')\n if (bad !== -1) {\n return fatal(diagnostics, {\n code: 'manifest-field-wrong-type',\n message: `plugin.json \"keywords[${bad}]\" must be a string (got ${describeJsonType(obj.keywords[bad])}).`,\n field: 'keywords',\n })\n }\n manifest.keywords = [...obj.keywords as string[]]\n }\n\n // --- author (closed object) -------------------------------------------\n if (obj.author !== undefined) {\n const author = obj.author\n if (typeof author !== 'object' || author === null || Array.isArray(author)) {\n return fatal(diagnostics, {\n code: 'manifest-field-wrong-type',\n message: `plugin.json \"author\" must be an object (got ${describeJsonType(author)}).`,\n field: 'author',\n })\n }\n const out: PluginAuthor = {}\n for (const [key, value] of Object.entries(author as Record<string, unknown>)) {\n // `author` is closed by the schema, and an unknown key here is NOT one\n // of the two non-fatal cases (which are scoped to TOP-LEVEL unknown\n // fields) — so this rejects the plugin.\n if (!AUTHOR_FIELDS.has(key)) {\n return fatal(diagnostics, {\n code: 'manifest-author-unknown-field',\n message: `plugin.json \"author.${key}\" is not a permitted field (allowed: ${[...AUTHOR_FIELDS].join(', ')}).`,\n field: 'author',\n })\n }\n if (typeof value !== 'string') {\n return fatal(diagnostics, {\n code: 'manifest-field-wrong-type',\n message: `plugin.json \"author.${key}\" must be a string (got ${describeJsonType(value)}).`,\n field: 'author',\n })\n }\n out[key as keyof PluginAuthor] = value\n }\n manifest.author = out\n }\n\n // --- extensions (non-fatal when not an object) ------------------------\n if (obj.extensions !== undefined) {\n const ext = obj.extensions\n if (typeof ext !== 'object' || ext === null || Array.isArray(ext)) {\n diagnostics.push({\n severity: 'warning',\n code: 'manifest-extensions-not-object',\n message: `plugin.json \"extensions\" must be an object (got ${describeJsonType(ext)}) — ignoring it and continuing to load components.`,\n field: 'extensions',\n })\n }\n else {\n // Member VALUES are intentionally not validated: the spec says to\n // ignore namespaces the client does not implement without validating\n // them, and the normative text governs over the machine-readable\n // schema (which types members as objects). A client that implements a\n // namespace validates its own member at the point of use.\n manifest.extensions = { ...ext as Record<string, unknown> }\n }\n }\n\n // --- unknown top-level fields (non-fatal) -----------------------------\n for (const key of Object.keys(obj)) {\n if (KNOWN_FIELDS.has(key))\n continue\n diagnostics.push({\n severity: 'warning',\n code: 'manifest-unknown-field',\n message: `plugin.json has unknown top-level field \"${key}\" — ignoring it. Client-specific data belongs under \"extensions\".`,\n field: key,\n })\n }\n\n return { ok: true, manifest, diagnostics }\n}\n\nfunction fatal(\n diagnostics: PluginDiagnostic[],\n detail: Omit<PluginDiagnostic, 'severity'>,\n): { ok: false, diagnostics: PluginDiagnostic[] } {\n diagnostics.push({ severity: 'error', ...detail })\n return { ok: false, diagnostics }\n}\n","/**\n * The `mcp.json` component type.\n *\n * This does NOT route through `normalizeMcpServers`. That function is\n * deliberately heuristic — it infers a transport from the presence of\n * `command` / `url`, accepts `httpUrl` / `sseUrl` / `type: 'http'` aliases,\n * and tolerates unknown keys — because its job is making a config pasted\n * from Cursor or Claude Desktop Just Work. The plugin spec wants the exact\n * opposite: a closed document, a closed entry per declared transport, and an\n * unknown field invalidating that ONE entry. Guessing on behalf of a\n * third-party package is how you spawn a command the author didn't write.\n *\n * Three spec rules carry real security weight and are implemented here:\n *\n * 1. **Placeholders.** Only `${PLUGIN_ROOT}` and `${PLUGIN_DATA}`, only in\n * `args`, `env` values and `cwd`. Single-pass and non-recursive, so an\n * expansion can't produce another placeholder. Everything else —\n * `command`, `url`, `headers` — keeps its literal text, which is why\n * the produced configs carry `preExpanded` (see\n * `McpServerConfig.preExpanded`).\n * 2. **stdio resolution.** `command` is ONE executable token: a bare name\n * goes to PATH lookup, a `./`-relative path resolves inside the plugin\n * root. No shell, no argv splitting. `cwd` defaults to the plugin root\n * and must stay within the root or the data directory.\n * 3. **Remote URLs.** HTTPS unless loopback, no userinfo, no fragment, and\n * headers pinned to the configured origin across redirects.\n */\n\nimport type { McpServerConfig } from '../mcp'\nimport type { PluginBoundary } from './boundary'\nimport type { PluginComponentStatus, PluginDiagnostic } from './types'\nimport { readFile, realpath } from 'node:fs/promises'\nimport { isAbsolute, resolve } from 'node:path'\n// Deep import: `../mcp` is a large module and this is a dependency-free leaf,\n// so `zidane/plugins` shouldn't pull the whole MCP runtime for one predicate.\nimport { isAllowedRemoteUrl } from '../mcp/origin-pinned-fetch'\nimport { isWithin, realPathWithin } from './boundary'\nimport { agentPluginsSchemaId, describeJsonType, parseSchemaId } from './types'\n\n/** Fixed location for the MCP component type. */\nexport const PLUGIN_MCP_FILE = 'mcp.json'\n\n/** The only placeholders the spec defines. */\nconst PLUGIN_ROOT_VAR = 'PLUGIN_ROOT'\nconst PLUGIN_DATA_VAR = 'PLUGIN_DATA'\n\n/**\n * Placeholder grammar — deliberately narrower than\n * `expandEnvPlaceholders`'s: exactly the two reserved names, no\n * `:-default` form, no `${env:…}` form. Anything else stays literal.\n */\nconst PLUGIN_VAR_RE = /\\$\\{(PLUGIN_ROOT|PLUGIN_DATA)\\}/g\n\n/** Closed top-level key set for the document. */\nconst DOCUMENT_FIELDS = new Set(['$schema', 'mcpServers'])\n\n/**\n * Closed key set per declared transport.\n *\n * A `Map` rather than an object literal: the keys are attacker-controlled\n * (`type` comes straight out of a third-party `mcp.json`), and `'constructor'\n * in objectLiteral` is `true`, which would sail past the membership check and\n * then blow up on `Object.prototype.constructor.has(...)`.\n */\nconst ENTRY_FIELDS = new Map<string, Set<string>>([\n ['stdio', new Set(['type', 'command', 'args', 'env', 'cwd'])],\n ['streamable-http', new Set(['type', 'url', 'headers'])],\n ['sse', new Set(['type', 'url', 'headers'])],\n])\n\n/**\n * Server-name grammar.\n *\n * `connectMcpServers` namespaces tools as `mcp_<server>_<tool>`, and providers\n * reject a tool name outside the letters / digits / underscore / hyphen shape\n * — rejecting the whole REQUEST, not just the offending tool. A user-authored\n * `mcps.json` has the same sharp edge, but there the user owns the file; a\n * plugin is untrusted input, so an unusable name is rejected per-entry instead\n * of poisoning every run.\n */\nconst SERVER_NAME_RE = /^[a-z0-9][\\w-]{0,63}$/i\n\n/**\n * Keys that hit a prototype setter instead of creating an own property.\n * Same guard the extension registration paths apply to untrusted keys — see\n * `isSafeRecordKey` in `../extensions/register.ts`. Assigning `__proto__` on\n * an object literal silently DISCARDS the value, so without this an env var\n * would just never reach the child process with nothing explaining why.\n */\nconst DANGEROUS_RECORD_KEYS = new Set(['__proto__', 'prototype', 'constructor'])\n\nexport interface PluginMcpResult {\n status: PluginComponentStatus\n servers: McpServerConfig[]\n diagnostics: PluginDiagnostic[]\n}\n\nexport interface LoadPluginMcpOptions {\n boundary: PluginBoundary\n /** Plugin name — prefixes server names when `namePrefix` is set. */\n pluginName: string\n /**\n * Dedicated writable directory exposed as `${PLUGIN_DATA}`. Created on\n * demand, and only when a server actually references it. MUST live outside\n * the plugin root so a plugin update (which replaces the package) does not\n * wipe the data the spec says must persist.\n */\n dataDir: string\n /** Spec version the manifest declared — `mcp.json` must match it. */\n specVersion: string\n /** Prefix applied to server names as `<prefix>-<name>`. */\n namePrefix?: string\n}\n\n/**\n * Load and validate the plugin's `mcp.json`.\n *\n * Status semantics mirror `loadPluginSkills`: a missing file is `absent`\n * (valid), a wrong-kind / escaping / malformed document is `invalid` (this\n * component only), and anything else is `loaded` — even when individual\n * entries were rejected, because per-entry isolation is the point.\n */\nexport async function loadPluginMcp(opts: LoadPluginMcpOptions): Promise<PluginMcpResult> {\n const { boundary, pluginName, dataDir, specVersion, namePrefix } = opts\n const diagnostics: PluginDiagnostic[] = []\n const path = resolve(boundary.root, PLUGIN_MCP_FILE)\n\n const located = await realPathWithin(boundary, path)\n if (!located.ok) {\n if (located.reason === 'missing')\n return { status: 'absent', servers: [], diagnostics }\n diagnostics.push({\n severity: 'error',\n code: 'mcp-file-escapes-root',\n message: `\"${PLUGIN_MCP_FILE}\" resolves outside the plugin root — the MCP component is disabled for this plugin.`,\n path,\n })\n return { status: 'invalid', servers: [], diagnostics }\n }\n\n let raw: unknown\n try {\n raw = JSON.parse(await readFile(located.real, 'utf8'))\n }\n catch (err) {\n diagnostics.push({\n severity: 'error',\n code: 'mcp-invalid-json',\n message: `\"${PLUGIN_MCP_FILE}\" could not be read as JSON: ${err instanceof Error ? err.message : String(err)}`,\n path: located.real,\n })\n return { status: 'invalid', servers: [], diagnostics }\n }\n\n // --- stage 1: the closed top-level document ---------------------------\n const document = validateDocument(raw, specVersion)\n if (!document.ok) {\n diagnostics.push({ severity: 'error', ...document.diagnostic, path: located.real })\n return { status: 'invalid', servers: [], diagnostics }\n }\n\n // --- stage 2: each entry, independently -------------------------------\n //\n // Note what does NOT happen here: the `${PLUGIN_DATA}` directory is not\n // created. Loading resolves the path and stops there, because loading is not\n // consent. A host discovers every plugin on disk in order to learn its name\n // (identity lives in the manifest, so you cannot filter before loading), and\n // the user's `enabledPlugins` gate applies afterwards — so creating the\n // directory here would leave one behind for every plugin the user has\n // switched OFF, on every discovery pass. Creation happens at spawn time in\n // `mcp/index.ts`, the only place that knows a process is actually starting.\n const servers: McpServerConfig[] = []\n for (const [name, entry] of Object.entries(document.servers)) {\n const built = await buildServer({\n name,\n entry,\n boundary,\n dataDir,\n pluginName,\n ...(namePrefix !== undefined ? { namePrefix } : {}),\n })\n if (!built.ok) {\n // Per-entry isolation: one bad server never disables the component.\n diagnostics.push({ severity: 'error', ...built.diagnostic, path: located.real })\n continue\n }\n servers.push(built.config)\n }\n\n return { status: 'loaded', servers, diagnostics }\n}\n\n// ---------------------------------------------------------------------------\n// Stage 1 — document\n// ---------------------------------------------------------------------------\n\ntype DocumentValidation\n = | { ok: true, servers: Record<string, unknown> }\n | { ok: false, diagnostic: Omit<PluginDiagnostic, 'severity'> }\n\nfunction validateDocument(raw: unknown, specVersion: string): DocumentValidation {\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {\n return {\n ok: false,\n diagnostic: {\n code: 'mcp-not-object',\n message: `\"${PLUGIN_MCP_FILE}\" must be a JSON object (got ${describeJsonType(raw)}).`,\n },\n }\n }\n const obj = raw as Record<string, unknown>\n\n const schema = obj.$schema\n if (typeof schema !== 'string') {\n return {\n ok: false,\n diagnostic: {\n code: 'mcp-schema-missing',\n message: `\"${PLUGIN_MCP_FILE}\" is missing the required \"$schema\" field. Expected \"${agentPluginsSchemaId('mcp', specVersion)}\".`,\n field: '$schema',\n },\n }\n }\n const parsed = parseSchemaId(schema)\n if (!parsed || parsed.kind !== 'mcp') {\n return {\n ok: false,\n diagnostic: {\n code: 'mcp-schema-unsupported',\n message: `\"${PLUGIN_MCP_FILE}\" \"$schema\" is not a canonical Agent Plugins MCP schema identifier: \"${schema}\".`,\n field: '$schema',\n },\n }\n }\n // The spec requires matching Agent Plugins versions across the two\n // documents — a plugin declaring 1.0.0 rules in the manifest cannot opt a\n // single component into a different contract.\n if (parsed.version !== specVersion) {\n return {\n ok: false,\n diagnostic: {\n code: 'mcp-schema-version-mismatch',\n message: `\"${PLUGIN_MCP_FILE}\" targets Agent Plugins ${parsed.version} but plugin.json targets ${specVersion} — the versions must match.`,\n field: '$schema',\n },\n }\n }\n\n for (const key of Object.keys(obj)) {\n if (!DOCUMENT_FIELDS.has(key)) {\n return {\n ok: false,\n diagnostic: {\n code: 'mcp-unknown-field',\n message: `\"${PLUGIN_MCP_FILE}\" has unknown top-level field \"${key}\".`,\n field: key,\n },\n }\n }\n }\n\n const servers = obj.mcpServers\n if (typeof servers !== 'object' || servers === null || Array.isArray(servers)) {\n return {\n ok: false,\n diagnostic: {\n code: 'mcp-servers-wrong-type',\n message: `\"${PLUGIN_MCP_FILE}\" \"mcpServers\" must be an object (got ${describeJsonType(servers)}).`,\n field: 'mcpServers',\n },\n }\n }\n\n return { ok: true, servers: servers as Record<string, unknown> }\n}\n\n// ---------------------------------------------------------------------------\n// Stage 2 — one entry\n// ---------------------------------------------------------------------------\n\ntype EntryValidation\n = | { ok: true, config: McpServerConfig }\n | { ok: false, diagnostic: Omit<PluginDiagnostic, 'severity'> }\n\nasync function buildServer(opts: {\n name: string\n entry: unknown\n boundary: PluginBoundary\n dataDir: string\n pluginName: string\n namePrefix?: string\n}): Promise<EntryValidation> {\n const { name, entry, boundary, dataDir, namePrefix } = opts\n const reject = (code: string, message: string): EntryValidation => ({\n ok: false,\n diagnostic: { code, message: `Skipped MCP server \"${name}\" — ${message}` },\n })\n\n // Validated in the form it will actually take in the model's tool catalog\n // (`mcp_<serverName>_<tool>`), which means AFTER `namePrefix` is applied:\n // the prefix is part of that string, so a caller-supplied prefix can\n // invalidate a name the plugin itself got right. Catching it here rather\n // than at the provider boundary matters because there an unusable name\n // fails the whole REQUEST, not just the one tool.\n const serverName = namePrefix ? `${namePrefix}-${name}` : name\n if (!SERVER_NAME_RE.test(serverName)) {\n return reject('mcp-entry-name-invalid', namePrefix\n ? `its namespaced name \"${serverName}\" is not usable as a tool prefix — the \"${namePrefix}\" namePrefix must be letters, digits, underscores or hyphens, and the two together at most 64 characters.`\n : 'its name must be 1-64 characters of letters, digits, underscores or hyphens, starting alphanumeric.')\n }\n\n if (typeof entry !== 'object' || entry === null || Array.isArray(entry))\n return reject('mcp-entry-not-object', `its value must be an object (got ${describeJsonType(entry)}).`)\n const obj = entry as Record<string, unknown>\n\n // The declared transport selects the closed key set AND the connection\n // attempt. It is never inferred: an entry without `type` is invalid, full\n // stop, because guessing is how a `url` typo becomes a spawned command.\n const type = typeof obj.type === 'string' ? obj.type : undefined\n const allowed = type === undefined ? undefined : ENTRY_FIELDS.get(type)\n if (type === undefined || !allowed)\n return reject('mcp-entry-transport-invalid', `\"type\" must be one of stdio, streamable-http, sse (got ${type === undefined ? describeJsonType(obj.type) : `\"${type}\"`}).`)\n\n for (const key of Object.keys(obj)) {\n if (!allowed.has(key))\n return reject('mcp-entry-unknown-field', `\"${key}\" is not a permitted field for a ${type} server (allowed: ${[...allowed].join(', ')}).`)\n }\n\n const vars = { [PLUGIN_ROOT_VAR]: boundary.root, [PLUGIN_DATA_VAR]: dataDir }\n\n if (type === 'stdio') {\n // --- command: exactly one executable token -------------------------\n const command = obj.command\n if (typeof command !== 'string' || command.length === 0)\n return reject('mcp-entry-command-invalid', 'a stdio server needs a non-empty \"command\".')\n // Placeholders are NOT expanded in `command`, so a `${PLUGIN_ROOT}` here\n // would be passed to the OS literally. Reject rather than spawn it.\n if (PLUGIN_VAR_RE.test(command)) {\n PLUGIN_VAR_RE.lastIndex = 0\n return reject('mcp-entry-command-invalid', 'placeholders are not expanded in \"command\" — use a \"./\"-relative path or a bare executable name.')\n }\n if (/\\s/.test(command))\n return reject('mcp-entry-command-invalid', `\"command\" must be a single executable token, not a command line (\"${command}\").`)\n const resolvedCommand = await resolveCommand(command, boundary)\n if (!resolvedCommand.ok)\n return reject('mcp-entry-command-invalid', resolvedCommand.error)\n\n // --- args ----------------------------------------------------------\n let args: string[] | undefined\n if (obj.args !== undefined) {\n if (!Array.isArray(obj.args) || obj.args.some(a => typeof a !== 'string'))\n return reject('mcp-entry-args-invalid', '\"args\" must be an array of strings.')\n args = (obj.args as string[]).map(a => expandPluginVars(a, vars))\n }\n\n // --- env -----------------------------------------------------------\n let env: Record<string, string> | undefined\n if (obj.env !== undefined) {\n if (typeof obj.env !== 'object' || obj.env === null || Array.isArray(obj.env))\n return reject('mcp-entry-env-invalid', '\"env\" must be an object of strings.')\n env = {}\n for (const [key, value] of Object.entries(obj.env as Record<string, unknown>)) {\n if (typeof value !== 'string')\n return reject('mcp-entry-env-invalid', `\"env.${key}\" must be a string (got ${describeJsonType(value)}).`)\n // The reserved names are supplied by the client, not the plugin.\n if (key === PLUGIN_ROOT_VAR || key === PLUGIN_DATA_VAR)\n return reject('mcp-entry-env-invalid', `\"env.${key}\" is reserved and cannot be set by a plugin.`)\n if (!isSafeRecordKey(key))\n return reject('mcp-entry-env-invalid', `\"env.${key}\" is not a usable variable name.`)\n env[key] = expandPluginVars(value, vars)\n }\n }\n\n // --- cwd -----------------------------------------------------------\n const cwdResult = await resolveCwd(obj.cwd, boundary, dataDir, vars)\n if (!cwdResult.ok)\n return reject('mcp-entry-cwd-invalid', cwdResult.error)\n\n const config: McpServerConfig = {\n name: serverName,\n transport: 'stdio',\n command: resolvedCommand.command,\n // Reserved variables are written LAST so a plugin cannot shadow them\n // through some other spelling, and so they always describe reality.\n env: { ...env, [PLUGIN_ROOT_VAR]: boundary.root, [PLUGIN_DATA_VAR]: dataDir },\n cwd: cwdResult.cwd,\n preExpanded: true,\n }\n if (args)\n config.args = args\n return { ok: true, config }\n }\n\n // --- remote transports ------------------------------------------------\n const url = obj.url\n if (typeof url !== 'string' || url.length === 0)\n return reject('mcp-entry-url-invalid', `a ${type} server needs a non-empty \"url\".`)\n const checked = validateRemoteUrl(url)\n if (!checked.ok)\n return reject('mcp-entry-url-invalid', checked.error)\n\n let headers: Record<string, string> | undefined\n if (obj.headers !== undefined) {\n if (typeof obj.headers !== 'object' || obj.headers === null || Array.isArray(obj.headers))\n return reject('mcp-entry-headers-invalid', '\"headers\" must be an object of strings.')\n headers = {}\n for (const [key, value] of Object.entries(obj.headers as Record<string, unknown>)) {\n if (!isSafeRecordKey(key))\n return reject('mcp-entry-headers-invalid', `\"headers.${key}\" is not a usable header name.`)\n if (typeof value !== 'string')\n return reject('mcp-entry-headers-invalid', `\"headers.${key}\" must be a string (got ${describeJsonType(value)}).`)\n // Not expanded — spec scopes placeholders to args/env/cwd.\n headers[key] = value\n }\n }\n\n const config: McpServerConfig = {\n name: serverName,\n transport: type === 'sse' ? 'sse' : 'streamable-http',\n url,\n preExpanded: true,\n pinHeaderOrigin: true,\n }\n if (headers)\n config.headers = headers\n return { ok: true, config }\n}\n\n// ---------------------------------------------------------------------------\n// Placeholders\n// ---------------------------------------------------------------------------\n\n/**\n * Substitute the two reserved placeholders in one string.\n *\n * Single-pass by construction (`String.replace` never re-scans its own\n * output), so a `${PLUGIN_ROOT}` whose value somehow contained\n * `${PLUGIN_DATA}` cannot expand twice. Unknown `${...}` text is left\n * verbatim: the spec defines exactly two placeholders, and silently\n * blanking anything else would corrupt legitimate literals.\n */\nexport function expandPluginVars(value: string, vars: Record<string, string>): string {\n return value.replace(PLUGIN_VAR_RE, (match, name: string) => vars[name] ?? match)\n}\n\n// ---------------------------------------------------------------------------\n// stdio resolution\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve the single `command` token.\n *\n * A bare name (`uvx`, `node`) is handed to the OS for PATH lookup — the\n * plugin declares a dependency on the host's toolchain, which is normal. A\n * `./`-relative token is a file the PACKAGE ships, so it resolves against\n * the plugin root and must survive the containment check. An absolute path\n * is refused: it is neither a PATH lookup nor a package file, and it is the\n * shape an escape attempt takes.\n */\nasync function resolveCommand(\n command: string,\n boundary: PluginBoundary,\n): Promise<{ ok: true, command: string } | { ok: false, error: string }> {\n if (isAbsolute(command))\n return { ok: false, error: `\"command\" must be a bare executable name or a \"./\"-relative path inside the plugin, not an absolute path (\"${command}\").` }\n\n // Bare token → PATH lookup by the OS. Note `foo/bar` (no leading `./`) is\n // also not a bare name; treat any separator as package-relative.\n if (!command.includes('/') && !command.includes('\\\\'))\n return { ok: true, command }\n\n const target = resolve(boundary.root, command)\n const within = await realPathWithin(boundary, target)\n if (!within.ok) {\n return {\n ok: false,\n error: within.reason === 'escaped'\n ? `\"command\" resolves outside the plugin root (\"${command}\").`\n : `\"command\" does not exist inside the plugin (\"${command}\").`,\n }\n }\n return { ok: true, command: within.real }\n}\n\n/**\n * Resolve `cwd`, defaulting to the plugin root.\n *\n * The authored form is constrained to `./…`, `${PLUGIN_ROOT}…` or\n * `${PLUGIN_DATA}…`, and containment is then verified against BOTH permitted\n * roots — the data directory legitimately sits outside the package.\n *\n * Both a lexical and a post-symlink check run, because neither alone is\n * sufficient: `cwd` may not exist yet (a server that creates its own working\n * directory on first run), so realpath cannot be the only gate; but the data\n * directory is writable BY the MCP server, so a server can plant a\n * `${PLUGIN_DATA}/work → /` symlink on one run and get `cwd=/` on the next\n * unless the resolved target is re-checked.\n */\nasync function resolveCwd(\n raw: unknown,\n boundary: PluginBoundary,\n dataDir: string,\n vars: Record<string, string>,\n): Promise<{ ok: true, cwd: string } | { ok: false, error: string }> {\n if (raw === undefined)\n return { ok: true, cwd: boundary.root }\n if (typeof raw !== 'string' || raw.length === 0)\n return { ok: false, error: '\"cwd\" must be a non-empty string.' }\n\n const startsWithVar = raw.startsWith(`\\${${PLUGIN_ROOT_VAR}}`) || raw.startsWith(`\\${${PLUGIN_DATA_VAR}}`)\n if (!raw.startsWith('./') && !startsWithVar)\n return { ok: false, error: `\"cwd\" must start with \"./\", \"\\${${PLUGIN_ROOT_VAR}}\" or \"\\${${PLUGIN_DATA_VAR}}\" (got \"${raw}\").` }\n\n const expanded = expandPluginVars(raw, vars)\n const absolute = isAbsolute(expanded) ? expanded : resolve(boundary.root, expanded)\n\n // Lexical, against the paths the placeholders actually produced.\n if (!isWithin(boundary.root, absolute) && !isWithin(dataDir, absolute))\n return { ok: false, error: `\"cwd\" escapes both the plugin root and the plugin data directory (\"${raw}\").` }\n\n // Post-symlink. `boundary.root` is already realpath-resolved; the data\n // directory is resolved here so a home path that itself traverses a symlink\n // (`/home` → `/usr/home`) doesn't make every comparison fail.\n const real = await realpathOrNull(absolute)\n if (real !== null) {\n const realDataDir = await realpathOrNull(dataDir) ?? dataDir\n if (!isWithin(boundary.root, real) && !isWithin(realDataDir, real))\n return { ok: false, error: `\"cwd\" resolves outside the plugin root and the plugin data directory via a symlink (\"${raw}\").` }\n }\n\n return { ok: true, cwd: absolute }\n}\n\n/** `realpath`, or `null` when the path doesn't exist yet. */\nasync function realpathOrNull(target: string): Promise<string | null> {\n try {\n return await realpath(target)\n }\n catch {\n return null\n }\n}\n\n// ---------------------------------------------------------------------------\n// Remote URLs\n// ---------------------------------------------------------------------------\n\n/**\n * Enforce the spec's remote-endpoint requirements: parseable, HTTPS unless\n * loopback, no embedded credentials, no fragment.\n *\n * Reachability (scheme + host) is decided by {@link isAllowedRemoteUrl}, the\n * single encoding of that policy — `originPinnedFetch` applies the same\n * predicate per redirect hop, so a URL refused here can't be reached by\n * redirect either. Only the message selection lives here; the userinfo and\n * fragment rules are authoring-only and have no redirect equivalent.\n */\nfunction validateRemoteUrl(raw: string): { ok: true } | { ok: false, error: string } {\n let url: URL\n try {\n url = new URL(raw)\n }\n catch {\n return { ok: false, error: `\"url\" is not a valid absolute URL (\"${raw}\").` }\n }\n if (!isAllowedRemoteUrl(url)) {\n return {\n ok: false,\n error: url.protocol === 'http:'\n ? `\"url\" must use https for non-loopback hosts (\"${raw}\").`\n : `\"url\" must use http or https (got \"${url.protocol}\").`,\n }\n }\n if (url.username !== '' || url.password !== '')\n return { ok: false, error: '\"url\" must not embed userinfo credentials.' }\n if (url.hash !== '')\n return { ok: false, error: '\"url\" must not contain a fragment.' }\n return { ok: true }\n}\n\n/** Reject keys that would hit a prototype setter instead of the record. */\nfunction isSafeRecordKey(key: string): boolean {\n return key.length > 0 && !DANGEROUS_RECORD_KEYS.has(key)\n}\n","/**\n * The `skills/` component type.\n *\n * Agent Plugins does not redefine the skill format — it defines only WHERE\n * skills live and HOW failures are isolated. So the format itself routes\n * through `parseSkillFile`, the same lenient Agent Skills parser that reads\n * `~/.agents/skills`, and this module contributes exactly two things the\n * plugin spec adds on top:\n *\n * 1. Immediate children only. `findSkillDirs` in `../skills/discovery.ts`\n * recurses four levels deep (correct for a user's `skills/` tree, where\n * category subdirectories are idiomatic); the plugin spec forbids\n * searching nested descendants, so discovery here is strictly depth-1.\n * 2. Boundary + kind enforcement per entry, with per-skill isolation: one\n * invalid or escaping skill is skipped, its siblings still load.\n */\n\nimport type { SkillConfig, SkillSource } from '../skills'\nimport type { PluginBoundary } from './boundary'\nimport type { PluginComponentStatus, PluginDiagnostic } from './types'\nimport { readdir } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport { parseSkillFile } from '../skills'\nimport { resolvePackagePath } from './boundary'\n\n/** Fixed location for the skills component type. */\nexport const PLUGIN_SKILLS_DIR = 'skills'\n\n/** Spec cap on a skill name, re-checked after a `namePrefix` is applied. */\nconst SKILL_NAME_MAX = 64\n\nexport interface PluginSkillsResult {\n status: PluginComponentStatus\n skills: SkillConfig[]\n diagnostics: PluginDiagnostic[]\n}\n\n/**\n * Discover every skill in the plugin's `skills/` directory.\n *\n * Status semantics follow the spec's failure ladder:\n * - `skills/` missing → `absent` (valid; not an error)\n * - `skills/` not a directory → `invalid` (this component type only)\n * - `skills/` escapes the root → `invalid` (this component type only)\n * - otherwise → `loaded`, possibly with zero skills\n */\nexport async function loadPluginSkills(opts: {\n boundary: PluginBoundary\n /** Plugin name, stamped on each skill as `metadata['zidane.plugin']`. */\n pluginName: string\n /** Source tag for the produced skills. Default `'project'`. */\n source?: SkillSource\n /** Optional `<prefix>-<name>` rename — see `LoadAgentPluginOptions.namePrefix`. */\n namePrefix?: string\n}): Promise<PluginSkillsResult> {\n const { boundary, pluginName, source = 'project', namePrefix } = opts\n const diagnostics: PluginDiagnostic[] = []\n const dir = join(boundary.root, PLUGIN_SKILLS_DIR)\n\n const located = await resolvePackagePath(boundary, dir, 'directory')\n if (!located.ok) {\n if (located.reason === 'missing')\n return { status: 'absent', skills: [], diagnostics }\n diagnostics.push({\n severity: 'error',\n code: located.reason === 'escaped' ? 'skills-dir-escapes-root' : 'skills-dir-wrong-kind',\n message: located.reason === 'escaped'\n ? `\"${PLUGIN_SKILLS_DIR}/\" resolves outside the plugin root — the skills component is disabled for this plugin.`\n : `\"${PLUGIN_SKILLS_DIR}\" exists but is not a directory — the skills component is disabled for this plugin.`,\n path: dir,\n })\n return { status: 'invalid', skills: [], diagnostics }\n }\n\n let entries: string[]\n try {\n entries = await readdir(located.real)\n }\n catch (err) {\n diagnostics.push({\n severity: 'error',\n code: 'skills-dir-unreadable',\n message: `Could not read \"${PLUGIN_SKILLS_DIR}/\": ${err instanceof Error ? err.message : String(err)}`,\n path: located.real,\n })\n return { status: 'invalid', skills: [], diagnostics }\n }\n\n const skills: SkillConfig[] = []\n // `readdir` order is filesystem-dependent; sort so a plugin's skills land\n // in the catalog deterministically (and so collision precedence between\n // two same-named skills in one plugin is stable rather than inode-order).\n for (const entry of entries.sort()) {\n const child = join(located.real, entry)\n const childDir = await resolvePackagePath(boundary, child, 'directory')\n if (!childDir.ok) {\n // A non-directory child (`README.md`, `.DS_Store`) simply isn't a\n // skill — silent. An ESCAPING child is the spec's \"deny access for\n // other escaping package paths\" boundary and worth surfacing.\n if (childDir.reason === 'escaped') {\n diagnostics.push({\n severity: 'warning',\n code: 'skill-dir-escapes-root',\n message: `Skipped \"${PLUGIN_SKILLS_DIR}/${entry}\" — it resolves outside the plugin root.`,\n path: child,\n })\n }\n continue\n }\n\n const skillFile = join(childDir.real, 'SKILL.md')\n const located2 = await resolvePackagePath(boundary, skillFile, 'file')\n if (!located2.ok) {\n // Missing SKILL.md means \"this directory is not a skill\" — per spec an\n // immediate child is a skill only when SKILL.md resolves to a regular\n // file. Silent, because bundling a non-skill directory is legal.\n if (located2.reason === 'escaped') {\n diagnostics.push({\n severity: 'error',\n code: 'skill-escapes-root',\n message: `Skipped skill \"${entry}\" — its SKILL.md resolves outside the plugin root.`,\n path: skillFile,\n })\n }\n else if (located2.reason === 'wrong-kind') {\n diagnostics.push({\n severity: 'warning',\n code: 'skill-file-wrong-kind',\n message: `Skipped \"${PLUGIN_SKILLS_DIR}/${entry}\" — its SKILL.md is not a regular file.`,\n path: skillFile,\n })\n }\n continue\n }\n\n // Parsed with the boundary-resolved path so `baseDir` (which gates\n // `skills_read` / `skills_run_script`) is anchored inside the root.\n //\n // `parseSkillFile` returns `null` for an invalid skill but still THROWS on\n // an unreadable file (permissions, a raced unlink, a device node). Both are\n // \"skip this skill\", never \"fail the plugin\".\n let parsed: SkillConfig | null\n try {\n parsed = await parseSkillFile(located2.real, { source })\n }\n catch (err) {\n diagnostics.push({\n severity: 'error',\n code: 'skill-unreadable',\n message: `Skipped skill \"${entry}\" — its SKILL.md could not be read: ${err instanceof Error ? err.message : String(err)}`,\n path: located2.real,\n })\n continue\n }\n if (!parsed) {\n diagnostics.push({\n severity: 'error',\n code: 'skill-invalid',\n message: `Skipped skill \"${entry}\" — its SKILL.md is not a valid Agent Skill (missing description, or unparseable frontmatter).`,\n path: located2.real,\n })\n continue\n }\n\n skills.push(stamp(parsed, { pluginName, namePrefix, entry, diagnostics }))\n }\n\n return { status: 'loaded', skills, diagnostics }\n}\n\n/**\n * Attach plugin provenance and apply the optional name prefix.\n *\n * Provenance goes in `metadata` under the `zidane.` prefix the Agent Skills\n * spec reserves for client-specific keys (see `../skills/types.ts`), so the\n * skill stays spec-conformant while a host UI can still say which plugin\n * shipped it.\n */\nfunction stamp(skill: SkillConfig, ctx: {\n pluginName: string\n namePrefix?: string\n entry: string\n diagnostics: PluginDiagnostic[]\n}): SkillConfig {\n const name = ctx.namePrefix ? `${ctx.namePrefix}-${skill.name}` : skill.name\n if (name.length > SKILL_NAME_MAX) {\n ctx.diagnostics.push({\n severity: 'warning',\n code: 'skill-name-too-long',\n message: `Prefixed skill name \"${name}\" exceeds the ${SKILL_NAME_MAX}-character spec limit. Loading anyway.`,\n })\n }\n return {\n ...skill,\n name,\n metadata: { ...skill.metadata, 'zidane.plugin': ctx.pluginName },\n }\n}\n","/**\n * Load one Agent Plugin from a directory.\n *\n * Order is mandated by the spec: establish the package boundary, load and\n * validate `plugin.json`, and only then discover components. A plugin whose\n * manifest is rejected never has its skills read or its MCP servers spawned.\n *\n * Nothing here throws for plugin-level problems. A host loading several\n * plugins must not lose the good ones to one bad package, so a rejection\n * comes back as `{ ok: false, diagnostics }`.\n */\n\nimport type { ResolveStorageDirsOptions } from '../chat/xdg'\nimport type { LoadAgentPluginOptions, LoadedPlugin, PluginDiagnostic } from './types'\nimport { readFile } from 'node:fs/promises'\nimport { join, resolve } from 'node:path'\nimport { resolveStorageDirs } from '../chat/xdg'\nimport { resolvePackagePath, resolvePluginBoundary } from './boundary'\nimport { parsePluginManifest } from './manifest'\nimport { loadPluginMcp } from './mcp'\nimport { loadPluginSkills } from './skills'\n\n/** Fixed location of the plugin manifest. */\nexport const PLUGIN_MANIFEST_FILE = 'plugin.json'\n\n/**\n * Default parent of every plugin's `${PLUGIN_DATA}` directory.\n *\n * Deliberately OUTSIDE any plugin root: the spec requires the data directory\n * to persist across plugin updates, and an update replaces the package tree.\n * Keyed by plugin name so two copies of the same plugin (project + user)\n * share state, which is what an author storing a cache or a token expects.\n *\n * Routed through `resolveStorageDirs` rather than hardcoding `~/.zidane` so it\n * honours `ZIDANE_STORAGE_DIR` and the XDG dirs like every other persisted\n * location — otherwise an XDG-mode install would scatter plugin data into a\n * `~/.zidane` nothing else in the app touches.\n *\n * NB: `resolveStorageDirs` does NOT read `ZIDANE_PREFIX`; it defaults `prefix`\n * to `.zidane`. Callers with a configured prefix must pass it, or plugin data\n * lands beside a prefix the rest of the install doesn't use.\n */\nexport function defaultPluginDataRoot(opts: ResolveStorageDirsOptions = {}): string {\n return join(resolveStorageDirs(opts).dataDir, 'plugin-data')\n}\n\n/**\n * Load an Agent Plugin from `dir`.\n *\n * @returns A {@link LoadedPlugin}. Check `ok` before trusting `manifest`;\n * check `components` to tell \"the plugin ships no skills\" (`absent`) from\n * \"its skills were rejected\" (`invalid`).\n */\nexport async function loadAgentPlugin(\n dir: string,\n opts: LoadAgentPluginOptions = {},\n): Promise<LoadedPlugin> {\n const diagnostics: PluginDiagnostic[] = []\n\n const boundary = await resolvePluginBoundary(dir)\n if (!boundary) {\n return rejected(resolve(dir), resolve(dir), [{\n severity: 'error',\n code: 'plugin-root-unreadable',\n message: `Plugin root \"${dir}\" does not exist or is not a directory.`,\n path: resolve(dir),\n }])\n }\n\n // --- manifest ---------------------------------------------------------\n const manifestPath = join(boundary.root, PLUGIN_MANIFEST_FILE)\n const located = await resolvePackagePath(boundary, manifestPath, 'file')\n if (!located.ok) {\n return rejected(boundary.dir, boundary.root, [{\n severity: 'error',\n code: located.reason === 'escaped' ? 'manifest-escapes-root' : 'manifest-missing',\n message: located.reason === 'escaped'\n // Boundary ladder rung 1: a manifest resolving outside the root\n // rejects the plugin outright — we will not read a package file\n // from somewhere the package doesn't own.\n ? `${PLUGIN_MANIFEST_FILE} resolves outside the plugin root.`\n : located.reason === 'wrong-kind'\n ? `${PLUGIN_MANIFEST_FILE} exists but is not a regular file.`\n : `No ${PLUGIN_MANIFEST_FILE} at the plugin root — not an Agent Plugin.`,\n path: manifestPath,\n }])\n }\n\n let text: string\n try {\n text = await readFile(located.real, 'utf8')\n }\n catch (err) {\n return rejected(boundary.dir, boundary.root, [{\n severity: 'error',\n code: 'manifest-unreadable',\n message: `Could not read ${PLUGIN_MANIFEST_FILE}: ${err instanceof Error ? err.message : String(err)}`,\n path: located.real,\n }])\n }\n\n const validated = parsePluginManifest(text)\n diagnostics.push(...validated.diagnostics)\n if (!validated.ok)\n return rejected(boundary.dir, boundary.root, diagnostics)\n\n const { manifest } = validated\n const result: LoadedPlugin = {\n ok: true,\n dir: boundary.dir,\n root: boundary.root,\n manifest,\n skills: [],\n mcpServers: [],\n components: { skills: 'unsupported', mcp: 'unsupported' },\n diagnostics,\n }\n\n // --- components -------------------------------------------------------\n //\n // Each discovery pass is wrapped so the never-throws contract is ENFORCED\n // rather than merely intended. Both passes walk attacker-controlled JSON and\n // filesystem state, so an unexpected throw (an unreadable SKILL.md, a raced\n // unlink, a shape no validator anticipated) is a question of when, not if —\n // and it would otherwise escape into `setup()` and fail the whole extension.\n // The narrowest boundary that still holds is the component type.\n if (opts.skills !== false) {\n await guardComponent(result, 'skills', diagnostics, async () => {\n const skills = await loadPluginSkills({\n boundary,\n pluginName: manifest.name,\n ...(opts.source !== undefined ? { source: opts.source } : {}),\n ...(opts.namePrefix !== undefined ? { namePrefix: opts.namePrefix } : {}),\n })\n result.components.skills = skills.status\n result.skills = skills.skills\n diagnostics.push(...skills.diagnostics)\n })\n }\n\n if (opts.mcp !== false) {\n await guardComponent(result, 'mcp', diagnostics, async () => {\n const mcp = await loadPluginMcp({\n boundary,\n pluginName: manifest.name,\n dataDir: opts.dataDir ?? join(opts.dataRoot ?? defaultPluginDataRoot(), manifest.name),\n specVersion: manifest.specVersion,\n ...(opts.namePrefix !== undefined ? { namePrefix: opts.namePrefix } : {}),\n })\n result.components.mcp = mcp.status\n result.mcpServers = mcp.servers\n diagnostics.push(...mcp.diagnostics)\n })\n }\n\n return result\n}\n\n/**\n * Run one component-discovery pass, converting an unexpected throw into an\n * `invalid` component plus a diagnostic. Partial results the pass already\n * assigned are dropped, so a half-discovered component never looks loaded.\n *\n * No input reachable through this module's public API is known to trigger it:\n * both component loaders catch their own filesystem and parse failures, which\n * is exactly the property their tests assert. It is kept deliberately, not\n * abandoned — `loadAgentPlugin` promises never to throw for plugin-level\n * problems, and that promise should survive a future component type whose\n * loader forgets a `try`. The observable half IS tested: see the \"never throws\"\n * matrix in `test/plugins/load.test.ts`.\n */\nasync function guardComponent(\n result: LoadedPlugin,\n component: 'skills' | 'mcp',\n diagnostics: PluginDiagnostic[],\n run: () => Promise<void>,\n): Promise<void> {\n try {\n await run()\n }\n catch (err) {\n result.components[component] = 'invalid'\n if (component === 'skills')\n result.skills = []\n else\n result.mcpServers = []\n diagnostics.push({\n severity: 'error',\n code: `${component}-discovery-failed`,\n message: `Unexpected error while loading the ${component} component: ${err instanceof Error ? err.message : String(err)}`,\n path: result.root,\n })\n }\n}\n\nfunction rejected(dir: string, root: string, diagnostics: PluginDiagnostic[]): LoadedPlugin {\n return {\n ok: false,\n dir,\n root,\n skills: [],\n mcpServers: [],\n components: { skills: 'unsupported', mcp: 'unsupported' },\n diagnostics,\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"plugins-gbI7SBA6.js","names":[],"sources":["../src/chat/xdg.ts","../src/plugins/boundary.ts","../src/plugins/types.ts","../src/plugins/manifest.ts","../src/plugins/mcp.ts","../src/plugins/skills.ts","../src/plugins/load.ts"],"sourcesContent":["/**\n * XDG Base Directory resolution for zidane.\n *\n * The user's storage spreads across four logical slots:\n *\n * - **config** — credentials, mcp-credentials, keybindings, config.json,\n * mcps.json, skills (user-editable surface).\n * - **data** — sessions.db (long-lived chat history).\n * - **state** — state.json (per-machine UI bookkeeping: last provider,\n * last model, last agent, settings).\n * - **cache** — persisted tool results, background-task logs,\n * auto-update registry cache (regenerable, safe to wipe).\n *\n * Historically all four collapsed to `~/.zidane/`. This module adds\n * XDG-Base-Directory-aware defaults so a Linux user with no existing\n * `~/.zidane/` lands in the conventional `~/.config/zidane/`,\n * `~/.local/share/zidane/`, `~/.local/state/zidane/`, `~/.cache/zidane/`\n * trio. Existing setups (anyone with a `~/.zidane/` directory or\n * `ZIDANE_STORAGE_DIR` set) keep the single-dir layout unchanged.\n *\n * Resolution flow — applied in this order:\n *\n * 1. Caller passed an explicit `storageDir` (`ChatOptions.storageDir`)\n * OR `ZIDANE_STORAGE_DIR` is set → **legacy-explicit** single-dir\n * layout under `<storageDir>/<prefix>`. The four slots collapse to\n * the same directory.\n * 2. `~/<prefix>/` already exists on disk → **legacy-existing**\n * single-dir layout under that directory. Upgrades never silently\n * shift files around.\n * 3. Any `XDG_*_HOME` env var is set OR `process.platform === 'linux'`\n * → **XDG split**. Each slot lands in its own dir. Per-slot\n * `ZIDANE_{CONFIG,DATA,CACHE,STATE}_DIR` overrides beat the XDG\n * vars for surgical tweaks.\n * 4. Otherwise (macOS/Windows, no XDG signal, no existing dir) →\n * **default** single-dir layout at `~/<prefix>/`. Day-one behavior\n * on these platforms is unchanged.\n *\n * The `userDir` legacy alias always equals `configDir` so existing code\n * that still references `paths.userDir` keeps reading credentials, mcps,\n * etc. from the right place.\n */\n\nimport { existsSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { resolve } from 'node:path'\n\n/** The four slot kinds we resolve. Names match the XDG spec. */\nexport type StorageSlot = 'config' | 'data' | 'state' | 'cache'\n\n/** Which resolution branch produced the layout — surfaced for debugging + tests. */\nexport type StorageMode = 'legacy-explicit' | 'legacy-existing' | 'xdg' | 'default'\n\n/**\n * Per-slot directories. In legacy / default modes the four fields all\n * point at the same path; in XDG mode they fan out into their\n * spec-conventional locations.\n *\n * `mode` carries the resolution branch so a host that wants to print\n * a startup banner (\"zidane is using XDG paths\") can detect the\n * layout without re-running the logic.\n */\nexport interface StorageDirs {\n configDir: string\n dataDir: string\n stateDir: string\n cacheDir: string\n mode: StorageMode\n}\n\nexport interface ResolveStorageDirsOptions {\n /** Storage prefix. Leading dot tolerated. Default: `'.zidane'`. */\n prefix?: string\n /**\n * Explicit storage root (`ChatOptions.storageDir`). When set, forces\n * legacy-explicit mode regardless of the platform / XDG signals.\n */\n storageDir?: string\n /** Override `os.homedir()` for tests. */\n home?: string\n /** Override `process.platform` for tests. */\n platform?: NodeJS.Platform\n /** Override `process.env` for tests. */\n env?: Readonly<Record<string, string | undefined>>\n}\n\n/**\n * Resolve the four storage slots according to the precedence above.\n *\n * Pure aside from one filesystem probe (`existsSync(home/<prefix>)`)\n * — the same probe `resolveStoragePaths` would do anyway when\n * computing `paths.userDir`. No directories are created here; the\n * relevant write paths (state store, credentials writer, persist\n * dir) handle their own lazy `mkdirSync` already.\n */\nexport function resolveStorageDirs(opts: ResolveStorageDirsOptions = {}): StorageDirs {\n const env = opts.env ?? process.env\n const home = opts.home ?? homedir()\n const platform = opts.platform ?? process.platform\n // Two prefix forms — legacy mode preserves whatever the caller\n // passed (no implicit dot insertion, so `prefix: 'myapp'` lands at\n // `<storageDir>/myapp` not `<storageDir>/.myapp` — matches the\n // pre-XDG behavior tests already rely on). XDG mode uses the de-\n // dotted form (`'.zidane'` → `'zidane'`) because the XDG dir itself\n // is already the dotfile container — `~/.config/.zidane/` would be\n // a double-dot offense.\n const rawPrefix = opts.prefix ?? '.zidane'\n const prefixBare = rawPrefix.replace(/^\\./, '')\n\n // Branch 1 — explicit storage root → legacy-explicit.\n // Host-supplied `storageDir` beats env so SDK callers can pin a\n // location for embedded usage; otherwise `ZIDANE_STORAGE_DIR` wins.\n const explicitStorageDir = opts.storageDir ?? env.ZIDANE_STORAGE_DIR\n if (explicitStorageDir) {\n const base = resolve(explicitStorageDir, rawPrefix)\n return single(base, 'legacy-explicit')\n }\n\n // Branch 2 — `~/<prefix>/` already exists → legacy-existing.\n // Detect ANY of the legacy locations the user might have:\n // - `~/.zidane/` (default prefix)\n // - `~/.<prefix>/` (custom prefix)\n // The probe is a single existsSync (cheap) and skipping it for a\n // user with a customized prefix would leak their data into XDG dirs\n // on next launch.\n const legacyHomeDir = resolve(home, rawPrefix)\n if (existsSync(legacyHomeDir))\n return single(legacyHomeDir, 'legacy-existing')\n\n // Branch 3 — XDG signals present → split layout.\n // The signal is generous: Linux always qualifies, any platform\n // where the user has set any `XDG_*_HOME` var opts in (a savvy\n // mac user can put zidane in their XDG hierarchy too), AND any\n // `ZIDANE_{CONFIG,DATA,STATE,CACHE}_DIR` per-slot override also\n // opts in — otherwise a user pinning JUST `ZIDANE_CACHE_DIR` on\n // macOS would have it silently ignored because none of the\n // `XDG_*_HOME` vars are set.\n const hasXdgSignal = platform === 'linux'\n || !!env.XDG_CONFIG_HOME\n || !!env.XDG_DATA_HOME\n || !!env.XDG_CACHE_HOME\n || !!env.XDG_STATE_HOME\n || !!env.ZIDANE_CONFIG_DIR\n || !!env.ZIDANE_DATA_DIR\n || !!env.ZIDANE_STATE_DIR\n || !!env.ZIDANE_CACHE_DIR\n\n if (hasXdgSignal) {\n return {\n configDir: env.ZIDANE_CONFIG_DIR\n ?? resolve(env.XDG_CONFIG_HOME || resolve(home, '.config'), prefixBare),\n dataDir: env.ZIDANE_DATA_DIR\n ?? resolve(env.XDG_DATA_HOME || resolve(home, '.local', 'share'), prefixBare),\n stateDir: env.ZIDANE_STATE_DIR\n ?? resolve(env.XDG_STATE_HOME || resolve(home, '.local', 'state'), prefixBare),\n cacheDir: env.ZIDANE_CACHE_DIR\n ?? resolve(env.XDG_CACHE_HOME || resolve(home, '.cache'), prefixBare),\n mode: 'xdg',\n }\n }\n\n // Branch 4 — default (mac/windows, no XDG signal, no existing dir).\n // Same as the day-one experience: everything under `~/<prefix>/`.\n return single(legacyHomeDir, 'default')\n}\n\nfunction single(base: string, mode: StorageMode): StorageDirs {\n return {\n configDir: base,\n dataDir: base,\n stateDir: base,\n cacheDir: base,\n mode,\n }\n}\n","/**\n * The Agent Plugins package boundary.\n *\n * The spec's central filesystem rule: \"Every package file a client\n * discovers, reads, or executes must remain inside the filesystem-resolved\n * root after resolving symlinks, junctions, reparse points, and equivalent\n * mechanisms.\"\n *\n * Lexical containment (`../skills/validate.ts`'s `validateResourcePath`) is\n * NOT sufficient here — a `skills` symlink pointing at `~/.ssh` passes every\n * lexical check. So each package path is resolved through `realpath` and\n * re-tested against the realpath-resolved root, and the required filesystem\n * kind is asserted with a symlink-FOLLOWING `stat` (the spec wants\n * `SKILL.md` to be a regular file, not a fifo or a directory wearing the\n * name).\n *\n * Containment is tested with `path.relative` rather than a string prefix so\n * `/plugin-root` vs `/plugin-root-evil` can't be confused and Windows\n * separators are handled by the platform.\n */\n\nimport { realpath, stat } from 'node:fs/promises'\nimport { isAbsolute, relative, resolve } from 'node:path'\n\n/**\n * A resolved plugin root. Hold one of these for the lifetime of a load and\n * pass it to every path check, so `realpath(root)` is paid once rather than\n * per package file.\n */\nexport interface PluginBoundary {\n /** Plugin root as requested, made absolute (symlinks NOT resolved). */\n dir: string\n /** Symlink-resolved plugin root. The boundary every package path is tested against. */\n root: string\n}\n\n/**\n * Why a package path is unusable.\n *\n * - `missing` the path does not exist. Often benign (a missing fixed\n * location is valid per spec), so callers decide severity.\n * - `escaped` the path resolved outside the plugin root.\n * - `wrong-kind` the path exists but is not the required filesystem kind.\n */\nexport type PackagePathFailure = 'missing' | 'escaped' | 'wrong-kind'\n\nexport type PackagePathResult\n = | { ok: true, real: string }\n | { ok: false, reason: PackagePathFailure }\n\n/** Filesystem kind a package path is required to have. */\nexport type PackagePathKind = 'file' | 'directory'\n\n/**\n * Resolve the plugin root itself. Returns `null` when the root does not\n * exist or is not a directory — the caller turns that into a plugin-level\n * rejection, since there is nothing to load.\n */\nexport async function resolvePluginBoundary(dir: string): Promise<PluginBoundary | null> {\n const absolute = resolve(dir)\n try {\n const root = await realpath(absolute)\n if (!(await stat(root)).isDirectory())\n return null\n return { dir: absolute, root }\n }\n catch {\n return null\n }\n}\n\n/**\n * True when `real` (an already symlink-resolved path) lives at or under\n * `root` (likewise resolved).\n */\nexport function isWithin(root: string, real: string): boolean {\n const rel = relative(root, real)\n // `''` is the root itself; a `..` lead or an absolute result means the\n // target sits outside (the latter happens across Windows drives).\n return rel === '' || (!rel.startsWith('..') && !isAbsolute(rel))\n}\n\n/**\n * Symlink-resolve `target` and confirm it stays inside the boundary.\n *\n * Use this for paths whose filesystem kind doesn't matter or that may not\n * exist yet (Phase 3's `cwd` handling); otherwise prefer\n * {@link resolvePackagePath}, which also asserts the kind.\n */\nexport async function realPathWithin(\n boundary: PluginBoundary,\n target: string,\n): Promise<PackagePathResult> {\n let real: string\n try {\n real = await realpath(target)\n }\n catch {\n return { ok: false, reason: 'missing' }\n }\n if (!isWithin(boundary.root, real))\n return { ok: false, reason: 'escaped' }\n return { ok: true, real }\n}\n\n/**\n * Resolve a package path and assert its filesystem kind.\n *\n * `stat` (not `lstat`) is deliberate: a symlink to a regular file INSIDE the\n * root is legitimate packaging, and containment is already enforced against\n * the resolved target. What we reject is the kind mismatch the spec calls\n * out — `skills` as a regular file, `SKILL.md` as a directory or a fifo.\n */\nexport async function resolvePackagePath(\n boundary: PluginBoundary,\n target: string,\n kind: PackagePathKind,\n): Promise<PackagePathResult> {\n const within = await realPathWithin(boundary, target)\n if (!within.ok)\n return within\n try {\n const info = await stat(within.real)\n const matches = kind === 'directory' ? info.isDirectory() : info.isFile()\n if (!matches)\n return { ok: false, reason: 'wrong-kind' }\n }\n catch {\n // Raced away between realpath and stat.\n return { ok: false, reason: 'missing' }\n }\n return within\n}\n","/**\n * Types for the Agent Plugins loader.\n *\n * Implements the Agent Plugins open standard (agent-plugins.org) — a\n * portable package format that places reusable agent components at fixed\n * locations inside a plugin root:\n *\n * plugin.json the closed manifest (identity + metadata)\n * skills/ immediate child dirs holding an Agent Skills `SKILL.md`\n * mcp.json one MCP server configuration document\n *\n * Agent Plugins deliberately does NOT redefine either component format —\n * skills are Agent Skills, MCP config is MCP config. So this module owns\n * only the packaging contract: manifest validation, the filesystem\n * boundary, fixed-location discovery, and the failure-isolation ladder.\n * The component formats themselves route through the existing loaders\n * (`../skills/discovery`, `../mcp`), which is why `LoadedPlugin` hands\n * back plain `SkillConfig` / `McpServerConfig` values that every\n * downstream consumer already understands.\n *\n * Validation here is STRICT, unlike `../skills/discovery` (lenient by\n * design) and `normalizeMcpServers` (heuristic by design). The spec\n * mandates closed schemas with narrow failure boundaries; a plugin is a\n * third-party package, so \"guess what the author meant\" is the wrong\n * default. Leniency is reserved for the two violations the spec\n * explicitly marks non-fatal (see `./manifest`).\n */\n\nimport type { McpServerConfig } from '../mcp'\nimport type { SkillConfig, SkillSource } from '../skills'\n\n// ---------------------------------------------------------------------------\n// Spec versions\n// ---------------------------------------------------------------------------\n\n/**\n * Agent Plugins spec versions this loader implements, newest first.\n *\n * The spec requires clients to select validation rules from the manifest's\n * `$schema` WITHOUT retrieving it, and to let plugins keep targeting older\n * versions under a locally supported compatibility policy. Our policy: a\n * version is supported iff it appears in this list. Adding `1.1.0` later\n * means adding it here plus any rule deltas in `./manifest` — never\n * reinterpreting an already-published identifier, which the spec forbids.\n */\nexport const SUPPORTED_AGENT_PLUGINS_VERSIONS = ['1.0.0'] as const\n\nexport type AgentPluginsVersion = typeof SUPPORTED_AGENT_PLUGINS_VERSIONS[number]\n\n/** Which canonical schema a `$schema` identifier selects. */\nexport type PluginSchemaKind = 'plugin' | 'mcp'\n\n/**\n * Canonical schema identifier for a given document kind + version. Built\n * rather than hardcoded so the two call sites (manifest, mcp.json) can't\n * drift, and so the version cross-check the spec requires between\n * `plugin.json` and `mcp.json` is a plain string comparison.\n */\nexport function agentPluginsSchemaId(kind: PluginSchemaKind, version: string): string {\n return `https://agent-plugins.org/schemas/${version}/${kind}.schema.json`\n}\n\n/**\n * Canonical schema identifier grammar. Anchored and exact — a `$schema`\n * that merely looks similar (http, a trailing slash, a different host) is\n * not the canonical identifier and must not select the contract.\n */\nconst SCHEMA_ID_RE = /^https:\\/\\/agent-plugins\\.org\\/schemas\\/([^/]+)\\/(plugin|mcp)\\.schema\\.json$/\n\n/**\n * Split a canonical `$schema` identifier into its document kind + version.\n * Returns `null` for anything that isn't a canonical identifier; the caller\n * decides whether that's fatal (manifest) or component-scoped (mcp.json).\n *\n * Purely syntactic: it never fetches. The spec forbids retrieving a schema\n * during load, so version support is a lookup against\n * {@link SUPPORTED_AGENT_PLUGINS_VERSIONS}, not a download.\n */\nexport function parseSchemaId(value: string): { kind: PluginSchemaKind, version: string } | null {\n const match = SCHEMA_ID_RE.exec(value)\n if (!match)\n return null\n return { kind: match[2] as PluginSchemaKind, version: match[1]! }\n}\n\n/** True when this loader implements the given Agent Plugins version. */\nexport function isSupportedAgentPluginsVersion(version: string): version is AgentPluginsVersion {\n return (SUPPORTED_AGENT_PLUGINS_VERSIONS as readonly string[]).includes(version)\n}\n\n/**\n * Type label for a rejected JSON value, for diagnostic messages.\n *\n * `typeof` alone is useless in a validator that has to tell an author what\n * they got wrong: `null` and `[]` both report `'object'`, and those are two of\n * the most common mistakes in a hand-written manifest. Shared by the manifest\n * and `mcp.json` validators, which produce the same class of message.\n *\n * Internal — not re-exported from the module barrel.\n */\nexport function describeJsonType(value: unknown): string {\n if (value === null)\n return 'null'\n if (Array.isArray(value))\n return 'array'\n return typeof value\n}\n\n// ---------------------------------------------------------------------------\n// Manifest\n// ---------------------------------------------------------------------------\n\n/** Optional author block. Closed: only these three keys, all strings. */\nexport interface PluginAuthor {\n name?: string\n email?: string\n url?: string\n}\n\n/**\n * A validated `plugin.json`. Only spec fields survive validation —\n * unknown top-level keys are reported and dropped, so consumers can\n * never accidentally depend on a non-portable field.\n *\n * `version` here is the PLUGIN's own version string; the spec version\n * selected by `$schema` lands on {@link PluginManifest.specVersion}.\n */\nexport interface PluginManifest {\n /** Agent Plugins version selected by the manifest's `$schema`. */\n specVersion: AgentPluginsVersion\n /** Plugin name + package identifier (1-64 chars, see `./manifest`). */\n name: string\n version?: string\n description?: string\n author?: PluginAuthor\n homepage?: string\n repository?: string\n license?: string\n keywords?: string[]\n /**\n * Client-owned data keyed by reverse-domain namespace. Values are\n * deliberately `unknown`: the spec says to ignore namespaces the client\n * does not implement WITHOUT validating their contents, so this loader\n * never inspects a member it doesn't own.\n */\n extensions?: Record<string, unknown>\n}\n\n// ---------------------------------------------------------------------------\n// Diagnostics\n// ---------------------------------------------------------------------------\n\n/**\n * A load-time finding. Mirrors `SkillDiagnostic`'s shape (severity + stable\n * code + message) so host UIs already rendering skill diagnostics can\n * render these with no new plumbing.\n *\n * `severity: 'error'` on a returned plugin means a narrow boundary fired\n * (a component type disabled, a skill skipped) — NOT that the whole plugin\n * failed. Plugin-level rejection is signalled by `LoadedPlugin.ok === false`.\n */\nexport interface PluginDiagnostic {\n severity: 'warning' | 'error'\n /** Stable machine-readable code (e.g. `manifest-unknown-field`). */\n code: string\n message: string\n /** Manifest field the finding relates to, when applicable. */\n field?: string\n /** Filesystem path the finding relates to, when applicable. */\n path?: string\n}\n\n// ---------------------------------------------------------------------------\n// Component status\n// ---------------------------------------------------------------------------\n\n/**\n * Per-component-type outcome. The spec insists a missing fixed location is\n * NOT an error, and that an invalid one disables only its own component\n * type — so these four states are load-bearing, not cosmetic:\n *\n * - `absent` fixed location not present. Valid.\n * - `loaded` discovered (possibly zero entries, e.g. an empty `skills/`).\n * - `invalid` wrong filesystem kind, or the location escaped the root.\n * - `unsupported` never discovered — not implemented by this client,\n * disabled by the caller, or the plugin was rejected\n * before component discovery ran.\n */\nexport type PluginComponentStatus = 'absent' | 'loaded' | 'invalid' | 'unsupported'\n\n// ---------------------------------------------------------------------------\n// Loaded plugin\n// ---------------------------------------------------------------------------\n\n/**\n * Result of {@link loadAgentPlugin}. Never thrown — a rejected plugin comes\n * back as `ok: false` with the reason in `diagnostics`, because one bad\n * plugin must not take down a host that's loading several.\n */\nexport interface LoadedPlugin {\n /**\n * `false` when a fatal manifest or boundary violation rejected the whole\n * plugin. Components are empty in that case and were never discovered —\n * the spec requires rejection to happen BEFORE component discovery.\n */\n ok: boolean\n /** Plugin root as requested, resolved to an absolute path. */\n dir: string\n /**\n * Symlink-resolved plugin root. Every package path a caller touches must\n * stay under this — it's the boundary the spec defines. Falls back to\n * `dir` when the root itself could not be resolved.\n */\n root: string\n /** Validated manifest. Absent iff `ok === false`. */\n manifest?: PluginManifest\n /** Skills discovered under `skills/`. */\n skills: SkillConfig[]\n /** MCP servers declared by `mcp.json`. */\n mcpServers: McpServerConfig[]\n /** Per-component-type outcome — see {@link PluginComponentStatus}. */\n components: {\n skills: PluginComponentStatus\n mcp: PluginComponentStatus\n }\n /** Everything worth reporting: rejections, disabled components, skipped skills. */\n diagnostics: PluginDiagnostic[]\n}\n\n// ---------------------------------------------------------------------------\n// Load options\n// ---------------------------------------------------------------------------\n\nexport interface LoadAgentPluginOptions {\n /**\n * Source tag stamped onto every discovered skill, driving collision\n * precedence and the `trustProjectSkills` gate downstream. Defaults to\n * `'project'` — the conservative choice, since a plugin sitting in a\n * repo is exactly the untrusted-input case that gate exists for.\n */\n source?: SkillSource\n /**\n * Prefix applied to discovered skill names as `<prefix>-<name>`.\n *\n * Agent Plugins leaves naming to the client, and zidane's skill catalog\n * is a single flat namespace (`discoverSkills` dedupes by name), so two\n * plugins shipping a `deploy` skill would silently shadow one another.\n * Opt in to prefixing when loading untrusted or multiple plugins.\n */\n namePrefix?: string\n /** Discover `skills/`. Default `true`. */\n skills?: boolean\n /** Discover `mcp.json`. Default `true`. */\n mcp?: boolean\n /**\n * Exact directory exposed to MCP servers as `${PLUGIN_DATA}`.\n *\n * Must live outside the plugin root: the spec requires this directory to\n * persist across plugin updates, and an update replaces the package tree.\n * Prefer {@link LoadAgentPluginOptions.dataRoot} unless you need to pin one\n * specific plugin's directory.\n */\n dataDir?: string\n /**\n * Parent directory under which `${PLUGIN_DATA}` is created as\n * `<dataRoot>/<plugin-name>/`.\n *\n * Exists because the plugin name comes from the manifest, which the caller\n * hasn't read yet — a host that wants its own namespace (the extensions\n * seam puts plugin data inside the loading extension's storage root) can\n * supply the parent and let the loader append the name.\n *\n * Defaults to `<dataDir>/plugin-data` from `resolveStorageDirs`. Ignored\n * when {@link LoadAgentPluginOptions.dataDir} is set.\n */\n dataRoot?: string\n}\n","/**\n * `plugin.json` validation.\n *\n * The manifest schema is CLOSED and validated locally — the spec is explicit\n * that a client selects its rules from `$schema` and must not retrieve a\n * schema while loading. So the 1.0.0 contract is encoded here as code rather\n * than fetched or bundled as JSON Schema (the repo has no schema validator,\n * and the document is small and closed enough that hand-rolling it stays\n * honest — same call as the hand-rolled frontmatter parser in\n * `../skills/discovery.ts`).\n *\n * Exactly two violations are non-fatal, per spec:\n *\n * 1. an unknown top-level field → report, ignore, continue\n * 2. a non-object `extensions` → report, ignore, continue\n *\n * Every other schema violation rejects the whole plugin, and rejection\n * happens BEFORE component discovery — a plugin with a broken manifest never\n * gets its skills read or its MCP servers spawned.\n */\n\nimport type { PluginAuthor, PluginDiagnostic, PluginManifest } from './types'\nimport {\n agentPluginsSchemaId,\n describeJsonType,\n isSupportedAgentPluginsVersion,\n parseSchemaId,\n SUPPORTED_AGENT_PLUGINS_VERSIONS,\n} from './types'\n\n/**\n * Plugin name grammar, lifted from the canonical schema: 1-64 chars,\n * lowercase alphanumerics plus `-` and `.`, alphanumeric at both ends, and\n * no `--` or `..` anywhere (the negative lookahead).\n *\n * Length is checked separately so an over-long name gets a message about\n * length instead of a generic \"doesn't match the grammar\".\n */\nconst PLUGIN_NAME_RE = /^(?!.*(?:--|\\.\\.))[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$/\n\nconst NAME_MAX = 64\n\n/** Top-level fields the 1.0.0 manifest permits. Anything else is unknown. */\nconst KNOWN_FIELDS = new Set([\n '$schema',\n 'name',\n 'version',\n 'description',\n 'author',\n 'homepage',\n 'repository',\n 'license',\n 'keywords',\n 'extensions',\n])\n\n/** Optional top-level fields whose value must be a string when present. */\nconst STRING_FIELDS = ['version', 'description', 'homepage', 'repository', 'license'] as const\n\n/** Keys the closed `author` object permits. */\nconst AUTHOR_FIELDS = new Set(['name', 'email', 'url'])\n\nexport type ManifestValidation\n = | { ok: true, manifest: PluginManifest, diagnostics: PluginDiagnostic[] }\n | { ok: false, diagnostics: PluginDiagnostic[] }\n\n/**\n * Parse manifest text, then validate it.\n *\n * A JSON syntax error is fatal — unlike `mcps.json` (where\n * `parseJsonTolerant` repairs copy-paste whitespace artifacts), a plugin\n * manifest is a package file produced by a build or an author's editor, not\n * pasted into a settings box. Repairing it would mean guessing at the\n * contents of a third-party package.\n */\nexport function parsePluginManifest(text: string): ManifestValidation {\n let raw: unknown\n try {\n raw = JSON.parse(text)\n }\n catch (err) {\n return {\n ok: false,\n diagnostics: [{\n severity: 'error',\n code: 'manifest-invalid-json',\n message: `plugin.json is not valid JSON: ${err instanceof Error ? err.message : String(err)}`,\n }],\n }\n }\n return validatePluginManifest(raw)\n}\n\n/**\n * Validate an already-parsed manifest value against the closed 1.0.0 schema.\n *\n * Fatal violations short-circuit: `$schema` and `name` are checked first\n * because without them there is no contract to validate against and no\n * identity to report problems under.\n */\nexport function validatePluginManifest(raw: unknown): ManifestValidation {\n const diagnostics: PluginDiagnostic[] = []\n\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {\n return {\n ok: false,\n diagnostics: [{\n severity: 'error',\n code: 'manifest-not-object',\n message: `plugin.json must be a JSON object (got ${Array.isArray(raw) ? 'array' : typeof raw}).`,\n }],\n }\n }\n\n const obj = raw as Record<string, unknown>\n\n // --- $schema: selects the contract. No contract, no plugin. ------------\n const schema = obj.$schema\n if (typeof schema !== 'string' || schema.length === 0) {\n return fatal(diagnostics, {\n code: 'manifest-schema-missing',\n message: `plugin.json is missing the required \"$schema\" field. Expected \"${agentPluginsSchemaId('plugin', SUPPORTED_AGENT_PLUGINS_VERSIONS[0])}\".`,\n field: '$schema',\n })\n }\n const parsed = parseSchemaId(schema)\n if (!parsed || parsed.kind !== 'plugin') {\n return fatal(diagnostics, {\n code: 'manifest-schema-unsupported',\n message: `plugin.json \"$schema\" is not a canonical Agent Plugins manifest schema identifier: \"${schema}\".`,\n field: '$schema',\n })\n }\n if (!isSupportedAgentPluginsVersion(parsed.version)) {\n return fatal(diagnostics, {\n code: 'manifest-schema-unsupported',\n message: `plugin.json targets Agent Plugins ${parsed.version}, which this client does not support (supported: ${SUPPORTED_AGENT_PLUGINS_VERSIONS.join(', ')}).`,\n field: '$schema',\n })\n }\n\n // --- name: identity. --------------------------------------------------\n const name = obj.name\n if (typeof name !== 'string') {\n return fatal(diagnostics, {\n code: 'manifest-name-missing',\n message: `plugin.json is missing the required \"name\" field${name === undefined ? '' : ` (got ${typeof name})`}.`,\n field: 'name',\n })\n }\n if (name.length === 0 || name.length > NAME_MAX) {\n return fatal(diagnostics, {\n code: 'manifest-name-invalid',\n message: `Plugin name must be 1-${NAME_MAX} characters (got ${name.length}).`,\n field: 'name',\n })\n }\n if (!PLUGIN_NAME_RE.test(name)) {\n return fatal(diagnostics, {\n code: 'manifest-name-invalid',\n message: `Plugin name \"${name}\" is invalid — use lowercase letters, digits, hyphens and periods, starting and ending alphanumeric, with no \"--\" or \"..\".`,\n field: 'name',\n })\n }\n\n const manifest: PluginManifest = { specVersion: parsed.version, name }\n\n // --- optional strings -------------------------------------------------\n for (const field of STRING_FIELDS) {\n const value = obj[field]\n if (value === undefined)\n continue\n if (typeof value !== 'string') {\n return fatal(diagnostics, {\n code: 'manifest-field-wrong-type',\n message: `plugin.json \"${field}\" must be a string (got ${describeJsonType(value)}).`,\n field,\n })\n }\n manifest[field] = value\n }\n\n // --- keywords ---------------------------------------------------------\n if (obj.keywords !== undefined) {\n if (!Array.isArray(obj.keywords)) {\n return fatal(diagnostics, {\n code: 'manifest-field-wrong-type',\n message: `plugin.json \"keywords\" must be an array of strings (got ${describeJsonType(obj.keywords)}).`,\n field: 'keywords',\n })\n }\n const bad = obj.keywords.findIndex(entry => typeof entry !== 'string')\n if (bad !== -1) {\n return fatal(diagnostics, {\n code: 'manifest-field-wrong-type',\n message: `plugin.json \"keywords[${bad}]\" must be a string (got ${describeJsonType(obj.keywords[bad])}).`,\n field: 'keywords',\n })\n }\n manifest.keywords = [...obj.keywords as string[]]\n }\n\n // --- author (closed object) -------------------------------------------\n if (obj.author !== undefined) {\n const author = obj.author\n if (typeof author !== 'object' || author === null || Array.isArray(author)) {\n return fatal(diagnostics, {\n code: 'manifest-field-wrong-type',\n message: `plugin.json \"author\" must be an object (got ${describeJsonType(author)}).`,\n field: 'author',\n })\n }\n const out: PluginAuthor = {}\n for (const [key, value] of Object.entries(author as Record<string, unknown>)) {\n // `author` is closed by the schema, and an unknown key here is NOT one\n // of the two non-fatal cases (which are scoped to TOP-LEVEL unknown\n // fields) — so this rejects the plugin.\n if (!AUTHOR_FIELDS.has(key)) {\n return fatal(diagnostics, {\n code: 'manifest-author-unknown-field',\n message: `plugin.json \"author.${key}\" is not a permitted field (allowed: ${[...AUTHOR_FIELDS].join(', ')}).`,\n field: 'author',\n })\n }\n if (typeof value !== 'string') {\n return fatal(diagnostics, {\n code: 'manifest-field-wrong-type',\n message: `plugin.json \"author.${key}\" must be a string (got ${describeJsonType(value)}).`,\n field: 'author',\n })\n }\n out[key as keyof PluginAuthor] = value\n }\n manifest.author = out\n }\n\n // --- extensions (non-fatal when not an object) ------------------------\n if (obj.extensions !== undefined) {\n const ext = obj.extensions\n if (typeof ext !== 'object' || ext === null || Array.isArray(ext)) {\n diagnostics.push({\n severity: 'warning',\n code: 'manifest-extensions-not-object',\n message: `plugin.json \"extensions\" must be an object (got ${describeJsonType(ext)}) — ignoring it and continuing to load components.`,\n field: 'extensions',\n })\n }\n else {\n // Member VALUES are intentionally not validated: the spec says to\n // ignore namespaces the client does not implement without validating\n // them, and the normative text governs over the machine-readable\n // schema (which types members as objects). A client that implements a\n // namespace validates its own member at the point of use.\n manifest.extensions = { ...ext as Record<string, unknown> }\n }\n }\n\n // --- unknown top-level fields (non-fatal) -----------------------------\n for (const key of Object.keys(obj)) {\n if (KNOWN_FIELDS.has(key))\n continue\n diagnostics.push({\n severity: 'warning',\n code: 'manifest-unknown-field',\n message: `plugin.json has unknown top-level field \"${key}\" — ignoring it. Client-specific data belongs under \"extensions\".`,\n field: key,\n })\n }\n\n return { ok: true, manifest, diagnostics }\n}\n\nfunction fatal(\n diagnostics: PluginDiagnostic[],\n detail: Omit<PluginDiagnostic, 'severity'>,\n): { ok: false, diagnostics: PluginDiagnostic[] } {\n diagnostics.push({ severity: 'error', ...detail })\n return { ok: false, diagnostics }\n}\n","/**\n * The `mcp.json` component type.\n *\n * This does NOT route through `normalizeMcpServers`. That function is\n * deliberately heuristic — it infers a transport from the presence of\n * `command` / `url`, accepts `httpUrl` / `sseUrl` / `type: 'http'` aliases,\n * and tolerates unknown keys — because its job is making a config pasted\n * from Cursor or Claude Desktop Just Work. The plugin spec wants the exact\n * opposite: a closed document, a closed entry per declared transport, and an\n * unknown field invalidating that ONE entry. Guessing on behalf of a\n * third-party package is how you spawn a command the author didn't write.\n *\n * Three spec rules carry real security weight and are implemented here:\n *\n * 1. **Placeholders.** Only `${PLUGIN_ROOT}` and `${PLUGIN_DATA}`, only in\n * `args`, `env` values and `cwd`. Single-pass and non-recursive, so an\n * expansion can't produce another placeholder. Everything else —\n * `command`, `url`, `headers` — keeps its literal text, which is why\n * the produced configs carry `preExpanded` (see\n * `McpServerConfig.preExpanded`).\n * 2. **stdio resolution.** `command` is ONE executable token: a bare name\n * goes to PATH lookup, a `./`-relative path resolves inside the plugin\n * root. No shell, no argv splitting. `cwd` defaults to the plugin root\n * and must stay within the root or the data directory.\n * 3. **Remote URLs.** HTTPS unless loopback, no userinfo, no fragment, and\n * headers pinned to the configured origin across redirects.\n */\n\nimport type { McpServerConfig } from '../mcp'\nimport type { PluginBoundary } from './boundary'\nimport type { PluginComponentStatus, PluginDiagnostic } from './types'\nimport { readFile, realpath } from 'node:fs/promises'\nimport { isAbsolute, resolve } from 'node:path'\n// Deep import: `../mcp` is a large module and this is a dependency-free leaf,\n// so `zidane/plugins` shouldn't pull the whole MCP runtime for one predicate.\nimport { isAllowedRemoteUrl } from '../mcp/origin-pinned-fetch'\nimport { isWithin, realPathWithin } from './boundary'\nimport { agentPluginsSchemaId, describeJsonType, parseSchemaId } from './types'\n\n/** Fixed location for the MCP component type. */\nexport const PLUGIN_MCP_FILE = 'mcp.json'\n\n/** The only placeholders the spec defines. */\nconst PLUGIN_ROOT_VAR = 'PLUGIN_ROOT'\nconst PLUGIN_DATA_VAR = 'PLUGIN_DATA'\n\n/**\n * Placeholder grammar — deliberately narrower than\n * `expandEnvPlaceholders`'s: exactly the two reserved names, no\n * `:-default` form, no `${env:…}` form. Anything else stays literal.\n */\nconst PLUGIN_VAR_RE = /\\$\\{(PLUGIN_ROOT|PLUGIN_DATA)\\}/g\n\n/** Closed top-level key set for the document. */\nconst DOCUMENT_FIELDS = new Set(['$schema', 'mcpServers'])\n\n/**\n * Closed key set per declared transport.\n *\n * A `Map` rather than an object literal: the keys are attacker-controlled\n * (`type` comes straight out of a third-party `mcp.json`), and `'constructor'\n * in objectLiteral` is `true`, which would sail past the membership check and\n * then blow up on `Object.prototype.constructor.has(...)`.\n */\nconst ENTRY_FIELDS = new Map<string, Set<string>>([\n ['stdio', new Set(['type', 'command', 'args', 'env', 'cwd'])],\n ['streamable-http', new Set(['type', 'url', 'headers'])],\n ['sse', new Set(['type', 'url', 'headers'])],\n])\n\n/**\n * Server-name grammar.\n *\n * `connectMcpServers` namespaces tools as `mcp_<server>_<tool>`, and providers\n * reject a tool name outside the letters / digits / underscore / hyphen shape\n * — rejecting the whole REQUEST, not just the offending tool. A user-authored\n * `mcps.json` has the same sharp edge, but there the user owns the file; a\n * plugin is untrusted input, so an unusable name is rejected per-entry instead\n * of poisoning every run.\n */\nconst SERVER_NAME_RE = /^[a-z0-9][\\w-]{0,63}$/i\n\n/**\n * Keys that hit a prototype setter instead of creating an own property.\n * Same guard the extension registration paths apply to untrusted keys — see\n * `isSafeRecordKey` in `../extensions/register.ts`. Assigning `__proto__` on\n * an object literal silently DISCARDS the value, so without this an env var\n * would just never reach the child process with nothing explaining why.\n */\nconst DANGEROUS_RECORD_KEYS = new Set(['__proto__', 'prototype', 'constructor'])\n\nexport interface PluginMcpResult {\n status: PluginComponentStatus\n servers: McpServerConfig[]\n diagnostics: PluginDiagnostic[]\n}\n\nexport interface LoadPluginMcpOptions {\n boundary: PluginBoundary\n /** Plugin name — prefixes server names when `namePrefix` is set. */\n pluginName: string\n /**\n * Dedicated writable directory exposed as `${PLUGIN_DATA}`. Created on\n * demand, and only when a server actually references it. MUST live outside\n * the plugin root so a plugin update (which replaces the package) does not\n * wipe the data the spec says must persist.\n */\n dataDir: string\n /** Spec version the manifest declared — `mcp.json` must match it. */\n specVersion: string\n /** Prefix applied to server names as `<prefix>-<name>`. */\n namePrefix?: string\n}\n\n/**\n * Load and validate the plugin's `mcp.json`.\n *\n * Status semantics mirror `loadPluginSkills`: a missing file is `absent`\n * (valid), a wrong-kind / escaping / malformed document is `invalid` (this\n * component only), and anything else is `loaded` — even when individual\n * entries were rejected, because per-entry isolation is the point.\n */\nexport async function loadPluginMcp(opts: LoadPluginMcpOptions): Promise<PluginMcpResult> {\n const { boundary, pluginName, dataDir, specVersion, namePrefix } = opts\n const diagnostics: PluginDiagnostic[] = []\n const path = resolve(boundary.root, PLUGIN_MCP_FILE)\n\n const located = await realPathWithin(boundary, path)\n if (!located.ok) {\n if (located.reason === 'missing')\n return { status: 'absent', servers: [], diagnostics }\n diagnostics.push({\n severity: 'error',\n code: 'mcp-file-escapes-root',\n message: `\"${PLUGIN_MCP_FILE}\" resolves outside the plugin root — the MCP component is disabled for this plugin.`,\n path,\n })\n return { status: 'invalid', servers: [], diagnostics }\n }\n\n let raw: unknown\n try {\n raw = JSON.parse(await readFile(located.real, 'utf8'))\n }\n catch (err) {\n diagnostics.push({\n severity: 'error',\n code: 'mcp-invalid-json',\n message: `\"${PLUGIN_MCP_FILE}\" could not be read as JSON: ${err instanceof Error ? err.message : String(err)}`,\n path: located.real,\n })\n return { status: 'invalid', servers: [], diagnostics }\n }\n\n // --- stage 1: the closed top-level document ---------------------------\n const document = validateDocument(raw, specVersion)\n if (!document.ok) {\n diagnostics.push({ severity: 'error', ...document.diagnostic, path: located.real })\n return { status: 'invalid', servers: [], diagnostics }\n }\n\n // --- stage 2: each entry, independently -------------------------------\n //\n // Note what does NOT happen here: the `${PLUGIN_DATA}` directory is not\n // created. Loading resolves the path and stops there, because loading is not\n // consent. A host discovers every plugin on disk in order to learn its name\n // (identity lives in the manifest, so you cannot filter before loading), and\n // the user's `enabledPlugins` gate applies afterwards — so creating the\n // directory here would leave one behind for every plugin the user has\n // switched OFF, on every discovery pass. Creation happens at spawn time in\n // `mcp/index.ts`, the only place that knows a process is actually starting.\n const servers: McpServerConfig[] = []\n for (const [name, entry] of Object.entries(document.servers)) {\n const built = await buildServer({\n name,\n entry,\n boundary,\n dataDir,\n pluginName,\n ...(namePrefix !== undefined ? { namePrefix } : {}),\n })\n if (!built.ok) {\n // Per-entry isolation: one bad server never disables the component.\n diagnostics.push({ severity: 'error', ...built.diagnostic, path: located.real })\n continue\n }\n servers.push(built.config)\n }\n\n return { status: 'loaded', servers, diagnostics }\n}\n\n// ---------------------------------------------------------------------------\n// Stage 1 — document\n// ---------------------------------------------------------------------------\n\ntype DocumentValidation\n = | { ok: true, servers: Record<string, unknown> }\n | { ok: false, diagnostic: Omit<PluginDiagnostic, 'severity'> }\n\nfunction validateDocument(raw: unknown, specVersion: string): DocumentValidation {\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {\n return {\n ok: false,\n diagnostic: {\n code: 'mcp-not-object',\n message: `\"${PLUGIN_MCP_FILE}\" must be a JSON object (got ${describeJsonType(raw)}).`,\n },\n }\n }\n const obj = raw as Record<string, unknown>\n\n const schema = obj.$schema\n if (typeof schema !== 'string') {\n return {\n ok: false,\n diagnostic: {\n code: 'mcp-schema-missing',\n message: `\"${PLUGIN_MCP_FILE}\" is missing the required \"$schema\" field. Expected \"${agentPluginsSchemaId('mcp', specVersion)}\".`,\n field: '$schema',\n },\n }\n }\n const parsed = parseSchemaId(schema)\n if (!parsed || parsed.kind !== 'mcp') {\n return {\n ok: false,\n diagnostic: {\n code: 'mcp-schema-unsupported',\n message: `\"${PLUGIN_MCP_FILE}\" \"$schema\" is not a canonical Agent Plugins MCP schema identifier: \"${schema}\".`,\n field: '$schema',\n },\n }\n }\n // The spec requires matching Agent Plugins versions across the two\n // documents — a plugin declaring 1.0.0 rules in the manifest cannot opt a\n // single component into a different contract.\n if (parsed.version !== specVersion) {\n return {\n ok: false,\n diagnostic: {\n code: 'mcp-schema-version-mismatch',\n message: `\"${PLUGIN_MCP_FILE}\" targets Agent Plugins ${parsed.version} but plugin.json targets ${specVersion} — the versions must match.`,\n field: '$schema',\n },\n }\n }\n\n for (const key of Object.keys(obj)) {\n if (!DOCUMENT_FIELDS.has(key)) {\n return {\n ok: false,\n diagnostic: {\n code: 'mcp-unknown-field',\n message: `\"${PLUGIN_MCP_FILE}\" has unknown top-level field \"${key}\".`,\n field: key,\n },\n }\n }\n }\n\n const servers = obj.mcpServers\n if (typeof servers !== 'object' || servers === null || Array.isArray(servers)) {\n return {\n ok: false,\n diagnostic: {\n code: 'mcp-servers-wrong-type',\n message: `\"${PLUGIN_MCP_FILE}\" \"mcpServers\" must be an object (got ${describeJsonType(servers)}).`,\n field: 'mcpServers',\n },\n }\n }\n\n return { ok: true, servers: servers as Record<string, unknown> }\n}\n\n// ---------------------------------------------------------------------------\n// Stage 2 — one entry\n// ---------------------------------------------------------------------------\n\ntype EntryValidation\n = | { ok: true, config: McpServerConfig }\n | { ok: false, diagnostic: Omit<PluginDiagnostic, 'severity'> }\n\nasync function buildServer(opts: {\n name: string\n entry: unknown\n boundary: PluginBoundary\n dataDir: string\n pluginName: string\n namePrefix?: string\n}): Promise<EntryValidation> {\n const { name, entry, boundary, dataDir, namePrefix } = opts\n const reject = (code: string, message: string): EntryValidation => ({\n ok: false,\n diagnostic: { code, message: `Skipped MCP server \"${name}\" — ${message}` },\n })\n\n // Validated in the form it will actually take in the model's tool catalog\n // (`mcp_<serverName>_<tool>`), which means AFTER `namePrefix` is applied:\n // the prefix is part of that string, so a caller-supplied prefix can\n // invalidate a name the plugin itself got right. Catching it here rather\n // than at the provider boundary matters because there an unusable name\n // fails the whole REQUEST, not just the one tool.\n const serverName = namePrefix ? `${namePrefix}-${name}` : name\n if (!SERVER_NAME_RE.test(serverName)) {\n return reject('mcp-entry-name-invalid', namePrefix\n ? `its namespaced name \"${serverName}\" is not usable as a tool prefix — the \"${namePrefix}\" namePrefix must be letters, digits, underscores or hyphens, and the two together at most 64 characters.`\n : 'its name must be 1-64 characters of letters, digits, underscores or hyphens, starting alphanumeric.')\n }\n\n if (typeof entry !== 'object' || entry === null || Array.isArray(entry))\n return reject('mcp-entry-not-object', `its value must be an object (got ${describeJsonType(entry)}).`)\n const obj = entry as Record<string, unknown>\n\n // The declared transport selects the closed key set AND the connection\n // attempt. It is never inferred: an entry without `type` is invalid, full\n // stop, because guessing is how a `url` typo becomes a spawned command.\n const type = typeof obj.type === 'string' ? obj.type : undefined\n const allowed = type === undefined ? undefined : ENTRY_FIELDS.get(type)\n if (type === undefined || !allowed)\n return reject('mcp-entry-transport-invalid', `\"type\" must be one of stdio, streamable-http, sse (got ${type === undefined ? describeJsonType(obj.type) : `\"${type}\"`}).`)\n\n for (const key of Object.keys(obj)) {\n if (!allowed.has(key))\n return reject('mcp-entry-unknown-field', `\"${key}\" is not a permitted field for a ${type} server (allowed: ${[...allowed].join(', ')}).`)\n }\n\n const vars = { [PLUGIN_ROOT_VAR]: boundary.root, [PLUGIN_DATA_VAR]: dataDir }\n\n if (type === 'stdio') {\n // --- command: exactly one executable token -------------------------\n const command = obj.command\n if (typeof command !== 'string' || command.length === 0)\n return reject('mcp-entry-command-invalid', 'a stdio server needs a non-empty \"command\".')\n // Placeholders are NOT expanded in `command`, so a `${PLUGIN_ROOT}` here\n // would be passed to the OS literally. Reject rather than spawn it.\n if (PLUGIN_VAR_RE.test(command)) {\n PLUGIN_VAR_RE.lastIndex = 0\n return reject('mcp-entry-command-invalid', 'placeholders are not expanded in \"command\" — use a \"./\"-relative path or a bare executable name.')\n }\n if (/\\s/.test(command))\n return reject('mcp-entry-command-invalid', `\"command\" must be a single executable token, not a command line (\"${command}\").`)\n const resolvedCommand = await resolveCommand(command, boundary)\n if (!resolvedCommand.ok)\n return reject('mcp-entry-command-invalid', resolvedCommand.error)\n\n // --- args ----------------------------------------------------------\n let args: string[] | undefined\n if (obj.args !== undefined) {\n if (!Array.isArray(obj.args) || obj.args.some(a => typeof a !== 'string'))\n return reject('mcp-entry-args-invalid', '\"args\" must be an array of strings.')\n args = (obj.args as string[]).map(a => expandPluginVars(a, vars))\n }\n\n // --- env -----------------------------------------------------------\n let env: Record<string, string> | undefined\n if (obj.env !== undefined) {\n if (typeof obj.env !== 'object' || obj.env === null || Array.isArray(obj.env))\n return reject('mcp-entry-env-invalid', '\"env\" must be an object of strings.')\n env = {}\n for (const [key, value] of Object.entries(obj.env as Record<string, unknown>)) {\n if (typeof value !== 'string')\n return reject('mcp-entry-env-invalid', `\"env.${key}\" must be a string (got ${describeJsonType(value)}).`)\n // The reserved names are supplied by the client, not the plugin.\n if (key === PLUGIN_ROOT_VAR || key === PLUGIN_DATA_VAR)\n return reject('mcp-entry-env-invalid', `\"env.${key}\" is reserved and cannot be set by a plugin.`)\n if (!isSafeRecordKey(key))\n return reject('mcp-entry-env-invalid', `\"env.${key}\" is not a usable variable name.`)\n env[key] = expandPluginVars(value, vars)\n }\n }\n\n // --- cwd -----------------------------------------------------------\n const cwdResult = await resolveCwd(obj.cwd, boundary, dataDir, vars)\n if (!cwdResult.ok)\n return reject('mcp-entry-cwd-invalid', cwdResult.error)\n\n const config: McpServerConfig = {\n name: serverName,\n transport: 'stdio',\n command: resolvedCommand.command,\n // Reserved variables are written LAST so a plugin cannot shadow them\n // through some other spelling, and so they always describe reality.\n env: { ...env, [PLUGIN_ROOT_VAR]: boundary.root, [PLUGIN_DATA_VAR]: dataDir },\n cwd: cwdResult.cwd,\n preExpanded: true,\n }\n if (args)\n config.args = args\n return { ok: true, config }\n }\n\n // --- remote transports ------------------------------------------------\n const url = obj.url\n if (typeof url !== 'string' || url.length === 0)\n return reject('mcp-entry-url-invalid', `a ${type} server needs a non-empty \"url\".`)\n const checked = validateRemoteUrl(url)\n if (!checked.ok)\n return reject('mcp-entry-url-invalid', checked.error)\n\n let headers: Record<string, string> | undefined\n if (obj.headers !== undefined) {\n if (typeof obj.headers !== 'object' || obj.headers === null || Array.isArray(obj.headers))\n return reject('mcp-entry-headers-invalid', '\"headers\" must be an object of strings.')\n headers = {}\n for (const [key, value] of Object.entries(obj.headers as Record<string, unknown>)) {\n if (!isSafeRecordKey(key))\n return reject('mcp-entry-headers-invalid', `\"headers.${key}\" is not a usable header name.`)\n if (typeof value !== 'string')\n return reject('mcp-entry-headers-invalid', `\"headers.${key}\" must be a string (got ${describeJsonType(value)}).`)\n // Not expanded — spec scopes placeholders to args/env/cwd.\n headers[key] = value\n }\n }\n\n const config: McpServerConfig = {\n name: serverName,\n transport: type === 'sse' ? 'sse' : 'streamable-http',\n url,\n preExpanded: true,\n pinHeaderOrigin: true,\n }\n if (headers)\n config.headers = headers\n return { ok: true, config }\n}\n\n// ---------------------------------------------------------------------------\n// Placeholders\n// ---------------------------------------------------------------------------\n\n/**\n * Substitute the two reserved placeholders in one string.\n *\n * Single-pass by construction (`String.replace` never re-scans its own\n * output), so a `${PLUGIN_ROOT}` whose value somehow contained\n * `${PLUGIN_DATA}` cannot expand twice. Unknown `${...}` text is left\n * verbatim: the spec defines exactly two placeholders, and silently\n * blanking anything else would corrupt legitimate literals.\n */\nexport function expandPluginVars(value: string, vars: Record<string, string>): string {\n return value.replace(PLUGIN_VAR_RE, (match, name: string) => vars[name] ?? match)\n}\n\n// ---------------------------------------------------------------------------\n// stdio resolution\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve the single `command` token.\n *\n * A bare name (`uvx`, `node`) is handed to the OS for PATH lookup — the\n * plugin declares a dependency on the host's toolchain, which is normal. A\n * `./`-relative token is a file the PACKAGE ships, so it resolves against\n * the plugin root and must survive the containment check. An absolute path\n * is refused: it is neither a PATH lookup nor a package file, and it is the\n * shape an escape attempt takes.\n */\nasync function resolveCommand(\n command: string,\n boundary: PluginBoundary,\n): Promise<{ ok: true, command: string } | { ok: false, error: string }> {\n if (isAbsolute(command))\n return { ok: false, error: `\"command\" must be a bare executable name or a \"./\"-relative path inside the plugin, not an absolute path (\"${command}\").` }\n\n // Bare token → PATH lookup by the OS. Note `foo/bar` (no leading `./`) is\n // also not a bare name; treat any separator as package-relative.\n if (!command.includes('/') && !command.includes('\\\\'))\n return { ok: true, command }\n\n const target = resolve(boundary.root, command)\n const within = await realPathWithin(boundary, target)\n if (!within.ok) {\n return {\n ok: false,\n error: within.reason === 'escaped'\n ? `\"command\" resolves outside the plugin root (\"${command}\").`\n : `\"command\" does not exist inside the plugin (\"${command}\").`,\n }\n }\n return { ok: true, command: within.real }\n}\n\n/**\n * Resolve `cwd`, defaulting to the plugin root.\n *\n * The authored form is constrained to `./…`, `${PLUGIN_ROOT}…` or\n * `${PLUGIN_DATA}…`, and containment is then verified against BOTH permitted\n * roots — the data directory legitimately sits outside the package.\n *\n * Both a lexical and a post-symlink check run, because neither alone is\n * sufficient: `cwd` may not exist yet (a server that creates its own working\n * directory on first run), so realpath cannot be the only gate; but the data\n * directory is writable BY the MCP server, so a server can plant a\n * `${PLUGIN_DATA}/work → /` symlink on one run and get `cwd=/` on the next\n * unless the resolved target is re-checked.\n */\nasync function resolveCwd(\n raw: unknown,\n boundary: PluginBoundary,\n dataDir: string,\n vars: Record<string, string>,\n): Promise<{ ok: true, cwd: string } | { ok: false, error: string }> {\n if (raw === undefined)\n return { ok: true, cwd: boundary.root }\n if (typeof raw !== 'string' || raw.length === 0)\n return { ok: false, error: '\"cwd\" must be a non-empty string.' }\n\n const startsWithVar = raw.startsWith(`\\${${PLUGIN_ROOT_VAR}}`) || raw.startsWith(`\\${${PLUGIN_DATA_VAR}}`)\n if (!raw.startsWith('./') && !startsWithVar)\n return { ok: false, error: `\"cwd\" must start with \"./\", \"\\${${PLUGIN_ROOT_VAR}}\" or \"\\${${PLUGIN_DATA_VAR}}\" (got \"${raw}\").` }\n\n const expanded = expandPluginVars(raw, vars)\n const absolute = isAbsolute(expanded) ? expanded : resolve(boundary.root, expanded)\n\n // Lexical, against the paths the placeholders actually produced.\n if (!isWithin(boundary.root, absolute) && !isWithin(dataDir, absolute))\n return { ok: false, error: `\"cwd\" escapes both the plugin root and the plugin data directory (\"${raw}\").` }\n\n // Post-symlink. `boundary.root` is already realpath-resolved; the data\n // directory is resolved here so a home path that itself traverses a symlink\n // (`/home` → `/usr/home`) doesn't make every comparison fail.\n const real = await realpathOrNull(absolute)\n if (real !== null) {\n const realDataDir = await realpathOrNull(dataDir) ?? dataDir\n if (!isWithin(boundary.root, real) && !isWithin(realDataDir, real))\n return { ok: false, error: `\"cwd\" resolves outside the plugin root and the plugin data directory via a symlink (\"${raw}\").` }\n }\n\n return { ok: true, cwd: absolute }\n}\n\n/** `realpath`, or `null` when the path doesn't exist yet. */\nasync function realpathOrNull(target: string): Promise<string | null> {\n try {\n return await realpath(target)\n }\n catch {\n return null\n }\n}\n\n// ---------------------------------------------------------------------------\n// Remote URLs\n// ---------------------------------------------------------------------------\n\n/**\n * Enforce the spec's remote-endpoint requirements: parseable, HTTPS unless\n * loopback, no embedded credentials, no fragment.\n *\n * Reachability (scheme + host) is decided by {@link isAllowedRemoteUrl}, the\n * single encoding of that policy — `originPinnedFetch` applies the same\n * predicate per redirect hop, so a URL refused here can't be reached by\n * redirect either. Only the message selection lives here; the userinfo and\n * fragment rules are authoring-only and have no redirect equivalent.\n */\nfunction validateRemoteUrl(raw: string): { ok: true } | { ok: false, error: string } {\n let url: URL\n try {\n url = new URL(raw)\n }\n catch {\n return { ok: false, error: `\"url\" is not a valid absolute URL (\"${raw}\").` }\n }\n if (!isAllowedRemoteUrl(url)) {\n return {\n ok: false,\n error: url.protocol === 'http:'\n ? `\"url\" must use https for non-loopback hosts (\"${raw}\").`\n : `\"url\" must use http or https (got \"${url.protocol}\").`,\n }\n }\n if (url.username !== '' || url.password !== '')\n return { ok: false, error: '\"url\" must not embed userinfo credentials.' }\n if (url.hash !== '')\n return { ok: false, error: '\"url\" must not contain a fragment.' }\n return { ok: true }\n}\n\n/** Reject keys that would hit a prototype setter instead of the record. */\nfunction isSafeRecordKey(key: string): boolean {\n return key.length > 0 && !DANGEROUS_RECORD_KEYS.has(key)\n}\n","/**\n * The `skills/` component type.\n *\n * Agent Plugins does not redefine the skill format — it defines only WHERE\n * skills live and HOW failures are isolated. So the format itself routes\n * through `parseSkillFile`, the same lenient Agent Skills parser that reads\n * `~/.agents/skills`, and this module contributes exactly two things the\n * plugin spec adds on top:\n *\n * 1. Immediate children only. `findSkillDirs` in `../skills/discovery.ts`\n * recurses four levels deep (correct for a user's `skills/` tree, where\n * category subdirectories are idiomatic); the plugin spec forbids\n * searching nested descendants, so discovery here is strictly depth-1.\n * 2. Boundary + kind enforcement per entry, with per-skill isolation: one\n * invalid or escaping skill is skipped, its siblings still load.\n */\n\nimport type { SkillConfig, SkillSource } from '../skills'\nimport type { PluginBoundary } from './boundary'\nimport type { PluginComponentStatus, PluginDiagnostic } from './types'\nimport { readdir } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport { parseSkillFile } from '../skills'\nimport { resolvePackagePath } from './boundary'\n\n/** Fixed location for the skills component type. */\nexport const PLUGIN_SKILLS_DIR = 'skills'\n\n/** Spec cap on a skill name, re-checked after a `namePrefix` is applied. */\nconst SKILL_NAME_MAX = 64\n\nexport interface PluginSkillsResult {\n status: PluginComponentStatus\n skills: SkillConfig[]\n diagnostics: PluginDiagnostic[]\n}\n\n/**\n * Discover every skill in the plugin's `skills/` directory.\n *\n * Status semantics follow the spec's failure ladder:\n * - `skills/` missing → `absent` (valid; not an error)\n * - `skills/` not a directory → `invalid` (this component type only)\n * - `skills/` escapes the root → `invalid` (this component type only)\n * - otherwise → `loaded`, possibly with zero skills\n */\nexport async function loadPluginSkills(opts: {\n boundary: PluginBoundary\n /** Plugin name, stamped on each skill as `metadata['zidane.plugin']`. */\n pluginName: string\n /** Source tag for the produced skills. Default `'project'`. */\n source?: SkillSource\n /** Optional `<prefix>-<name>` rename — see `LoadAgentPluginOptions.namePrefix`. */\n namePrefix?: string\n}): Promise<PluginSkillsResult> {\n const { boundary, pluginName, source = 'project', namePrefix } = opts\n const diagnostics: PluginDiagnostic[] = []\n const dir = join(boundary.root, PLUGIN_SKILLS_DIR)\n\n const located = await resolvePackagePath(boundary, dir, 'directory')\n if (!located.ok) {\n if (located.reason === 'missing')\n return { status: 'absent', skills: [], diagnostics }\n diagnostics.push({\n severity: 'error',\n code: located.reason === 'escaped' ? 'skills-dir-escapes-root' : 'skills-dir-wrong-kind',\n message: located.reason === 'escaped'\n ? `\"${PLUGIN_SKILLS_DIR}/\" resolves outside the plugin root — the skills component is disabled for this plugin.`\n : `\"${PLUGIN_SKILLS_DIR}\" exists but is not a directory — the skills component is disabled for this plugin.`,\n path: dir,\n })\n return { status: 'invalid', skills: [], diagnostics }\n }\n\n let entries: string[]\n try {\n entries = await readdir(located.real)\n }\n catch (err) {\n diagnostics.push({\n severity: 'error',\n code: 'skills-dir-unreadable',\n message: `Could not read \"${PLUGIN_SKILLS_DIR}/\": ${err instanceof Error ? err.message : String(err)}`,\n path: located.real,\n })\n return { status: 'invalid', skills: [], diagnostics }\n }\n\n const skills: SkillConfig[] = []\n // `readdir` order is filesystem-dependent; sort so a plugin's skills land\n // in the catalog deterministically (and so collision precedence between\n // two same-named skills in one plugin is stable rather than inode-order).\n for (const entry of entries.sort()) {\n const child = join(located.real, entry)\n const childDir = await resolvePackagePath(boundary, child, 'directory')\n if (!childDir.ok) {\n // A non-directory child (`README.md`, `.DS_Store`) simply isn't a\n // skill — silent. An ESCAPING child is the spec's \"deny access for\n // other escaping package paths\" boundary and worth surfacing.\n if (childDir.reason === 'escaped') {\n diagnostics.push({\n severity: 'warning',\n code: 'skill-dir-escapes-root',\n message: `Skipped \"${PLUGIN_SKILLS_DIR}/${entry}\" — it resolves outside the plugin root.`,\n path: child,\n })\n }\n continue\n }\n\n const skillFile = join(childDir.real, 'SKILL.md')\n const located2 = await resolvePackagePath(boundary, skillFile, 'file')\n if (!located2.ok) {\n // Missing SKILL.md means \"this directory is not a skill\" — per spec an\n // immediate child is a skill only when SKILL.md resolves to a regular\n // file. Silent, because bundling a non-skill directory is legal.\n if (located2.reason === 'escaped') {\n diagnostics.push({\n severity: 'error',\n code: 'skill-escapes-root',\n message: `Skipped skill \"${entry}\" — its SKILL.md resolves outside the plugin root.`,\n path: skillFile,\n })\n }\n else if (located2.reason === 'wrong-kind') {\n diagnostics.push({\n severity: 'warning',\n code: 'skill-file-wrong-kind',\n message: `Skipped \"${PLUGIN_SKILLS_DIR}/${entry}\" — its SKILL.md is not a regular file.`,\n path: skillFile,\n })\n }\n continue\n }\n\n // Parsed with the boundary-resolved path so `baseDir` (which gates\n // `skills_read` / `skills_run_script`) is anchored inside the root.\n //\n // `parseSkillFile` returns `null` for an invalid skill but still THROWS on\n // an unreadable file (permissions, a raced unlink, a device node). Both are\n // \"skip this skill\", never \"fail the plugin\".\n let parsed: SkillConfig | null\n try {\n parsed = await parseSkillFile(located2.real, { source })\n }\n catch (err) {\n diagnostics.push({\n severity: 'error',\n code: 'skill-unreadable',\n message: `Skipped skill \"${entry}\" — its SKILL.md could not be read: ${err instanceof Error ? err.message : String(err)}`,\n path: located2.real,\n })\n continue\n }\n if (!parsed) {\n diagnostics.push({\n severity: 'error',\n code: 'skill-invalid',\n message: `Skipped skill \"${entry}\" — its SKILL.md is not a valid Agent Skill (missing description, or unparseable frontmatter).`,\n path: located2.real,\n })\n continue\n }\n\n skills.push(stamp(parsed, { pluginName, namePrefix, entry, diagnostics }))\n }\n\n return { status: 'loaded', skills, diagnostics }\n}\n\n/**\n * Attach plugin provenance and apply the optional name prefix.\n *\n * Provenance goes in `metadata` under the `zidane.` prefix the Agent Skills\n * spec reserves for client-specific keys (see `../skills/types.ts`), so the\n * skill stays spec-conformant while a host UI can still say which plugin\n * shipped it.\n */\nfunction stamp(skill: SkillConfig, ctx: {\n pluginName: string\n namePrefix?: string\n entry: string\n diagnostics: PluginDiagnostic[]\n}): SkillConfig {\n const name = ctx.namePrefix ? `${ctx.namePrefix}-${skill.name}` : skill.name\n if (name.length > SKILL_NAME_MAX) {\n ctx.diagnostics.push({\n severity: 'warning',\n code: 'skill-name-too-long',\n message: `Prefixed skill name \"${name}\" exceeds the ${SKILL_NAME_MAX}-character spec limit. Loading anyway.`,\n })\n }\n return {\n ...skill,\n name,\n metadata: { ...skill.metadata, 'zidane.plugin': ctx.pluginName },\n }\n}\n","/**\n * Load one Agent Plugin from a directory.\n *\n * Order is mandated by the spec: establish the package boundary, load and\n * validate `plugin.json`, and only then discover components. A plugin whose\n * manifest is rejected never has its skills read or its MCP servers spawned.\n *\n * Nothing here throws for plugin-level problems. A host loading several\n * plugins must not lose the good ones to one bad package, so a rejection\n * comes back as `{ ok: false, diagnostics }`.\n */\n\nimport type { ResolveStorageDirsOptions } from '../chat/xdg'\nimport type { LoadAgentPluginOptions, LoadedPlugin, PluginDiagnostic } from './types'\nimport { readFile } from 'node:fs/promises'\nimport { join, resolve } from 'node:path'\nimport { resolveStorageDirs } from '../chat/xdg'\nimport { resolvePackagePath, resolvePluginBoundary } from './boundary'\nimport { parsePluginManifest } from './manifest'\nimport { loadPluginMcp } from './mcp'\nimport { loadPluginSkills } from './skills'\n\n/** Fixed location of the plugin manifest. */\nexport const PLUGIN_MANIFEST_FILE = 'plugin.json'\n\n/**\n * Default parent of every plugin's `${PLUGIN_DATA}` directory.\n *\n * Deliberately OUTSIDE any plugin root: the spec requires the data directory\n * to persist across plugin updates, and an update replaces the package tree.\n * Keyed by plugin name so two copies of the same plugin (project + user)\n * share state, which is what an author storing a cache or a token expects.\n *\n * Routed through `resolveStorageDirs` rather than hardcoding `~/.zidane` so it\n * honours `ZIDANE_STORAGE_DIR` and the XDG dirs like every other persisted\n * location — otherwise an XDG-mode install would scatter plugin data into a\n * `~/.zidane` nothing else in the app touches.\n *\n * NB: `resolveStorageDirs` does NOT read `ZIDANE_PREFIX`; it defaults `prefix`\n * to `.zidane`. Callers with a configured prefix must pass it, or plugin data\n * lands beside a prefix the rest of the install doesn't use.\n */\nexport function defaultPluginDataRoot(opts: ResolveStorageDirsOptions = {}): string {\n return join(resolveStorageDirs(opts).dataDir, 'plugin-data')\n}\n\n/**\n * Load an Agent Plugin from `dir`.\n *\n * @returns A {@link LoadedPlugin}. Check `ok` before trusting `manifest`;\n * check `components` to tell \"the plugin ships no skills\" (`absent`) from\n * \"its skills were rejected\" (`invalid`).\n */\nexport async function loadAgentPlugin(\n dir: string,\n opts: LoadAgentPluginOptions = {},\n): Promise<LoadedPlugin> {\n const diagnostics: PluginDiagnostic[] = []\n\n const boundary = await resolvePluginBoundary(dir)\n if (!boundary) {\n return rejected(resolve(dir), resolve(dir), [{\n severity: 'error',\n code: 'plugin-root-unreadable',\n message: `Plugin root \"${dir}\" does not exist or is not a directory.`,\n path: resolve(dir),\n }])\n }\n\n // --- manifest ---------------------------------------------------------\n const manifestPath = join(boundary.root, PLUGIN_MANIFEST_FILE)\n const located = await resolvePackagePath(boundary, manifestPath, 'file')\n if (!located.ok) {\n return rejected(boundary.dir, boundary.root, [{\n severity: 'error',\n code: located.reason === 'escaped' ? 'manifest-escapes-root' : 'manifest-missing',\n message: located.reason === 'escaped'\n // Boundary ladder rung 1: a manifest resolving outside the root\n // rejects the plugin outright — we will not read a package file\n // from somewhere the package doesn't own.\n ? `${PLUGIN_MANIFEST_FILE} resolves outside the plugin root.`\n : located.reason === 'wrong-kind'\n ? `${PLUGIN_MANIFEST_FILE} exists but is not a regular file.`\n : `No ${PLUGIN_MANIFEST_FILE} at the plugin root — not an Agent Plugin.`,\n path: manifestPath,\n }])\n }\n\n let text: string\n try {\n text = await readFile(located.real, 'utf8')\n }\n catch (err) {\n return rejected(boundary.dir, boundary.root, [{\n severity: 'error',\n code: 'manifest-unreadable',\n message: `Could not read ${PLUGIN_MANIFEST_FILE}: ${err instanceof Error ? err.message : String(err)}`,\n path: located.real,\n }])\n }\n\n const validated = parsePluginManifest(text)\n diagnostics.push(...validated.diagnostics)\n if (!validated.ok)\n return rejected(boundary.dir, boundary.root, diagnostics)\n\n const { manifest } = validated\n const result: LoadedPlugin = {\n ok: true,\n dir: boundary.dir,\n root: boundary.root,\n manifest,\n skills: [],\n mcpServers: [],\n components: { skills: 'unsupported', mcp: 'unsupported' },\n diagnostics,\n }\n\n // --- components -------------------------------------------------------\n //\n // Each discovery pass is wrapped so the never-throws contract is ENFORCED\n // rather than merely intended. Both passes walk attacker-controlled JSON and\n // filesystem state, so an unexpected throw (an unreadable SKILL.md, a raced\n // unlink, a shape no validator anticipated) is a question of when, not if —\n // and it would otherwise escape into `setup()` and fail the whole extension.\n // The narrowest boundary that still holds is the component type.\n if (opts.skills !== false) {\n await guardComponent(result, 'skills', diagnostics, async () => {\n const skills = await loadPluginSkills({\n boundary,\n pluginName: manifest.name,\n ...(opts.source !== undefined ? { source: opts.source } : {}),\n ...(opts.namePrefix !== undefined ? { namePrefix: opts.namePrefix } : {}),\n })\n result.components.skills = skills.status\n result.skills = skills.skills\n diagnostics.push(...skills.diagnostics)\n })\n }\n\n if (opts.mcp !== false) {\n await guardComponent(result, 'mcp', diagnostics, async () => {\n const mcp = await loadPluginMcp({\n boundary,\n pluginName: manifest.name,\n dataDir: opts.dataDir ?? join(opts.dataRoot ?? defaultPluginDataRoot(), manifest.name),\n specVersion: manifest.specVersion,\n ...(opts.namePrefix !== undefined ? { namePrefix: opts.namePrefix } : {}),\n })\n result.components.mcp = mcp.status\n result.mcpServers = mcp.servers\n diagnostics.push(...mcp.diagnostics)\n })\n }\n\n return result\n}\n\n/**\n * Run one component-discovery pass, converting an unexpected throw into an\n * `invalid` component plus a diagnostic. Partial results the pass already\n * assigned are dropped, so a half-discovered component never looks loaded.\n *\n * No input reachable through this module's public API is known to trigger it:\n * both component loaders catch their own filesystem and parse failures, which\n * is exactly the property their tests assert. It is kept deliberately, not\n * abandoned — `loadAgentPlugin` promises never to throw for plugin-level\n * problems, and that promise should survive a future component type whose\n * loader forgets a `try`. The observable half IS tested: see the \"never throws\"\n * matrix in `test/plugins/load.test.ts`.\n */\nasync function guardComponent(\n result: LoadedPlugin,\n component: 'skills' | 'mcp',\n diagnostics: PluginDiagnostic[],\n run: () => Promise<void>,\n): Promise<void> {\n try {\n await run()\n }\n catch (err) {\n result.components[component] = 'invalid'\n if (component === 'skills')\n result.skills = []\n else\n result.mcpServers = []\n diagnostics.push({\n severity: 'error',\n code: `${component}-discovery-failed`,\n message: `Unexpected error while loading the ${component} component: ${err instanceof Error ? err.message : String(err)}`,\n path: result.root,\n })\n }\n}\n\nfunction rejected(dir: string, root: string, diagnostics: PluginDiagnostic[]): LoadedPlugin {\n return {\n ok: false,\n dir,\n root,\n skills: [],\n mcpServers: [],\n components: { skills: 'unsupported', mcp: 'unsupported' },\n diagnostics,\n }\n}\n"],"mappings":"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"}
|
package/dist/plugins.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Ac as parsePluginManifest, Bc as PluginDiagnostic, Dc as PLUGIN_MCP_FILE, Ec as PLUGIN_SKILLS_DIR, Fc as AgentPluginsVersion, Gc as isSupportedAgentPluginsVersion, Hc as PluginSchemaKind, Ic as LoadAgentPluginOptions, Kc as parseSchemaId, Lc as LoadedPlugin, Mc as PLUGIN_MANIFEST_FILE, Nc as defaultPluginDataRoot, Oc as expandPluginVars, Pc as loadAgentPlugin, Rc as PluginAuthor, Uc as SUPPORTED_AGENT_PLUGINS_VERSIONS, Vc as PluginManifest, Wc as agentPluginsSchemaId, jc as validatePluginManifest, kc as ManifestValidation, zc as PluginComponentStatus } from "./index-
|
|
1
|
+
import { Ac as parsePluginManifest, Bc as PluginDiagnostic, Dc as PLUGIN_MCP_FILE, Ec as PLUGIN_SKILLS_DIR, Fc as AgentPluginsVersion, Gc as isSupportedAgentPluginsVersion, Hc as PluginSchemaKind, Ic as LoadAgentPluginOptions, Kc as parseSchemaId, Lc as LoadedPlugin, Mc as PLUGIN_MANIFEST_FILE, Nc as defaultPluginDataRoot, Oc as expandPluginVars, Pc as loadAgentPlugin, Rc as PluginAuthor, Uc as SUPPORTED_AGENT_PLUGINS_VERSIONS, Vc as PluginManifest, Wc as agentPluginsSchemaId, jc as validatePluginManifest, kc as ManifestValidation, zc as PluginComponentStatus } from "./index-DZhrTn-v.js";
|
|
2
2
|
export { type AgentPluginsVersion, type LoadAgentPluginOptions, type LoadedPlugin, type ManifestValidation, PLUGIN_MANIFEST_FILE, PLUGIN_MCP_FILE, PLUGIN_SKILLS_DIR, type PluginAuthor, type PluginComponentStatus, type PluginDiagnostic, type PluginManifest, type PluginSchemaKind, SUPPORTED_AGENT_PLUGINS_VERSIONS, agentPluginsSchemaId, defaultPluginDataRoot, expandPluginVars, isSupportedAgentPluginsVersion, loadAgentPlugin, parsePluginManifest, parseSchemaId, validatePluginManifest };
|
package/dist/plugins.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as PLUGIN_MCP_FILE, c as validatePluginManifest, d as isSupportedAgentPluginsVersion, f as parseSchemaId, i as PLUGIN_SKILLS_DIR, l as SUPPORTED_AGENT_PLUGINS_VERSIONS, n as defaultPluginDataRoot, o as expandPluginVars, r as loadAgentPlugin, s as parsePluginManifest, t as PLUGIN_MANIFEST_FILE, u as agentPluginsSchemaId } from "./plugins-
|
|
1
|
+
import { a as PLUGIN_MCP_FILE, c as validatePluginManifest, d as isSupportedAgentPluginsVersion, f as parseSchemaId, i as PLUGIN_SKILLS_DIR, l as SUPPORTED_AGENT_PLUGINS_VERSIONS, n as defaultPluginDataRoot, o as expandPluginVars, r as loadAgentPlugin, s as parsePluginManifest, t as PLUGIN_MANIFEST_FILE, u as agentPluginsSchemaId } from "./plugins-gbI7SBA6.js";
|
|
2
2
|
export { PLUGIN_MANIFEST_FILE, PLUGIN_MCP_FILE, PLUGIN_SKILLS_DIR, SUPPORTED_AGENT_PLUGINS_VERSIONS, agentPluginsSchemaId, defaultPluginDataRoot, expandPluginVars, isSupportedAgentPluginsVersion, loadAgentPlugin, parsePluginManifest, parseSchemaId, validatePluginManifest };
|
package/dist/presets.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Ji as AgentHookMap, Ki as _default, a as basicTools, i as _default$1, n as composePresets, r as definePreset, t as Preset } from "./index-
|
|
1
|
+
import { Ji as AgentHookMap, Ki as _default, a as basicTools, i as _default$1, n as composePresets, r as definePreset, t as Preset } from "./index-DZhrTn-v.js";
|
|
2
2
|
export { type AgentHookMap, Preset, _default as artifacts, _default$1 as basic, basicTools, composePresets, definePreset };
|
package/dist/presets.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Ct as basic_default, St as basicTools, Xt as artifacts_default, bt as composePresets, xt as definePreset } from "./agent-
|
|
1
|
+
import { Ct as basic_default, St as basicTools, Xt as artifacts_default, bt as composePresets, xt as definePreset } from "./agent-_xxElOgH.js";
|
|
2
2
|
export { artifacts_default as artifacts, basic_default as basic, basicTools, composePresets, definePreset };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Ah as
|
|
2
|
-
export { AnthropicBedrockConfig, AnthropicContextManagement, AnthropicParams, AnthropicThinkingPlan, EXTENDED_CACHE_TTL_BETA, anthropic, applyAnthropicCacheBreakpoints, buildAnthropicClientOptions, cacheWriteTtlMultiplier, classifyAnthropicError, credentialIdentity, defaultAnthropicMaxTokens, planAnthropicThinking, resolveAnthropicAuthShape, resolveAnthropicBetas, resolveAnthropicMaxOutput };
|
|
1
|
+
import { Ah as AnthropicParams, Bh as credentialIdentity, Fh as anthropic, Gh as resolveAnthropicMaxOutput, Hh as planAnthropicThinking, Ih as applyAnthropicCacheBreakpoints, Kh as resolveThinkingBinding, Lh as buildAnthropicClientOptions, Mh as EXTENDED_CACHE_TTL_BETA, Nh as THINKING_BINDING_SETTING_ENV, Oh as AnthropicBedrockConfig, Ph as ThinkingBindingBehavior, Rh as cacheWriteTtlMultiplier, Uh as resolveAnthropicAuthShape, Vh as defaultAnthropicMaxTokens, Wh as resolveAnthropicBetas, jh as AnthropicThinkingPlan, kh as AnthropicContextManagement, zh as classifyAnthropicError } from "../index-DZhrTn-v.js";
|
|
2
|
+
export { AnthropicBedrockConfig, AnthropicContextManagement, AnthropicParams, AnthropicThinkingPlan, EXTENDED_CACHE_TTL_BETA, THINKING_BINDING_SETTING_ENV, ThinkingBindingBehavior, anthropic, applyAnthropicCacheBreakpoints, buildAnthropicClientOptions, cacheWriteTtlMultiplier, classifyAnthropicError, credentialIdentity, defaultAnthropicMaxTokens, planAnthropicThinking, resolveAnthropicAuthShape, resolveAnthropicBetas, resolveAnthropicMaxOutput, resolveThinkingBinding };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { EXTENDED_CACHE_TTL_BETA, anthropic, applyAnthropicCacheBreakpoints, buildAnthropicClientOptions, cacheWriteTtlMultiplier, classifyAnthropicError, credentialIdentity, defaultAnthropicMaxTokens, planAnthropicThinking, resolveAnthropicAuthShape, resolveAnthropicBetas, resolveAnthropicMaxOutput };
|
|
1
|
+
import { a as buildAnthropicClientOptions, c as credentialIdentity, d as resolveAnthropicAuthShape, f as resolveAnthropicBetas, i as applyAnthropicCacheBreakpoints, l as defaultAnthropicMaxTokens, m as resolveThinkingBinding, n as THINKING_BINDING_SETTING_ENV, o as cacheWriteTtlMultiplier, p as resolveAnthropicMaxOutput, r as anthropic, s as classifyAnthropicError, t as EXTENDED_CACHE_TTL_BETA, u as planAnthropicThinking } from "../anthropic-DPPs3wjJ.js";
|
|
2
|
+
export { EXTENDED_CACHE_TTL_BETA, THINKING_BINDING_SETTING_ENV, anthropic, applyAnthropicCacheBreakpoints, buildAnthropicClientOptions, cacheWriteTtlMultiplier, classifyAnthropicError, credentialIdentity, defaultAnthropicMaxTokens, planAnthropicThinking, resolveAnthropicAuthShape, resolveAnthropicBetas, resolveAnthropicMaxOutput, resolveThinkingBinding };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Dh as arcee, Eh as ArceeParams } from "../index-DZhrTn-v.js";
|
|
2
2
|
export { ArceeParams, arcee };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Ch as
|
|
1
|
+
import { Ch as BasetenParams, Th as planBasetenReasoning, wh as baseten } from "../index-DZhrTn-v.js";
|
|
2
2
|
export { BasetenParams, baseten, planBasetenReasoning };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Sh as cerebras, xh as CerebrasParams } from "../index-DZhrTn-v.js";
|
|
2
2
|
export { CerebrasParams, cerebras };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _h as
|
|
1
|
+
import { _h as LocalParams, vh as local } from "../index-DZhrTn-v.js";
|
|
2
2
|
export { LocalParams, local };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { $m as
|
|
1
|
+
import { $m as buildAssistantContent, Gm as OpenAICompatAuthHeader, Hm as ASSISTANT_TOOL_CALLS_TAG, Jm as OpenAICompatStreamError, Km as OpenAICompatHttpError, Qm as assistantMessage, Um as OAIMessage, Wm as OAITool, Xm as applyOAICacheBreakpoints, Ym as TOOL_RESULTS_TAG, Zm as applyOAIToolCacheBreakpoint, ah as openaiCompat, ch as userMessage, eh as classifyOpenAICompatError, ih as openAICompatPromptMessage, nh as formatTools, oh as toOAIMessages, qm as OpenAICompatParams, rh as mapOAIFinishReason, sh as toolResultsMessage, th as consumeSSE } from "../index-DZhrTn-v.js";
|
|
2
2
|
export { ASSISTANT_TOOL_CALLS_TAG, OAIMessage, OAITool, OpenAICompatAuthHeader, OpenAICompatHttpError, OpenAICompatParams, OpenAICompatStreamError, TOOL_RESULTS_TAG, applyOAICacheBreakpoints, applyOAIToolCacheBreakpoint, assistantMessage, buildAssistantContent, classifyOpenAICompatError, consumeSSE, formatTools, mapOAIFinishReason, openAICompatPromptMessage, openaiCompat, toOAIMessages, toolResultsMessage, userMessage };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { dh as mapCodexStopReason, fh as openai, lh as OpenAIParams, ph as toPiMessages, uh as classifyOpenAIError } from "../index-DZhrTn-v.js";
|
|
2
2
|
export { OpenAIParams, classifyOpenAIError, mapCodexStopReason, openai, toPiMessages };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Bm as
|
|
1
|
+
import { Bm as normalizeOpenRouterModelId, Vm as openrouter, zm as OpenRouterParams } from "../index-DZhrTn-v.js";
|
|
2
2
|
export { OpenRouterParams, normalizeOpenRouterModelId, openrouter };
|
package/dist/providers/xai.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Mm as
|
|
1
|
+
import { Mm as XaiParams, Nm as xai } from "../index-DZhrTn-v.js";
|
|
2
2
|
export { XaiParams, xai };
|
package/dist/providers.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { $h as
|
|
2
|
-
export { type AnthropicParams, type ArceeParams, type BasetenParams, type CerebrasParams, type CursorParams, HistoryRepair, type LocalParams, type MistralParams, type ModelCatalog, type ModelCatalogEntry, type ModelCatalogSource, type OAuthParams, type OAuthProviderInterface, type OpenAICompatAuthHeader, OpenAICompatHttpError, type OpenAICompatParams, type OpenAIParams, type OpenRouterParams, type PromptCacheKeyContext, type PromptCacheKeyOption, Provider, ProviderCapabilities, ProviderMeta, type ResolveOAuthApiKeyOptions, type SchemaSanitizeOptions, type SchemaSanitizeProfile, type SchemaSanitizeResult, StreamCallbacks, StreamOptions, TokenCountPayload, ToolCall, ToolResult, ToolSpec, TurnResult, type XaiParams, type ZaiParams, anthropic, applyAnthropicCacheBreakpoints, arcee, baseten, cerebras, classifyOpenAICompatError, credentialsFilePath, credentialsFromParams, cursor, derivePromptCacheKey, ensureBundledOAuthFlows, extractRuntimeCredentials, getModelCatalog, getOAuthApiKey, getOAuthProvider, isOAuthAccessToken, local, mapOAIFinishReason, mistral, openai, openaiCompat, openrouter, planBasetenReasoning, planMistralReasoning, planZaiReasoning, readOAuthCredentials, refreshAnthropicToken, refreshOpenAICodexToken, registerCustomOAuthProvider, registerOAuthProvider, resolveOAuthApiKey, resolvePromptCacheKey, sanitizeToolSchema, sanitizeToolSpecs, setModelCatalog, writeOAuthCredentials, xai, zai };
|
|
1
|
+
import { $h as credentialsFilePath, Ah as AnthropicParams, Am as planZaiReasoning, Ch as BasetenParams, Cm as StreamOptions, Dh as arcee, Dm as ToolSpec, Dy as getModelCatalog, Eh as ArceeParams, Em as ToolResult, Ey as ModelCatalogSource, Fh as anthropic, Fm as SchemaSanitizeProfile, Gm as OpenAICompatAuthHeader, Ih as applyAnthropicCacheBreakpoints, Im as SchemaSanitizeResult, Jh as PromptCacheKeyOption, Km as OpenAICompatHttpError, Lm as sanitizeToolSchema, Mm as XaiParams, Nm as xai, Om as TurnResult, Oy as setModelCatalog, Pm as SchemaSanitizeOptions, Qh as ResolveOAuthApiKeyOptions, Rm as sanitizeToolSpecs, Sh as cerebras, Sm as StreamCallbacks, Th as planBasetenReasoning, Tm as ToolCall, Ty as ModelCatalogEntry, Vm as openrouter, Xh as resolvePromptCacheKey, Yh as derivePromptCacheKey, Zh as OAuthParams, _h as LocalParams, _m as HistoryRepair, ag as resolveOAuthApiKey, ah as openaiCompat, bh as cursor, bm as ProviderCapabilities, cg as ensureBundledOAuthFlows, dg as refreshAnthropicToken, eg as credentialsFromParams, eh as classifyOpenAICompatError, fg as refreshOpenAICodexToken, fh as openai, gh as planMistralReasoning, hh as mistral, ig as registerCustomOAuthProvider, jm as zai, km as ZaiParams, lg as getOAuthApiKey, lh as OpenAIParams, mh as MistralParams, ng as isOAuthAccessToken, og as writeOAuthCredentials, pg as registerOAuthProvider, qh as PromptCacheKeyContext, qm as OpenAICompatParams, rg as readOAuthCredentials, rh as mapOAIFinishReason, sg as OAuthProviderInterface, tg as extractRuntimeCredentials, ug as getOAuthProvider, vh as local, vm as InputTransformation, wh as baseten, wm as TokenCountPayload, wy as ModelCatalog, xh as CerebrasParams, xm as ProviderMeta, yh as CursorParams, ym as Provider, zm as OpenRouterParams } from "./index-DZhrTn-v.js";
|
|
2
|
+
export { type AnthropicParams, type ArceeParams, type BasetenParams, type CerebrasParams, type CursorParams, HistoryRepair, InputTransformation, type LocalParams, type MistralParams, type ModelCatalog, type ModelCatalogEntry, type ModelCatalogSource, type OAuthParams, type OAuthProviderInterface, type OpenAICompatAuthHeader, OpenAICompatHttpError, type OpenAICompatParams, type OpenAIParams, type OpenRouterParams, type PromptCacheKeyContext, type PromptCacheKeyOption, Provider, ProviderCapabilities, ProviderMeta, type ResolveOAuthApiKeyOptions, type SchemaSanitizeOptions, type SchemaSanitizeProfile, type SchemaSanitizeResult, StreamCallbacks, StreamOptions, TokenCountPayload, ToolCall, ToolResult, ToolSpec, TurnResult, type XaiParams, type ZaiParams, anthropic, applyAnthropicCacheBreakpoints, arcee, baseten, cerebras, classifyOpenAICompatError, credentialsFilePath, credentialsFromParams, cursor, derivePromptCacheKey, ensureBundledOAuthFlows, extractRuntimeCredentials, getModelCatalog, getOAuthApiKey, getOAuthProvider, isOAuthAccessToken, local, mapOAIFinishReason, mistral, openai, openaiCompat, openrouter, planBasetenReasoning, planMistralReasoning, planZaiReasoning, readOAuthCredentials, refreshAnthropicToken, refreshOpenAICodexToken, registerCustomOAuthProvider, registerOAuthProvider, resolveOAuthApiKey, resolvePromptCacheKey, sanitizeToolSchema, sanitizeToolSpecs, setModelCatalog, writeOAuthCredentials, xai, zai };
|