@kolisachint/hoocode-agent 0.5.2 → 0.5.4
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/CHANGELOG.md +31 -0
- package/dist/cli/args.d.ts +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +10 -7
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +10 -2
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/capabilities/deferral.d.ts +78 -0
- package/dist/core/capabilities/deferral.d.ts.map +1 -0
- package/dist/core/capabilities/deferral.js +99 -0
- package/dist/core/capabilities/deferral.js.map +1 -0
- package/dist/core/capabilities/dense.d.ts +51 -0
- package/dist/core/capabilities/dense.d.ts.map +1 -0
- package/dist/core/capabilities/dense.js +121 -0
- package/dist/core/capabilities/dense.js.map +1 -0
- package/dist/core/capabilities/lexical.d.ts +43 -0
- package/dist/core/capabilities/lexical.d.ts.map +1 -0
- package/dist/core/capabilities/lexical.js +104 -0
- package/dist/core/capabilities/lexical.js.map +1 -0
- package/dist/core/capabilities/registry.d.ts +56 -0
- package/dist/core/capabilities/registry.d.ts.map +1 -0
- package/dist/core/capabilities/registry.js +0 -0
- package/dist/core/capabilities/registry.js.map +1 -0
- package/dist/core/capabilities/search.d.ts +47 -0
- package/dist/core/capabilities/search.d.ts.map +1 -0
- package/dist/core/capabilities/search.js +82 -0
- package/dist/core/capabilities/search.js.map +1 -0
- package/dist/core/extensions/loader.d.ts +27 -3
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +61 -7
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/plugins/authoring.d.ts +56 -9
- package/dist/core/extensions/plugins/authoring.d.ts.map +1 -1
- package/dist/core/extensions/plugins/authoring.js +0 -0
- package/dist/core/extensions/plugins/authoring.js.map +1 -1
- package/dist/core/extensions/plugins/drift.d.ts +75 -0
- package/dist/core/extensions/plugins/drift.d.ts.map +1 -0
- package/dist/core/extensions/plugins/drift.js +194 -0
- package/dist/core/extensions/plugins/drift.js.map +1 -0
- package/dist/core/extensions/plugins/formats/claude.d.ts.map +1 -1
- package/dist/core/extensions/plugins/formats/claude.js +5 -0
- package/dist/core/extensions/plugins/formats/claude.js.map +1 -1
- package/dist/core/extensions/plugins/formats/copilot.d.ts +6 -0
- package/dist/core/extensions/plugins/formats/copilot.d.ts.map +1 -1
- package/dist/core/extensions/plugins/formats/copilot.js +57 -16
- package/dist/core/extensions/plugins/formats/copilot.js.map +1 -1
- package/dist/core/extensions/plugins/formats/index.d.ts +39 -1
- package/dist/core/extensions/plugins/formats/index.d.ts.map +1 -1
- package/dist/core/extensions/plugins/formats/index.js +90 -13
- package/dist/core/extensions/plugins/formats/index.js.map +1 -1
- package/dist/core/extensions/plugins/formats/jsonManifest.d.ts +14 -0
- package/dist/core/extensions/plugins/formats/jsonManifest.d.ts.map +1 -1
- package/dist/core/extensions/plugins/formats/jsonManifest.js +37 -4
- package/dist/core/extensions/plugins/formats/jsonManifest.js.map +1 -1
- package/dist/core/extensions/plugins/formats/platform-targets.d.ts +48 -24
- package/dist/core/extensions/plugins/formats/platform-targets.d.ts.map +1 -1
- package/dist/core/extensions/plugins/formats/platform-targets.js +62 -30
- package/dist/core/extensions/plugins/formats/platform-targets.js.map +1 -1
- package/dist/core/extensions/plugins/formats/shared.d.ts +22 -0
- package/dist/core/extensions/plugins/formats/shared.d.ts.map +1 -1
- package/dist/core/extensions/plugins/formats/shared.js +81 -4
- package/dist/core/extensions/plugins/formats/shared.js.map +1 -1
- package/dist/core/extensions/plugins/formats/types.d.ts +10 -1
- package/dist/core/extensions/plugins/formats/types.d.ts.map +1 -1
- package/dist/core/extensions/plugins/formats/types.js.map +1 -1
- package/dist/core/extensions/plugins/gates.d.ts +64 -0
- package/dist/core/extensions/plugins/gates.d.ts.map +1 -0
- package/dist/core/extensions/plugins/gates.js +297 -0
- package/dist/core/extensions/plugins/gates.js.map +1 -0
- package/dist/core/extensions/plugins/hooks-bridge.d.ts +1 -1
- package/dist/core/extensions/plugins/hooks-bridge.d.ts.map +1 -1
- package/dist/core/extensions/plugins/hooks-bridge.js +12 -8
- package/dist/core/extensions/plugins/hooks-bridge.js.map +1 -1
- package/dist/core/extensions/plugins/index.d.ts +36 -5
- package/dist/core/extensions/plugins/index.d.ts.map +1 -1
- package/dist/core/extensions/plugins/index.js +66 -15
- package/dist/core/extensions/plugins/index.js.map +1 -1
- package/dist/core/extensions/plugins/install.d.ts +43 -24
- package/dist/core/extensions/plugins/install.d.ts.map +1 -1
- package/dist/core/extensions/plugins/install.js +167 -54
- package/dist/core/extensions/plugins/install.js.map +1 -1
- package/dist/core/extensions/plugins/locations.d.ts +84 -0
- package/dist/core/extensions/plugins/locations.d.ts.map +1 -0
- package/dist/core/extensions/plugins/locations.js +137 -0
- package/dist/core/extensions/plugins/locations.js.map +1 -0
- package/dist/core/extensions/plugins/manifest.d.ts +21 -1
- package/dist/core/extensions/plugins/manifest.d.ts.map +1 -1
- package/dist/core/extensions/plugins/manifest.js +2 -2
- package/dist/core/extensions/plugins/manifest.js.map +1 -1
- package/dist/core/extensions/plugins/packaging.d.ts +115 -0
- package/dist/core/extensions/plugins/packaging.d.ts.map +1 -0
- package/dist/core/extensions/plugins/packaging.js +362 -0
- package/dist/core/extensions/plugins/packaging.js.map +1 -0
- package/dist/core/extensions/plugins/smoke.d.ts +33 -0
- package/dist/core/extensions/plugins/smoke.d.ts.map +1 -0
- package/dist/core/extensions/plugins/smoke.js +231 -0
- package/dist/core/extensions/plugins/smoke.js.map +1 -0
- package/dist/core/extensions/plugins/trigger-eval.d.ts +136 -0
- package/dist/core/extensions/plugins/trigger-eval.d.ts.map +1 -0
- package/dist/core/extensions/plugins/trigger-eval.js +0 -0
- package/dist/core/extensions/plugins/trigger-eval.js.map +1 -0
- package/dist/core/package-manager.d.ts +6 -0
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/resource-loader.d.ts +2 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +15 -0
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/settings-manager.d.ts +2 -2
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +3 -3
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/settings-types.d.ts +1 -1
- package/dist/core/settings-types.d.ts.map +1 -1
- package/dist/core/settings-types.js.map +1 -1
- package/dist/core/skills.d.ts +9 -0
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +23 -3
- package/dist/core/skills.js.map +1 -1
- package/dist/core/tools/package-plugin.d.ts +19 -0
- package/dist/core/tools/package-plugin.d.ts.map +1 -0
- package/dist/core/tools/package-plugin.js +81 -0
- package/dist/core/tools/package-plugin.js.map +1 -0
- package/dist/core/tools/plugin-tool-names.d.ts +1 -0
- package/dist/core/tools/plugin-tool-names.d.ts.map +1 -1
- package/dist/core/tools/plugin-tool-names.js +6 -0
- package/dist/core/tools/plugin-tool-names.js.map +1 -1
- package/dist/core/tools/plugins.d.ts.map +1 -1
- package/dist/core/tools/plugins.js +48 -7
- package/dist/core/tools/plugins.js.map +1 -1
- package/dist/core/tools/propose-plugin.d.ts.map +1 -1
- package/dist/core/tools/propose-plugin.js +49 -21
- package/dist/core/tools/propose-plugin.js.map +1 -1
- package/dist/core/tools/webfetch.d.ts +3 -1
- package/dist/core/tools/webfetch.d.ts.map +1 -1
- package/dist/core/tools/webfetch.js +8 -2
- package/dist/core/tools/webfetch.js.map +1 -1
- package/dist/core/tools/websearch.d.ts +2 -0
- package/dist/core/tools/websearch.d.ts.map +1 -1
- package/dist/core/tools/websearch.js +2 -1
- package/dist/core/tools/websearch.js.map +1 -1
- package/dist/core/tools/webtools-shared.d.ts +23 -2
- package/dist/core/tools/webtools-shared.d.ts.map +1 -1
- package/dist/core/tools/webtools-shared.js +59 -9
- package/dist/core/tools/webtools-shared.js.map +1 -1
- package/dist/extensions/core/marketplace.d.ts +14 -3
- package/dist/extensions/core/marketplace.d.ts.map +1 -1
- package/dist/extensions/core/marketplace.js +77 -18
- package/dist/extensions/core/marketplace.js.map +1 -1
- package/dist/extensions/core/mcp-deferred.d.ts +39 -2
- package/dist/extensions/core/mcp-deferred.d.ts.map +1 -1
- package/dist/extensions/core/mcp-deferred.js +74 -10
- package/dist/extensions/core/mcp-deferred.js.map +1 -1
- package/dist/extensions/core/mcp-loader.d.ts.map +1 -1
- package/dist/extensions/core/mcp-loader.js +52 -9
- package/dist/extensions/core/mcp-loader.js.map +1 -1
- package/dist/extensions/core/scaffold.d.ts +3 -3
- package/dist/extensions/core/scaffold.d.ts.map +1 -1
- package/dist/extensions/core/scaffold.js +9 -9
- package/dist/extensions/core/scaffold.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +25 -7
- package/dist/main.js.map +1 -1
- package/dist/utils/tools-manager.d.ts +8 -0
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +12 -3
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/providers.md +11 -0
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +5 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../../../src/core/extensions/plugins/install.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Plugin install/uninstall/discovery — the shared engine behind both the\n * `/plugin` slash command (human-driven) and the model-facing lifecycle tools\n * (`SearchPlugins`, `InstallPlugin`, ...). Keeping it in one place means the two\n * surfaces can never drift on where plugins live or how sources resolve.\n *\n * Trust model (see docs/plugin-system-spec.md): *adding* a marketplace is the\n * human trust boundary; *installing* from an already-trusted marketplace is the\n * model's discretion (package-manager model), and must stay transparent and\n * reversible. This module performs the mechanical install/remove; the gating\n * (announce, injection carve-out) lives with the callers.\n */\n\nimport { spawn } from \"node:child_process\";\nimport { cpSync, existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { getAgentDir } from \"../../../config.js\";\nimport { defaultPluginDirs } from \"../loader.js\";\nimport type { MarketplacePlatform } from \"./formats/types.js\";\nimport { discoverPlugins } from \"./index.js\";\nimport type { NormalizedPlugin } from \"./manifest.js\";\nimport { parsePluginDir } from \"./manifest.js\";\nimport {\n\ttype MarketplacePluginSource,\n\ttype MarketplaceRecord,\n\tparseMarketplaceDir,\n\treadMarketplaceStore,\n\tresolvePluginSource,\n} from \"./marketplace.js\";\n\n/** `.agents/` is the primary, cross-vendor home for installed plugins and the added-marketplace registry. */\nexport function installedPluginsDir(cwd: string): string {\n\treturn path.join(cwd, \".agents\", \"plugins\");\n}\n\nfunction marketplaceStorePath(cwd: string): string {\n\treturn path.join(cwd, \".agents\", \"marketplaces.json\");\n}\n\nfunction legacyStorePath(cwd: string): string {\n\treturn path.join(cwd, \".hoocode\", \"marketplaces.json\");\n}\n\n/** Filesystem-safe directory name derived from a plugin name (matches the `/plugin` command). */\nexport function sanitizeForDir(s: string): string {\n\treturn s.replace(/[^a-zA-Z0-9._-]+/g, \"_\").slice(0, 80);\n}\n\n/** Absolute path to the curated default marketplace bundled with hoocode. */\nfunction defaultMarketplaceDir(): string {\n\treturn fileURLToPath(new URL(\"./default-marketplace/\", import.meta.url));\n}\n\n/** The default marketplace record — always present so source-level trust is meaningful out of the box. */\nexport function defaultMarketplaceRecord(): MarketplaceRecord {\n\treturn { location: \"hoocode-default\", dir: defaultMarketplaceDir() };\n}\n\n/**\n * Curated well-known marketplaces, trusted out of the box. Shipping an entry\n * here is a maintainer-level trust decision (the human half of the \"adding a\n * marketplace is the human trust boundary\" rule) — keep this list short and\n * high-trust. Indices are cloned lazily into the marketplace cache on first\n * search and never auto-updated afterwards (plugin sources inside the official\n * index are sha-pinned).\n */\nexport const WELL_KNOWN_MARKETPLACES: ReadonlyArray<{ name: string; url: string }> = [\n\t{ name: \"claude-plugins-official\", url: \"https://github.com/anthropics/claude-plugins-official\" },\n\t// The Copilot plugin directory ships both a `.github/plugin/marketplace.json`\n\t// and a `.claude-plugin/marketplace.json`, so it parses with\n\t// supportPlatform [\"claude\", \"github\"] — the default `github` source.\n\t{ name: \"copilot-plugins\", url: \"https://github.com/github/copilot-plugins\" },\n];\n\n/** Local cache directory for a marketplace fetched from `url` (same convention as `/plugin marketplace add`). */\nexport function marketplaceCacheDir(cwd: string, url: string): string {\n\treturn path.join(cwd, \".agents\", \"marketplace-cache\", sanitizeForDir(url));\n}\n\n/**\n * Clone any well-known marketplace index that is not in the local cache yet.\n * No-op (and no network) when every index is already cached. Returns one error\n * string per marketplace that could not be fetched (offline is non-fatal —\n * search degrades to the marketplaces already available).\n */\nexport async function ensureWellKnownMarketplaces(cwd: string): Promise<string[]> {\n\tconst errors: string[] = [];\n\tfor (const wk of WELL_KNOWN_MARKETPLACES) {\n\t\tconst dir = marketplaceCacheDir(cwd, wk.url);\n\t\tif (existsSync(dir)) continue;\n\t\tmkdirSync(path.dirname(dir), { recursive: true });\n\t\tconst res = await cloneGitRepo(wk.url, dir);\n\t\tif (res.code !== 0) {\n\t\t\trmSync(dir, { recursive: true, force: true });\n\t\t\terrors.push(`${wk.name}: ${(res.stderr || res.stdout).trim()}`);\n\t\t}\n\t}\n\treturn errors;\n}\n\n/**\n * All marketplace records in effect: the bundled default first (curated,\n * trusted), then user-added ones from `.agents/` (falling back to legacy\n * `.hoocode/`). Deduplicated by directory.\n */\nexport function readMarketplaceRecords(cwd: string): MarketplaceRecord[] {\n\tconst records: MarketplaceRecord[] = [];\n\tconst def = defaultMarketplaceRecord();\n\tif (existsSync(def.dir)) records.push(def);\n\n\t// Well-known marketplaces participate once their index is cached locally\n\t// (see ensureWellKnownMarketplaces; SearchPlugins fetches lazily).\n\tfor (const wk of WELL_KNOWN_MARKETPLACES) {\n\t\tconst dir = marketplaceCacheDir(cwd, wk.url);\n\t\tif (existsSync(dir) && !records.some((x) => x.dir === dir)) {\n\t\t\trecords.push({ location: wk.url, dir });\n\t\t}\n\t}\n\n\tconst primary = readMarketplaceStore(marketplaceStorePath(cwd));\n\tconst user =\n\t\tprimary.length > 0 || existsSync(marketplaceStorePath(cwd))\n\t\t\t? primary\n\t\t\t: readMarketplaceStore(legacyStorePath(cwd));\n\tfor (const r of user) {\n\t\tif (!records.some((x) => x.dir === r.dir)) records.push(r);\n\t}\n\treturn records;\n}\n\n/** A plugin offered by some registered marketplace (not necessarily installed). */\nexport interface AvailablePlugin {\n\tname: string;\n\tdescription?: string;\n\t/** Relative path, git URL, `npm:<spec>`, or structured source object. */\n\tsource: MarketplacePluginSource;\n\t/** Resolved source kind, for display and gating. */\n\tsourceKind: \"local\" | \"git\" | \"git-subdir\" | \"npm\";\n\tmarketplaceName: string;\n\tmarketplaceRoot: string;\n\t/** Platforms this entry targets (per-entry hint, else the marketplace's). */\n\tsupportPlatform: MarketplacePlatform[];\n}\n\n/** Every plugin offered across all registered marketplaces (first marketplace wins on name clash). */\nexport function listAvailablePlugins(cwd: string): AvailablePlugin[] {\n\tconst out: AvailablePlugin[] = [];\n\tconst seen = new Set<string>();\n\tfor (const rec of readMarketplaceRecords(cwd)) {\n\t\tconst market = parseMarketplaceDir(rec.dir);\n\t\tif (!market) continue;\n\t\tfor (const entry of market.plugins) {\n\t\t\tif (seen.has(entry.name)) continue;\n\t\t\tseen.add(entry.name);\n\t\t\tout.push({\n\t\t\t\tname: entry.name,\n\t\t\t\tdescription: entry.description,\n\t\t\t\tsource: entry.source,\n\t\t\t\tsourceKind: resolvePluginSource(entry.source, market.root).kind,\n\t\t\t\tmarketplaceName: market.name,\n\t\t\t\tmarketplaceRoot: market.root,\n\t\t\t\tsupportPlatform: entry.supportPlatform ?? market.supportPlatform,\n\t\t\t});\n\t\t}\n\t}\n\treturn out;\n}\n\n/** Find a single available plugin by exact name. */\nexport function findAvailablePlugin(cwd: string, name: string): AvailablePlugin | undefined {\n\treturn listAvailablePlugins(cwd).find((p) => p.name === name);\n}\n\n/** All currently installed plugins (project + global plugin dirs). */\nexport function listInstalledPlugins(cwd: string, agentDir: string = getAgentDir()): NormalizedPlugin[] {\n\treturn discoverPlugins(defaultPluginDirs(cwd, agentDir));\n}\n\n/** Whether a plugin with `name` (by id) is already installed. */\nexport function isPluginInstalled(cwd: string, name: string, agentDir: string = getAgentDir()): boolean {\n\treturn listInstalledPlugins(cwd, agentDir).some((p) => p.id === name);\n}\n\nfunction execGit(args: string[]): Promise<{ code: number; stdout: string; stderr: string }> {\n\treturn new Promise((resolve) => {\n\t\tconst child = spawn(\"git\", args);\n\t\tlet stdout = \"\";\n\t\tlet stderr = \"\";\n\t\tchild.stdout?.on(\"data\", (d) => {\n\t\t\tstdout += d.toString();\n\t\t});\n\t\tchild.stderr?.on(\"data\", (d) => {\n\t\t\tstderr += d.toString();\n\t\t});\n\t\tchild.on(\"error\", (e) => resolve({ code: 1, stdout, stderr: stderr || String(e) }));\n\t\tchild.on(\"close\", (code) => resolve({ code: code ?? 1, stdout, stderr }));\n\t});\n}\n\n/**\n * Clone a git repository into `dest`.\n * If `ref` is provided, does a shallow clone of that branch/tag.\n * If only `sha` is provided, does a full clone and checks out the commit.\n * Returns the clone result; on failure `dest` may be partially created.\n */\nasync function cloneGitRepo(\n\turl: string,\n\tdest: string,\n\tref?: string,\n\tsha?: string,\n): Promise<{ code: number; stdout: string; stderr: string }> {\n\tif (ref) {\n\t\treturn execGit([\"clone\", \"--branch\", ref, \"--depth\", \"1\", \"--\", url, dest]);\n\t}\n\tif (sha) {\n\t\tconst cloneRes = await execGit([\"clone\", \"--\", url, dest]);\n\t\tif (cloneRes.code !== 0) return cloneRes;\n\t\treturn execGit([\"-C\", dest, \"checkout\", \"--quiet\", sha]);\n\t}\n\treturn execGit([\"clone\", \"--depth\", \"1\", \"--\", url, dest]);\n}\n\n/**\n * Resolve a git-subdir source: clone the repo, checkout the requested ref/sha,\n * and copy the subdirectory to `dest`. Cleans up the temporary clone on failure.\n */\nasync function installGitSubdir(\n\turl: string,\n\tsubdir: string,\n\tdest: string,\n\tref?: string,\n\tsha?: string,\n): Promise<{ ok: true } | { ok: false; message: string }> {\n\tconst tmpDir = mkdtempSync(path.join(os.tmpdir(), \"hoo-plugin-clone-\"));\n\ttry {\n\t\tconst cloneRes = await cloneGitRepo(url, tmpDir, ref, sha);\n\t\tif (cloneRes.code !== 0) {\n\t\t\treturn { ok: false, message: `git clone failed: ${cloneRes.stderr || cloneRes.stdout}`.trim() };\n\t\t}\n\t\tconst src = path.resolve(tmpDir, subdir);\n\t\tif (!existsSync(src)) {\n\t\t\treturn { ok: false, message: `Plugin subdirectory not found in cloned repo: ${subdir}` };\n\t\t}\n\t\tcpSync(src, dest, { recursive: true });\n\t\treturn { ok: true };\n\t} finally {\n\t\trmSync(tmpDir, { recursive: true, force: true });\n\t}\n}\n\nexport interface InstallOutcome {\n\tinstalled: boolean;\n\t/** Install destination directory (when installed). */\n\tdest?: string;\n\t/** Platforms the installed plugin supports (read back from disk). */\n\tsupportPlatform?: MarketplacePlatform[];\n\t/** Human-readable summary suitable for a tool result or notification. */\n\tmessage: string;\n}\n\n/**\n * Install an available plugin by name into `.agents/plugins`. Copies local\n * sources; clones git sources. Transparent + reversible by construction — the\n * plugin lands in a named directory and {@link uninstallPlugin} removes it.\n * Callers activate the result (live activation via AgentSession.activatePlugin,\n * or a reload).\n */\nexport async function installAvailablePlugin(cwd: string, name: string): Promise<InstallOutcome> {\n\tconst found = findAvailablePlugin(cwd, name);\n\tif (!found) return { installed: false, message: `Plugin \"${name}\" not found in any registered marketplace.` };\n\n\tconst resolved = resolvePluginSource(found.source, found.marketplaceRoot);\n\tconst dest = path.join(installedPluginsDir(cwd), sanitizeForDir(name));\n\trmSync(dest, { recursive: true, force: true });\n\tmkdirSync(installedPluginsDir(cwd), { recursive: true });\n\n\tif (resolved.kind === \"local\") {\n\t\tif (!existsSync(resolved.path)) {\n\t\t\treturn { installed: false, message: `Plugin source path not found: ${resolved.path}` };\n\t\t}\n\t\tcpSync(resolved.path, dest, { recursive: true });\n\t} else if (resolved.kind === \"git\") {\n\t\tconst res = await cloneGitRepo(resolved.url, dest, resolved.ref, resolved.sha);\n\t\tif (res.code !== 0) {\n\t\t\trmSync(dest, { recursive: true, force: true });\n\t\t\treturn { installed: false, message: `git clone failed: ${res.stderr || res.stdout}`.trim() };\n\t\t}\n\t} else if (resolved.kind === \"git-subdir\") {\n\t\tconst res = await installGitSubdir(resolved.url, resolved.path, dest, resolved.ref, resolved.sha);\n\t\tif (!res.ok) {\n\t\t\trmSync(dest, { recursive: true, force: true });\n\t\t\treturn { installed: false, message: res.message };\n\t\t}\n\t} else {\n\t\treturn { installed: false, message: `npm plugin sources are not supported yet (${resolved.spec}).` };\n\t}\n\n\tlet parsed = parsePluginDir(dest);\n\tif (!parsed) {\n\t\t// Manifest-less plugin dir (some marketplaces index bare capability trees,\n\t\t// e.g. a plugin that is just a `skills/` directory): synthesize a native\n\t\t// manifest from the marketplace entry so the standard loader can carry it.\n\t\tconst manifestDir = path.join(dest, \".agents-plugin\");\n\t\tmkdirSync(manifestDir, { recursive: true });\n\t\twriteFileSync(\n\t\t\tpath.join(manifestDir, \"plugin.json\"),\n\t\t\t`${JSON.stringify(\n\t\t\t\t{ name: found.name, ...(found.description ? { description: found.description } : {}) },\n\t\t\t\tnull,\n\t\t\t\t2,\n\t\t\t)}\\n`,\n\t\t\t\"utf8\",\n\t\t);\n\t\tparsed = parsePluginDir(dest);\n\t}\n\tif (!parsed) {\n\t\trmSync(dest, { recursive: true, force: true });\n\t\treturn { installed: false, message: `Installed source for \"${name}\" has no recognizable plugin manifest.` };\n\t}\n\treturn {\n\t\tinstalled: true,\n\t\tdest,\n\t\tsupportPlatform: parsed.supportPlatform,\n\t\tmessage:\n\t\t\t`Installed \"${name}\" from marketplace \"${found.marketplaceName}\" ` +\n\t\t\t`(${parsed.supportPlatform.join(\", \")}) to ${path.relative(cwd, dest) || dest}. ` +\n\t\t\t`Remove it with UninstallPlugin.`,\n\t};\n}\n\nexport interface UninstallOutcome {\n\tremoved: boolean;\n\tmessage: string;\n}\n\n/** Remove an installed plugin from `.agents/plugins` (and the legacy `.hoocode/plugins`). */\nexport function uninstallPlugin(cwd: string, name: string): UninstallOutcome {\n\tconst candidates = [\n\t\tpath.join(installedPluginsDir(cwd), sanitizeForDir(name)),\n\t\tpath.join(cwd, \".hoocode\", \"plugins\", sanitizeForDir(name)),\n\t];\n\tconst present = candidates.filter((p) => existsSync(p));\n\tif (present.length === 0) return { removed: false, message: `Plugin \"${name}\" is not installed.` };\n\tfor (const p of present) rmSync(p, { recursive: true, force: true });\n\treturn { removed: true, message: `Removed \"${name}\".` };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../../../src/core/extensions/plugins/install.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Plugin install/uninstall/discovery — the shared engine behind both the\n * `/plugin` slash command (human-driven) and the model-facing lifecycle tools\n * (`SearchPlugins`, `InstallPlugin`, ...). Keeping it in one place means the two\n * surfaces can never drift on where plugins live or how sources resolve.\n *\n * Trust model (see docs/plugin-system-spec.md): *adding* a marketplace is the\n * human trust boundary; *installing* from an already-trusted marketplace is the\n * model's discretion (package-manager model), and must stay transparent and\n * reversible. This module performs the mechanical install/remove; the gating\n * (announce, injection carve-out) lives with the callers.\n */\n\nimport { spawn } from \"node:child_process\";\nimport { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, renameSync, rmSync, writeFileSync } from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { getAgentDir } from \"../../../config.js\";\nimport { defaultPluginDirs } from \"../loader.js\";\nimport { hasAnyManifest } from \"./formats/index.js\";\nimport type { MarketplacePlatform } from \"./formats/types.js\";\nimport { discoverPlugins } from \"./index.js\";\nimport {\n\tcandidatePluginDirs,\n\tconsumptionPluginsDir,\n\tmarketplaceCacheDir,\n\tmarketplaceCacheMetaPath,\n\tmarketplaceCacheRoot,\n\tmarketplaceStorePath,\n\tsanitizeForDir,\n} from \"./locations.js\";\nimport type { NormalizedPlugin } from \"./manifest.js\";\nimport { parsePluginDir } from \"./manifest.js\";\nimport {\n\ttype MarketplacePluginSource,\n\ttype MarketplaceRecord,\n\tparseMarketplaceDir,\n\treadMarketplaceStore,\n\tresolvePluginSource,\n} from \"./marketplace.js\";\n\n/**\n * Marketplace registries older versions wrote into the working tree, newest\n * convention first. Still read so a user who added a marketplace before the\n * registry moved to the agent dir does not silently lose it; nothing writes here.\n */\nfunction legacyStorePaths(cwd: string): string[] {\n\treturn [path.join(cwd, \".agents\", \"marketplaces.json\"), path.join(cwd, \".hoocode\", \"marketplaces.json\")];\n}\n\n/** Absolute path to the curated default marketplace bundled with hoocode. */\nfunction defaultMarketplaceDir(): string {\n\treturn fileURLToPath(new URL(\"./default-marketplace/\", import.meta.url));\n}\n\n/** The default marketplace record — always present so source-level trust is meaningful out of the box. */\nexport function defaultMarketplaceRecord(): MarketplaceRecord {\n\treturn { location: \"hoocode-default\", dir: defaultMarketplaceDir() };\n}\n\n/**\n * Curated well-known marketplaces, trusted out of the box. Shipping an entry\n * here is a maintainer-level trust decision (the human half of the \"adding a\n * marketplace is the human trust boundary\" rule) — keep this list short and\n * high-trust. Indices are cloned lazily into the marketplace cache on first\n * search and refreshed on a TTL thereafter. Refreshing the *index* only changes\n * what is discoverable; installed plugins are still never auto-updated, and\n * plugin sources inside the official index are sha-pinned.\n */\nexport const WELL_KNOWN_MARKETPLACES: ReadonlyArray<{ name: string; url: string }> = [\n\t{ name: \"claude-plugins-official\", url: \"https://github.com/anthropics/claude-plugins-official\" },\n\t// The Copilot plugin directory ships both a `.github/plugin/marketplace.json`\n\t// and a `.claude-plugin/marketplace.json`, so it parses with\n\t// supportPlatform [\"claude\", \"github\"] — the default `github` source.\n\t{ name: \"copilot-plugins\", url: \"https://github.com/github/copilot-plugins\" },\n];\n\n/**\n * How long a cached marketplace index is considered fresh.\n *\n * Refreshing an *index* is safe to automate: it changes what is discoverable,\n * not what is installed. The rule that an installed plugin is never auto-updated\n * from a remote is untouched — that is the supply-chain boundary, and this is a\n * catalog listing.\n */\nconst MARKETPLACE_TTL_MS = 24 * 60 * 60 * 1000;\n\nfunction marketplaceTtlMs(): number {\n\tconst raw = Number(process.env.HOOCODE_MARKETPLACE_TTL_MS);\n\treturn Number.isFinite(raw) && raw >= 0 ? raw : MARKETPLACE_TTL_MS;\n}\n\ntype CacheMeta = Record<string, string>;\n\nfunction readCacheMeta(agentDir: string): CacheMeta {\n\tconst parsed = readJsonFile<CacheMeta>(marketplaceCacheMetaPath(agentDir));\n\treturn parsed && typeof parsed === \"object\" ? parsed : {};\n}\n\nfunction recordFetch(agentDir: string, url: string): void {\n\tconst meta = readCacheMeta(agentDir);\n\tmeta[url] = new Date().toISOString();\n\tconst file = marketplaceCacheMetaPath(agentDir);\n\tmkdirSync(path.dirname(file), { recursive: true });\n\twriteFileSync(file, `${JSON.stringify(meta, null, 2)}\\n`, \"utf8\");\n}\n\nfunction isStale(agentDir: string, url: string): boolean {\n\tconst ttl = marketplaceTtlMs();\n\tif (ttl === 0) return true;\n\tconst at = readCacheMeta(agentDir)[url];\n\tif (!at) return true;\n\tconst age = Date.now() - Date.parse(at);\n\treturn !Number.isFinite(age) || age > ttl;\n}\n\nfunction readJsonFile<T>(file: string): T | null {\n\ttry {\n\t\treturn JSON.parse(readFileSync(file, \"utf8\")) as T;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Bring an existing clone up to date, falling back to a fresh clone when the pull\n * cannot fast-forward (a force-pushed remote, or a corrupt cache).\n *\n * The re-clone goes to a temp directory and is swapped in only on success. An\n * earlier version deleted the cache first, which meant a refresh attempted while\n * offline destroyed a perfectly good index — the opposite of the \"offline is\n * non-fatal\" property the caller depends on.\n */\nasync function refreshClone(url: string, dir: string): Promise<{ code: number; stdout: string; stderr: string }> {\n\tconst pulled = await execGit([\"-C\", dir, \"pull\", \"--ff-only\"]);\n\tif (pulled.code === 0) return pulled;\n\n\tconst staging = mkdtempSync(path.join(os.tmpdir(), \"hoo-market-refresh-\"));\n\tconst target = path.join(staging, \"clone\");\n\tconst cloned = await cloneGitRepo(url, target);\n\tif (cloned.code !== 0) {\n\t\trmSync(staging, { recursive: true, force: true });\n\t\treturn cloned;\n\t}\n\trmSync(dir, { recursive: true, force: true });\n\tmkdirSync(path.dirname(dir), { recursive: true });\n\ttry {\n\t\trenameSync(target, dir);\n\t} catch {\n\t\tcpSync(target, dir, { recursive: true });\n\t}\n\trmSync(staging, { recursive: true, force: true });\n\treturn cloned;\n}\n\nexport interface EnsureMarketplacesOptions {\n\t/** Refresh regardless of the TTL. */\n\tforce?: boolean;\n}\n\n/**\n * Make sure every well-known marketplace index is cached and reasonably fresh.\n *\n * Clones what is missing and pulls what has gone stale. Without the TTL the\n * indices were fetched exactly once and never again, so a plugin added upstream\n * stayed permanently invisible — the inherit half of the system quietly stopped\n * inheriting. Offline is non-fatal: each failure is returned and search degrades\n * to whatever is already on disk.\n */\nexport async function ensureWellKnownMarketplaces(\n\tagentDir: string = getAgentDir(),\n\toptions: EnsureMarketplacesOptions = {},\n): Promise<string[]> {\n\tconst errors: string[] = [];\n\tfor (const wk of WELL_KNOWN_MARKETPLACES) {\n\t\tconst dir = marketplaceCacheDir(wk.url, agentDir);\n\t\tconst present = existsSync(dir);\n\t\tif (present && !options.force && !isStale(agentDir, wk.url)) continue;\n\n\t\tmkdirSync(path.dirname(dir), { recursive: true });\n\t\tconst res = present ? await refreshClone(wk.url, dir) : await cloneGitRepo(wk.url, dir);\n\t\tif (res.code !== 0) {\n\t\t\t// A failed *refresh* keeps the stale copy: an out-of-date index is far\n\t\t\t// more useful than none, and the network may simply be down.\n\t\t\tif (!present) rmSync(dir, { recursive: true, force: true });\n\t\t\terrors.push(`${wk.name}: ${(res.stderr || res.stdout).trim()}`);\n\t\t\tcontinue;\n\t\t}\n\t\trecordFetch(agentDir, wk.url);\n\t}\n\treturn errors;\n}\n\n/**\n * Refresh every cached index — well-known and user-added — ignoring the TTL.\n * The explicit half of the freshness story, for when a user knows the upstream\n * changed and does not want to wait out the interval.\n */\nexport async function refreshMarketplaces(\n\tcwd: string,\n\tagentDir: string = getAgentDir(),\n): Promise<{ refreshed: string[]; errors: string[] }> {\n\tconst errors = await ensureWellKnownMarketplaces(agentDir, { force: true });\n\tconst refreshed = WELL_KNOWN_MARKETPLACES.filter((wk) => existsSync(marketplaceCacheDir(wk.url, agentDir))).map(\n\t\t(wk) => wk.name,\n\t);\n\n\t// User-added marketplaces are cached the same way when they came from git; a\n\t// local-path marketplace is read in place and has nothing to refresh.\n\tfor (const record of readMarketplaceRecords(cwd, agentDir)) {\n\t\tconst isCachedClone = record.dir.startsWith(marketplaceCacheRoot(agentDir));\n\t\tif (!isCachedClone || WELL_KNOWN_MARKETPLACES.some((wk) => wk.url === record.location)) continue;\n\t\tconst res = await refreshClone(record.location, record.dir);\n\t\tif (res.code !== 0) errors.push(`${record.location}: ${(res.stderr || res.stdout).trim()}`);\n\t\telse {\n\t\t\trecordFetch(agentDir, record.location);\n\t\t\trefreshed.push(record.location);\n\t\t}\n\t}\n\treturn { refreshed, errors };\n}\n\n/**\n * All marketplace records in effect: the bundled default first (curated,\n * trusted), then user-added ones from `.agents/` (falling back to legacy\n * `.hoocode/`). Deduplicated by directory.\n */\nexport function readMarketplaceRecords(cwd: string, agentDir: string = getAgentDir()): MarketplaceRecord[] {\n\tconst records: MarketplaceRecord[] = [];\n\tconst def = defaultMarketplaceRecord();\n\tif (existsSync(def.dir)) records.push(def);\n\n\t// Well-known marketplaces participate once their index is cached locally\n\t// (see ensureWellKnownMarketplaces; SearchPlugins fetches lazily).\n\tfor (const wk of WELL_KNOWN_MARKETPLACES) {\n\t\tconst dir = marketplaceCacheDir(wk.url, agentDir);\n\t\tif (existsSync(dir) && !records.some((x) => x.dir === dir)) {\n\t\t\trecords.push({ location: wk.url, dir });\n\t\t}\n\t}\n\n\t// The registry lives in the agent dir. Project-local ones are a migration\n\t// read-path: merged in, never written back, so an older setup keeps working.\n\tconst user = [\n\t\t...readMarketplaceStore(marketplaceStorePath(agentDir)),\n\t\t...legacyStorePaths(cwd).flatMap((p) => readMarketplaceStore(p)),\n\t];\n\tfor (const r of user) {\n\t\tif (!records.some((x) => x.dir === r.dir)) records.push(r);\n\t}\n\treturn records;\n}\n\n/** A plugin offered by some registered marketplace (not necessarily installed). */\nexport interface AvailablePlugin {\n\tname: string;\n\tdescription?: string;\n\t/** Relative path, git URL, `npm:<spec>`, or structured source object. */\n\tsource: MarketplacePluginSource;\n\t/** Resolved source kind, for display and gating. */\n\tsourceKind: \"local\" | \"git\" | \"git-subdir\" | \"npm\";\n\tmarketplaceName: string;\n\tmarketplaceRoot: string;\n\t/** Platforms this entry targets (per-entry hint, else the marketplace's). */\n\tsupportPlatform: MarketplacePlatform[];\n}\n\n/** Every plugin offered across all registered marketplaces (first marketplace wins on name clash). */\nexport function listAvailablePlugins(cwd: string, agentDir: string = getAgentDir()): AvailablePlugin[] {\n\tconst out: AvailablePlugin[] = [];\n\tconst seen = new Set<string>();\n\tfor (const rec of readMarketplaceRecords(cwd, agentDir)) {\n\t\tconst market = parseMarketplaceDir(rec.dir);\n\t\tif (!market) continue;\n\t\tfor (const entry of market.plugins) {\n\t\t\tif (seen.has(entry.name)) continue;\n\t\t\tseen.add(entry.name);\n\t\t\tout.push({\n\t\t\t\tname: entry.name,\n\t\t\t\tdescription: entry.description,\n\t\t\t\tsource: entry.source,\n\t\t\t\tsourceKind: resolvePluginSource(entry.source, market.root).kind,\n\t\t\t\tmarketplaceName: market.name,\n\t\t\t\tmarketplaceRoot: market.root,\n\t\t\t\tsupportPlatform: entry.supportPlatform ?? market.supportPlatform,\n\t\t\t});\n\t\t}\n\t}\n\treturn out;\n}\n\n/** Find a single available plugin by exact name. */\nexport function findAvailablePlugin(\n\tcwd: string,\n\tname: string,\n\tagentDir: string = getAgentDir(),\n): AvailablePlugin | undefined {\n\treturn listAvailablePlugins(cwd, agentDir).find((p) => p.name === name);\n}\n\n/** All currently installed plugins (project + global plugin dirs). */\nexport function listInstalledPlugins(cwd: string, agentDir: string = getAgentDir()): NormalizedPlugin[] {\n\treturn discoverPlugins(defaultPluginDirs(cwd, agentDir));\n}\n\n/** Whether a plugin with `name` (by id) is already installed. */\nexport function isPluginInstalled(cwd: string, name: string, agentDir: string = getAgentDir()): boolean {\n\treturn listInstalledPlugins(cwd, agentDir).some((p) => p.id === name);\n}\n\nfunction execGit(args: string[]): Promise<{ code: number; stdout: string; stderr: string }> {\n\treturn new Promise((resolve) => {\n\t\tconst child = spawn(\"git\", args);\n\t\tlet stdout = \"\";\n\t\tlet stderr = \"\";\n\t\tchild.stdout?.on(\"data\", (d) => {\n\t\t\tstdout += d.toString();\n\t\t});\n\t\tchild.stderr?.on(\"data\", (d) => {\n\t\t\tstderr += d.toString();\n\t\t});\n\t\tchild.on(\"error\", (e) => resolve({ code: 1, stdout, stderr: stderr || String(e) }));\n\t\tchild.on(\"close\", (code) => resolve({ code: code ?? 1, stdout, stderr }));\n\t});\n}\n\n/**\n * Clone a git repository into `dest`.\n * If `ref` is provided, does a shallow clone of that branch/tag.\n * If only `sha` is provided, does a full clone and checks out the commit.\n * Returns the clone result; on failure `dest` may be partially created.\n */\nasync function cloneGitRepo(\n\turl: string,\n\tdest: string,\n\tref?: string,\n\tsha?: string,\n): Promise<{ code: number; stdout: string; stderr: string }> {\n\tif (ref) {\n\t\treturn execGit([\"clone\", \"--branch\", ref, \"--depth\", \"1\", \"--\", url, dest]);\n\t}\n\tif (sha) {\n\t\tconst cloneRes = await execGit([\"clone\", \"--\", url, dest]);\n\t\tif (cloneRes.code !== 0) return cloneRes;\n\t\treturn execGit([\"-C\", dest, \"checkout\", \"--quiet\", sha]);\n\t}\n\treturn execGit([\"clone\", \"--depth\", \"1\", \"--\", url, dest]);\n}\n\n/**\n * Resolve a git-subdir source: clone the repo, checkout the requested ref/sha,\n * and copy the subdirectory to `dest`. Cleans up the temporary clone on failure.\n */\nasync function installGitSubdir(\n\turl: string,\n\tsubdir: string,\n\tdest: string,\n\tref?: string,\n\tsha?: string,\n): Promise<{ ok: true } | { ok: false; message: string }> {\n\tconst tmpDir = mkdtempSync(path.join(os.tmpdir(), \"hoo-plugin-clone-\"));\n\ttry {\n\t\tconst cloneRes = await cloneGitRepo(url, tmpDir, ref, sha);\n\t\tif (cloneRes.code !== 0) {\n\t\t\treturn { ok: false, message: `git clone failed: ${cloneRes.stderr || cloneRes.stdout}`.trim() };\n\t\t}\n\t\tconst src = path.resolve(tmpDir, subdir);\n\t\tif (!existsSync(src)) {\n\t\t\treturn { ok: false, message: `Plugin subdirectory not found in cloned repo: ${subdir}` };\n\t\t}\n\t\tcpSync(src, dest, { recursive: true });\n\t\treturn { ok: true };\n\t} finally {\n\t\trmSync(tmpDir, { recursive: true, force: true });\n\t}\n}\n\nexport interface InstallOutcome {\n\tinstalled: boolean;\n\t/** Install destination directory (when installed). */\n\tdest?: string;\n\t/** Platforms the installed plugin supports (read back from disk). */\n\tsupportPlatform?: MarketplacePlatform[];\n\t/** Human-readable summary suitable for a tool result or notification. */\n\tmessage: string;\n}\n\n/**\n * Install an available plugin by name into the **consumption home** — the global\n * `~/.agents/plugins/`, not the working tree. A plugin is portable and reusable\n * across projects, so installing into the repo would both dirty `git status` and\n * hide the capability from every other checkout.\n *\n * Copies local sources; clones git sources. Transparent + reversible by\n * construction — the plugin lands in a named directory and\n * {@link uninstallPlugin} removes it. Callers activate the result (live\n * activation via AgentSession.activatePlugin, or a reload).\n */\nexport async function installAvailablePlugin(\n\tcwd: string,\n\tname: string,\n\tagentDir: string = getAgentDir(),\n): Promise<InstallOutcome> {\n\tconst found = findAvailablePlugin(cwd, name, agentDir);\n\tif (!found) return { installed: false, message: `Plugin \"${name}\" not found in any registered marketplace.` };\n\n\tconst resolved = resolvePluginSource(found.source, found.marketplaceRoot);\n\tconst home = consumptionPluginsDir(agentDir);\n\tconst dest = path.join(home, sanitizeForDir(name));\n\trmSync(dest, { recursive: true, force: true });\n\tmkdirSync(home, { recursive: true });\n\n\tif (resolved.kind === \"local\") {\n\t\tif (!existsSync(resolved.path)) {\n\t\t\treturn { installed: false, message: `Plugin source path not found: ${resolved.path}` };\n\t\t}\n\t\tcpSync(resolved.path, dest, { recursive: true });\n\t} else if (resolved.kind === \"git\") {\n\t\tconst res = await cloneGitRepo(resolved.url, dest, resolved.ref, resolved.sha);\n\t\tif (res.code !== 0) {\n\t\t\trmSync(dest, { recursive: true, force: true });\n\t\t\treturn { installed: false, message: `git clone failed: ${res.stderr || res.stdout}`.trim() };\n\t\t}\n\t} else if (resolved.kind === \"git-subdir\") {\n\t\tconst res = await installGitSubdir(resolved.url, resolved.path, dest, resolved.ref, resolved.sha);\n\t\tif (!res.ok) {\n\t\t\trmSync(dest, { recursive: true, force: true });\n\t\t\treturn { installed: false, message: res.message };\n\t\t}\n\t} else {\n\t\treturn { installed: false, message: `npm plugin sources are not supported yet (${resolved.spec}).` };\n\t}\n\n\tlet parsed = parsePluginDir(dest);\n\tif (!hasAnyManifest(dest)) {\n\t\t// Manifest-less plugin dir (some marketplaces index bare capability trees,\n\t\t// e.g. a plugin that is just a `skills/` directory). Such a directory now\n\t\t// *parses* on its own — the vendors make the manifest optional — but the\n\t\t// entry's name and description live only in the marketplace index, and the\n\t\t// derived id would be the sanitized directory name. Synthesize a native\n\t\t// manifest so both survive the install.\n\t\tconst manifestDir = path.join(dest, \".agents-plugin\");\n\t\tmkdirSync(manifestDir, { recursive: true });\n\t\twriteFileSync(\n\t\t\tpath.join(manifestDir, \"plugin.json\"),\n\t\t\t`${JSON.stringify(\n\t\t\t\t{ name: found.name, ...(found.description ? { description: found.description } : {}) },\n\t\t\t\tnull,\n\t\t\t\t2,\n\t\t\t)}\\n`,\n\t\t\t\"utf8\",\n\t\t);\n\t\tparsed = parsePluginDir(dest);\n\t}\n\tif (!parsed) {\n\t\trmSync(dest, { recursive: true, force: true });\n\t\treturn { installed: false, message: `Installed source for \"${name}\" has no recognizable plugin manifest.` };\n\t}\n\treturn {\n\t\tinstalled: true,\n\t\tdest,\n\t\tsupportPlatform: parsed.supportPlatform,\n\t\tmessage:\n\t\t\t`Installed \"${name}\" from marketplace \"${found.marketplaceName}\" ` +\n\t\t\t`(${parsed.supportPlatform.join(\", \")}) to ${dest}. ` +\n\t\t\t`Remove it with UninstallPlugin.`,\n\t};\n}\n\nexport interface UninstallOutcome {\n\tremoved: boolean;\n\tmessage: string;\n}\n\n/**\n * Remove an installed or authored plugin from every location it could occupy:\n * the consumption home, both production homes, and the legacy project-local\n * directories that older versions wrote into.\n */\nexport function uninstallPlugin(cwd: string, name: string, agentDir: string = getAgentDir()): UninstallOutcome {\n\tconst candidates = [\n\t\t...candidatePluginDirs(cwd, name, agentDir),\n\t\tpath.join(cwd, \".hoocode\", \"plugins\", sanitizeForDir(name)),\n\t];\n\tconst present = candidates.filter((p) => existsSync(p));\n\tif (present.length === 0) return { removed: false, message: `Plugin \"${name}\" is not installed.` };\n\tfor (const p of present) rmSync(p, { recursive: true, force: true });\n\treturn { removed: true, message: `Removed \"${name}\".` };\n}\n"]}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where plugins live on disk.
|
|
3
|
+
*
|
|
4
|
+
* Three distinct roles, deliberately named apart — an earlier design called all
|
|
5
|
+
* three "staging", which is how the wrong directory ends up in code:
|
|
6
|
+
*
|
|
7
|
+
* Draft dir Ephemeral. Holds an authored plugin while the eval gates
|
|
8
|
+
* run, and is deleted on any failure. Nothing here is ever
|
|
9
|
+
* loaded; it is promoted into a production home or thrown
|
|
10
|
+
* away. {@link makeDraftDir}
|
|
11
|
+
* Consumption home Persistent, global. Where marketplace installs land, in
|
|
12
|
+
* whatever format the marketplace served. hoocode
|
|
13
|
+
* installing for itself. {@link consumptionPluginsDir}
|
|
14
|
+
* Production home Persistent, global, per platform. Where a plugin hoocode
|
|
15
|
+
* *authored* lives. {@link productionPluginDir}
|
|
16
|
+
*
|
|
17
|
+
* All three are user-scoped. A plugin is portable, versioned and reusable across
|
|
18
|
+
* projects, so writing one into the working tree means the capability is
|
|
19
|
+
* invisible in every other repo and the agent dirties `git status` with content
|
|
20
|
+
* unrelated to the task. The project-local home is still *read* so plugins
|
|
21
|
+
* installed by older versions keep working ({@link legacyProjectPluginsDir}).
|
|
22
|
+
*
|
|
23
|
+
* The two production homes are asymmetric because the vendors are. Claude Code
|
|
24
|
+
* discovers `~/.claude/skills/<id>/` in place, with no install step, so an
|
|
25
|
+
* authored plugin is live there on its next session. Copilot CLI has no
|
|
26
|
+
* equivalent — `copilot plugin install` copies into a cache it owns — so a
|
|
27
|
+
* github artifact lives in a hoocode-owned home and reaches the ecosystem
|
|
28
|
+
* through the publish lane instead.
|
|
29
|
+
*
|
|
30
|
+
* See docs/plugin-system-architecture.md §5.3 and §8.3.
|
|
31
|
+
*/
|
|
32
|
+
import type { PluginPlatform } from "./formats/platform-targets.js";
|
|
33
|
+
/** Filesystem-safe directory name derived from a plugin name (matches the `/plugin` command). */
|
|
34
|
+
export declare function sanitizeForDir(s: string): string;
|
|
35
|
+
/** `~/.agents/plugins/` — where marketplace installs land. Format-agnostic. */
|
|
36
|
+
export declare function consumptionPluginsDir(agentDir?: string): string;
|
|
37
|
+
/** The project-local home older versions installed into. Read-only now; still uninstalled from. */
|
|
38
|
+
export declare function legacyProjectPluginsDir(cwd: string): string;
|
|
39
|
+
/**
|
|
40
|
+
* Root of a platform's production home — the parent that {@link productionPluginDir}
|
|
41
|
+
* places plugin directories under.
|
|
42
|
+
*/
|
|
43
|
+
export declare function productionRoot(platform: PluginPlatform, agentDir?: string): string;
|
|
44
|
+
/** Where an authored plugin for `platform` lives. */
|
|
45
|
+
export declare function productionPluginDir(platform: PluginPlatform, id: string, agentDir?: string): string;
|
|
46
|
+
/** `~/.agents/marketplaces.json` — the added-marketplace registry. */
|
|
47
|
+
export declare function marketplaceStorePath(agentDir?: string): string;
|
|
48
|
+
/** Root of the local marketplace clone cache. A cache is never repo content. */
|
|
49
|
+
export declare function marketplaceCacheRoot(agentDir?: string): string;
|
|
50
|
+
/** Local cache directory for a marketplace fetched from `url`. */
|
|
51
|
+
export declare function marketplaceCacheDir(url: string, agentDir?: string): string;
|
|
52
|
+
/**
|
|
53
|
+
* Records when each cached marketplace index was last fetched.
|
|
54
|
+
*
|
|
55
|
+
* Kept beside the caches rather than inferred from directory mtimes: a clone's
|
|
56
|
+
* mtime moves for reasons that have nothing to do with freshness, and "when did
|
|
57
|
+
* we last talk to the remote" is the only question the TTL is asking.
|
|
58
|
+
*/
|
|
59
|
+
export declare function marketplaceCacheMetaPath(agentDir?: string): string;
|
|
60
|
+
/**
|
|
61
|
+
* Every directory a plugin with `id` could occupy, in the order a lookup should
|
|
62
|
+
* try them: the platform production homes, then the consumption home, then the
|
|
63
|
+
* legacy project home. Used to find an existing plugin without knowing which
|
|
64
|
+
* role wrote it.
|
|
65
|
+
*/
|
|
66
|
+
export declare function candidatePluginDirs(cwd: string, id: string, agentDir?: string): string[];
|
|
67
|
+
/**
|
|
68
|
+
* Persistent, writable directory unique to an installed plugin — the target of
|
|
69
|
+
* `${CLAUDE_PLUGIN_DATA}` / `${COPILOT_PLUGIN_DATA}`, which both vendors document
|
|
70
|
+
* as the place for plugin runtime state.
|
|
71
|
+
*
|
|
72
|
+
* Deliberately outside every plugin home. A plugin's own directory is replaced
|
|
73
|
+
* wholesale on promote and deleted on uninstall, and the vendors are explicit
|
|
74
|
+
* that this must not live "inside the installed-plugins cache directory" — state
|
|
75
|
+
* that vanishes on reinstall is not state.
|
|
76
|
+
*/
|
|
77
|
+
export declare function pluginDataDir(id: string, agentDir?: string): string;
|
|
78
|
+
/** {@link pluginDataDir}, created if absent. */
|
|
79
|
+
export declare function ensurePluginDataDir(id: string, agentDir?: string): string;
|
|
80
|
+
/** Create an ephemeral draft directory. The caller must promote or {@link discardDraftDir} it. */
|
|
81
|
+
export declare function makeDraftDir(): string;
|
|
82
|
+
/** Delete a draft directory. Safe to call twice. */
|
|
83
|
+
export declare function discardDraftDir(dir: string): void;
|
|
84
|
+
//# sourceMappingURL=locations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"locations.d.ts","sourceRoot":"","sources":["../../../../src/core/extensions/plugins/locations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAEpE,iGAAiG;AACjG,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEhD;AAWD,iFAA+E;AAC/E,wBAAgB,qBAAqB,CAAC,QAAQ,GAAE,MAAsB,GAAG,MAAM,CAE9E;AAED,mGAAmG;AACnG,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,cAAc,EAAE,QAAQ,GAAE,MAAsB,GAAG,MAAM,CAOjG;AAED,qDAAqD;AACrD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAsB,GAAG,MAAM,CAElH;AAED,wEAAsE;AACtE,wBAAgB,oBAAoB,CAAC,QAAQ,GAAE,MAAsB,GAAG,MAAM,CAE7E;AAED,gFAAgF;AAChF,wBAAgB,oBAAoB,CAAC,QAAQ,GAAE,MAAsB,GAAG,MAAM,CAE7E;AAED,kEAAkE;AAClE,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAsB,GAAG,MAAM,CAEzF;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,GAAE,MAAsB,GAAG,MAAM,CAEjF;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAsB,GAAG,MAAM,EAAE,CAQvG;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAsB,GAAG,MAAM,CAElF;AAED,gDAAgD;AAChD,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAsB,GAAG,MAAM,CAIxF;AAED,kGAAkG;AAClG,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,oDAAoD;AACpD,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEjD","sourcesContent":["/**\n * Where plugins live on disk.\n *\n * Three distinct roles, deliberately named apart — an earlier design called all\n * three \"staging\", which is how the wrong directory ends up in code:\n *\n * Draft dir Ephemeral. Holds an authored plugin while the eval gates\n * run, and is deleted on any failure. Nothing here is ever\n * loaded; it is promoted into a production home or thrown\n * away. {@link makeDraftDir}\n * Consumption home Persistent, global. Where marketplace installs land, in\n * whatever format the marketplace served. hoocode\n * installing for itself. {@link consumptionPluginsDir}\n * Production home Persistent, global, per platform. Where a plugin hoocode\n * *authored* lives. {@link productionPluginDir}\n *\n * All three are user-scoped. A plugin is portable, versioned and reusable across\n * projects, so writing one into the working tree means the capability is\n * invisible in every other repo and the agent dirties `git status` with content\n * unrelated to the task. The project-local home is still *read* so plugins\n * installed by older versions keep working ({@link legacyProjectPluginsDir}).\n *\n * The two production homes are asymmetric because the vendors are. Claude Code\n * discovers `~/.claude/skills/<id>/` in place, with no install step, so an\n * authored plugin is live there on its next session. Copilot CLI has no\n * equivalent — `copilot plugin install` copies into a cache it owns — so a\n * github artifact lives in a hoocode-owned home and reaches the ecosystem\n * through the publish lane instead.\n *\n * See docs/plugin-system-architecture.md §5.3 and §8.3.\n */\n\nimport { mkdirSync, mkdtempSync, rmSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport * as path from \"node:path\";\nimport { getAgentDir } from \"../../../config.js\";\nimport type { PluginPlatform } from \"./formats/platform-targets.js\";\n\n/** Filesystem-safe directory name derived from a plugin name (matches the `/plugin` command). */\nexport function sanitizeForDir(s: string): string {\n\treturn s.replace(/[^a-zA-Z0-9._-]+/g, \"_\").slice(0, 80);\n}\n\n/**\n * Home root the global surfaces hang off. Derived from the agent dir rather than\n * `homedir()` so `HOOCODE_AGENT_DIR` relocates every plugin location together —\n * which is what makes these paths testable.\n */\nfunction homeRoot(agentDir: string): string {\n\treturn path.dirname(agentDir);\n}\n\n/** `~/.agents/plugins/` — where marketplace installs land. Format-agnostic. */\nexport function consumptionPluginsDir(agentDir: string = getAgentDir()): string {\n\treturn path.join(homeRoot(agentDir), \".agents\", \"plugins\");\n}\n\n/** The project-local home older versions installed into. Read-only now; still uninstalled from. */\nexport function legacyProjectPluginsDir(cwd: string): string {\n\treturn path.join(cwd, \".agents\", \"plugins\");\n}\n\n/**\n * Root of a platform's production home — the parent that {@link productionPluginDir}\n * places plugin directories under.\n */\nexport function productionRoot(platform: PluginPlatform, agentDir: string = getAgentDir()): string {\n\t// Claude: the documented skills-directory drop-in. A folder here carrying a\n\t// `.claude-plugin/plugin.json` loads as `<id>@skills-dir` with no install step.\n\tif (platform === \"claude\") return path.join(homeRoot(agentDir), \".claude\", \"skills\");\n\t// GitHub: no vendor drop-in exists, so this is hoocode's own home for a\n\t// github-targeted artifact. PackagePlugin works in it and publish reads from it.\n\treturn path.join(homeRoot(agentDir), \".agents\", \"publish\", \"github\");\n}\n\n/** Where an authored plugin for `platform` lives. */\nexport function productionPluginDir(platform: PluginPlatform, id: string, agentDir: string = getAgentDir()): string {\n\treturn path.join(productionRoot(platform, agentDir), sanitizeForDir(id));\n}\n\n/** `~/.agents/marketplaces.json` — the added-marketplace registry. */\nexport function marketplaceStorePath(agentDir: string = getAgentDir()): string {\n\treturn path.join(homeRoot(agentDir), \".agents\", \"marketplaces.json\");\n}\n\n/** Root of the local marketplace clone cache. A cache is never repo content. */\nexport function marketplaceCacheRoot(agentDir: string = getAgentDir()): string {\n\treturn path.join(homeRoot(agentDir), \".agents\", \"marketplace-cache\");\n}\n\n/** Local cache directory for a marketplace fetched from `url`. */\nexport function marketplaceCacheDir(url: string, agentDir: string = getAgentDir()): string {\n\treturn path.join(marketplaceCacheRoot(agentDir), sanitizeForDir(url));\n}\n\n/**\n * Records when each cached marketplace index was last fetched.\n *\n * Kept beside the caches rather than inferred from directory mtimes: a clone's\n * mtime moves for reasons that have nothing to do with freshness, and \"when did\n * we last talk to the remote\" is the only question the TTL is asking.\n */\nexport function marketplaceCacheMetaPath(agentDir: string = getAgentDir()): string {\n\treturn path.join(marketplaceCacheRoot(agentDir), \".fetched.json\");\n}\n\n/**\n * Every directory a plugin with `id` could occupy, in the order a lookup should\n * try them: the platform production homes, then the consumption home, then the\n * legacy project home. Used to find an existing plugin without knowing which\n * role wrote it.\n */\nexport function candidatePluginDirs(cwd: string, id: string, agentDir: string = getAgentDir()): string[] {\n\tconst slug = sanitizeForDir(id);\n\treturn [\n\t\tproductionPluginDir(\"claude\", id, agentDir),\n\t\tproductionPluginDir(\"github\", id, agentDir),\n\t\tpath.join(consumptionPluginsDir(agentDir), slug),\n\t\tpath.join(legacyProjectPluginsDir(cwd), slug),\n\t];\n}\n\n/**\n * Persistent, writable directory unique to an installed plugin — the target of\n * `${CLAUDE_PLUGIN_DATA}` / `${COPILOT_PLUGIN_DATA}`, which both vendors document\n * as the place for plugin runtime state.\n *\n * Deliberately outside every plugin home. A plugin's own directory is replaced\n * wholesale on promote and deleted on uninstall, and the vendors are explicit\n * that this must not live \"inside the installed-plugins cache directory\" — state\n * that vanishes on reinstall is not state.\n */\nexport function pluginDataDir(id: string, agentDir: string = getAgentDir()): string {\n\treturn path.join(homeRoot(agentDir), \".agents\", \"plugin-data\", sanitizeForDir(id));\n}\n\n/** {@link pluginDataDir}, created if absent. */\nexport function ensurePluginDataDir(id: string, agentDir: string = getAgentDir()): string {\n\tconst dir = pluginDataDir(id, agentDir);\n\tmkdirSync(dir, { recursive: true });\n\treturn dir;\n}\n\n/** Create an ephemeral draft directory. The caller must promote or {@link discardDraftDir} it. */\nexport function makeDraftDir(): string {\n\treturn mkdtempSync(path.join(tmpdir(), \"hoo-plugin-draft-\"));\n}\n\n/** Delete a draft directory. Safe to call twice. */\nexport function discardDraftDir(dir: string): void {\n\trmSync(dir, { recursive: true, force: true });\n}\n"]}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where plugins live on disk.
|
|
3
|
+
*
|
|
4
|
+
* Three distinct roles, deliberately named apart — an earlier design called all
|
|
5
|
+
* three "staging", which is how the wrong directory ends up in code:
|
|
6
|
+
*
|
|
7
|
+
* Draft dir Ephemeral. Holds an authored plugin while the eval gates
|
|
8
|
+
* run, and is deleted on any failure. Nothing here is ever
|
|
9
|
+
* loaded; it is promoted into a production home or thrown
|
|
10
|
+
* away. {@link makeDraftDir}
|
|
11
|
+
* Consumption home Persistent, global. Where marketplace installs land, in
|
|
12
|
+
* whatever format the marketplace served. hoocode
|
|
13
|
+
* installing for itself. {@link consumptionPluginsDir}
|
|
14
|
+
* Production home Persistent, global, per platform. Where a plugin hoocode
|
|
15
|
+
* *authored* lives. {@link productionPluginDir}
|
|
16
|
+
*
|
|
17
|
+
* All three are user-scoped. A plugin is portable, versioned and reusable across
|
|
18
|
+
* projects, so writing one into the working tree means the capability is
|
|
19
|
+
* invisible in every other repo and the agent dirties `git status` with content
|
|
20
|
+
* unrelated to the task. The project-local home is still *read* so plugins
|
|
21
|
+
* installed by older versions keep working ({@link legacyProjectPluginsDir}).
|
|
22
|
+
*
|
|
23
|
+
* The two production homes are asymmetric because the vendors are. Claude Code
|
|
24
|
+
* discovers `~/.claude/skills/<id>/` in place, with no install step, so an
|
|
25
|
+
* authored plugin is live there on its next session. Copilot CLI has no
|
|
26
|
+
* equivalent — `copilot plugin install` copies into a cache it owns — so a
|
|
27
|
+
* github artifact lives in a hoocode-owned home and reaches the ecosystem
|
|
28
|
+
* through the publish lane instead.
|
|
29
|
+
*
|
|
30
|
+
* See docs/plugin-system-architecture.md §5.3 and §8.3.
|
|
31
|
+
*/
|
|
32
|
+
import { mkdirSync, mkdtempSync, rmSync } from "node:fs";
|
|
33
|
+
import { tmpdir } from "node:os";
|
|
34
|
+
import * as path from "node:path";
|
|
35
|
+
import { getAgentDir } from "../../../config.js";
|
|
36
|
+
/** Filesystem-safe directory name derived from a plugin name (matches the `/plugin` command). */
|
|
37
|
+
export function sanitizeForDir(s) {
|
|
38
|
+
return s.replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 80);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Home root the global surfaces hang off. Derived from the agent dir rather than
|
|
42
|
+
* `homedir()` so `HOOCODE_AGENT_DIR` relocates every plugin location together —
|
|
43
|
+
* which is what makes these paths testable.
|
|
44
|
+
*/
|
|
45
|
+
function homeRoot(agentDir) {
|
|
46
|
+
return path.dirname(agentDir);
|
|
47
|
+
}
|
|
48
|
+
/** `~/.agents/plugins/` — where marketplace installs land. Format-agnostic. */
|
|
49
|
+
export function consumptionPluginsDir(agentDir = getAgentDir()) {
|
|
50
|
+
return path.join(homeRoot(agentDir), ".agents", "plugins");
|
|
51
|
+
}
|
|
52
|
+
/** The project-local home older versions installed into. Read-only now; still uninstalled from. */
|
|
53
|
+
export function legacyProjectPluginsDir(cwd) {
|
|
54
|
+
return path.join(cwd, ".agents", "plugins");
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Root of a platform's production home — the parent that {@link productionPluginDir}
|
|
58
|
+
* places plugin directories under.
|
|
59
|
+
*/
|
|
60
|
+
export function productionRoot(platform, agentDir = getAgentDir()) {
|
|
61
|
+
// Claude: the documented skills-directory drop-in. A folder here carrying a
|
|
62
|
+
// `.claude-plugin/plugin.json` loads as `<id>@skills-dir` with no install step.
|
|
63
|
+
if (platform === "claude")
|
|
64
|
+
return path.join(homeRoot(agentDir), ".claude", "skills");
|
|
65
|
+
// GitHub: no vendor drop-in exists, so this is hoocode's own home for a
|
|
66
|
+
// github-targeted artifact. PackagePlugin works in it and publish reads from it.
|
|
67
|
+
return path.join(homeRoot(agentDir), ".agents", "publish", "github");
|
|
68
|
+
}
|
|
69
|
+
/** Where an authored plugin for `platform` lives. */
|
|
70
|
+
export function productionPluginDir(platform, id, agentDir = getAgentDir()) {
|
|
71
|
+
return path.join(productionRoot(platform, agentDir), sanitizeForDir(id));
|
|
72
|
+
}
|
|
73
|
+
/** `~/.agents/marketplaces.json` — the added-marketplace registry. */
|
|
74
|
+
export function marketplaceStorePath(agentDir = getAgentDir()) {
|
|
75
|
+
return path.join(homeRoot(agentDir), ".agents", "marketplaces.json");
|
|
76
|
+
}
|
|
77
|
+
/** Root of the local marketplace clone cache. A cache is never repo content. */
|
|
78
|
+
export function marketplaceCacheRoot(agentDir = getAgentDir()) {
|
|
79
|
+
return path.join(homeRoot(agentDir), ".agents", "marketplace-cache");
|
|
80
|
+
}
|
|
81
|
+
/** Local cache directory for a marketplace fetched from `url`. */
|
|
82
|
+
export function marketplaceCacheDir(url, agentDir = getAgentDir()) {
|
|
83
|
+
return path.join(marketplaceCacheRoot(agentDir), sanitizeForDir(url));
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Records when each cached marketplace index was last fetched.
|
|
87
|
+
*
|
|
88
|
+
* Kept beside the caches rather than inferred from directory mtimes: a clone's
|
|
89
|
+
* mtime moves for reasons that have nothing to do with freshness, and "when did
|
|
90
|
+
* we last talk to the remote" is the only question the TTL is asking.
|
|
91
|
+
*/
|
|
92
|
+
export function marketplaceCacheMetaPath(agentDir = getAgentDir()) {
|
|
93
|
+
return path.join(marketplaceCacheRoot(agentDir), ".fetched.json");
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Every directory a plugin with `id` could occupy, in the order a lookup should
|
|
97
|
+
* try them: the platform production homes, then the consumption home, then the
|
|
98
|
+
* legacy project home. Used to find an existing plugin without knowing which
|
|
99
|
+
* role wrote it.
|
|
100
|
+
*/
|
|
101
|
+
export function candidatePluginDirs(cwd, id, agentDir = getAgentDir()) {
|
|
102
|
+
const slug = sanitizeForDir(id);
|
|
103
|
+
return [
|
|
104
|
+
productionPluginDir("claude", id, agentDir),
|
|
105
|
+
productionPluginDir("github", id, agentDir),
|
|
106
|
+
path.join(consumptionPluginsDir(agentDir), slug),
|
|
107
|
+
path.join(legacyProjectPluginsDir(cwd), slug),
|
|
108
|
+
];
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Persistent, writable directory unique to an installed plugin — the target of
|
|
112
|
+
* `${CLAUDE_PLUGIN_DATA}` / `${COPILOT_PLUGIN_DATA}`, which both vendors document
|
|
113
|
+
* as the place for plugin runtime state.
|
|
114
|
+
*
|
|
115
|
+
* Deliberately outside every plugin home. A plugin's own directory is replaced
|
|
116
|
+
* wholesale on promote and deleted on uninstall, and the vendors are explicit
|
|
117
|
+
* that this must not live "inside the installed-plugins cache directory" — state
|
|
118
|
+
* that vanishes on reinstall is not state.
|
|
119
|
+
*/
|
|
120
|
+
export function pluginDataDir(id, agentDir = getAgentDir()) {
|
|
121
|
+
return path.join(homeRoot(agentDir), ".agents", "plugin-data", sanitizeForDir(id));
|
|
122
|
+
}
|
|
123
|
+
/** {@link pluginDataDir}, created if absent. */
|
|
124
|
+
export function ensurePluginDataDir(id, agentDir = getAgentDir()) {
|
|
125
|
+
const dir = pluginDataDir(id, agentDir);
|
|
126
|
+
mkdirSync(dir, { recursive: true });
|
|
127
|
+
return dir;
|
|
128
|
+
}
|
|
129
|
+
/** Create an ephemeral draft directory. The caller must promote or {@link discardDraftDir} it. */
|
|
130
|
+
export function makeDraftDir() {
|
|
131
|
+
return mkdtempSync(path.join(tmpdir(), "hoo-plugin-draft-"));
|
|
132
|
+
}
|
|
133
|
+
/** Delete a draft directory. Safe to call twice. */
|
|
134
|
+
export function discardDraftDir(dir) {
|
|
135
|
+
rmSync(dir, { recursive: true, force: true });
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=locations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"locations.js","sourceRoot":"","sources":["../../../../src/core/extensions/plugins/locations.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Where plugins live on disk.\n *\n * Three distinct roles, deliberately named apart — an earlier design called all\n * three \"staging\", which is how the wrong directory ends up in code:\n *\n * Draft dir Ephemeral. Holds an authored plugin while the eval gates\n * run, and is deleted on any failure. Nothing here is ever\n * loaded; it is promoted into a production home or thrown\n * away. {@link makeDraftDir}\n * Consumption home Persistent, global. Where marketplace installs land, in\n * whatever format the marketplace served. hoocode\n * installing for itself. {@link consumptionPluginsDir}\n * Production home Persistent, global, per platform. Where a plugin hoocode\n * *authored* lives. {@link productionPluginDir}\n *\n * All three are user-scoped. A plugin is portable, versioned and reusable across\n * projects, so writing one into the working tree means the capability is\n * invisible in every other repo and the agent dirties `git status` with content\n * unrelated to the task. The project-local home is still *read* so plugins\n * installed by older versions keep working ({@link legacyProjectPluginsDir}).\n *\n * The two production homes are asymmetric because the vendors are. Claude Code\n * discovers `~/.claude/skills/<id>/` in place, with no install step, so an\n * authored plugin is live there on its next session. Copilot CLI has no\n * equivalent — `copilot plugin install` copies into a cache it owns — so a\n * github artifact lives in a hoocode-owned home and reaches the ecosystem\n * through the publish lane instead.\n *\n * See docs/plugin-system-architecture.md §5.3 and §8.3.\n */\n\nimport { mkdirSync, mkdtempSync, rmSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport * as path from \"node:path\";\nimport { getAgentDir } from \"../../../config.js\";\nimport type { PluginPlatform } from \"./formats/platform-targets.js\";\n\n/** Filesystem-safe directory name derived from a plugin name (matches the `/plugin` command). */\nexport function sanitizeForDir(s: string): string {\n\treturn s.replace(/[^a-zA-Z0-9._-]+/g, \"_\").slice(0, 80);\n}\n\n/**\n * Home root the global surfaces hang off. Derived from the agent dir rather than\n * `homedir()` so `HOOCODE_AGENT_DIR` relocates every plugin location together —\n * which is what makes these paths testable.\n */\nfunction homeRoot(agentDir: string): string {\n\treturn path.dirname(agentDir);\n}\n\n/** `~/.agents/plugins/` — where marketplace installs land. Format-agnostic. */\nexport function consumptionPluginsDir(agentDir: string = getAgentDir()): string {\n\treturn path.join(homeRoot(agentDir), \".agents\", \"plugins\");\n}\n\n/** The project-local home older versions installed into. Read-only now; still uninstalled from. */\nexport function legacyProjectPluginsDir(cwd: string): string {\n\treturn path.join(cwd, \".agents\", \"plugins\");\n}\n\n/**\n * Root of a platform's production home — the parent that {@link productionPluginDir}\n * places plugin directories under.\n */\nexport function productionRoot(platform: PluginPlatform, agentDir: string = getAgentDir()): string {\n\t// Claude: the documented skills-directory drop-in. A folder here carrying a\n\t// `.claude-plugin/plugin.json` loads as `<id>@skills-dir` with no install step.\n\tif (platform === \"claude\") return path.join(homeRoot(agentDir), \".claude\", \"skills\");\n\t// GitHub: no vendor drop-in exists, so this is hoocode's own home for a\n\t// github-targeted artifact. PackagePlugin works in it and publish reads from it.\n\treturn path.join(homeRoot(agentDir), \".agents\", \"publish\", \"github\");\n}\n\n/** Where an authored plugin for `platform` lives. */\nexport function productionPluginDir(platform: PluginPlatform, id: string, agentDir: string = getAgentDir()): string {\n\treturn path.join(productionRoot(platform, agentDir), sanitizeForDir(id));\n}\n\n/** `~/.agents/marketplaces.json` — the added-marketplace registry. */\nexport function marketplaceStorePath(agentDir: string = getAgentDir()): string {\n\treturn path.join(homeRoot(agentDir), \".agents\", \"marketplaces.json\");\n}\n\n/** Root of the local marketplace clone cache. A cache is never repo content. */\nexport function marketplaceCacheRoot(agentDir: string = getAgentDir()): string {\n\treturn path.join(homeRoot(agentDir), \".agents\", \"marketplace-cache\");\n}\n\n/** Local cache directory for a marketplace fetched from `url`. */\nexport function marketplaceCacheDir(url: string, agentDir: string = getAgentDir()): string {\n\treturn path.join(marketplaceCacheRoot(agentDir), sanitizeForDir(url));\n}\n\n/**\n * Records when each cached marketplace index was last fetched.\n *\n * Kept beside the caches rather than inferred from directory mtimes: a clone's\n * mtime moves for reasons that have nothing to do with freshness, and \"when did\n * we last talk to the remote\" is the only question the TTL is asking.\n */\nexport function marketplaceCacheMetaPath(agentDir: string = getAgentDir()): string {\n\treturn path.join(marketplaceCacheRoot(agentDir), \".fetched.json\");\n}\n\n/**\n * Every directory a plugin with `id` could occupy, in the order a lookup should\n * try them: the platform production homes, then the consumption home, then the\n * legacy project home. Used to find an existing plugin without knowing which\n * role wrote it.\n */\nexport function candidatePluginDirs(cwd: string, id: string, agentDir: string = getAgentDir()): string[] {\n\tconst slug = sanitizeForDir(id);\n\treturn [\n\t\tproductionPluginDir(\"claude\", id, agentDir),\n\t\tproductionPluginDir(\"github\", id, agentDir),\n\t\tpath.join(consumptionPluginsDir(agentDir), slug),\n\t\tpath.join(legacyProjectPluginsDir(cwd), slug),\n\t];\n}\n\n/**\n * Persistent, writable directory unique to an installed plugin — the target of\n * `${CLAUDE_PLUGIN_DATA}` / `${COPILOT_PLUGIN_DATA}`, which both vendors document\n * as the place for plugin runtime state.\n *\n * Deliberately outside every plugin home. A plugin's own directory is replaced\n * wholesale on promote and deleted on uninstall, and the vendors are explicit\n * that this must not live \"inside the installed-plugins cache directory\" — state\n * that vanishes on reinstall is not state.\n */\nexport function pluginDataDir(id: string, agentDir: string = getAgentDir()): string {\n\treturn path.join(homeRoot(agentDir), \".agents\", \"plugin-data\", sanitizeForDir(id));\n}\n\n/** {@link pluginDataDir}, created if absent. */\nexport function ensurePluginDataDir(id: string, agentDir: string = getAgentDir()): string {\n\tconst dir = pluginDataDir(id, agentDir);\n\tmkdirSync(dir, { recursive: true });\n\treturn dir;\n}\n\n/** Create an ephemeral draft directory. The caller must promote or {@link discardDraftDir} it. */\nexport function makeDraftDir(): string {\n\treturn mkdtempSync(path.join(tmpdir(), \"hoo-plugin-draft-\"));\n}\n\n/** Delete a draft directory. Safe to call twice. */\nexport function discardDraftDir(dir: string): void {\n\trmSync(dir, { recursive: true, force: true });\n}\n"]}
|
|
@@ -72,6 +72,24 @@ export interface NormalizedPlugin {
|
|
|
72
72
|
mcpServers?: Record<string, unknown>;
|
|
73
73
|
/** Native-only: providers to register. */
|
|
74
74
|
providers?: PluginProvider[];
|
|
75
|
+
/**
|
|
76
|
+
* Manifest keys this adapter does not model, preserved verbatim.
|
|
77
|
+
*
|
|
78
|
+
* Load-bearing, not diagnostic: an edit re-emits the manifest, so anything not
|
|
79
|
+
* carried here is silently dropped from a plugin we did not write in full.
|
|
80
|
+
* Vendor schemas grow independently of ours (Copilot has `extensions` and
|
|
81
|
+
* `lspServers`; Claude keeps adding component keys), and losing one on a
|
|
82
|
+
* plugin destined for someone else's ecosystem is worse than failing to read
|
|
83
|
+
* it.
|
|
84
|
+
*/
|
|
85
|
+
unknownFields?: Record<string, unknown>;
|
|
86
|
+
/**
|
|
87
|
+
* On-disk surfaces present but unhandled, e.g. `[".lsp.json", "monitors/"]`.
|
|
88
|
+
* Reported rather than implemented: the files stay on disk untouched, and
|
|
89
|
+
* `ListPlugins` says so, which turns the next round of vendor drift into a
|
|
90
|
+
* visible signal instead of a silent gap.
|
|
91
|
+
*/
|
|
92
|
+
unsupportedSurfaces?: string[];
|
|
75
93
|
}
|
|
76
94
|
/**
|
|
77
95
|
* Parse and normalize a single plugin directory.
|
|
@@ -79,5 +97,7 @@ export interface NormalizedPlugin {
|
|
|
79
97
|
*
|
|
80
98
|
* Delegates to the format registry; see {@link ./formats/index.ts}.
|
|
81
99
|
*/
|
|
82
|
-
export declare function parsePluginDir(root: string
|
|
100
|
+
export declare function parsePluginDir(root: string, options?: {
|
|
101
|
+
requireManifest?: boolean;
|
|
102
|
+
}): NormalizedPlugin | null;
|
|
83
103
|
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../../src/core/extensions/plugins/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE9D,gDAAgD;AAChD,MAAM,WAAW,iBAAiB;IACjC,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,kEAAkE;AAClE,MAAM,WAAW,sBAAsB;IACtC,kFAAkF;IAClF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,iBAAiB,EAAE,CAAC;CAC3B;AAED;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,sBAAsB,EAAE,CAAC,CAAC;AAEzE,4FAA4F;AAC5F,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,cAAc,CAAC;CACvB;AAED,8DAA8D;AAC9D,MAAM,WAAW,gBAAgB;IAChC,2CAA2C;IAC3C,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,YAAY,EAAE,MAAM,CAAC;IACrB,0EAA0E;IAC1E,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IACxC;;;;;;OAMG;IACH,eAAe,EAAE,mBAAmB,EAAE,CAAC;IACvC,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gEAAgE;IAChE,KAAK,CAAC,EAAE,iBAAiB,CAAC;IAC1B,oGAAoG;IACpG,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,0CAA0C;IAC1C,SAAS,CAAC,EAAE,cAAc,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../../src/core/extensions/plugins/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE9D,gDAAgD;AAChD,MAAM,WAAW,iBAAiB;IACjC,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,kEAAkE;AAClE,MAAM,WAAW,sBAAsB;IACtC,kFAAkF;IAClF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,iBAAiB,EAAE,CAAC;CAC3B;AAED;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,sBAAsB,EAAE,CAAC,CAAC;AAEzE,4FAA4F;AAC5F,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,cAAc,CAAC;CACvB;AAED,8DAA8D;AAC9D,MAAM,WAAW,gBAAgB;IAChC,2CAA2C;IAC3C,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,YAAY,EAAE,MAAM,CAAC;IACrB,0EAA0E;IAC1E,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IACxC;;;;;;OAMG;IACH,eAAe,EAAE,mBAAmB,EAAE,CAAC;IACvC,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gEAAgE;IAChE,KAAK,CAAC,EAAE,iBAAiB,CAAC;IAC1B,oGAAoG;IACpG,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,0CAA0C;IAC1C,SAAS,CAAC,EAAE,cAAc,EAAE,CAAC;IAC7B;;;;;;;;;OASG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,eAAe,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,gBAAgB,GAAG,IAAI,CAE7G","sourcesContent":["/**\n * Plugin manifest types and the format-dispatching parse entry point.\n *\n * A \"plugin\" is a directory that bundles agent capabilities (skills, commands,\n * agents/modes, themes, providers, hooks, MCP servers) behind a single manifest.\n * Several vendor formats are supported and parsed into one {@link NormalizedPlugin}:\n *\n * - `.agents-plugin/plugin.json` — native format (a strict superset)\n * - `.claude-plugin/plugin.json` — Claude Code compatible format\n * - `.github/copilot-plugin.json` — GitHub Copilot format (`.github/` layout)\n *\n * The per-format detect/parse/emit logic lives in {@link ./formats}, one adapter\n * per vendor, behind the {@link PluginFormatAdapter} contract — so this module\n * carries only the shared types and delegates directory parsing to the registry.\n * When a directory carries more than one format, the highest-precedence one wins\n * (native > Claude > Copilot; no merge).\n */\n\nimport type { ProviderConfig } from \"../types.js\";\nimport { parsePluginWithFormats } from \"./formats/index.js\";\nimport type { MarketplacePlatform } from \"./formats/types.js\";\n\n/** A single shell command invoked by a hook. */\nexport interface PluginHookCommand {\n\ttype?: \"command\";\n\tcommand: string;\n\t/** Timeout in seconds (Claude Code convention). */\n\ttimeout?: number;\n}\n\n/** A matcher group: run these commands when `matcher` matches. */\nexport interface PluginHookMatcherGroup {\n\t/** Regex string matched against the tool name. Empty / \"*\" matches everything. */\n\tmatcher?: string;\n\thooks: PluginHookCommand[];\n}\n\n/**\n * Hook event map keyed by Claude Code event name\n * (PreToolUse, PostToolUse, UserPromptSubmit, SessionStart, Stop, ...).\n */\nexport type PluginHooksConfig = Record<string, PluginHookMatcherGroup[]>;\n\n/** A provider contributed by a native plugin (config-only; uses a built-in API handler). */\nexport interface PluginProvider {\n\tname: string;\n\tconfig: ProviderConfig;\n}\n\n/** Normalized, format-agnostic representation of a plugin. */\nexport interface NormalizedPlugin {\n\t/** Stable identifier (manifest `name`). */\n\tid: string;\n\tversion?: string;\n\tdescription?: string;\n\tauthor?: string;\n\t/** Absolute path to the plugin root directory. */\n\troot: string;\n\t/** Absolute path to the parsed manifest file. */\n\tmanifestPath: string;\n\t/** Which manifest format produced this plugin (the precedence winner). */\n\tformat: \"agents\" | \"claude\" | \"copilot\";\n\t/**\n\t * Every platform this plugin directory offers. When a directory carries more\n\t * than one format manifest (e.g. both `.claude-plugin/` and `.github/`), all\n\t * are recorded here — the precedence winner's platform first — rather than\n\t * hidden behind the single `format`. Always non-empty (at least `format`'s\n\t * platform), mirroring the marketplace's `supportPlatform`.\n\t */\n\tsupportPlatform: MarketplacePlatform[];\n\t/** Resolved capability directories (only set when they exist on disk). */\n\tskillsDir?: string;\n\tcommandsDir?: string;\n\tagentsDir?: string;\n\tthemesDir?: string;\n\t/** Parsed hooks (from `hooks/hooks.json` or inline `hooks`). */\n\thooks?: PluginHooksConfig;\n\t/** Parsed MCP servers (from `.mcp.json` or inline `mcpServers`); connected via the MCP registry. */\n\tmcpServers?: Record<string, unknown>;\n\t/** Native-only: providers to register. */\n\tproviders?: PluginProvider[];\n\t/**\n\t * Manifest keys this adapter does not model, preserved verbatim.\n\t *\n\t * Load-bearing, not diagnostic: an edit re-emits the manifest, so anything not\n\t * carried here is silently dropped from a plugin we did not write in full.\n\t * Vendor schemas grow independently of ours (Copilot has `extensions` and\n\t * `lspServers`; Claude keeps adding component keys), and losing one on a\n\t * plugin destined for someone else's ecosystem is worse than failing to read\n\t * it.\n\t */\n\tunknownFields?: Record<string, unknown>;\n\t/**\n\t * On-disk surfaces present but unhandled, e.g. `[\".lsp.json\", \"monitors/\"]`.\n\t * Reported rather than implemented: the files stay on disk untouched, and\n\t * `ListPlugins` says so, which turns the next round of vendor drift into a\n\t * visible signal instead of a silent gap.\n\t */\n\tunsupportedSurfaces?: string[];\n}\n\n/**\n * Parse and normalize a single plugin directory.\n * Returns null if no recognized manifest is present or it is invalid.\n *\n * Delegates to the format registry; see {@link ./formats/index.ts}.\n */\nexport function parsePluginDir(root: string, options?: { requireManifest?: boolean }): NormalizedPlugin | null {\n\treturn parsePluginWithFormats(root, options);\n}\n"]}
|
|
@@ -22,7 +22,7 @@ import { parsePluginWithFormats } from "./formats/index.js";
|
|
|
22
22
|
*
|
|
23
23
|
* Delegates to the format registry; see {@link ./formats/index.ts}.
|
|
24
24
|
*/
|
|
25
|
-
export function parsePluginDir(root) {
|
|
26
|
-
return parsePluginWithFormats(root);
|
|
25
|
+
export function parsePluginDir(root, options) {
|
|
26
|
+
return parsePluginWithFormats(root, options);
|
|
27
27
|
}
|
|
28
28
|
//# sourceMappingURL=manifest.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../../src/core/extensions/plugins/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../../src/core/extensions/plugins/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAkF5D;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,OAAuC,EAA2B;IAC9G,OAAO,sBAAsB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAAA,CAC7C","sourcesContent":["/**\n * Plugin manifest types and the format-dispatching parse entry point.\n *\n * A \"plugin\" is a directory that bundles agent capabilities (skills, commands,\n * agents/modes, themes, providers, hooks, MCP servers) behind a single manifest.\n * Several vendor formats are supported and parsed into one {@link NormalizedPlugin}:\n *\n * - `.agents-plugin/plugin.json` — native format (a strict superset)\n * - `.claude-plugin/plugin.json` — Claude Code compatible format\n * - `.github/copilot-plugin.json` — GitHub Copilot format (`.github/` layout)\n *\n * The per-format detect/parse/emit logic lives in {@link ./formats}, one adapter\n * per vendor, behind the {@link PluginFormatAdapter} contract — so this module\n * carries only the shared types and delegates directory parsing to the registry.\n * When a directory carries more than one format, the highest-precedence one wins\n * (native > Claude > Copilot; no merge).\n */\n\nimport type { ProviderConfig } from \"../types.js\";\nimport { parsePluginWithFormats } from \"./formats/index.js\";\nimport type { MarketplacePlatform } from \"./formats/types.js\";\n\n/** A single shell command invoked by a hook. */\nexport interface PluginHookCommand {\n\ttype?: \"command\";\n\tcommand: string;\n\t/** Timeout in seconds (Claude Code convention). */\n\ttimeout?: number;\n}\n\n/** A matcher group: run these commands when `matcher` matches. */\nexport interface PluginHookMatcherGroup {\n\t/** Regex string matched against the tool name. Empty / \"*\" matches everything. */\n\tmatcher?: string;\n\thooks: PluginHookCommand[];\n}\n\n/**\n * Hook event map keyed by Claude Code event name\n * (PreToolUse, PostToolUse, UserPromptSubmit, SessionStart, Stop, ...).\n */\nexport type PluginHooksConfig = Record<string, PluginHookMatcherGroup[]>;\n\n/** A provider contributed by a native plugin (config-only; uses a built-in API handler). */\nexport interface PluginProvider {\n\tname: string;\n\tconfig: ProviderConfig;\n}\n\n/** Normalized, format-agnostic representation of a plugin. */\nexport interface NormalizedPlugin {\n\t/** Stable identifier (manifest `name`). */\n\tid: string;\n\tversion?: string;\n\tdescription?: string;\n\tauthor?: string;\n\t/** Absolute path to the plugin root directory. */\n\troot: string;\n\t/** Absolute path to the parsed manifest file. */\n\tmanifestPath: string;\n\t/** Which manifest format produced this plugin (the precedence winner). */\n\tformat: \"agents\" | \"claude\" | \"copilot\";\n\t/**\n\t * Every platform this plugin directory offers. When a directory carries more\n\t * than one format manifest (e.g. both `.claude-plugin/` and `.github/`), all\n\t * are recorded here — the precedence winner's platform first — rather than\n\t * hidden behind the single `format`. Always non-empty (at least `format`'s\n\t * platform), mirroring the marketplace's `supportPlatform`.\n\t */\n\tsupportPlatform: MarketplacePlatform[];\n\t/** Resolved capability directories (only set when they exist on disk). */\n\tskillsDir?: string;\n\tcommandsDir?: string;\n\tagentsDir?: string;\n\tthemesDir?: string;\n\t/** Parsed hooks (from `hooks/hooks.json` or inline `hooks`). */\n\thooks?: PluginHooksConfig;\n\t/** Parsed MCP servers (from `.mcp.json` or inline `mcpServers`); connected via the MCP registry. */\n\tmcpServers?: Record<string, unknown>;\n\t/** Native-only: providers to register. */\n\tproviders?: PluginProvider[];\n\t/**\n\t * Manifest keys this adapter does not model, preserved verbatim.\n\t *\n\t * Load-bearing, not diagnostic: an edit re-emits the manifest, so anything not\n\t * carried here is silently dropped from a plugin we did not write in full.\n\t * Vendor schemas grow independently of ours (Copilot has `extensions` and\n\t * `lspServers`; Claude keeps adding component keys), and losing one on a\n\t * plugin destined for someone else's ecosystem is worse than failing to read\n\t * it.\n\t */\n\tunknownFields?: Record<string, unknown>;\n\t/**\n\t * On-disk surfaces present but unhandled, e.g. `[\".lsp.json\", \"monitors/\"]`.\n\t * Reported rather than implemented: the files stay on disk untouched, and\n\t * `ListPlugins` says so, which turns the next round of vendor drift into a\n\t * visible signal instead of a silent gap.\n\t */\n\tunsupportedSurfaces?: string[];\n}\n\n/**\n * Parse and normalize a single plugin directory.\n * Returns null if no recognized manifest is present or it is invalid.\n *\n * Delegates to the format registry; see {@link ./formats/index.ts}.\n */\nexport function parsePluginDir(root: string, options?: { requireManifest?: boolean }): NormalizedPlugin | null {\n\treturn parsePluginWithFormats(root, options);\n}\n"]}
|