@nospt/plugin-dev-ai-hub-common 1.1.1 → 1.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/dist/index.d.ts +19 -4
- package/dist/resources.cjs.js +29 -12
- package/dist/resources.cjs.js.map +1 -1
- package/dist/resources.esm.js +29 -12
- package/dist/resources.esm.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -185,10 +185,14 @@ interface ResourceListResponse {
|
|
|
185
185
|
type BodyShape = 'markdown' | 'json';
|
|
186
186
|
declare function getBodyShape(type: ResourceType): BodyShape;
|
|
187
187
|
/**
|
|
188
|
-
* Whether the detail panel shows a "Content" section for this type.
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
188
|
+
* Whether the detail panel shows a "Content" section for this type.
|
|
189
|
+
*
|
|
190
|
+
* Suppressed for exactly the JSON-bodied types (`getBodyShape` === 'json'):
|
|
191
|
+
* `plugin` and `marketplace` are containers whose value is the relationship
|
|
192
|
+
* graph rather than the manifest, and an `mcp-config`'s body is a settings
|
|
193
|
+
* fragment to merge — in all three the raw JSON buries the panel and is
|
|
194
|
+
* better reached through Copy, Download or the install dialog, which is
|
|
195
|
+
* where it is actionable. The markdown types keep their rendered body.
|
|
192
196
|
*/
|
|
193
197
|
declare function showsContentSection(type: ResourceType): boolean;
|
|
194
198
|
/**
|
|
@@ -271,6 +275,17 @@ interface ResourceDeepLink {
|
|
|
271
275
|
/** Host application name; render as "Add in <label>" / "Install in <label>". */
|
|
272
276
|
label: string;
|
|
273
277
|
href: string;
|
|
278
|
+
/**
|
|
279
|
+
* The framework token this launcher installs into, for the `tool` column on
|
|
280
|
+
* the `install` event it records (ADR-0011). Not 1:1 with `label`:
|
|
281
|
+
* `github-copilot` offers both "VS Code" and "VS Code Insiders".
|
|
282
|
+
*
|
|
283
|
+
* Optional only to keep this published interface additive — every link the
|
|
284
|
+
* generators below build sets it, which `resources.test.ts` pins. A caller
|
|
285
|
+
* reading a generated link can rely on it; one constructing its own shape
|
|
286
|
+
* is not forced to supply it.
|
|
287
|
+
*/
|
|
288
|
+
framework?: string;
|
|
274
289
|
}
|
|
275
290
|
interface MarketplaceAddCommand {
|
|
276
291
|
framework: string;
|
package/dist/resources.cjs.js
CHANGED
|
@@ -119,7 +119,7 @@ function getBodyShape(type) {
|
|
|
119
119
|
return type === "mcp-config" || type === "plugin" || type === "marketplace" ? "json" : "markdown";
|
|
120
120
|
}
|
|
121
121
|
function showsContentSection(type) {
|
|
122
|
-
return type !== "
|
|
122
|
+
return getBodyShape(type) !== "json";
|
|
123
123
|
}
|
|
124
124
|
function hasDownloadableArtifact(_type) {
|
|
125
125
|
return true;
|
|
@@ -254,7 +254,8 @@ function getMarketplaceAddCommands(frameworks, repoSlug) {
|
|
|
254
254
|
deepLinks: [
|
|
255
255
|
{
|
|
256
256
|
label: "Claude",
|
|
257
|
-
href: `claude-cli://open?q=${encodeURIComponent(command)}
|
|
257
|
+
href: `claude-cli://open?q=${encodeURIComponent(command)}`,
|
|
258
|
+
framework
|
|
258
259
|
}
|
|
259
260
|
]
|
|
260
261
|
});
|
|
@@ -266,11 +267,13 @@ function getMarketplaceAddCommands(frameworks, repoSlug) {
|
|
|
266
267
|
deepLinks: [
|
|
267
268
|
{
|
|
268
269
|
label: "VS Code",
|
|
269
|
-
href: `vscode://chat-plugin/add-marketplace?ref=${ref}
|
|
270
|
+
href: `vscode://chat-plugin/add-marketplace?ref=${ref}`,
|
|
271
|
+
framework
|
|
270
272
|
},
|
|
271
273
|
{
|
|
272
274
|
label: "VS Code Insiders",
|
|
273
|
-
href: `vscode-insiders://chat-plugin/add-marketplace?ref=${ref}
|
|
275
|
+
href: `vscode-insiders://chat-plugin/add-marketplace?ref=${ref}`,
|
|
276
|
+
framework
|
|
274
277
|
}
|
|
275
278
|
]
|
|
276
279
|
});
|
|
@@ -302,7 +305,8 @@ function getRawGithubFileUrl(sourceLocation) {
|
|
|
302
305
|
function claudePromptLink(prompt) {
|
|
303
306
|
return {
|
|
304
307
|
label: "Claude",
|
|
305
|
-
href: `claude-cli://open?q=${encodeURIComponent(prompt)}
|
|
308
|
+
href: `claude-cli://open?q=${encodeURIComponent(prompt)}`,
|
|
309
|
+
framework: "claude-code"
|
|
306
310
|
};
|
|
307
311
|
}
|
|
308
312
|
function cursorPromptLink(prompt) {
|
|
@@ -310,7 +314,8 @@ function cursorPromptLink(prompt) {
|
|
|
310
314
|
label: "Cursor",
|
|
311
315
|
href: `cursor://anysphere.cursor-deeplink/prompt?text=${encodeURIComponent(
|
|
312
316
|
prompt
|
|
313
|
-
)}
|
|
317
|
+
)}`,
|
|
318
|
+
framework: "cursor"
|
|
314
319
|
};
|
|
315
320
|
}
|
|
316
321
|
const AGENT_LINK_CAPABLE_FRAMEWORKS = [
|
|
@@ -387,11 +392,13 @@ function getAgentInstallLinks(sourceLocation, name, frameworks = []) {
|
|
|
387
392
|
} else if (framework === "github-copilot") {
|
|
388
393
|
links.push({
|
|
389
394
|
label: "VS Code",
|
|
390
|
-
href: `vscode:chat-agent/install?url=${encodedRawUrl}
|
|
395
|
+
href: `vscode:chat-agent/install?url=${encodedRawUrl}`,
|
|
396
|
+
framework
|
|
391
397
|
});
|
|
392
398
|
links.push({
|
|
393
399
|
label: "VS Code Insiders",
|
|
394
|
-
href: `vscode-insiders:chat-agent/install?url=${encodedRawUrl}
|
|
400
|
+
href: `vscode-insiders:chat-agent/install?url=${encodedRawUrl}`,
|
|
401
|
+
framework
|
|
395
402
|
});
|
|
396
403
|
}
|
|
397
404
|
}
|
|
@@ -439,15 +446,24 @@ function getMcpInstallLinks(frameworks, resourceName, bodyContent) {
|
|
|
439
446
|
const prompt = encodeURIComponent(
|
|
440
447
|
`Install this MCP config by running: claude mcp add-json ${serverName} '${configJson}'`
|
|
441
448
|
);
|
|
442
|
-
links.push({
|
|
449
|
+
links.push({
|
|
450
|
+
label: "Claude",
|
|
451
|
+
href: `claude-cli://open?q=${prompt}`,
|
|
452
|
+
framework
|
|
453
|
+
});
|
|
443
454
|
} else if (framework === "github-copilot") {
|
|
444
455
|
const vsConfig = encodeURIComponent(
|
|
445
456
|
JSON.stringify({ name: serverName, ...config })
|
|
446
457
|
);
|
|
447
|
-
links.push({
|
|
458
|
+
links.push({
|
|
459
|
+
label: "VS Code",
|
|
460
|
+
href: `vscode:mcp/install?${vsConfig}`,
|
|
461
|
+
framework
|
|
462
|
+
});
|
|
448
463
|
links.push({
|
|
449
464
|
label: "VS Code Insiders",
|
|
450
|
-
href: `vscode-insiders:mcp/install?${vsConfig}
|
|
465
|
+
href: `vscode-insiders:mcp/install?${vsConfig}`,
|
|
466
|
+
framework
|
|
451
467
|
});
|
|
452
468
|
} else if (framework === "cursor") {
|
|
453
469
|
try {
|
|
@@ -455,7 +471,8 @@ function getMcpInstallLinks(frameworks, resourceName, bodyContent) {
|
|
|
455
471
|
label: "Cursor",
|
|
456
472
|
href: `cursor://anysphere.cursor-deeplink/mcp/install?name=${encodeURIComponent(
|
|
457
473
|
serverName
|
|
458
|
-
)}&config=${btoa(configJson)}
|
|
474
|
+
)}&config=${btoa(configJson)}`,
|
|
475
|
+
framework
|
|
459
476
|
});
|
|
460
477
|
} catch {
|
|
461
478
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resources.cjs.js","sources":["../src/resources.ts"],"sourcesContent":["/**\n * The v2 read contract: AiResource vocabulary, the flat ResourceSummary\n * returned by the backend, and the shared framework resolver (ADR-0003).\n *\n * The legacy asset-model types in `types.ts` coexist with this module until\n * the legacy silo is deleted (slice 8, issue #34).\n */\n\n/** The six canonical `spec.type` values of an AiResource (ADR-0003, ADR-0010). */\nexport const RESOURCE_TYPES = [\n 'skill',\n 'agent',\n 'hook',\n 'mcp-config',\n 'plugin',\n 'marketplace',\n] as const;\n\nexport type ResourceType = (typeof RESOURCE_TYPES)[number];\n\nexport function isResourceType(value: unknown): value is ResourceType {\n return (\n typeof value === 'string' &&\n (RESOURCE_TYPES as readonly string[]).includes(value)\n );\n}\n\n/**\n * The AiResource types a `plugin` may contain — restricted to the component\n * kinds a real Claude Code / GitHub Copilot plugin manifest allows: `skills`,\n * `agents`, `hooks` and `mcpServers` (schemastore `claude-code-plugin` /\n * `claude-code-marketplace.json`). A plugin's other manifest components\n * (`commands`, `lspServers`, `outputStyles`, `themes`, `channels`, `monitors`)\n * have no AiResource type, so they are never members here; other plugins are\n * `dependencies`, not containment.\n */\nexport const PLUGIN_MEMBER_TYPES: readonly ResourceType[] = [\n 'skill',\n 'agent',\n 'hook',\n 'mcp-config',\n];\n\n/**\n * The AiResource types a `marketplace` may contain: `plugin` only. A real\n * `.claude-plugin/marketplace.json` `plugins` array lists plugins and nothing\n * else (required by the schema Claude Code and Copilot CLI both read).\n */\nexport const MARKETPLACE_MEMBER_TYPES: readonly ResourceType[] = ['plugin'];\n\n/**\n * Whether a container of `parent` type renders a child of `child` type as a\n * member — restricted to what a real Claude/Copilot plugin or marketplace\n * manifest permits (ADR-0010/0015). A `marketplace` contains `plugin` only; a\n * `plugin` contains the component types DevAI Hub models. Any other pairing is\n * silently not rendered. This is a rendering convention, not catalog\n * validation (upstream `allowedKinds` is the broad `[\"AiResource\"]`).\n */\nexport function isRenderableContainment(\n parent: ResourceType,\n child: ResourceType,\n): boolean {\n if (parent === 'marketplace') return MARKETPLACE_MEMBER_TYPES.includes(child);\n if (parent === 'plugin') return PLUGIN_MEMBER_TYPES.includes(child);\n return false;\n}\n\n/** Annotation prefix owned by DevAI Hub. */\nexport const DEVAIHUB_ANNOTATION_PREFIX = 'devaihub.io';\n\n/** Comma-separated compatible-framework tokens (non-skill read path, ADR-0003). */\nexport const ANNOTATION_COMPATIBLE_FRAMEWORKS = `${DEVAIHUB_ANNOTATION_PREFIX}/compatible-frameworks`;\n\n/** Optional free-form help text shown on the detail panel. */\nexport const ANNOTATION_HELP = `${DEVAIHUB_ANNOTATION_PREFIX}/help`;\n\n/** Known framework tokens; unknown tokens pass through as-is (ADR-0003). */\nexport const KNOWN_FRAMEWORKS = [\n 'github-copilot',\n 'claude-code',\n 'cursor',\n 'google-gemini',\n 'opencode',\n 'all',\n] as const;\n\nexport type FrameworkToken = (typeof KNOWN_FRAMEWORKS)[number];\n\nconst FRAMEWORK_ALIASES: Record<string, FrameworkToken> = {\n copilot: 'github-copilot',\n claude: 'claude-code',\n gemini: 'google-gemini',\n};\n\n/**\n * Normalise a framework token: trim, lowercase, resolve aliases\n * (`claude` → `claude-code`). Unknown tokens pass through literally.\n */\nexport function normalizeFramework(token: string): string {\n const t = token.trim().toLowerCase();\n return FRAMEWORK_ALIASES[t] ?? t;\n}\n\n/**\n * Narrow a resource's frameworks to a deployment-level allow-list\n * (`devAiHub.frameworks.allowed`). Omitting the config key (`allowed` is\n * `undefined`) permits every framework; an explicit empty list permits none,\n * so a deployment can suppress framework exposure entirely. Both sides are\n * normalised (aliases resolved) before comparison.\n *\n * The `all` wildcard is expanded to the allow-list itself before filtering, so\n * a resource that declares `all` degrades to \"every permitted host\" rather\n * than disappearing entirely.\n */\nexport function filterAllowedFrameworks(\n frameworks: string[],\n allowed: string[] | undefined,\n): string[] {\n if (allowed === undefined) {\n return frameworks;\n }\n const permitted = new Set(\n allowed.map(normalizeFramework).filter(f => f && f !== 'all'),\n );\n const expanded = frameworks.flatMap(f =>\n normalizeFramework(f) === 'all' ? [...permitted] : [normalizeFramework(f)],\n );\n return Array.from(new Set(expanded)).filter(f => permitted.has(f));\n}\n\n/**\n * The minimal structural shape of an AiResource entity that the read helpers\n * need. A real `@backstage/catalog-model` `Entity` satisfies it, but keeping\n * the shape local means `-common` (and therefore the frontend) never depends\n * on catalog packages (architecture.md).\n */\nexport interface AiResourceEntityLike {\n metadata: {\n annotations?: Record<string, string>;\n };\n spec?: {\n type?: unknown;\n /** Native compatible-frameworks field, honoured regardless of `spec.type`. */\n agents?: unknown;\n [key: string]: unknown;\n };\n}\n\n/**\n * Resolve the compatible frameworks of an AiResource (ADR-0003):\n * 1. a non-empty `spec.agents` → the native field, for any `spec.type`;\n * 2. otherwise → the `devaihub.io/compatible-frameworks` annotation\n * (also the fallback when `spec.agents` is empty/absent);\n * 3. otherwise → `[]`.\n * Tokens are normalised; unknown tokens pass through. `spec.agents` is\n * preferred over the annotation because it lives on the entity itself\n * rather than in an annotation namespace we may retire.\n */\nexport function getFrameworks(entity: AiResourceEntityLike): string[] {\n if (Array.isArray(entity.spec?.agents)) {\n const agents = entity.spec.agents\n .filter((a): a is string => typeof a === 'string')\n .map(normalizeFramework)\n .filter(Boolean);\n if (agents.length > 0) {\n return dedupe(agents);\n }\n }\n\n const raw = entity.metadata.annotations?.[ANNOTATION_COMPATIBLE_FRAMEWORKS];\n if (!raw) {\n return [];\n }\n return dedupe(raw.split(',').map(normalizeFramework).filter(Boolean));\n}\n\nfunction dedupe(tokens: string[]): string[] {\n return Array.from(new Set(tokens));\n}\n\n/**\n * Icon identifiers for the type→card registry. `-common` is imported by the\n * backend, so it stays React-free: the frontend maps these identifiers to\n * actual icon components.\n */\nexport type ResourceTypeIcon =\n | 'tools'\n | 'robot'\n | 'flash'\n | 'plug'\n | 'puzzle'\n | 'store';\n\nexport interface ResourceTypeInfo {\n type: ResourceType;\n /** Singular display label, e.g. \"Skill\" (card type caption). */\n label: string;\n /** Plural display label, e.g. \"Skills\" (stat tiles, filters). */\n pluralLabel: string;\n /** Icon identifier resolved to a component by the frontend. */\n icon: ResourceTypeIcon;\n /**\n * Colour role name; the frontend resolves it to the plugin-owned\n * `--devaihub-type-<role>` custom properties (ADR-0008, NOS palette).\n */\n colorRole: ResourceType;\n}\n\n/**\n * The typed type→card registry (ADR-0003/ADR-0008): producer vocabulary and\n * consumer rendering share this single source, so they cannot drift. Adding\n * a type is one entry here plus one CSS token pair in the frontend.\n */\nexport const RESOURCE_TYPE_REGISTRY: Record<ResourceType, ResourceTypeInfo> = {\n skill: {\n type: 'skill',\n label: 'Skill',\n pluralLabel: 'Skills',\n icon: 'tools',\n colorRole: 'skill',\n },\n agent: {\n type: 'agent',\n label: 'Agent',\n pluralLabel: 'Agents',\n icon: 'robot',\n colorRole: 'agent',\n },\n hook: {\n type: 'hook',\n label: 'Hook',\n pluralLabel: 'Hooks',\n icon: 'flash',\n colorRole: 'hook',\n },\n 'mcp-config': {\n type: 'mcp-config',\n label: 'MCP Config',\n pluralLabel: 'MCP Configs',\n icon: 'plug',\n colorRole: 'mcp-config',\n },\n plugin: {\n type: 'plugin',\n label: 'Plugin',\n pluralLabel: 'Plugins',\n icon: 'puzzle',\n colorRole: 'plugin',\n },\n marketplace: {\n type: 'marketplace',\n label: 'Marketplace',\n pluralLabel: 'Marketplaces',\n icon: 'store',\n colorRole: 'marketplace',\n },\n};\n\n/**\n * The flat contract the backend returns to the frontend. The frontend never\n * sees a raw Backstage `Entity` — only this (architecture.md).\n */\nexport interface ResourceSummary {\n entityRef: string;\n name: string;\n title?: string;\n description?: string;\n tags: string[];\n type: ResourceType;\n lifecycle: string;\n owner?: string;\n sourceLocation?: string;\n frameworks: string[];\n /**\n * True when an active deployment allow-list (`devAiHub.frameworks.allowed`)\n * left this resource with no frameworks — either it removed the ones the\n * author declared, or the allow-list itself is empty. Lets the UI tell\n * \"author declared nothing\" (`frameworks: []`, show neutral install\n * defaults) apart from \"the deployment suppressed them\" (hide generated\n * install paths and launchers; Copy/Download still work).\n */\n frameworksRestricted?: boolean;\n /**\n * The framework set that install-path and launcher generation must be\n * scoped to, when it differs from `frameworks`. Only set for a resource\n * that declared no frameworks (which otherwise means \"every host\") under an\n * active allow-list: it holds the allow-list itself, so a bare resource\n * cannot produce launchers for tools the deployment disallowed. Kept\n * separate from `frameworks` so this inferred set never renders as a\n * compatibility badge the author never claimed.\n */\n installFrameworks?: string[];\n version?: string;\n kind: string;\n /**\n * Entity refs this container declares as its contents — a `marketplace`'s\n * `spec.plugins`, a `plugin`'s `spec.skills`; empty for leaf types. Filtered\n * to the caller's visible set and to the child types the container renders\n * (ADR-0015). The frontend resolves each ref against the summaries it holds.\n */\n children: string[];\n /**\n * Entity refs of the containers that declare this resource — the in-memory\n * inverse of `children`, built over the same caller-visible catalog read\n * (ADR-0015). A resource can belong to several containers.\n */\n parents: string[];\n /** Count of `children` (their declared, caller-visible members). */\n childCount?: number;\n helpText?: string;\n annotations: Record<string, string>;\n}\n\nexport interface ResourceListResponse {\n items: ResourceSummary[];\n}\n\n/**\n * The shape of a resource's body (CONTEXT.md: bodies are type-shaped, not\n * uniformly markdown). Drives detail-panel rendering: markdown is rendered,\n * json is pretty-printed and syntax-highlighted (ADR-0014). `plugin` and\n * `marketplace` bodies are the real Claude Code `plugin.json` /\n * `marketplace.json` manifest — not a hand-authored pointer doc, superseding\n * ADR-0010's markdown-only body for `marketplace`.\n */\nexport type BodyShape = 'markdown' | 'json';\n\nexport function getBodyShape(type: ResourceType): BodyShape {\n return type === 'mcp-config' || type === 'plugin' || type === 'marketplace'\n ? 'json'\n : 'markdown';\n}\n\n/**\n * Whether the detail panel shows a \"Content\" section for this type. `plugin`\n * and `marketplace` resources are containers — their body is the raw manifest\n * JSON and their real value is the relationship graph, not the file — so the\n * Content block is suppressed for them and kept for every other type.\n */\nexport function showsContentSection(type: ResourceType): boolean {\n return type !== 'plugin' && type !== 'marketplace';\n}\n\n/**\n * Whether downloading the body delivers the artifact itself. True for every\n * type: `plugin`/`marketplace` bodies are now the real manifest JSON, so a\n * download delivers that file itself rather than a non-actionable pointer\n * doc (ADR-0014, superseding ADR-0009's amendment and ADR-0010 on this\n * point).\n */\nexport function hasDownloadableArtifact(_type: ResourceType): boolean {\n return true;\n}\n\n/**\n * Whether copying the body to the clipboard is a meaningful install action.\n * True for every type: `marketplace`'s body is now the real manifest JSON,\n * not an instructions doc, so copying it is no longer a misrepresentation\n * (ADR-0014, superseding ADR-0010 on this point).\n */\nexport function hasCopyableBody(_type: ResourceType): boolean {\n return true;\n}\n\n/**\n * How a body reaches its install path.\n *\n * `drop-in` — the body becomes the file (or directory) at `path`, which is\n * the resource's own; writing it touches nothing else.\n *\n * `merge` — `path` is a shared settings file the user already owns, and the\n * body is a fragment to merge into it. The distinction is not cosmetic:\n * following a `merge` target as if it were a `drop-in` overwrites the user's\n * existing configuration, so the UI must never present the two identically.\n */\nexport type InstallMode = 'drop-in' | 'merge';\n\nexport interface ResourceInstallTarget {\n /** Workspace-relative path. */\n path: string;\n mode: InstallMode;\n}\n\n/**\n * The concrete framework tokens a body can be installed into — `all` is a\n * wildcard over these, never a destination itself.\n */\nexport const INSTALLABLE_FRAMEWORKS = [\n 'claude-code',\n 'github-copilot',\n 'google-gemini',\n 'cursor',\n 'opencode',\n] as const;\n\n/**\n * Convention table: (type, framework) → where the body goes and how.\n * A missing entry means the pair has no filesystem convention — `plugin` and\n * `marketplace` bodies are pointers that install through their framework\n * (ADR-0009, ADR-0010), so they carry install commands rather than paths.\n */\nconst INSTALL_PATHS: Record<\n ResourceType,\n Record<string, { mode: InstallMode; path: (name: string) => string }>\n> = {\n // Every host reads a skill as a self-contained directory. Copilot also\n // picks up `.claude/skills`, but each tool's own path is what we recommend;\n // `.agents/skills` is the cross-tool alias Copilot and Gemini both honour,\n // which makes it the right answer for an unrecognised framework.\n skill: {\n 'claude-code': { mode: 'drop-in', path: name => `.claude/skills/${name}/` },\n 'github-copilot': {\n mode: 'drop-in',\n path: name => `.github/skills/${name}/`,\n },\n 'google-gemini': {\n mode: 'drop-in',\n path: name => `.gemini/skills/${name}/`,\n },\n cursor: { mode: 'drop-in', path: name => `.cursor/skills/${name}/` },\n opencode: { mode: 'drop-in', path: name => `.opencode/skills/${name}/` },\n default: { mode: 'drop-in', path: name => `.agents/skills/${name}/` },\n },\n agent: {\n 'claude-code': {\n mode: 'drop-in',\n path: name => `.claude/agents/${name}.md`,\n },\n 'github-copilot': {\n mode: 'drop-in',\n path: name => `.github/agents/${name}.agent.md`,\n },\n 'google-gemini': {\n mode: 'drop-in',\n path: name => `.gemini/agents/${name}.md`,\n },\n cursor: { mode: 'drop-in', path: name => `.cursor/rules/${name}.mdc` },\n opencode: { mode: 'drop-in', path: name => `.opencode/agents/${name}.md` },\n default: { mode: 'drop-in', path: name => `.ai/agents/${name}.md` },\n },\n // All four hosts have a hook system, but only Copilot gives each hook its\n // own file; the rest register hooks inside a shared settings document.\n // OpenCode has no declarative hook config at all — hooks are exclusively\n // JS/TS plugin modules — so it deliberately carries no entry here, the same\n // way it carries no `default`.\n hook: {\n 'claude-code': { mode: 'merge', path: () => `.claude/settings.json` },\n 'github-copilot': {\n mode: 'drop-in',\n path: name => `.github/hooks/${name}.json`,\n },\n 'google-gemini': { mode: 'merge', path: () => `.gemini/settings.json` },\n cursor: { mode: 'merge', path: () => `.cursor/hooks.json` },\n },\n 'mcp-config': {\n 'claude-code': { mode: 'merge', path: () => `.mcp.json` },\n 'github-copilot': { mode: 'merge', path: () => `.vscode/mcp.json` },\n 'google-gemini': { mode: 'merge', path: () => `.gemini/settings.json` },\n cursor: { mode: 'merge', path: () => `.cursor/mcp.json` },\n opencode: { mode: 'merge', path: () => `opencode.json` },\n },\n plugin: {},\n marketplace: {},\n};\n\n/**\n * Where a resource's body installs for one framework, and whether that path\n * is the body's own file or a settings file to merge into. Returns\n * `undefined` when the (type, framework) pair has no filesystem convention.\n */\nexport function getResourceInstallTarget(\n type: ResourceType,\n framework: string,\n name: string,\n): ResourceInstallTarget | undefined {\n const conventions = INSTALL_PATHS[type];\n const entry =\n conventions[normalizeFramework(framework)] ?? conventions.default;\n return entry ? { path: entry.path(name), mode: entry.mode } : undefined;\n}\n\n/**\n * The frameworks to show install paths for. An empty list means the resource\n * declared no compatibility and gets the neutral `default` convention; `all`\n * is a wildcard and expands to every installable host, so it never collapses\n * to a single row — or, for types with no `default`, to no rows at all.\n */\nexport function expandInstallFrameworks(frameworks: string[]): string[] {\n const normalized = dedupe(frameworks.map(normalizeFramework));\n if (normalized.length === 0) {\n return ['default'];\n }\n if (normalized.includes('all')) {\n return [...INSTALLABLE_FRAMEWORKS];\n }\n return normalized;\n}\n\n/*\n * Marketplace journey helpers (ADR-0010). A marketplace installs in two\n * steps — register the catalog with the AI tool, then install plugins from\n * it. Both Claude Code and Copilot CLI read the same\n * `.claude-plugin/marketplace.json` format and address the repo as\n * `owner/repo`; the plugin derives that slug from the mandatory\n * `source-location` (the producer contract requires the body doc to live\n * inside the marketplace repo). No derivation → the UI falls back to the\n * rendered body, which stays canonical.\n */\n\n/** Frameworks with a marketplace-add concept (Cursor/Gemini have none). */\nexport const MARKETPLACE_CAPABLE_FRAMEWORKS = [\n 'claude-code',\n 'github-copilot',\n] as const;\n\n/**\n * Narrow a resource's declared frameworks to those a given journey can\n * actually launch. A deep link is a claim about compatibility: offering\n * \"Install in Claude\" for a resource that never declared `claude-code` tells\n * the user something untrue about the resource.\n *\n * `all` and an empty list both mean \"unrestricted\" and expand to every\n * capable host. Anything else is intersected, so a declared framework with no\n * handler (Gemini) — or an unknown token — yields no links rather than\n * silently widening to every host.\n */\nexport function resolveCapableFrameworks(\n declared: string[],\n capable: readonly string[],\n): string[] {\n const normalized = dedupe(declared.map(normalizeFramework));\n if (normalized.length === 0 || normalized.includes('all')) {\n return [...capable];\n }\n return normalized.filter(f => capable.includes(f));\n}\n\n/**\n * Derive the `owner/repo` slug from a marketplace's `source-location`.\n * GitHub URLs only — other hosts return `undefined` (body-only fallback).\n */\nexport function getMarketplaceRepoSlug(\n sourceLocation: string | undefined,\n): string | undefined {\n if (!sourceLocation) {\n return undefined;\n }\n let url: URL;\n try {\n url = new URL(sourceLocation.replace(/^url:/, ''));\n } catch {\n return undefined;\n }\n if (url.hostname !== 'github.com') {\n return undefined;\n }\n const [owner, repo] = url.pathname.split('/').filter(Boolean);\n if (!owner || !repo) {\n return undefined;\n }\n return `${owner}/${repo.replace(/\\.git$/, '')}`;\n}\n\n/**\n * A one-click launcher for an add command: a custom-scheme URL that opens\n * the host app with the command pre-filled in the prompt box. The host\n * never auto-executes it — the user reviews and presses Enter — and an\n * unregistered scheme is a harmless no-op, so these complement the copy\n * button rather than replace it.\n */\nexport interface ResourceDeepLink {\n /** Host application name; render as \"Add in <label>\" / \"Install in <label>\". */\n label: string;\n href: string;\n}\n\nexport interface MarketplaceAddCommand {\n framework: string;\n command: string;\n deepLinks: ResourceDeepLink[];\n}\n\n/**\n * The copyable marketplace-add command per compatible framework. `all`,\n * unknown-only, or empty framework lists expand to every capable framework;\n * frameworks without a marketplace concept produce no row.\n *\n * Claude Code carries a single deep link on the CLI's documented\n * `claude-cli://open?q=` handler, which opens a Claude Code terminal\n * session with the command pre-filled regardless of the user's editor.\n *\n * Copilot's CLI still has no URI scheme, but Copilot's *other* surface does:\n * VS Code 1.113 ships `vscode://chat-plugin/add-marketplace?ref=`, which\n * accepts a plain or base64 `owner/repo` and always shows a confirmation\n * dialog before registering the marketplace (it also dedupes against the\n * user's existing entries). So the Copilot row keeps its terminal command for\n * CLI users *and* gains editor launchers, mirroring how `mcp-config` already\n * maps `github-copilot` onto the VS Code stable/Insiders pair.\n */\nexport function getMarketplaceAddCommands(\n frameworks: string[],\n repoSlug: string,\n): MarketplaceAddCommand[] {\n const capable = resolveCapableFrameworks(\n frameworks,\n MARKETPLACE_CAPABLE_FRAMEWORKS,\n );\n const commands: MarketplaceAddCommand[] = [];\n for (const framework of capable) {\n if (framework === 'claude-code') {\n const command = `/plugin marketplace add ${repoSlug}`;\n commands.push({\n framework,\n command,\n deepLinks: [\n {\n label: 'Claude',\n href: `claude-cli://open?q=${encodeURIComponent(command)}`,\n },\n ],\n });\n } else if (framework === 'github-copilot') {\n const ref = encodeURIComponent(repoSlug);\n commands.push({\n framework,\n command: `copilot plugin marketplace add ${repoSlug}`,\n deepLinks: [\n {\n label: 'VS Code',\n href: `vscode://chat-plugin/add-marketplace?ref=${ref}`,\n },\n {\n label: 'VS Code Insiders',\n href: `vscode-insiders://chat-plugin/add-marketplace?ref=${ref}`,\n },\n ],\n });\n }\n }\n return commands;\n}\n\n/** The raw-file URL for a GitHub blob `source-location`; else `undefined`. */\nfunction getRawGithubFileUrl(\n sourceLocation: string | undefined,\n): string | undefined {\n if (!sourceLocation) {\n return undefined;\n }\n let url: URL;\n try {\n url = new URL(sourceLocation.replace(/^url:/, ''));\n } catch {\n return undefined;\n }\n if (url.hostname !== 'github.com') {\n return undefined;\n }\n const [owner, repo, marker, ref, ...path] = url.pathname\n .split('/')\n .filter(Boolean);\n if (!owner || !repo || marker !== 'blob' || !ref || path.length === 0) {\n return undefined;\n }\n return `https://raw.githubusercontent.com/${owner}/${repo}/${ref}/${path.join(\n '/',\n )}`;\n}\n\n/**\n * A launcher that opens an agent with an install prompt pre-filled. Neither\n * host auto-executes: the user reads the prompt and presses Enter. Claude Code\n * and Cursor are the two tools exposing a generic prompt URI — Copilot's\n * editor has purpose-built routes but no prompt handler, and Gemini has\n * neither (its `gemini.google.com/app?prompt=` link drives the web app, which\n * cannot write to a local workspace).\n *\n * Cursor truncates a deeplink at the first raw `&`, so the prompt must be\n * percent-encoded — `encodeURIComponent` handles that. Cursor also caps the\n * URL at ~8000 characters; these prompts are a URL plus a path, far under it.\n */\nfunction claudePromptLink(prompt: string): ResourceDeepLink {\n return {\n label: 'Claude',\n href: `claude-cli://open?q=${encodeURIComponent(prompt)}`,\n };\n}\n\nfunction cursorPromptLink(prompt: string): ResourceDeepLink {\n return {\n label: 'Cursor',\n href: `cursor://anysphere.cursor-deeplink/prompt?text=${encodeURIComponent(\n prompt,\n )}`,\n };\n}\n\n/**\n * Frameworks with a one-click agent-install handler (Gemini has none).\n * OpenCode's Desktop app does register a real `opencode://` scheme, but every\n * route (`open-project`, `new-session`) requires an absolute local\n * `directory` param a web page cannot supply, so it's excluded here too.\n */\nexport const AGENT_LINK_CAPABLE_FRAMEWORKS = [\n 'claude-code',\n 'github-copilot',\n 'cursor',\n] as const;\n\n/** Hosts reachable by a generic prompt URI — the only route for skill/hook. */\nexport const PROMPT_LINK_CAPABLE_FRAMEWORKS = [\n 'claude-code',\n 'cursor',\n] as const;\n\n/**\n * The plain http(s) URL behind a `source-location`. Unlike\n * `getRawGithubFileUrl` this accepts **directory (`tree`) URLs**, which is what\n * a multi-file `skill` actually carries — a raw-file URL would resolve to\n * `undefined` for exactly the type that most needs a launcher.\n */\nfunction getSourceUrl(sourceLocation: string | undefined): string | undefined {\n if (!sourceLocation) {\n return undefined;\n }\n try {\n const url = new URL(sourceLocation.replace(/^url:/, ''));\n return url.protocol === 'http:' || url.protocol === 'https:'\n ? url.toString()\n : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * One-click launchers for the types with no purpose-built install route —\n * `skill` and `hook`. Both ride the generic prompt handlers, so the prompt\n * names the *host's own* install path and respects its install mode: a `merge`\n * target is asked to be merged into, never overwritten, so a launcher can\n * never cost the user their existing settings.\n *\n * Returns `[]` when the source URL cannot be derived, or for hosts with no\n * prompt route (Copilot, Gemini) — the path list and copy/download remain.\n */\nexport function getPromptInstallLinks(\n type: ResourceType,\n sourceLocation: string | undefined,\n name: string,\n frameworks: string[] = [],\n): ResourceDeepLink[] {\n return getInstallSteps(type, sourceLocation, name, frameworks)\n .map(step => step.link)\n .filter((link): link is ResourceDeepLink => !!link);\n}\n\n/**\n * Everything a single host needs to install a resource: where the body goes,\n * the prompt that puts it there, and a launcher when the host has a URI to\n * launch.\n *\n * `link` is absent for hosts with no prompt route — Copilot and Gemini. That\n * absence is why the step carries `prompt` as text: a host without a URI is\n * not a host without an install path, and the same instruction that a launcher\n * would pre-fill can be pasted into that agent by hand. Every declared\n * framework therefore gets something actionable, not a bare path.\n */\nexport interface ResourceInstallStep {\n framework: string;\n target: ResourceInstallTarget;\n /** The install instruction, ready to run in that host's agent. */\n prompt: string;\n /** One-click launcher, where the host exposes a generic prompt URI. */\n link?: ResourceDeepLink;\n}\n\nexport function getInstallSteps(\n type: ResourceType,\n sourceLocation: string | undefined,\n name: string,\n frameworks: string[] = [],\n): ResourceInstallStep[] {\n const sourceUrl = getSourceUrl(sourceLocation);\n if (!sourceUrl) {\n return [];\n }\n const label = RESOURCE_TYPE_REGISTRY[type].label.toLowerCase();\n const steps: ResourceInstallStep[] = [];\n for (const framework of expandInstallFrameworks(frameworks)) {\n const target = getResourceInstallTarget(type, framework, name);\n if (!target) {\n continue;\n }\n const prompt =\n target.mode === 'merge'\n ? `Install the \"${name}\" ${label}: fetch ${sourceUrl} and merge it into ${target.path}, keeping my existing settings intact.`\n : `Install the \"${name}\" ${label}: fetch ${sourceUrl} and save it to ${target.path}.`;\n let link: ResourceDeepLink | undefined;\n if (framework === 'claude-code') {\n link = claudePromptLink(prompt);\n } else if (framework === 'cursor') {\n link = cursorPromptLink(prompt);\n }\n steps.push({ framework, target, prompt, link });\n }\n return steps;\n}\n\n/** Frameworks with a one-click MCP-install handler (Gemini has none). */\nexport const MCP_LINK_CAPABLE_FRAMEWORKS = [\n 'claude-code',\n 'github-copilot',\n 'cursor',\n] as const;\n\n/**\n * One-click install links for an `agent` resource, restricted to the\n * resource's own compatible frameworks. VS Code stable and Insiders use the\n * native `chat-agent/install?url=` handler (the mechanism behind\n * awesome-copilot's Install buttons) and are Copilot's hosts, so they follow\n * `github-copilot`: VS Code downloads the file at `url` and asks the user\n * where to save it. Claude Code uses the `claude-cli://open?q=` handler with\n * an install prompt pre-filled to the convention path — reviewed and sent by\n * the user, never auto-executed. All derive from the GitHub blob URL in\n * `source-location`; anything else returns `[]` (copy/download fallback).\n */\nexport function getAgentInstallLinks(\n sourceLocation: string | undefined,\n name: string,\n frameworks: string[] = [],\n): ResourceDeepLink[] {\n const rawUrl = getRawGithubFileUrl(sourceLocation);\n if (!rawUrl) {\n return [];\n }\n const capable = resolveCapableFrameworks(\n frameworks,\n AGENT_LINK_CAPABLE_FRAMEWORKS,\n );\n const encodedRawUrl = encodeURIComponent(rawUrl);\n const installPrompt = (framework: string) => {\n const target = getResourceInstallTarget('agent', framework, name);\n return `Install this agent: fetch ${rawUrl} and save it to ${target?.path}`;\n };\n const links: ResourceDeepLink[] = [];\n for (const framework of capable) {\n if (framework === 'claude-code') {\n links.push(claudePromptLink(installPrompt('claude-code')));\n } else if (framework === 'cursor') {\n links.push(cursorPromptLink(installPrompt('cursor')));\n } else if (framework === 'github-copilot') {\n links.push({\n label: 'VS Code',\n href: `vscode:chat-agent/install?url=${encodedRawUrl}`,\n });\n links.push({\n label: 'VS Code Insiders',\n href: `vscode-insiders:chat-agent/install?url=${encodedRawUrl}`,\n });\n }\n }\n return links;\n}\n\n/**\n * One-click install links for an `mcp-config` resource, derived from its body —\n * the canonical `.mcp.json` snippet (spec §3.4). VS Code carries a native\n * `vscode:mcp/install?{json}` handler (Insiders scheme twin), Cursor a\n * documented `cursor://anysphere.cursor-deeplink/mcp/install` one, and\n * Claude Code gets a `claude-cli://open?q=` prompt around\n * `claude mcp add-json` — pre-filled, reviewed, never auto-executed.\n * Hosts follow the resource's own compatible frameworks: `all`/empty expand\n * to every capable host, anything else is intersected, so an mcp-config\n * declaring only Gemini (no handler) gets no links rather than every host's.\n * A missing, unparseable, or multi-server body returns `[]` (copy fallback) —\n * the body stays canonical, links are conveniences derived from it.\n */\nexport function getMcpInstallLinks(\n frameworks: string[],\n resourceName: string,\n bodyContent: string | undefined,\n): ResourceDeepLink[] {\n if (!bodyContent) {\n return [];\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(bodyContent);\n } catch {\n return [];\n }\n if (typeof parsed !== 'object' || parsed === null) {\n return [];\n }\n\n let serverName = resourceName;\n let config: Record<string, unknown>;\n const servers = (parsed as { mcpServers?: unknown }).mcpServers;\n if (servers !== undefined) {\n if (typeof servers !== 'object' || servers === null) {\n return [];\n }\n const entries = Object.entries(servers as Record<string, unknown>);\n if (\n entries.length !== 1 ||\n typeof entries[0][1] !== 'object' ||\n entries[0][1] === null\n ) {\n return [];\n }\n serverName = entries[0][0];\n config = entries[0][1] as Record<string, unknown>;\n } else if ('command' in parsed || 'url' in parsed) {\n config = parsed as Record<string, unknown>;\n } else {\n return [];\n }\n\n const capable = resolveCapableFrameworks(\n frameworks,\n MCP_LINK_CAPABLE_FRAMEWORKS,\n );\n\n const configJson = JSON.stringify(config);\n const links: ResourceDeepLink[] = [];\n for (const framework of capable) {\n if (framework === 'claude-code') {\n const prompt = encodeURIComponent(\n `Install this MCP config by running: claude mcp add-json ${serverName} '${configJson}'`,\n );\n links.push({ label: 'Claude', href: `claude-cli://open?q=${prompt}` });\n } else if (framework === 'github-copilot') {\n const vsConfig = encodeURIComponent(\n JSON.stringify({ name: serverName, ...config }),\n );\n links.push({ label: 'VS Code', href: `vscode:mcp/install?${vsConfig}` });\n links.push({\n label: 'VS Code Insiders',\n href: `vscode-insiders:mcp/install?${vsConfig}`,\n });\n } else if (framework === 'cursor') {\n try {\n links.push({\n label: 'Cursor',\n href: `cursor://anysphere.cursor-deeplink/mcp/install?name=${encodeURIComponent(\n serverName,\n )}&config=${btoa(configJson)}`,\n });\n } catch {\n // btoa rejects non-Latin1 config content — skip the Cursor link.\n }\n }\n }\n return links;\n}\n\n/**\n * Step two of the journey: how to install a plugin from the marketplace.\n * `marketplaceName` is the entity name, which the producer contract requires\n * to equal the `name` in `marketplace.json`.\n */\nexport function getMarketplaceInstallTemplate(marketplaceName: string): string {\n return `/plugin install <plugin>@${marketplaceName}`;\n}\n\n/**\n * The `.claude/settings.json` snippet a team commits so collaborators are\n * prompted to install the marketplace automatically (Claude Code).\n */\nexport function getMarketplaceTeamSnippet(\n marketplaceName: string,\n repoSlug: string,\n): string {\n return JSON.stringify(\n {\n extraKnownMarketplaces: {\n [marketplaceName]: { source: { source: 'github', repo: repoSlug } },\n },\n },\n null,\n 2,\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"resources.cjs.js","sources":["../src/resources.ts"],"sourcesContent":["/**\n * The v2 read contract: AiResource vocabulary, the flat ResourceSummary\n * returned by the backend, and the shared framework resolver (ADR-0003).\n *\n * The legacy asset-model types in `types.ts` coexist with this module until\n * the legacy silo is deleted (slice 8, issue #34).\n */\n\n/** The six canonical `spec.type` values of an AiResource (ADR-0003, ADR-0010). */\nexport const RESOURCE_TYPES = [\n 'skill',\n 'agent',\n 'hook',\n 'mcp-config',\n 'plugin',\n 'marketplace',\n] as const;\n\nexport type ResourceType = (typeof RESOURCE_TYPES)[number];\n\nexport function isResourceType(value: unknown): value is ResourceType {\n return (\n typeof value === 'string' &&\n (RESOURCE_TYPES as readonly string[]).includes(value)\n );\n}\n\n/**\n * The AiResource types a `plugin` may contain — restricted to the component\n * kinds a real Claude Code / GitHub Copilot plugin manifest allows: `skills`,\n * `agents`, `hooks` and `mcpServers` (schemastore `claude-code-plugin` /\n * `claude-code-marketplace.json`). A plugin's other manifest components\n * (`commands`, `lspServers`, `outputStyles`, `themes`, `channels`, `monitors`)\n * have no AiResource type, so they are never members here; other plugins are\n * `dependencies`, not containment.\n */\nexport const PLUGIN_MEMBER_TYPES: readonly ResourceType[] = [\n 'skill',\n 'agent',\n 'hook',\n 'mcp-config',\n];\n\n/**\n * The AiResource types a `marketplace` may contain: `plugin` only. A real\n * `.claude-plugin/marketplace.json` `plugins` array lists plugins and nothing\n * else (required by the schema Claude Code and Copilot CLI both read).\n */\nexport const MARKETPLACE_MEMBER_TYPES: readonly ResourceType[] = ['plugin'];\n\n/**\n * Whether a container of `parent` type renders a child of `child` type as a\n * member — restricted to what a real Claude/Copilot plugin or marketplace\n * manifest permits (ADR-0010/0015). A `marketplace` contains `plugin` only; a\n * `plugin` contains the component types DevAI Hub models. Any other pairing is\n * silently not rendered. This is a rendering convention, not catalog\n * validation (upstream `allowedKinds` is the broad `[\"AiResource\"]`).\n */\nexport function isRenderableContainment(\n parent: ResourceType,\n child: ResourceType,\n): boolean {\n if (parent === 'marketplace') return MARKETPLACE_MEMBER_TYPES.includes(child);\n if (parent === 'plugin') return PLUGIN_MEMBER_TYPES.includes(child);\n return false;\n}\n\n/** Annotation prefix owned by DevAI Hub. */\nexport const DEVAIHUB_ANNOTATION_PREFIX = 'devaihub.io';\n\n/** Comma-separated compatible-framework tokens (non-skill read path, ADR-0003). */\nexport const ANNOTATION_COMPATIBLE_FRAMEWORKS = `${DEVAIHUB_ANNOTATION_PREFIX}/compatible-frameworks`;\n\n/** Optional free-form help text shown on the detail panel. */\nexport const ANNOTATION_HELP = `${DEVAIHUB_ANNOTATION_PREFIX}/help`;\n\n/** Known framework tokens; unknown tokens pass through as-is (ADR-0003). */\nexport const KNOWN_FRAMEWORKS = [\n 'github-copilot',\n 'claude-code',\n 'cursor',\n 'google-gemini',\n 'opencode',\n 'all',\n] as const;\n\nexport type FrameworkToken = (typeof KNOWN_FRAMEWORKS)[number];\n\nconst FRAMEWORK_ALIASES: Record<string, FrameworkToken> = {\n copilot: 'github-copilot',\n claude: 'claude-code',\n gemini: 'google-gemini',\n};\n\n/**\n * Normalise a framework token: trim, lowercase, resolve aliases\n * (`claude` → `claude-code`). Unknown tokens pass through literally.\n */\nexport function normalizeFramework(token: string): string {\n const t = token.trim().toLowerCase();\n return FRAMEWORK_ALIASES[t] ?? t;\n}\n\n/**\n * Narrow a resource's frameworks to a deployment-level allow-list\n * (`devAiHub.frameworks.allowed`). Omitting the config key (`allowed` is\n * `undefined`) permits every framework; an explicit empty list permits none,\n * so a deployment can suppress framework exposure entirely. Both sides are\n * normalised (aliases resolved) before comparison.\n *\n * The `all` wildcard is expanded to the allow-list itself before filtering, so\n * a resource that declares `all` degrades to \"every permitted host\" rather\n * than disappearing entirely.\n */\nexport function filterAllowedFrameworks(\n frameworks: string[],\n allowed: string[] | undefined,\n): string[] {\n if (allowed === undefined) {\n return frameworks;\n }\n const permitted = new Set(\n allowed.map(normalizeFramework).filter(f => f && f !== 'all'),\n );\n const expanded = frameworks.flatMap(f =>\n normalizeFramework(f) === 'all' ? [...permitted] : [normalizeFramework(f)],\n );\n return Array.from(new Set(expanded)).filter(f => permitted.has(f));\n}\n\n/**\n * The minimal structural shape of an AiResource entity that the read helpers\n * need. A real `@backstage/catalog-model` `Entity` satisfies it, but keeping\n * the shape local means `-common` (and therefore the frontend) never depends\n * on catalog packages (architecture.md).\n */\nexport interface AiResourceEntityLike {\n metadata: {\n annotations?: Record<string, string>;\n };\n spec?: {\n type?: unknown;\n /** Native compatible-frameworks field, honoured regardless of `spec.type`. */\n agents?: unknown;\n [key: string]: unknown;\n };\n}\n\n/**\n * Resolve the compatible frameworks of an AiResource (ADR-0003):\n * 1. a non-empty `spec.agents` → the native field, for any `spec.type`;\n * 2. otherwise → the `devaihub.io/compatible-frameworks` annotation\n * (also the fallback when `spec.agents` is empty/absent);\n * 3. otherwise → `[]`.\n * Tokens are normalised; unknown tokens pass through. `spec.agents` is\n * preferred over the annotation because it lives on the entity itself\n * rather than in an annotation namespace we may retire.\n */\nexport function getFrameworks(entity: AiResourceEntityLike): string[] {\n if (Array.isArray(entity.spec?.agents)) {\n const agents = entity.spec.agents\n .filter((a): a is string => typeof a === 'string')\n .map(normalizeFramework)\n .filter(Boolean);\n if (agents.length > 0) {\n return dedupe(agents);\n }\n }\n\n const raw = entity.metadata.annotations?.[ANNOTATION_COMPATIBLE_FRAMEWORKS];\n if (!raw) {\n return [];\n }\n return dedupe(raw.split(',').map(normalizeFramework).filter(Boolean));\n}\n\nfunction dedupe(tokens: string[]): string[] {\n return Array.from(new Set(tokens));\n}\n\n/**\n * Icon identifiers for the type→card registry. `-common` is imported by the\n * backend, so it stays React-free: the frontend maps these identifiers to\n * actual icon components.\n */\nexport type ResourceTypeIcon =\n | 'tools'\n | 'robot'\n | 'flash'\n | 'plug'\n | 'puzzle'\n | 'store';\n\nexport interface ResourceTypeInfo {\n type: ResourceType;\n /** Singular display label, e.g. \"Skill\" (card type caption). */\n label: string;\n /** Plural display label, e.g. \"Skills\" (stat tiles, filters). */\n pluralLabel: string;\n /** Icon identifier resolved to a component by the frontend. */\n icon: ResourceTypeIcon;\n /**\n * Colour role name; the frontend resolves it to the plugin-owned\n * `--devaihub-type-<role>` custom properties (ADR-0008, NOS palette).\n */\n colorRole: ResourceType;\n}\n\n/**\n * The typed type→card registry (ADR-0003/ADR-0008): producer vocabulary and\n * consumer rendering share this single source, so they cannot drift. Adding\n * a type is one entry here plus one CSS token pair in the frontend.\n */\nexport const RESOURCE_TYPE_REGISTRY: Record<ResourceType, ResourceTypeInfo> = {\n skill: {\n type: 'skill',\n label: 'Skill',\n pluralLabel: 'Skills',\n icon: 'tools',\n colorRole: 'skill',\n },\n agent: {\n type: 'agent',\n label: 'Agent',\n pluralLabel: 'Agents',\n icon: 'robot',\n colorRole: 'agent',\n },\n hook: {\n type: 'hook',\n label: 'Hook',\n pluralLabel: 'Hooks',\n icon: 'flash',\n colorRole: 'hook',\n },\n 'mcp-config': {\n type: 'mcp-config',\n label: 'MCP Config',\n pluralLabel: 'MCP Configs',\n icon: 'plug',\n colorRole: 'mcp-config',\n },\n plugin: {\n type: 'plugin',\n label: 'Plugin',\n pluralLabel: 'Plugins',\n icon: 'puzzle',\n colorRole: 'plugin',\n },\n marketplace: {\n type: 'marketplace',\n label: 'Marketplace',\n pluralLabel: 'Marketplaces',\n icon: 'store',\n colorRole: 'marketplace',\n },\n};\n\n/**\n * The flat contract the backend returns to the frontend. The frontend never\n * sees a raw Backstage `Entity` — only this (architecture.md).\n */\nexport interface ResourceSummary {\n entityRef: string;\n name: string;\n title?: string;\n description?: string;\n tags: string[];\n type: ResourceType;\n lifecycle: string;\n owner?: string;\n sourceLocation?: string;\n frameworks: string[];\n /**\n * True when an active deployment allow-list (`devAiHub.frameworks.allowed`)\n * left this resource with no frameworks — either it removed the ones the\n * author declared, or the allow-list itself is empty. Lets the UI tell\n * \"author declared nothing\" (`frameworks: []`, show neutral install\n * defaults) apart from \"the deployment suppressed them\" (hide generated\n * install paths and launchers; Copy/Download still work).\n */\n frameworksRestricted?: boolean;\n /**\n * The framework set that install-path and launcher generation must be\n * scoped to, when it differs from `frameworks`. Only set for a resource\n * that declared no frameworks (which otherwise means \"every host\") under an\n * active allow-list: it holds the allow-list itself, so a bare resource\n * cannot produce launchers for tools the deployment disallowed. Kept\n * separate from `frameworks` so this inferred set never renders as a\n * compatibility badge the author never claimed.\n */\n installFrameworks?: string[];\n version?: string;\n kind: string;\n /**\n * Entity refs this container declares as its contents — a `marketplace`'s\n * `spec.plugins`, a `plugin`'s `spec.skills`; empty for leaf types. Filtered\n * to the caller's visible set and to the child types the container renders\n * (ADR-0015). The frontend resolves each ref against the summaries it holds.\n */\n children: string[];\n /**\n * Entity refs of the containers that declare this resource — the in-memory\n * inverse of `children`, built over the same caller-visible catalog read\n * (ADR-0015). A resource can belong to several containers.\n */\n parents: string[];\n /** Count of `children` (their declared, caller-visible members). */\n childCount?: number;\n helpText?: string;\n annotations: Record<string, string>;\n}\n\nexport interface ResourceListResponse {\n items: ResourceSummary[];\n}\n\n/**\n * The shape of a resource's body (CONTEXT.md: bodies are type-shaped, not\n * uniformly markdown). Drives detail-panel rendering: markdown is rendered,\n * json is pretty-printed and syntax-highlighted (ADR-0014). `plugin` and\n * `marketplace` bodies are the real Claude Code `plugin.json` /\n * `marketplace.json` manifest — not a hand-authored pointer doc, superseding\n * ADR-0010's markdown-only body for `marketplace`.\n */\nexport type BodyShape = 'markdown' | 'json';\n\nexport function getBodyShape(type: ResourceType): BodyShape {\n return type === 'mcp-config' || type === 'plugin' || type === 'marketplace'\n ? 'json'\n : 'markdown';\n}\n\n/**\n * Whether the detail panel shows a \"Content\" section for this type.\n *\n * Suppressed for exactly the JSON-bodied types (`getBodyShape` === 'json'):\n * `plugin` and `marketplace` are containers whose value is the relationship\n * graph rather than the manifest, and an `mcp-config`'s body is a settings\n * fragment to merge — in all three the raw JSON buries the panel and is\n * better reached through Copy, Download or the install dialog, which is\n * where it is actionable. The markdown types keep their rendered body.\n */\nexport function showsContentSection(type: ResourceType): boolean {\n return getBodyShape(type) !== 'json';\n}\n\n/**\n * Whether downloading the body delivers the artifact itself. True for every\n * type: `plugin`/`marketplace` bodies are now the real manifest JSON, so a\n * download delivers that file itself rather than a non-actionable pointer\n * doc (ADR-0014, superseding ADR-0009's amendment and ADR-0010 on this\n * point).\n */\nexport function hasDownloadableArtifact(_type: ResourceType): boolean {\n return true;\n}\n\n/**\n * Whether copying the body to the clipboard is a meaningful install action.\n * True for every type: `marketplace`'s body is now the real manifest JSON,\n * not an instructions doc, so copying it is no longer a misrepresentation\n * (ADR-0014, superseding ADR-0010 on this point).\n */\nexport function hasCopyableBody(_type: ResourceType): boolean {\n return true;\n}\n\n/**\n * How a body reaches its install path.\n *\n * `drop-in` — the body becomes the file (or directory) at `path`, which is\n * the resource's own; writing it touches nothing else.\n *\n * `merge` — `path` is a shared settings file the user already owns, and the\n * body is a fragment to merge into it. The distinction is not cosmetic:\n * following a `merge` target as if it were a `drop-in` overwrites the user's\n * existing configuration, so the UI must never present the two identically.\n */\nexport type InstallMode = 'drop-in' | 'merge';\n\nexport interface ResourceInstallTarget {\n /** Workspace-relative path. */\n path: string;\n mode: InstallMode;\n}\n\n/**\n * The concrete framework tokens a body can be installed into — `all` is a\n * wildcard over these, never a destination itself.\n */\nexport const INSTALLABLE_FRAMEWORKS = [\n 'claude-code',\n 'github-copilot',\n 'google-gemini',\n 'cursor',\n 'opencode',\n] as const;\n\n/**\n * Convention table: (type, framework) → where the body goes and how.\n * A missing entry means the pair has no filesystem convention — `plugin` and\n * `marketplace` bodies are pointers that install through their framework\n * (ADR-0009, ADR-0010), so they carry install commands rather than paths.\n */\nconst INSTALL_PATHS: Record<\n ResourceType,\n Record<string, { mode: InstallMode; path: (name: string) => string }>\n> = {\n // Every host reads a skill as a self-contained directory. Copilot also\n // picks up `.claude/skills`, but each tool's own path is what we recommend;\n // `.agents/skills` is the cross-tool alias Copilot and Gemini both honour,\n // which makes it the right answer for an unrecognised framework.\n skill: {\n 'claude-code': { mode: 'drop-in', path: name => `.claude/skills/${name}/` },\n 'github-copilot': {\n mode: 'drop-in',\n path: name => `.github/skills/${name}/`,\n },\n 'google-gemini': {\n mode: 'drop-in',\n path: name => `.gemini/skills/${name}/`,\n },\n cursor: { mode: 'drop-in', path: name => `.cursor/skills/${name}/` },\n opencode: { mode: 'drop-in', path: name => `.opencode/skills/${name}/` },\n default: { mode: 'drop-in', path: name => `.agents/skills/${name}/` },\n },\n agent: {\n 'claude-code': {\n mode: 'drop-in',\n path: name => `.claude/agents/${name}.md`,\n },\n 'github-copilot': {\n mode: 'drop-in',\n path: name => `.github/agents/${name}.agent.md`,\n },\n 'google-gemini': {\n mode: 'drop-in',\n path: name => `.gemini/agents/${name}.md`,\n },\n cursor: { mode: 'drop-in', path: name => `.cursor/rules/${name}.mdc` },\n opencode: { mode: 'drop-in', path: name => `.opencode/agents/${name}.md` },\n default: { mode: 'drop-in', path: name => `.ai/agents/${name}.md` },\n },\n // All four hosts have a hook system, but only Copilot gives each hook its\n // own file; the rest register hooks inside a shared settings document.\n // OpenCode has no declarative hook config at all — hooks are exclusively\n // JS/TS plugin modules — so it deliberately carries no entry here, the same\n // way it carries no `default`.\n hook: {\n 'claude-code': { mode: 'merge', path: () => `.claude/settings.json` },\n 'github-copilot': {\n mode: 'drop-in',\n path: name => `.github/hooks/${name}.json`,\n },\n 'google-gemini': { mode: 'merge', path: () => `.gemini/settings.json` },\n cursor: { mode: 'merge', path: () => `.cursor/hooks.json` },\n },\n 'mcp-config': {\n 'claude-code': { mode: 'merge', path: () => `.mcp.json` },\n 'github-copilot': { mode: 'merge', path: () => `.vscode/mcp.json` },\n 'google-gemini': { mode: 'merge', path: () => `.gemini/settings.json` },\n cursor: { mode: 'merge', path: () => `.cursor/mcp.json` },\n opencode: { mode: 'merge', path: () => `opencode.json` },\n },\n plugin: {},\n marketplace: {},\n};\n\n/**\n * Where a resource's body installs for one framework, and whether that path\n * is the body's own file or a settings file to merge into. Returns\n * `undefined` when the (type, framework) pair has no filesystem convention.\n */\nexport function getResourceInstallTarget(\n type: ResourceType,\n framework: string,\n name: string,\n): ResourceInstallTarget | undefined {\n const conventions = INSTALL_PATHS[type];\n const entry =\n conventions[normalizeFramework(framework)] ?? conventions.default;\n return entry ? { path: entry.path(name), mode: entry.mode } : undefined;\n}\n\n/**\n * The frameworks to show install paths for. An empty list means the resource\n * declared no compatibility and gets the neutral `default` convention; `all`\n * is a wildcard and expands to every installable host, so it never collapses\n * to a single row — or, for types with no `default`, to no rows at all.\n */\nexport function expandInstallFrameworks(frameworks: string[]): string[] {\n const normalized = dedupe(frameworks.map(normalizeFramework));\n if (normalized.length === 0) {\n return ['default'];\n }\n if (normalized.includes('all')) {\n return [...INSTALLABLE_FRAMEWORKS];\n }\n return normalized;\n}\n\n/*\n * Marketplace journey helpers (ADR-0010). A marketplace installs in two\n * steps — register the catalog with the AI tool, then install plugins from\n * it. Both Claude Code and Copilot CLI read the same\n * `.claude-plugin/marketplace.json` format and address the repo as\n * `owner/repo`; the plugin derives that slug from the mandatory\n * `source-location` (the producer contract requires the body doc to live\n * inside the marketplace repo). No derivation → the UI falls back to the\n * rendered body, which stays canonical.\n */\n\n/** Frameworks with a marketplace-add concept (Cursor/Gemini have none). */\nexport const MARKETPLACE_CAPABLE_FRAMEWORKS = [\n 'claude-code',\n 'github-copilot',\n] as const;\n\n/**\n * Narrow a resource's declared frameworks to those a given journey can\n * actually launch. A deep link is a claim about compatibility: offering\n * \"Install in Claude\" for a resource that never declared `claude-code` tells\n * the user something untrue about the resource.\n *\n * `all` and an empty list both mean \"unrestricted\" and expand to every\n * capable host. Anything else is intersected, so a declared framework with no\n * handler (Gemini) — or an unknown token — yields no links rather than\n * silently widening to every host.\n */\nexport function resolveCapableFrameworks(\n declared: string[],\n capable: readonly string[],\n): string[] {\n const normalized = dedupe(declared.map(normalizeFramework));\n if (normalized.length === 0 || normalized.includes('all')) {\n return [...capable];\n }\n return normalized.filter(f => capable.includes(f));\n}\n\n/**\n * Derive the `owner/repo` slug from a marketplace's `source-location`.\n * GitHub URLs only — other hosts return `undefined` (body-only fallback).\n */\nexport function getMarketplaceRepoSlug(\n sourceLocation: string | undefined,\n): string | undefined {\n if (!sourceLocation) {\n return undefined;\n }\n let url: URL;\n try {\n url = new URL(sourceLocation.replace(/^url:/, ''));\n } catch {\n return undefined;\n }\n if (url.hostname !== 'github.com') {\n return undefined;\n }\n const [owner, repo] = url.pathname.split('/').filter(Boolean);\n if (!owner || !repo) {\n return undefined;\n }\n return `${owner}/${repo.replace(/\\.git$/, '')}`;\n}\n\n/**\n * A one-click launcher for an add command: a custom-scheme URL that opens\n * the host app with the command pre-filled in the prompt box. The host\n * never auto-executes it — the user reviews and presses Enter — and an\n * unregistered scheme is a harmless no-op, so these complement the copy\n * button rather than replace it.\n */\nexport interface ResourceDeepLink {\n /** Host application name; render as \"Add in <label>\" / \"Install in <label>\". */\n label: string;\n href: string;\n /**\n * The framework token this launcher installs into, for the `tool` column on\n * the `install` event it records (ADR-0011). Not 1:1 with `label`:\n * `github-copilot` offers both \"VS Code\" and \"VS Code Insiders\".\n *\n * Optional only to keep this published interface additive — every link the\n * generators below build sets it, which `resources.test.ts` pins. A caller\n * reading a generated link can rely on it; one constructing its own shape\n * is not forced to supply it.\n */\n framework?: string;\n}\n\nexport interface MarketplaceAddCommand {\n framework: string;\n command: string;\n deepLinks: ResourceDeepLink[];\n}\n\n/**\n * The copyable marketplace-add command per compatible framework. `all`,\n * unknown-only, or empty framework lists expand to every capable framework;\n * frameworks without a marketplace concept produce no row.\n *\n * Claude Code carries a single deep link on the CLI's documented\n * `claude-cli://open?q=` handler, which opens a Claude Code terminal\n * session with the command pre-filled regardless of the user's editor.\n *\n * Copilot's CLI still has no URI scheme, but Copilot's *other* surface does:\n * VS Code 1.113 ships `vscode://chat-plugin/add-marketplace?ref=`, which\n * accepts a plain or base64 `owner/repo` and always shows a confirmation\n * dialog before registering the marketplace (it also dedupes against the\n * user's existing entries). So the Copilot row keeps its terminal command for\n * CLI users *and* gains editor launchers, mirroring how `mcp-config` already\n * maps `github-copilot` onto the VS Code stable/Insiders pair.\n */\nexport function getMarketplaceAddCommands(\n frameworks: string[],\n repoSlug: string,\n): MarketplaceAddCommand[] {\n const capable = resolveCapableFrameworks(\n frameworks,\n MARKETPLACE_CAPABLE_FRAMEWORKS,\n );\n const commands: MarketplaceAddCommand[] = [];\n for (const framework of capable) {\n if (framework === 'claude-code') {\n const command = `/plugin marketplace add ${repoSlug}`;\n commands.push({\n framework,\n command,\n deepLinks: [\n {\n label: 'Claude',\n href: `claude-cli://open?q=${encodeURIComponent(command)}`,\n framework,\n },\n ],\n });\n } else if (framework === 'github-copilot') {\n const ref = encodeURIComponent(repoSlug);\n commands.push({\n framework,\n command: `copilot plugin marketplace add ${repoSlug}`,\n deepLinks: [\n {\n label: 'VS Code',\n href: `vscode://chat-plugin/add-marketplace?ref=${ref}`,\n framework,\n },\n {\n label: 'VS Code Insiders',\n href: `vscode-insiders://chat-plugin/add-marketplace?ref=${ref}`,\n framework,\n },\n ],\n });\n }\n }\n return commands;\n}\n\n/** The raw-file URL for a GitHub blob `source-location`; else `undefined`. */\nfunction getRawGithubFileUrl(\n sourceLocation: string | undefined,\n): string | undefined {\n if (!sourceLocation) {\n return undefined;\n }\n let url: URL;\n try {\n url = new URL(sourceLocation.replace(/^url:/, ''));\n } catch {\n return undefined;\n }\n if (url.hostname !== 'github.com') {\n return undefined;\n }\n const [owner, repo, marker, ref, ...path] = url.pathname\n .split('/')\n .filter(Boolean);\n if (!owner || !repo || marker !== 'blob' || !ref || path.length === 0) {\n return undefined;\n }\n return `https://raw.githubusercontent.com/${owner}/${repo}/${ref}/${path.join(\n '/',\n )}`;\n}\n\n/**\n * A launcher that opens an agent with an install prompt pre-filled. Neither\n * host auto-executes: the user reads the prompt and presses Enter. Claude Code\n * and Cursor are the two tools exposing a generic prompt URI — Copilot's\n * editor has purpose-built routes but no prompt handler, and Gemini has\n * neither (its `gemini.google.com/app?prompt=` link drives the web app, which\n * cannot write to a local workspace).\n *\n * Cursor truncates a deeplink at the first raw `&`, so the prompt must be\n * percent-encoded — `encodeURIComponent` handles that. Cursor also caps the\n * URL at ~8000 characters; these prompts are a URL plus a path, far under it.\n */\nfunction claudePromptLink(prompt: string): ResourceDeepLink {\n return {\n label: 'Claude',\n href: `claude-cli://open?q=${encodeURIComponent(prompt)}`,\n framework: 'claude-code',\n };\n}\n\nfunction cursorPromptLink(prompt: string): ResourceDeepLink {\n return {\n label: 'Cursor',\n href: `cursor://anysphere.cursor-deeplink/prompt?text=${encodeURIComponent(\n prompt,\n )}`,\n framework: 'cursor',\n };\n}\n\n/**\n * Frameworks with a one-click agent-install handler (Gemini has none).\n * OpenCode's Desktop app does register a real `opencode://` scheme, but every\n * route (`open-project`, `new-session`) requires an absolute local\n * `directory` param a web page cannot supply, so it's excluded here too.\n */\nexport const AGENT_LINK_CAPABLE_FRAMEWORKS = [\n 'claude-code',\n 'github-copilot',\n 'cursor',\n] as const;\n\n/** Hosts reachable by a generic prompt URI — the only route for skill/hook. */\nexport const PROMPT_LINK_CAPABLE_FRAMEWORKS = [\n 'claude-code',\n 'cursor',\n] as const;\n\n/**\n * The plain http(s) URL behind a `source-location`. Unlike\n * `getRawGithubFileUrl` this accepts **directory (`tree`) URLs**, which is what\n * a multi-file `skill` actually carries — a raw-file URL would resolve to\n * `undefined` for exactly the type that most needs a launcher.\n */\nfunction getSourceUrl(sourceLocation: string | undefined): string | undefined {\n if (!sourceLocation) {\n return undefined;\n }\n try {\n const url = new URL(sourceLocation.replace(/^url:/, ''));\n return url.protocol === 'http:' || url.protocol === 'https:'\n ? url.toString()\n : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * One-click launchers for the types with no purpose-built install route —\n * `skill` and `hook`. Both ride the generic prompt handlers, so the prompt\n * names the *host's own* install path and respects its install mode: a `merge`\n * target is asked to be merged into, never overwritten, so a launcher can\n * never cost the user their existing settings.\n *\n * Returns `[]` when the source URL cannot be derived, or for hosts with no\n * prompt route (Copilot, Gemini) — the path list and copy/download remain.\n */\nexport function getPromptInstallLinks(\n type: ResourceType,\n sourceLocation: string | undefined,\n name: string,\n frameworks: string[] = [],\n): ResourceDeepLink[] {\n return getInstallSteps(type, sourceLocation, name, frameworks)\n .map(step => step.link)\n .filter((link): link is ResourceDeepLink => !!link);\n}\n\n/**\n * Everything a single host needs to install a resource: where the body goes,\n * the prompt that puts it there, and a launcher when the host has a URI to\n * launch.\n *\n * `link` is absent for hosts with no prompt route — Copilot and Gemini. That\n * absence is why the step carries `prompt` as text: a host without a URI is\n * not a host without an install path, and the same instruction that a launcher\n * would pre-fill can be pasted into that agent by hand. Every declared\n * framework therefore gets something actionable, not a bare path.\n */\nexport interface ResourceInstallStep {\n framework: string;\n target: ResourceInstallTarget;\n /** The install instruction, ready to run in that host's agent. */\n prompt: string;\n /** One-click launcher, where the host exposes a generic prompt URI. */\n link?: ResourceDeepLink;\n}\n\nexport function getInstallSteps(\n type: ResourceType,\n sourceLocation: string | undefined,\n name: string,\n frameworks: string[] = [],\n): ResourceInstallStep[] {\n const sourceUrl = getSourceUrl(sourceLocation);\n if (!sourceUrl) {\n return [];\n }\n const label = RESOURCE_TYPE_REGISTRY[type].label.toLowerCase();\n const steps: ResourceInstallStep[] = [];\n for (const framework of expandInstallFrameworks(frameworks)) {\n const target = getResourceInstallTarget(type, framework, name);\n if (!target) {\n continue;\n }\n const prompt =\n target.mode === 'merge'\n ? `Install the \"${name}\" ${label}: fetch ${sourceUrl} and merge it into ${target.path}, keeping my existing settings intact.`\n : `Install the \"${name}\" ${label}: fetch ${sourceUrl} and save it to ${target.path}.`;\n let link: ResourceDeepLink | undefined;\n if (framework === 'claude-code') {\n link = claudePromptLink(prompt);\n } else if (framework === 'cursor') {\n link = cursorPromptLink(prompt);\n }\n steps.push({ framework, target, prompt, link });\n }\n return steps;\n}\n\n/** Frameworks with a one-click MCP-install handler (Gemini has none). */\nexport const MCP_LINK_CAPABLE_FRAMEWORKS = [\n 'claude-code',\n 'github-copilot',\n 'cursor',\n] as const;\n\n/**\n * One-click install links for an `agent` resource, restricted to the\n * resource's own compatible frameworks. VS Code stable and Insiders use the\n * native `chat-agent/install?url=` handler (the mechanism behind\n * awesome-copilot's Install buttons) and are Copilot's hosts, so they follow\n * `github-copilot`: VS Code downloads the file at `url` and asks the user\n * where to save it. Claude Code uses the `claude-cli://open?q=` handler with\n * an install prompt pre-filled to the convention path — reviewed and sent by\n * the user, never auto-executed. All derive from the GitHub blob URL in\n * `source-location`; anything else returns `[]` (copy/download fallback).\n */\nexport function getAgentInstallLinks(\n sourceLocation: string | undefined,\n name: string,\n frameworks: string[] = [],\n): ResourceDeepLink[] {\n const rawUrl = getRawGithubFileUrl(sourceLocation);\n if (!rawUrl) {\n return [];\n }\n const capable = resolveCapableFrameworks(\n frameworks,\n AGENT_LINK_CAPABLE_FRAMEWORKS,\n );\n const encodedRawUrl = encodeURIComponent(rawUrl);\n const installPrompt = (framework: string) => {\n const target = getResourceInstallTarget('agent', framework, name);\n return `Install this agent: fetch ${rawUrl} and save it to ${target?.path}`;\n };\n const links: ResourceDeepLink[] = [];\n for (const framework of capable) {\n if (framework === 'claude-code') {\n links.push(claudePromptLink(installPrompt('claude-code')));\n } else if (framework === 'cursor') {\n links.push(cursorPromptLink(installPrompt('cursor')));\n } else if (framework === 'github-copilot') {\n links.push({\n label: 'VS Code',\n href: `vscode:chat-agent/install?url=${encodedRawUrl}`,\n framework,\n });\n links.push({\n label: 'VS Code Insiders',\n href: `vscode-insiders:chat-agent/install?url=${encodedRawUrl}`,\n framework,\n });\n }\n }\n return links;\n}\n\n/**\n * One-click install links for an `mcp-config` resource, derived from its body —\n * the canonical `.mcp.json` snippet (spec §3.4). VS Code carries a native\n * `vscode:mcp/install?{json}` handler (Insiders scheme twin), Cursor a\n * documented `cursor://anysphere.cursor-deeplink/mcp/install` one, and\n * Claude Code gets a `claude-cli://open?q=` prompt around\n * `claude mcp add-json` — pre-filled, reviewed, never auto-executed.\n * Hosts follow the resource's own compatible frameworks: `all`/empty expand\n * to every capable host, anything else is intersected, so an mcp-config\n * declaring only Gemini (no handler) gets no links rather than every host's.\n * A missing, unparseable, or multi-server body returns `[]` (copy fallback) —\n * the body stays canonical, links are conveniences derived from it.\n */\nexport function getMcpInstallLinks(\n frameworks: string[],\n resourceName: string,\n bodyContent: string | undefined,\n): ResourceDeepLink[] {\n if (!bodyContent) {\n return [];\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(bodyContent);\n } catch {\n return [];\n }\n if (typeof parsed !== 'object' || parsed === null) {\n return [];\n }\n\n let serverName = resourceName;\n let config: Record<string, unknown>;\n const servers = (parsed as { mcpServers?: unknown }).mcpServers;\n if (servers !== undefined) {\n if (typeof servers !== 'object' || servers === null) {\n return [];\n }\n const entries = Object.entries(servers as Record<string, unknown>);\n if (\n entries.length !== 1 ||\n typeof entries[0][1] !== 'object' ||\n entries[0][1] === null\n ) {\n return [];\n }\n serverName = entries[0][0];\n config = entries[0][1] as Record<string, unknown>;\n } else if ('command' in parsed || 'url' in parsed) {\n config = parsed as Record<string, unknown>;\n } else {\n return [];\n }\n\n const capable = resolveCapableFrameworks(\n frameworks,\n MCP_LINK_CAPABLE_FRAMEWORKS,\n );\n\n const configJson = JSON.stringify(config);\n const links: ResourceDeepLink[] = [];\n for (const framework of capable) {\n if (framework === 'claude-code') {\n const prompt = encodeURIComponent(\n `Install this MCP config by running: claude mcp add-json ${serverName} '${configJson}'`,\n );\n links.push({\n label: 'Claude',\n href: `claude-cli://open?q=${prompt}`,\n framework,\n });\n } else if (framework === 'github-copilot') {\n const vsConfig = encodeURIComponent(\n JSON.stringify({ name: serverName, ...config }),\n );\n links.push({\n label: 'VS Code',\n href: `vscode:mcp/install?${vsConfig}`,\n framework,\n });\n links.push({\n label: 'VS Code Insiders',\n href: `vscode-insiders:mcp/install?${vsConfig}`,\n framework,\n });\n } else if (framework === 'cursor') {\n try {\n links.push({\n label: 'Cursor',\n href: `cursor://anysphere.cursor-deeplink/mcp/install?name=${encodeURIComponent(\n serverName,\n )}&config=${btoa(configJson)}`,\n framework,\n });\n } catch {\n // btoa rejects non-Latin1 config content — skip the Cursor link.\n }\n }\n }\n return links;\n}\n\n/**\n * Step two of the journey: how to install a plugin from the marketplace.\n * `marketplaceName` is the entity name, which the producer contract requires\n * to equal the `name` in `marketplace.json`.\n */\nexport function getMarketplaceInstallTemplate(marketplaceName: string): string {\n return `/plugin install <plugin>@${marketplaceName}`;\n}\n\n/**\n * The `.claude/settings.json` snippet a team commits so collaborators are\n * prompted to install the marketplace automatically (Claude Code).\n */\nexport function getMarketplaceTeamSnippet(\n marketplaceName: string,\n repoSlug: string,\n): string {\n return JSON.stringify(\n {\n extraKnownMarketplaces: {\n [marketplaceName]: { source: { source: 'github', repo: repoSlug } },\n },\n },\n null,\n 2,\n );\n}\n"],"names":[],"mappings":"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"}
|
package/dist/resources.esm.js
CHANGED
|
@@ -117,7 +117,7 @@ function getBodyShape(type) {
|
|
|
117
117
|
return type === "mcp-config" || type === "plugin" || type === "marketplace" ? "json" : "markdown";
|
|
118
118
|
}
|
|
119
119
|
function showsContentSection(type) {
|
|
120
|
-
return type !== "
|
|
120
|
+
return getBodyShape(type) !== "json";
|
|
121
121
|
}
|
|
122
122
|
function hasDownloadableArtifact(_type) {
|
|
123
123
|
return true;
|
|
@@ -252,7 +252,8 @@ function getMarketplaceAddCommands(frameworks, repoSlug) {
|
|
|
252
252
|
deepLinks: [
|
|
253
253
|
{
|
|
254
254
|
label: "Claude",
|
|
255
|
-
href: `claude-cli://open?q=${encodeURIComponent(command)}
|
|
255
|
+
href: `claude-cli://open?q=${encodeURIComponent(command)}`,
|
|
256
|
+
framework
|
|
256
257
|
}
|
|
257
258
|
]
|
|
258
259
|
});
|
|
@@ -264,11 +265,13 @@ function getMarketplaceAddCommands(frameworks, repoSlug) {
|
|
|
264
265
|
deepLinks: [
|
|
265
266
|
{
|
|
266
267
|
label: "VS Code",
|
|
267
|
-
href: `vscode://chat-plugin/add-marketplace?ref=${ref}
|
|
268
|
+
href: `vscode://chat-plugin/add-marketplace?ref=${ref}`,
|
|
269
|
+
framework
|
|
268
270
|
},
|
|
269
271
|
{
|
|
270
272
|
label: "VS Code Insiders",
|
|
271
|
-
href: `vscode-insiders://chat-plugin/add-marketplace?ref=${ref}
|
|
273
|
+
href: `vscode-insiders://chat-plugin/add-marketplace?ref=${ref}`,
|
|
274
|
+
framework
|
|
272
275
|
}
|
|
273
276
|
]
|
|
274
277
|
});
|
|
@@ -300,7 +303,8 @@ function getRawGithubFileUrl(sourceLocation) {
|
|
|
300
303
|
function claudePromptLink(prompt) {
|
|
301
304
|
return {
|
|
302
305
|
label: "Claude",
|
|
303
|
-
href: `claude-cli://open?q=${encodeURIComponent(prompt)}
|
|
306
|
+
href: `claude-cli://open?q=${encodeURIComponent(prompt)}`,
|
|
307
|
+
framework: "claude-code"
|
|
304
308
|
};
|
|
305
309
|
}
|
|
306
310
|
function cursorPromptLink(prompt) {
|
|
@@ -308,7 +312,8 @@ function cursorPromptLink(prompt) {
|
|
|
308
312
|
label: "Cursor",
|
|
309
313
|
href: `cursor://anysphere.cursor-deeplink/prompt?text=${encodeURIComponent(
|
|
310
314
|
prompt
|
|
311
|
-
)}
|
|
315
|
+
)}`,
|
|
316
|
+
framework: "cursor"
|
|
312
317
|
};
|
|
313
318
|
}
|
|
314
319
|
const AGENT_LINK_CAPABLE_FRAMEWORKS = [
|
|
@@ -385,11 +390,13 @@ function getAgentInstallLinks(sourceLocation, name, frameworks = []) {
|
|
|
385
390
|
} else if (framework === "github-copilot") {
|
|
386
391
|
links.push({
|
|
387
392
|
label: "VS Code",
|
|
388
|
-
href: `vscode:chat-agent/install?url=${encodedRawUrl}
|
|
393
|
+
href: `vscode:chat-agent/install?url=${encodedRawUrl}`,
|
|
394
|
+
framework
|
|
389
395
|
});
|
|
390
396
|
links.push({
|
|
391
397
|
label: "VS Code Insiders",
|
|
392
|
-
href: `vscode-insiders:chat-agent/install?url=${encodedRawUrl}
|
|
398
|
+
href: `vscode-insiders:chat-agent/install?url=${encodedRawUrl}`,
|
|
399
|
+
framework
|
|
393
400
|
});
|
|
394
401
|
}
|
|
395
402
|
}
|
|
@@ -437,15 +444,24 @@ function getMcpInstallLinks(frameworks, resourceName, bodyContent) {
|
|
|
437
444
|
const prompt = encodeURIComponent(
|
|
438
445
|
`Install this MCP config by running: claude mcp add-json ${serverName} '${configJson}'`
|
|
439
446
|
);
|
|
440
|
-
links.push({
|
|
447
|
+
links.push({
|
|
448
|
+
label: "Claude",
|
|
449
|
+
href: `claude-cli://open?q=${prompt}`,
|
|
450
|
+
framework
|
|
451
|
+
});
|
|
441
452
|
} else if (framework === "github-copilot") {
|
|
442
453
|
const vsConfig = encodeURIComponent(
|
|
443
454
|
JSON.stringify({ name: serverName, ...config })
|
|
444
455
|
);
|
|
445
|
-
links.push({
|
|
456
|
+
links.push({
|
|
457
|
+
label: "VS Code",
|
|
458
|
+
href: `vscode:mcp/install?${vsConfig}`,
|
|
459
|
+
framework
|
|
460
|
+
});
|
|
446
461
|
links.push({
|
|
447
462
|
label: "VS Code Insiders",
|
|
448
|
-
href: `vscode-insiders:mcp/install?${vsConfig}
|
|
463
|
+
href: `vscode-insiders:mcp/install?${vsConfig}`,
|
|
464
|
+
framework
|
|
449
465
|
});
|
|
450
466
|
} else if (framework === "cursor") {
|
|
451
467
|
try {
|
|
@@ -453,7 +469,8 @@ function getMcpInstallLinks(frameworks, resourceName, bodyContent) {
|
|
|
453
469
|
label: "Cursor",
|
|
454
470
|
href: `cursor://anysphere.cursor-deeplink/mcp/install?name=${encodeURIComponent(
|
|
455
471
|
serverName
|
|
456
|
-
)}&config=${btoa(configJson)}
|
|
472
|
+
)}&config=${btoa(configJson)}`,
|
|
473
|
+
framework
|
|
457
474
|
});
|
|
458
475
|
} catch {
|
|
459
476
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resources.esm.js","sources":["../src/resources.ts"],"sourcesContent":["/**\n * The v2 read contract: AiResource vocabulary, the flat ResourceSummary\n * returned by the backend, and the shared framework resolver (ADR-0003).\n *\n * The legacy asset-model types in `types.ts` coexist with this module until\n * the legacy silo is deleted (slice 8, issue #34).\n */\n\n/** The six canonical `spec.type` values of an AiResource (ADR-0003, ADR-0010). */\nexport const RESOURCE_TYPES = [\n 'skill',\n 'agent',\n 'hook',\n 'mcp-config',\n 'plugin',\n 'marketplace',\n] as const;\n\nexport type ResourceType = (typeof RESOURCE_TYPES)[number];\n\nexport function isResourceType(value: unknown): value is ResourceType {\n return (\n typeof value === 'string' &&\n (RESOURCE_TYPES as readonly string[]).includes(value)\n );\n}\n\n/**\n * The AiResource types a `plugin` may contain — restricted to the component\n * kinds a real Claude Code / GitHub Copilot plugin manifest allows: `skills`,\n * `agents`, `hooks` and `mcpServers` (schemastore `claude-code-plugin` /\n * `claude-code-marketplace.json`). A plugin's other manifest components\n * (`commands`, `lspServers`, `outputStyles`, `themes`, `channels`, `monitors`)\n * have no AiResource type, so they are never members here; other plugins are\n * `dependencies`, not containment.\n */\nexport const PLUGIN_MEMBER_TYPES: readonly ResourceType[] = [\n 'skill',\n 'agent',\n 'hook',\n 'mcp-config',\n];\n\n/**\n * The AiResource types a `marketplace` may contain: `plugin` only. A real\n * `.claude-plugin/marketplace.json` `plugins` array lists plugins and nothing\n * else (required by the schema Claude Code and Copilot CLI both read).\n */\nexport const MARKETPLACE_MEMBER_TYPES: readonly ResourceType[] = ['plugin'];\n\n/**\n * Whether a container of `parent` type renders a child of `child` type as a\n * member — restricted to what a real Claude/Copilot plugin or marketplace\n * manifest permits (ADR-0010/0015). A `marketplace` contains `plugin` only; a\n * `plugin` contains the component types DevAI Hub models. Any other pairing is\n * silently not rendered. This is a rendering convention, not catalog\n * validation (upstream `allowedKinds` is the broad `[\"AiResource\"]`).\n */\nexport function isRenderableContainment(\n parent: ResourceType,\n child: ResourceType,\n): boolean {\n if (parent === 'marketplace') return MARKETPLACE_MEMBER_TYPES.includes(child);\n if (parent === 'plugin') return PLUGIN_MEMBER_TYPES.includes(child);\n return false;\n}\n\n/** Annotation prefix owned by DevAI Hub. */\nexport const DEVAIHUB_ANNOTATION_PREFIX = 'devaihub.io';\n\n/** Comma-separated compatible-framework tokens (non-skill read path, ADR-0003). */\nexport const ANNOTATION_COMPATIBLE_FRAMEWORKS = `${DEVAIHUB_ANNOTATION_PREFIX}/compatible-frameworks`;\n\n/** Optional free-form help text shown on the detail panel. */\nexport const ANNOTATION_HELP = `${DEVAIHUB_ANNOTATION_PREFIX}/help`;\n\n/** Known framework tokens; unknown tokens pass through as-is (ADR-0003). */\nexport const KNOWN_FRAMEWORKS = [\n 'github-copilot',\n 'claude-code',\n 'cursor',\n 'google-gemini',\n 'opencode',\n 'all',\n] as const;\n\nexport type FrameworkToken = (typeof KNOWN_FRAMEWORKS)[number];\n\nconst FRAMEWORK_ALIASES: Record<string, FrameworkToken> = {\n copilot: 'github-copilot',\n claude: 'claude-code',\n gemini: 'google-gemini',\n};\n\n/**\n * Normalise a framework token: trim, lowercase, resolve aliases\n * (`claude` → `claude-code`). Unknown tokens pass through literally.\n */\nexport function normalizeFramework(token: string): string {\n const t = token.trim().toLowerCase();\n return FRAMEWORK_ALIASES[t] ?? t;\n}\n\n/**\n * Narrow a resource's frameworks to a deployment-level allow-list\n * (`devAiHub.frameworks.allowed`). Omitting the config key (`allowed` is\n * `undefined`) permits every framework; an explicit empty list permits none,\n * so a deployment can suppress framework exposure entirely. Both sides are\n * normalised (aliases resolved) before comparison.\n *\n * The `all` wildcard is expanded to the allow-list itself before filtering, so\n * a resource that declares `all` degrades to \"every permitted host\" rather\n * than disappearing entirely.\n */\nexport function filterAllowedFrameworks(\n frameworks: string[],\n allowed: string[] | undefined,\n): string[] {\n if (allowed === undefined) {\n return frameworks;\n }\n const permitted = new Set(\n allowed.map(normalizeFramework).filter(f => f && f !== 'all'),\n );\n const expanded = frameworks.flatMap(f =>\n normalizeFramework(f) === 'all' ? [...permitted] : [normalizeFramework(f)],\n );\n return Array.from(new Set(expanded)).filter(f => permitted.has(f));\n}\n\n/**\n * The minimal structural shape of an AiResource entity that the read helpers\n * need. A real `@backstage/catalog-model` `Entity` satisfies it, but keeping\n * the shape local means `-common` (and therefore the frontend) never depends\n * on catalog packages (architecture.md).\n */\nexport interface AiResourceEntityLike {\n metadata: {\n annotations?: Record<string, string>;\n };\n spec?: {\n type?: unknown;\n /** Native compatible-frameworks field, honoured regardless of `spec.type`. */\n agents?: unknown;\n [key: string]: unknown;\n };\n}\n\n/**\n * Resolve the compatible frameworks of an AiResource (ADR-0003):\n * 1. a non-empty `spec.agents` → the native field, for any `spec.type`;\n * 2. otherwise → the `devaihub.io/compatible-frameworks` annotation\n * (also the fallback when `spec.agents` is empty/absent);\n * 3. otherwise → `[]`.\n * Tokens are normalised; unknown tokens pass through. `spec.agents` is\n * preferred over the annotation because it lives on the entity itself\n * rather than in an annotation namespace we may retire.\n */\nexport function getFrameworks(entity: AiResourceEntityLike): string[] {\n if (Array.isArray(entity.spec?.agents)) {\n const agents = entity.spec.agents\n .filter((a): a is string => typeof a === 'string')\n .map(normalizeFramework)\n .filter(Boolean);\n if (agents.length > 0) {\n return dedupe(agents);\n }\n }\n\n const raw = entity.metadata.annotations?.[ANNOTATION_COMPATIBLE_FRAMEWORKS];\n if (!raw) {\n return [];\n }\n return dedupe(raw.split(',').map(normalizeFramework).filter(Boolean));\n}\n\nfunction dedupe(tokens: string[]): string[] {\n return Array.from(new Set(tokens));\n}\n\n/**\n * Icon identifiers for the type→card registry. `-common` is imported by the\n * backend, so it stays React-free: the frontend maps these identifiers to\n * actual icon components.\n */\nexport type ResourceTypeIcon =\n | 'tools'\n | 'robot'\n | 'flash'\n | 'plug'\n | 'puzzle'\n | 'store';\n\nexport interface ResourceTypeInfo {\n type: ResourceType;\n /** Singular display label, e.g. \"Skill\" (card type caption). */\n label: string;\n /** Plural display label, e.g. \"Skills\" (stat tiles, filters). */\n pluralLabel: string;\n /** Icon identifier resolved to a component by the frontend. */\n icon: ResourceTypeIcon;\n /**\n * Colour role name; the frontend resolves it to the plugin-owned\n * `--devaihub-type-<role>` custom properties (ADR-0008, NOS palette).\n */\n colorRole: ResourceType;\n}\n\n/**\n * The typed type→card registry (ADR-0003/ADR-0008): producer vocabulary and\n * consumer rendering share this single source, so they cannot drift. Adding\n * a type is one entry here plus one CSS token pair in the frontend.\n */\nexport const RESOURCE_TYPE_REGISTRY: Record<ResourceType, ResourceTypeInfo> = {\n skill: {\n type: 'skill',\n label: 'Skill',\n pluralLabel: 'Skills',\n icon: 'tools',\n colorRole: 'skill',\n },\n agent: {\n type: 'agent',\n label: 'Agent',\n pluralLabel: 'Agents',\n icon: 'robot',\n colorRole: 'agent',\n },\n hook: {\n type: 'hook',\n label: 'Hook',\n pluralLabel: 'Hooks',\n icon: 'flash',\n colorRole: 'hook',\n },\n 'mcp-config': {\n type: 'mcp-config',\n label: 'MCP Config',\n pluralLabel: 'MCP Configs',\n icon: 'plug',\n colorRole: 'mcp-config',\n },\n plugin: {\n type: 'plugin',\n label: 'Plugin',\n pluralLabel: 'Plugins',\n icon: 'puzzle',\n colorRole: 'plugin',\n },\n marketplace: {\n type: 'marketplace',\n label: 'Marketplace',\n pluralLabel: 'Marketplaces',\n icon: 'store',\n colorRole: 'marketplace',\n },\n};\n\n/**\n * The flat contract the backend returns to the frontend. The frontend never\n * sees a raw Backstage `Entity` — only this (architecture.md).\n */\nexport interface ResourceSummary {\n entityRef: string;\n name: string;\n title?: string;\n description?: string;\n tags: string[];\n type: ResourceType;\n lifecycle: string;\n owner?: string;\n sourceLocation?: string;\n frameworks: string[];\n /**\n * True when an active deployment allow-list (`devAiHub.frameworks.allowed`)\n * left this resource with no frameworks — either it removed the ones the\n * author declared, or the allow-list itself is empty. Lets the UI tell\n * \"author declared nothing\" (`frameworks: []`, show neutral install\n * defaults) apart from \"the deployment suppressed them\" (hide generated\n * install paths and launchers; Copy/Download still work).\n */\n frameworksRestricted?: boolean;\n /**\n * The framework set that install-path and launcher generation must be\n * scoped to, when it differs from `frameworks`. Only set for a resource\n * that declared no frameworks (which otherwise means \"every host\") under an\n * active allow-list: it holds the allow-list itself, so a bare resource\n * cannot produce launchers for tools the deployment disallowed. Kept\n * separate from `frameworks` so this inferred set never renders as a\n * compatibility badge the author never claimed.\n */\n installFrameworks?: string[];\n version?: string;\n kind: string;\n /**\n * Entity refs this container declares as its contents — a `marketplace`'s\n * `spec.plugins`, a `plugin`'s `spec.skills`; empty for leaf types. Filtered\n * to the caller's visible set and to the child types the container renders\n * (ADR-0015). The frontend resolves each ref against the summaries it holds.\n */\n children: string[];\n /**\n * Entity refs of the containers that declare this resource — the in-memory\n * inverse of `children`, built over the same caller-visible catalog read\n * (ADR-0015). A resource can belong to several containers.\n */\n parents: string[];\n /** Count of `children` (their declared, caller-visible members). */\n childCount?: number;\n helpText?: string;\n annotations: Record<string, string>;\n}\n\nexport interface ResourceListResponse {\n items: ResourceSummary[];\n}\n\n/**\n * The shape of a resource's body (CONTEXT.md: bodies are type-shaped, not\n * uniformly markdown). Drives detail-panel rendering: markdown is rendered,\n * json is pretty-printed and syntax-highlighted (ADR-0014). `plugin` and\n * `marketplace` bodies are the real Claude Code `plugin.json` /\n * `marketplace.json` manifest — not a hand-authored pointer doc, superseding\n * ADR-0010's markdown-only body for `marketplace`.\n */\nexport type BodyShape = 'markdown' | 'json';\n\nexport function getBodyShape(type: ResourceType): BodyShape {\n return type === 'mcp-config' || type === 'plugin' || type === 'marketplace'\n ? 'json'\n : 'markdown';\n}\n\n/**\n * Whether the detail panel shows a \"Content\" section for this type. `plugin`\n * and `marketplace` resources are containers — their body is the raw manifest\n * JSON and their real value is the relationship graph, not the file — so the\n * Content block is suppressed for them and kept for every other type.\n */\nexport function showsContentSection(type: ResourceType): boolean {\n return type !== 'plugin' && type !== 'marketplace';\n}\n\n/**\n * Whether downloading the body delivers the artifact itself. True for every\n * type: `plugin`/`marketplace` bodies are now the real manifest JSON, so a\n * download delivers that file itself rather than a non-actionable pointer\n * doc (ADR-0014, superseding ADR-0009's amendment and ADR-0010 on this\n * point).\n */\nexport function hasDownloadableArtifact(_type: ResourceType): boolean {\n return true;\n}\n\n/**\n * Whether copying the body to the clipboard is a meaningful install action.\n * True for every type: `marketplace`'s body is now the real manifest JSON,\n * not an instructions doc, so copying it is no longer a misrepresentation\n * (ADR-0014, superseding ADR-0010 on this point).\n */\nexport function hasCopyableBody(_type: ResourceType): boolean {\n return true;\n}\n\n/**\n * How a body reaches its install path.\n *\n * `drop-in` — the body becomes the file (or directory) at `path`, which is\n * the resource's own; writing it touches nothing else.\n *\n * `merge` — `path` is a shared settings file the user already owns, and the\n * body is a fragment to merge into it. The distinction is not cosmetic:\n * following a `merge` target as if it were a `drop-in` overwrites the user's\n * existing configuration, so the UI must never present the two identically.\n */\nexport type InstallMode = 'drop-in' | 'merge';\n\nexport interface ResourceInstallTarget {\n /** Workspace-relative path. */\n path: string;\n mode: InstallMode;\n}\n\n/**\n * The concrete framework tokens a body can be installed into — `all` is a\n * wildcard over these, never a destination itself.\n */\nexport const INSTALLABLE_FRAMEWORKS = [\n 'claude-code',\n 'github-copilot',\n 'google-gemini',\n 'cursor',\n 'opencode',\n] as const;\n\n/**\n * Convention table: (type, framework) → where the body goes and how.\n * A missing entry means the pair has no filesystem convention — `plugin` and\n * `marketplace` bodies are pointers that install through their framework\n * (ADR-0009, ADR-0010), so they carry install commands rather than paths.\n */\nconst INSTALL_PATHS: Record<\n ResourceType,\n Record<string, { mode: InstallMode; path: (name: string) => string }>\n> = {\n // Every host reads a skill as a self-contained directory. Copilot also\n // picks up `.claude/skills`, but each tool's own path is what we recommend;\n // `.agents/skills` is the cross-tool alias Copilot and Gemini both honour,\n // which makes it the right answer for an unrecognised framework.\n skill: {\n 'claude-code': { mode: 'drop-in', path: name => `.claude/skills/${name}/` },\n 'github-copilot': {\n mode: 'drop-in',\n path: name => `.github/skills/${name}/`,\n },\n 'google-gemini': {\n mode: 'drop-in',\n path: name => `.gemini/skills/${name}/`,\n },\n cursor: { mode: 'drop-in', path: name => `.cursor/skills/${name}/` },\n opencode: { mode: 'drop-in', path: name => `.opencode/skills/${name}/` },\n default: { mode: 'drop-in', path: name => `.agents/skills/${name}/` },\n },\n agent: {\n 'claude-code': {\n mode: 'drop-in',\n path: name => `.claude/agents/${name}.md`,\n },\n 'github-copilot': {\n mode: 'drop-in',\n path: name => `.github/agents/${name}.agent.md`,\n },\n 'google-gemini': {\n mode: 'drop-in',\n path: name => `.gemini/agents/${name}.md`,\n },\n cursor: { mode: 'drop-in', path: name => `.cursor/rules/${name}.mdc` },\n opencode: { mode: 'drop-in', path: name => `.opencode/agents/${name}.md` },\n default: { mode: 'drop-in', path: name => `.ai/agents/${name}.md` },\n },\n // All four hosts have a hook system, but only Copilot gives each hook its\n // own file; the rest register hooks inside a shared settings document.\n // OpenCode has no declarative hook config at all — hooks are exclusively\n // JS/TS plugin modules — so it deliberately carries no entry here, the same\n // way it carries no `default`.\n hook: {\n 'claude-code': { mode: 'merge', path: () => `.claude/settings.json` },\n 'github-copilot': {\n mode: 'drop-in',\n path: name => `.github/hooks/${name}.json`,\n },\n 'google-gemini': { mode: 'merge', path: () => `.gemini/settings.json` },\n cursor: { mode: 'merge', path: () => `.cursor/hooks.json` },\n },\n 'mcp-config': {\n 'claude-code': { mode: 'merge', path: () => `.mcp.json` },\n 'github-copilot': { mode: 'merge', path: () => `.vscode/mcp.json` },\n 'google-gemini': { mode: 'merge', path: () => `.gemini/settings.json` },\n cursor: { mode: 'merge', path: () => `.cursor/mcp.json` },\n opencode: { mode: 'merge', path: () => `opencode.json` },\n },\n plugin: {},\n marketplace: {},\n};\n\n/**\n * Where a resource's body installs for one framework, and whether that path\n * is the body's own file or a settings file to merge into. Returns\n * `undefined` when the (type, framework) pair has no filesystem convention.\n */\nexport function getResourceInstallTarget(\n type: ResourceType,\n framework: string,\n name: string,\n): ResourceInstallTarget | undefined {\n const conventions = INSTALL_PATHS[type];\n const entry =\n conventions[normalizeFramework(framework)] ?? conventions.default;\n return entry ? { path: entry.path(name), mode: entry.mode } : undefined;\n}\n\n/**\n * The frameworks to show install paths for. An empty list means the resource\n * declared no compatibility and gets the neutral `default` convention; `all`\n * is a wildcard and expands to every installable host, so it never collapses\n * to a single row — or, for types with no `default`, to no rows at all.\n */\nexport function expandInstallFrameworks(frameworks: string[]): string[] {\n const normalized = dedupe(frameworks.map(normalizeFramework));\n if (normalized.length === 0) {\n return ['default'];\n }\n if (normalized.includes('all')) {\n return [...INSTALLABLE_FRAMEWORKS];\n }\n return normalized;\n}\n\n/*\n * Marketplace journey helpers (ADR-0010). A marketplace installs in two\n * steps — register the catalog with the AI tool, then install plugins from\n * it. Both Claude Code and Copilot CLI read the same\n * `.claude-plugin/marketplace.json` format and address the repo as\n * `owner/repo`; the plugin derives that slug from the mandatory\n * `source-location` (the producer contract requires the body doc to live\n * inside the marketplace repo). No derivation → the UI falls back to the\n * rendered body, which stays canonical.\n */\n\n/** Frameworks with a marketplace-add concept (Cursor/Gemini have none). */\nexport const MARKETPLACE_CAPABLE_FRAMEWORKS = [\n 'claude-code',\n 'github-copilot',\n] as const;\n\n/**\n * Narrow a resource's declared frameworks to those a given journey can\n * actually launch. A deep link is a claim about compatibility: offering\n * \"Install in Claude\" for a resource that never declared `claude-code` tells\n * the user something untrue about the resource.\n *\n * `all` and an empty list both mean \"unrestricted\" and expand to every\n * capable host. Anything else is intersected, so a declared framework with no\n * handler (Gemini) — or an unknown token — yields no links rather than\n * silently widening to every host.\n */\nexport function resolveCapableFrameworks(\n declared: string[],\n capable: readonly string[],\n): string[] {\n const normalized = dedupe(declared.map(normalizeFramework));\n if (normalized.length === 0 || normalized.includes('all')) {\n return [...capable];\n }\n return normalized.filter(f => capable.includes(f));\n}\n\n/**\n * Derive the `owner/repo` slug from a marketplace's `source-location`.\n * GitHub URLs only — other hosts return `undefined` (body-only fallback).\n */\nexport function getMarketplaceRepoSlug(\n sourceLocation: string | undefined,\n): string | undefined {\n if (!sourceLocation) {\n return undefined;\n }\n let url: URL;\n try {\n url = new URL(sourceLocation.replace(/^url:/, ''));\n } catch {\n return undefined;\n }\n if (url.hostname !== 'github.com') {\n return undefined;\n }\n const [owner, repo] = url.pathname.split('/').filter(Boolean);\n if (!owner || !repo) {\n return undefined;\n }\n return `${owner}/${repo.replace(/\\.git$/, '')}`;\n}\n\n/**\n * A one-click launcher for an add command: a custom-scheme URL that opens\n * the host app with the command pre-filled in the prompt box. The host\n * never auto-executes it — the user reviews and presses Enter — and an\n * unregistered scheme is a harmless no-op, so these complement the copy\n * button rather than replace it.\n */\nexport interface ResourceDeepLink {\n /** Host application name; render as \"Add in <label>\" / \"Install in <label>\". */\n label: string;\n href: string;\n}\n\nexport interface MarketplaceAddCommand {\n framework: string;\n command: string;\n deepLinks: ResourceDeepLink[];\n}\n\n/**\n * The copyable marketplace-add command per compatible framework. `all`,\n * unknown-only, or empty framework lists expand to every capable framework;\n * frameworks without a marketplace concept produce no row.\n *\n * Claude Code carries a single deep link on the CLI's documented\n * `claude-cli://open?q=` handler, which opens a Claude Code terminal\n * session with the command pre-filled regardless of the user's editor.\n *\n * Copilot's CLI still has no URI scheme, but Copilot's *other* surface does:\n * VS Code 1.113 ships `vscode://chat-plugin/add-marketplace?ref=`, which\n * accepts a plain or base64 `owner/repo` and always shows a confirmation\n * dialog before registering the marketplace (it also dedupes against the\n * user's existing entries). So the Copilot row keeps its terminal command for\n * CLI users *and* gains editor launchers, mirroring how `mcp-config` already\n * maps `github-copilot` onto the VS Code stable/Insiders pair.\n */\nexport function getMarketplaceAddCommands(\n frameworks: string[],\n repoSlug: string,\n): MarketplaceAddCommand[] {\n const capable = resolveCapableFrameworks(\n frameworks,\n MARKETPLACE_CAPABLE_FRAMEWORKS,\n );\n const commands: MarketplaceAddCommand[] = [];\n for (const framework of capable) {\n if (framework === 'claude-code') {\n const command = `/plugin marketplace add ${repoSlug}`;\n commands.push({\n framework,\n command,\n deepLinks: [\n {\n label: 'Claude',\n href: `claude-cli://open?q=${encodeURIComponent(command)}`,\n },\n ],\n });\n } else if (framework === 'github-copilot') {\n const ref = encodeURIComponent(repoSlug);\n commands.push({\n framework,\n command: `copilot plugin marketplace add ${repoSlug}`,\n deepLinks: [\n {\n label: 'VS Code',\n href: `vscode://chat-plugin/add-marketplace?ref=${ref}`,\n },\n {\n label: 'VS Code Insiders',\n href: `vscode-insiders://chat-plugin/add-marketplace?ref=${ref}`,\n },\n ],\n });\n }\n }\n return commands;\n}\n\n/** The raw-file URL for a GitHub blob `source-location`; else `undefined`. */\nfunction getRawGithubFileUrl(\n sourceLocation: string | undefined,\n): string | undefined {\n if (!sourceLocation) {\n return undefined;\n }\n let url: URL;\n try {\n url = new URL(sourceLocation.replace(/^url:/, ''));\n } catch {\n return undefined;\n }\n if (url.hostname !== 'github.com') {\n return undefined;\n }\n const [owner, repo, marker, ref, ...path] = url.pathname\n .split('/')\n .filter(Boolean);\n if (!owner || !repo || marker !== 'blob' || !ref || path.length === 0) {\n return undefined;\n }\n return `https://raw.githubusercontent.com/${owner}/${repo}/${ref}/${path.join(\n '/',\n )}`;\n}\n\n/**\n * A launcher that opens an agent with an install prompt pre-filled. Neither\n * host auto-executes: the user reads the prompt and presses Enter. Claude Code\n * and Cursor are the two tools exposing a generic prompt URI — Copilot's\n * editor has purpose-built routes but no prompt handler, and Gemini has\n * neither (its `gemini.google.com/app?prompt=` link drives the web app, which\n * cannot write to a local workspace).\n *\n * Cursor truncates a deeplink at the first raw `&`, so the prompt must be\n * percent-encoded — `encodeURIComponent` handles that. Cursor also caps the\n * URL at ~8000 characters; these prompts are a URL plus a path, far under it.\n */\nfunction claudePromptLink(prompt: string): ResourceDeepLink {\n return {\n label: 'Claude',\n href: `claude-cli://open?q=${encodeURIComponent(prompt)}`,\n };\n}\n\nfunction cursorPromptLink(prompt: string): ResourceDeepLink {\n return {\n label: 'Cursor',\n href: `cursor://anysphere.cursor-deeplink/prompt?text=${encodeURIComponent(\n prompt,\n )}`,\n };\n}\n\n/**\n * Frameworks with a one-click agent-install handler (Gemini has none).\n * OpenCode's Desktop app does register a real `opencode://` scheme, but every\n * route (`open-project`, `new-session`) requires an absolute local\n * `directory` param a web page cannot supply, so it's excluded here too.\n */\nexport const AGENT_LINK_CAPABLE_FRAMEWORKS = [\n 'claude-code',\n 'github-copilot',\n 'cursor',\n] as const;\n\n/** Hosts reachable by a generic prompt URI — the only route for skill/hook. */\nexport const PROMPT_LINK_CAPABLE_FRAMEWORKS = [\n 'claude-code',\n 'cursor',\n] as const;\n\n/**\n * The plain http(s) URL behind a `source-location`. Unlike\n * `getRawGithubFileUrl` this accepts **directory (`tree`) URLs**, which is what\n * a multi-file `skill` actually carries — a raw-file URL would resolve to\n * `undefined` for exactly the type that most needs a launcher.\n */\nfunction getSourceUrl(sourceLocation: string | undefined): string | undefined {\n if (!sourceLocation) {\n return undefined;\n }\n try {\n const url = new URL(sourceLocation.replace(/^url:/, ''));\n return url.protocol === 'http:' || url.protocol === 'https:'\n ? url.toString()\n : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * One-click launchers for the types with no purpose-built install route —\n * `skill` and `hook`. Both ride the generic prompt handlers, so the prompt\n * names the *host's own* install path and respects its install mode: a `merge`\n * target is asked to be merged into, never overwritten, so a launcher can\n * never cost the user their existing settings.\n *\n * Returns `[]` when the source URL cannot be derived, or for hosts with no\n * prompt route (Copilot, Gemini) — the path list and copy/download remain.\n */\nexport function getPromptInstallLinks(\n type: ResourceType,\n sourceLocation: string | undefined,\n name: string,\n frameworks: string[] = [],\n): ResourceDeepLink[] {\n return getInstallSteps(type, sourceLocation, name, frameworks)\n .map(step => step.link)\n .filter((link): link is ResourceDeepLink => !!link);\n}\n\n/**\n * Everything a single host needs to install a resource: where the body goes,\n * the prompt that puts it there, and a launcher when the host has a URI to\n * launch.\n *\n * `link` is absent for hosts with no prompt route — Copilot and Gemini. That\n * absence is why the step carries `prompt` as text: a host without a URI is\n * not a host without an install path, and the same instruction that a launcher\n * would pre-fill can be pasted into that agent by hand. Every declared\n * framework therefore gets something actionable, not a bare path.\n */\nexport interface ResourceInstallStep {\n framework: string;\n target: ResourceInstallTarget;\n /** The install instruction, ready to run in that host's agent. */\n prompt: string;\n /** One-click launcher, where the host exposes a generic prompt URI. */\n link?: ResourceDeepLink;\n}\n\nexport function getInstallSteps(\n type: ResourceType,\n sourceLocation: string | undefined,\n name: string,\n frameworks: string[] = [],\n): ResourceInstallStep[] {\n const sourceUrl = getSourceUrl(sourceLocation);\n if (!sourceUrl) {\n return [];\n }\n const label = RESOURCE_TYPE_REGISTRY[type].label.toLowerCase();\n const steps: ResourceInstallStep[] = [];\n for (const framework of expandInstallFrameworks(frameworks)) {\n const target = getResourceInstallTarget(type, framework, name);\n if (!target) {\n continue;\n }\n const prompt =\n target.mode === 'merge'\n ? `Install the \"${name}\" ${label}: fetch ${sourceUrl} and merge it into ${target.path}, keeping my existing settings intact.`\n : `Install the \"${name}\" ${label}: fetch ${sourceUrl} and save it to ${target.path}.`;\n let link: ResourceDeepLink | undefined;\n if (framework === 'claude-code') {\n link = claudePromptLink(prompt);\n } else if (framework === 'cursor') {\n link = cursorPromptLink(prompt);\n }\n steps.push({ framework, target, prompt, link });\n }\n return steps;\n}\n\n/** Frameworks with a one-click MCP-install handler (Gemini has none). */\nexport const MCP_LINK_CAPABLE_FRAMEWORKS = [\n 'claude-code',\n 'github-copilot',\n 'cursor',\n] as const;\n\n/**\n * One-click install links for an `agent` resource, restricted to the\n * resource's own compatible frameworks. VS Code stable and Insiders use the\n * native `chat-agent/install?url=` handler (the mechanism behind\n * awesome-copilot's Install buttons) and are Copilot's hosts, so they follow\n * `github-copilot`: VS Code downloads the file at `url` and asks the user\n * where to save it. Claude Code uses the `claude-cli://open?q=` handler with\n * an install prompt pre-filled to the convention path — reviewed and sent by\n * the user, never auto-executed. All derive from the GitHub blob URL in\n * `source-location`; anything else returns `[]` (copy/download fallback).\n */\nexport function getAgentInstallLinks(\n sourceLocation: string | undefined,\n name: string,\n frameworks: string[] = [],\n): ResourceDeepLink[] {\n const rawUrl = getRawGithubFileUrl(sourceLocation);\n if (!rawUrl) {\n return [];\n }\n const capable = resolveCapableFrameworks(\n frameworks,\n AGENT_LINK_CAPABLE_FRAMEWORKS,\n );\n const encodedRawUrl = encodeURIComponent(rawUrl);\n const installPrompt = (framework: string) => {\n const target = getResourceInstallTarget('agent', framework, name);\n return `Install this agent: fetch ${rawUrl} and save it to ${target?.path}`;\n };\n const links: ResourceDeepLink[] = [];\n for (const framework of capable) {\n if (framework === 'claude-code') {\n links.push(claudePromptLink(installPrompt('claude-code')));\n } else if (framework === 'cursor') {\n links.push(cursorPromptLink(installPrompt('cursor')));\n } else if (framework === 'github-copilot') {\n links.push({\n label: 'VS Code',\n href: `vscode:chat-agent/install?url=${encodedRawUrl}`,\n });\n links.push({\n label: 'VS Code Insiders',\n href: `vscode-insiders:chat-agent/install?url=${encodedRawUrl}`,\n });\n }\n }\n return links;\n}\n\n/**\n * One-click install links for an `mcp-config` resource, derived from its body —\n * the canonical `.mcp.json` snippet (spec §3.4). VS Code carries a native\n * `vscode:mcp/install?{json}` handler (Insiders scheme twin), Cursor a\n * documented `cursor://anysphere.cursor-deeplink/mcp/install` one, and\n * Claude Code gets a `claude-cli://open?q=` prompt around\n * `claude mcp add-json` — pre-filled, reviewed, never auto-executed.\n * Hosts follow the resource's own compatible frameworks: `all`/empty expand\n * to every capable host, anything else is intersected, so an mcp-config\n * declaring only Gemini (no handler) gets no links rather than every host's.\n * A missing, unparseable, or multi-server body returns `[]` (copy fallback) —\n * the body stays canonical, links are conveniences derived from it.\n */\nexport function getMcpInstallLinks(\n frameworks: string[],\n resourceName: string,\n bodyContent: string | undefined,\n): ResourceDeepLink[] {\n if (!bodyContent) {\n return [];\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(bodyContent);\n } catch {\n return [];\n }\n if (typeof parsed !== 'object' || parsed === null) {\n return [];\n }\n\n let serverName = resourceName;\n let config: Record<string, unknown>;\n const servers = (parsed as { mcpServers?: unknown }).mcpServers;\n if (servers !== undefined) {\n if (typeof servers !== 'object' || servers === null) {\n return [];\n }\n const entries = Object.entries(servers as Record<string, unknown>);\n if (\n entries.length !== 1 ||\n typeof entries[0][1] !== 'object' ||\n entries[0][1] === null\n ) {\n return [];\n }\n serverName = entries[0][0];\n config = entries[0][1] as Record<string, unknown>;\n } else if ('command' in parsed || 'url' in parsed) {\n config = parsed as Record<string, unknown>;\n } else {\n return [];\n }\n\n const capable = resolveCapableFrameworks(\n frameworks,\n MCP_LINK_CAPABLE_FRAMEWORKS,\n );\n\n const configJson = JSON.stringify(config);\n const links: ResourceDeepLink[] = [];\n for (const framework of capable) {\n if (framework === 'claude-code') {\n const prompt = encodeURIComponent(\n `Install this MCP config by running: claude mcp add-json ${serverName} '${configJson}'`,\n );\n links.push({ label: 'Claude', href: `claude-cli://open?q=${prompt}` });\n } else if (framework === 'github-copilot') {\n const vsConfig = encodeURIComponent(\n JSON.stringify({ name: serverName, ...config }),\n );\n links.push({ label: 'VS Code', href: `vscode:mcp/install?${vsConfig}` });\n links.push({\n label: 'VS Code Insiders',\n href: `vscode-insiders:mcp/install?${vsConfig}`,\n });\n } else if (framework === 'cursor') {\n try {\n links.push({\n label: 'Cursor',\n href: `cursor://anysphere.cursor-deeplink/mcp/install?name=${encodeURIComponent(\n serverName,\n )}&config=${btoa(configJson)}`,\n });\n } catch {\n // btoa rejects non-Latin1 config content — skip the Cursor link.\n }\n }\n }\n return links;\n}\n\n/**\n * Step two of the journey: how to install a plugin from the marketplace.\n * `marketplaceName` is the entity name, which the producer contract requires\n * to equal the `name` in `marketplace.json`.\n */\nexport function getMarketplaceInstallTemplate(marketplaceName: string): string {\n return `/plugin install <plugin>@${marketplaceName}`;\n}\n\n/**\n * The `.claude/settings.json` snippet a team commits so collaborators are\n * prompted to install the marketplace automatically (Claude Code).\n */\nexport function getMarketplaceTeamSnippet(\n marketplaceName: string,\n repoSlug: string,\n): string {\n return JSON.stringify(\n {\n extraKnownMarketplaces: {\n [marketplaceName]: { source: { source: 'github', repo: repoSlug } },\n },\n },\n null,\n 2,\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"resources.esm.js","sources":["../src/resources.ts"],"sourcesContent":["/**\n * The v2 read contract: AiResource vocabulary, the flat ResourceSummary\n * returned by the backend, and the shared framework resolver (ADR-0003).\n *\n * The legacy asset-model types in `types.ts` coexist with this module until\n * the legacy silo is deleted (slice 8, issue #34).\n */\n\n/** The six canonical `spec.type` values of an AiResource (ADR-0003, ADR-0010). */\nexport const RESOURCE_TYPES = [\n 'skill',\n 'agent',\n 'hook',\n 'mcp-config',\n 'plugin',\n 'marketplace',\n] as const;\n\nexport type ResourceType = (typeof RESOURCE_TYPES)[number];\n\nexport function isResourceType(value: unknown): value is ResourceType {\n return (\n typeof value === 'string' &&\n (RESOURCE_TYPES as readonly string[]).includes(value)\n );\n}\n\n/**\n * The AiResource types a `plugin` may contain — restricted to the component\n * kinds a real Claude Code / GitHub Copilot plugin manifest allows: `skills`,\n * `agents`, `hooks` and `mcpServers` (schemastore `claude-code-plugin` /\n * `claude-code-marketplace.json`). A plugin's other manifest components\n * (`commands`, `lspServers`, `outputStyles`, `themes`, `channels`, `monitors`)\n * have no AiResource type, so they are never members here; other plugins are\n * `dependencies`, not containment.\n */\nexport const PLUGIN_MEMBER_TYPES: readonly ResourceType[] = [\n 'skill',\n 'agent',\n 'hook',\n 'mcp-config',\n];\n\n/**\n * The AiResource types a `marketplace` may contain: `plugin` only. A real\n * `.claude-plugin/marketplace.json` `plugins` array lists plugins and nothing\n * else (required by the schema Claude Code and Copilot CLI both read).\n */\nexport const MARKETPLACE_MEMBER_TYPES: readonly ResourceType[] = ['plugin'];\n\n/**\n * Whether a container of `parent` type renders a child of `child` type as a\n * member — restricted to what a real Claude/Copilot plugin or marketplace\n * manifest permits (ADR-0010/0015). A `marketplace` contains `plugin` only; a\n * `plugin` contains the component types DevAI Hub models. Any other pairing is\n * silently not rendered. This is a rendering convention, not catalog\n * validation (upstream `allowedKinds` is the broad `[\"AiResource\"]`).\n */\nexport function isRenderableContainment(\n parent: ResourceType,\n child: ResourceType,\n): boolean {\n if (parent === 'marketplace') return MARKETPLACE_MEMBER_TYPES.includes(child);\n if (parent === 'plugin') return PLUGIN_MEMBER_TYPES.includes(child);\n return false;\n}\n\n/** Annotation prefix owned by DevAI Hub. */\nexport const DEVAIHUB_ANNOTATION_PREFIX = 'devaihub.io';\n\n/** Comma-separated compatible-framework tokens (non-skill read path, ADR-0003). */\nexport const ANNOTATION_COMPATIBLE_FRAMEWORKS = `${DEVAIHUB_ANNOTATION_PREFIX}/compatible-frameworks`;\n\n/** Optional free-form help text shown on the detail panel. */\nexport const ANNOTATION_HELP = `${DEVAIHUB_ANNOTATION_PREFIX}/help`;\n\n/** Known framework tokens; unknown tokens pass through as-is (ADR-0003). */\nexport const KNOWN_FRAMEWORKS = [\n 'github-copilot',\n 'claude-code',\n 'cursor',\n 'google-gemini',\n 'opencode',\n 'all',\n] as const;\n\nexport type FrameworkToken = (typeof KNOWN_FRAMEWORKS)[number];\n\nconst FRAMEWORK_ALIASES: Record<string, FrameworkToken> = {\n copilot: 'github-copilot',\n claude: 'claude-code',\n gemini: 'google-gemini',\n};\n\n/**\n * Normalise a framework token: trim, lowercase, resolve aliases\n * (`claude` → `claude-code`). Unknown tokens pass through literally.\n */\nexport function normalizeFramework(token: string): string {\n const t = token.trim().toLowerCase();\n return FRAMEWORK_ALIASES[t] ?? t;\n}\n\n/**\n * Narrow a resource's frameworks to a deployment-level allow-list\n * (`devAiHub.frameworks.allowed`). Omitting the config key (`allowed` is\n * `undefined`) permits every framework; an explicit empty list permits none,\n * so a deployment can suppress framework exposure entirely. Both sides are\n * normalised (aliases resolved) before comparison.\n *\n * The `all` wildcard is expanded to the allow-list itself before filtering, so\n * a resource that declares `all` degrades to \"every permitted host\" rather\n * than disappearing entirely.\n */\nexport function filterAllowedFrameworks(\n frameworks: string[],\n allowed: string[] | undefined,\n): string[] {\n if (allowed === undefined) {\n return frameworks;\n }\n const permitted = new Set(\n allowed.map(normalizeFramework).filter(f => f && f !== 'all'),\n );\n const expanded = frameworks.flatMap(f =>\n normalizeFramework(f) === 'all' ? [...permitted] : [normalizeFramework(f)],\n );\n return Array.from(new Set(expanded)).filter(f => permitted.has(f));\n}\n\n/**\n * The minimal structural shape of an AiResource entity that the read helpers\n * need. A real `@backstage/catalog-model` `Entity` satisfies it, but keeping\n * the shape local means `-common` (and therefore the frontend) never depends\n * on catalog packages (architecture.md).\n */\nexport interface AiResourceEntityLike {\n metadata: {\n annotations?: Record<string, string>;\n };\n spec?: {\n type?: unknown;\n /** Native compatible-frameworks field, honoured regardless of `spec.type`. */\n agents?: unknown;\n [key: string]: unknown;\n };\n}\n\n/**\n * Resolve the compatible frameworks of an AiResource (ADR-0003):\n * 1. a non-empty `spec.agents` → the native field, for any `spec.type`;\n * 2. otherwise → the `devaihub.io/compatible-frameworks` annotation\n * (also the fallback when `spec.agents` is empty/absent);\n * 3. otherwise → `[]`.\n * Tokens are normalised; unknown tokens pass through. `spec.agents` is\n * preferred over the annotation because it lives on the entity itself\n * rather than in an annotation namespace we may retire.\n */\nexport function getFrameworks(entity: AiResourceEntityLike): string[] {\n if (Array.isArray(entity.spec?.agents)) {\n const agents = entity.spec.agents\n .filter((a): a is string => typeof a === 'string')\n .map(normalizeFramework)\n .filter(Boolean);\n if (agents.length > 0) {\n return dedupe(agents);\n }\n }\n\n const raw = entity.metadata.annotations?.[ANNOTATION_COMPATIBLE_FRAMEWORKS];\n if (!raw) {\n return [];\n }\n return dedupe(raw.split(',').map(normalizeFramework).filter(Boolean));\n}\n\nfunction dedupe(tokens: string[]): string[] {\n return Array.from(new Set(tokens));\n}\n\n/**\n * Icon identifiers for the type→card registry. `-common` is imported by the\n * backend, so it stays React-free: the frontend maps these identifiers to\n * actual icon components.\n */\nexport type ResourceTypeIcon =\n | 'tools'\n | 'robot'\n | 'flash'\n | 'plug'\n | 'puzzle'\n | 'store';\n\nexport interface ResourceTypeInfo {\n type: ResourceType;\n /** Singular display label, e.g. \"Skill\" (card type caption). */\n label: string;\n /** Plural display label, e.g. \"Skills\" (stat tiles, filters). */\n pluralLabel: string;\n /** Icon identifier resolved to a component by the frontend. */\n icon: ResourceTypeIcon;\n /**\n * Colour role name; the frontend resolves it to the plugin-owned\n * `--devaihub-type-<role>` custom properties (ADR-0008, NOS palette).\n */\n colorRole: ResourceType;\n}\n\n/**\n * The typed type→card registry (ADR-0003/ADR-0008): producer vocabulary and\n * consumer rendering share this single source, so they cannot drift. Adding\n * a type is one entry here plus one CSS token pair in the frontend.\n */\nexport const RESOURCE_TYPE_REGISTRY: Record<ResourceType, ResourceTypeInfo> = {\n skill: {\n type: 'skill',\n label: 'Skill',\n pluralLabel: 'Skills',\n icon: 'tools',\n colorRole: 'skill',\n },\n agent: {\n type: 'agent',\n label: 'Agent',\n pluralLabel: 'Agents',\n icon: 'robot',\n colorRole: 'agent',\n },\n hook: {\n type: 'hook',\n label: 'Hook',\n pluralLabel: 'Hooks',\n icon: 'flash',\n colorRole: 'hook',\n },\n 'mcp-config': {\n type: 'mcp-config',\n label: 'MCP Config',\n pluralLabel: 'MCP Configs',\n icon: 'plug',\n colorRole: 'mcp-config',\n },\n plugin: {\n type: 'plugin',\n label: 'Plugin',\n pluralLabel: 'Plugins',\n icon: 'puzzle',\n colorRole: 'plugin',\n },\n marketplace: {\n type: 'marketplace',\n label: 'Marketplace',\n pluralLabel: 'Marketplaces',\n icon: 'store',\n colorRole: 'marketplace',\n },\n};\n\n/**\n * The flat contract the backend returns to the frontend. The frontend never\n * sees a raw Backstage `Entity` — only this (architecture.md).\n */\nexport interface ResourceSummary {\n entityRef: string;\n name: string;\n title?: string;\n description?: string;\n tags: string[];\n type: ResourceType;\n lifecycle: string;\n owner?: string;\n sourceLocation?: string;\n frameworks: string[];\n /**\n * True when an active deployment allow-list (`devAiHub.frameworks.allowed`)\n * left this resource with no frameworks — either it removed the ones the\n * author declared, or the allow-list itself is empty. Lets the UI tell\n * \"author declared nothing\" (`frameworks: []`, show neutral install\n * defaults) apart from \"the deployment suppressed them\" (hide generated\n * install paths and launchers; Copy/Download still work).\n */\n frameworksRestricted?: boolean;\n /**\n * The framework set that install-path and launcher generation must be\n * scoped to, when it differs from `frameworks`. Only set for a resource\n * that declared no frameworks (which otherwise means \"every host\") under an\n * active allow-list: it holds the allow-list itself, so a bare resource\n * cannot produce launchers for tools the deployment disallowed. Kept\n * separate from `frameworks` so this inferred set never renders as a\n * compatibility badge the author never claimed.\n */\n installFrameworks?: string[];\n version?: string;\n kind: string;\n /**\n * Entity refs this container declares as its contents — a `marketplace`'s\n * `spec.plugins`, a `plugin`'s `spec.skills`; empty for leaf types. Filtered\n * to the caller's visible set and to the child types the container renders\n * (ADR-0015). The frontend resolves each ref against the summaries it holds.\n */\n children: string[];\n /**\n * Entity refs of the containers that declare this resource — the in-memory\n * inverse of `children`, built over the same caller-visible catalog read\n * (ADR-0015). A resource can belong to several containers.\n */\n parents: string[];\n /** Count of `children` (their declared, caller-visible members). */\n childCount?: number;\n helpText?: string;\n annotations: Record<string, string>;\n}\n\nexport interface ResourceListResponse {\n items: ResourceSummary[];\n}\n\n/**\n * The shape of a resource's body (CONTEXT.md: bodies are type-shaped, not\n * uniformly markdown). Drives detail-panel rendering: markdown is rendered,\n * json is pretty-printed and syntax-highlighted (ADR-0014). `plugin` and\n * `marketplace` bodies are the real Claude Code `plugin.json` /\n * `marketplace.json` manifest — not a hand-authored pointer doc, superseding\n * ADR-0010's markdown-only body for `marketplace`.\n */\nexport type BodyShape = 'markdown' | 'json';\n\nexport function getBodyShape(type: ResourceType): BodyShape {\n return type === 'mcp-config' || type === 'plugin' || type === 'marketplace'\n ? 'json'\n : 'markdown';\n}\n\n/**\n * Whether the detail panel shows a \"Content\" section for this type.\n *\n * Suppressed for exactly the JSON-bodied types (`getBodyShape` === 'json'):\n * `plugin` and `marketplace` are containers whose value is the relationship\n * graph rather than the manifest, and an `mcp-config`'s body is a settings\n * fragment to merge — in all three the raw JSON buries the panel and is\n * better reached through Copy, Download or the install dialog, which is\n * where it is actionable. The markdown types keep their rendered body.\n */\nexport function showsContentSection(type: ResourceType): boolean {\n return getBodyShape(type) !== 'json';\n}\n\n/**\n * Whether downloading the body delivers the artifact itself. True for every\n * type: `plugin`/`marketplace` bodies are now the real manifest JSON, so a\n * download delivers that file itself rather than a non-actionable pointer\n * doc (ADR-0014, superseding ADR-0009's amendment and ADR-0010 on this\n * point).\n */\nexport function hasDownloadableArtifact(_type: ResourceType): boolean {\n return true;\n}\n\n/**\n * Whether copying the body to the clipboard is a meaningful install action.\n * True for every type: `marketplace`'s body is now the real manifest JSON,\n * not an instructions doc, so copying it is no longer a misrepresentation\n * (ADR-0014, superseding ADR-0010 on this point).\n */\nexport function hasCopyableBody(_type: ResourceType): boolean {\n return true;\n}\n\n/**\n * How a body reaches its install path.\n *\n * `drop-in` — the body becomes the file (or directory) at `path`, which is\n * the resource's own; writing it touches nothing else.\n *\n * `merge` — `path` is a shared settings file the user already owns, and the\n * body is a fragment to merge into it. The distinction is not cosmetic:\n * following a `merge` target as if it were a `drop-in` overwrites the user's\n * existing configuration, so the UI must never present the two identically.\n */\nexport type InstallMode = 'drop-in' | 'merge';\n\nexport interface ResourceInstallTarget {\n /** Workspace-relative path. */\n path: string;\n mode: InstallMode;\n}\n\n/**\n * The concrete framework tokens a body can be installed into — `all` is a\n * wildcard over these, never a destination itself.\n */\nexport const INSTALLABLE_FRAMEWORKS = [\n 'claude-code',\n 'github-copilot',\n 'google-gemini',\n 'cursor',\n 'opencode',\n] as const;\n\n/**\n * Convention table: (type, framework) → where the body goes and how.\n * A missing entry means the pair has no filesystem convention — `plugin` and\n * `marketplace` bodies are pointers that install through their framework\n * (ADR-0009, ADR-0010), so they carry install commands rather than paths.\n */\nconst INSTALL_PATHS: Record<\n ResourceType,\n Record<string, { mode: InstallMode; path: (name: string) => string }>\n> = {\n // Every host reads a skill as a self-contained directory. Copilot also\n // picks up `.claude/skills`, but each tool's own path is what we recommend;\n // `.agents/skills` is the cross-tool alias Copilot and Gemini both honour,\n // which makes it the right answer for an unrecognised framework.\n skill: {\n 'claude-code': { mode: 'drop-in', path: name => `.claude/skills/${name}/` },\n 'github-copilot': {\n mode: 'drop-in',\n path: name => `.github/skills/${name}/`,\n },\n 'google-gemini': {\n mode: 'drop-in',\n path: name => `.gemini/skills/${name}/`,\n },\n cursor: { mode: 'drop-in', path: name => `.cursor/skills/${name}/` },\n opencode: { mode: 'drop-in', path: name => `.opencode/skills/${name}/` },\n default: { mode: 'drop-in', path: name => `.agents/skills/${name}/` },\n },\n agent: {\n 'claude-code': {\n mode: 'drop-in',\n path: name => `.claude/agents/${name}.md`,\n },\n 'github-copilot': {\n mode: 'drop-in',\n path: name => `.github/agents/${name}.agent.md`,\n },\n 'google-gemini': {\n mode: 'drop-in',\n path: name => `.gemini/agents/${name}.md`,\n },\n cursor: { mode: 'drop-in', path: name => `.cursor/rules/${name}.mdc` },\n opencode: { mode: 'drop-in', path: name => `.opencode/agents/${name}.md` },\n default: { mode: 'drop-in', path: name => `.ai/agents/${name}.md` },\n },\n // All four hosts have a hook system, but only Copilot gives each hook its\n // own file; the rest register hooks inside a shared settings document.\n // OpenCode has no declarative hook config at all — hooks are exclusively\n // JS/TS plugin modules — so it deliberately carries no entry here, the same\n // way it carries no `default`.\n hook: {\n 'claude-code': { mode: 'merge', path: () => `.claude/settings.json` },\n 'github-copilot': {\n mode: 'drop-in',\n path: name => `.github/hooks/${name}.json`,\n },\n 'google-gemini': { mode: 'merge', path: () => `.gemini/settings.json` },\n cursor: { mode: 'merge', path: () => `.cursor/hooks.json` },\n },\n 'mcp-config': {\n 'claude-code': { mode: 'merge', path: () => `.mcp.json` },\n 'github-copilot': { mode: 'merge', path: () => `.vscode/mcp.json` },\n 'google-gemini': { mode: 'merge', path: () => `.gemini/settings.json` },\n cursor: { mode: 'merge', path: () => `.cursor/mcp.json` },\n opencode: { mode: 'merge', path: () => `opencode.json` },\n },\n plugin: {},\n marketplace: {},\n};\n\n/**\n * Where a resource's body installs for one framework, and whether that path\n * is the body's own file or a settings file to merge into. Returns\n * `undefined` when the (type, framework) pair has no filesystem convention.\n */\nexport function getResourceInstallTarget(\n type: ResourceType,\n framework: string,\n name: string,\n): ResourceInstallTarget | undefined {\n const conventions = INSTALL_PATHS[type];\n const entry =\n conventions[normalizeFramework(framework)] ?? conventions.default;\n return entry ? { path: entry.path(name), mode: entry.mode } : undefined;\n}\n\n/**\n * The frameworks to show install paths for. An empty list means the resource\n * declared no compatibility and gets the neutral `default` convention; `all`\n * is a wildcard and expands to every installable host, so it never collapses\n * to a single row — or, for types with no `default`, to no rows at all.\n */\nexport function expandInstallFrameworks(frameworks: string[]): string[] {\n const normalized = dedupe(frameworks.map(normalizeFramework));\n if (normalized.length === 0) {\n return ['default'];\n }\n if (normalized.includes('all')) {\n return [...INSTALLABLE_FRAMEWORKS];\n }\n return normalized;\n}\n\n/*\n * Marketplace journey helpers (ADR-0010). A marketplace installs in two\n * steps — register the catalog with the AI tool, then install plugins from\n * it. Both Claude Code and Copilot CLI read the same\n * `.claude-plugin/marketplace.json` format and address the repo as\n * `owner/repo`; the plugin derives that slug from the mandatory\n * `source-location` (the producer contract requires the body doc to live\n * inside the marketplace repo). No derivation → the UI falls back to the\n * rendered body, which stays canonical.\n */\n\n/** Frameworks with a marketplace-add concept (Cursor/Gemini have none). */\nexport const MARKETPLACE_CAPABLE_FRAMEWORKS = [\n 'claude-code',\n 'github-copilot',\n] as const;\n\n/**\n * Narrow a resource's declared frameworks to those a given journey can\n * actually launch. A deep link is a claim about compatibility: offering\n * \"Install in Claude\" for a resource that never declared `claude-code` tells\n * the user something untrue about the resource.\n *\n * `all` and an empty list both mean \"unrestricted\" and expand to every\n * capable host. Anything else is intersected, so a declared framework with no\n * handler (Gemini) — or an unknown token — yields no links rather than\n * silently widening to every host.\n */\nexport function resolveCapableFrameworks(\n declared: string[],\n capable: readonly string[],\n): string[] {\n const normalized = dedupe(declared.map(normalizeFramework));\n if (normalized.length === 0 || normalized.includes('all')) {\n return [...capable];\n }\n return normalized.filter(f => capable.includes(f));\n}\n\n/**\n * Derive the `owner/repo` slug from a marketplace's `source-location`.\n * GitHub URLs only — other hosts return `undefined` (body-only fallback).\n */\nexport function getMarketplaceRepoSlug(\n sourceLocation: string | undefined,\n): string | undefined {\n if (!sourceLocation) {\n return undefined;\n }\n let url: URL;\n try {\n url = new URL(sourceLocation.replace(/^url:/, ''));\n } catch {\n return undefined;\n }\n if (url.hostname !== 'github.com') {\n return undefined;\n }\n const [owner, repo] = url.pathname.split('/').filter(Boolean);\n if (!owner || !repo) {\n return undefined;\n }\n return `${owner}/${repo.replace(/\\.git$/, '')}`;\n}\n\n/**\n * A one-click launcher for an add command: a custom-scheme URL that opens\n * the host app with the command pre-filled in the prompt box. The host\n * never auto-executes it — the user reviews and presses Enter — and an\n * unregistered scheme is a harmless no-op, so these complement the copy\n * button rather than replace it.\n */\nexport interface ResourceDeepLink {\n /** Host application name; render as \"Add in <label>\" / \"Install in <label>\". */\n label: string;\n href: string;\n /**\n * The framework token this launcher installs into, for the `tool` column on\n * the `install` event it records (ADR-0011). Not 1:1 with `label`:\n * `github-copilot` offers both \"VS Code\" and \"VS Code Insiders\".\n *\n * Optional only to keep this published interface additive — every link the\n * generators below build sets it, which `resources.test.ts` pins. A caller\n * reading a generated link can rely on it; one constructing its own shape\n * is not forced to supply it.\n */\n framework?: string;\n}\n\nexport interface MarketplaceAddCommand {\n framework: string;\n command: string;\n deepLinks: ResourceDeepLink[];\n}\n\n/**\n * The copyable marketplace-add command per compatible framework. `all`,\n * unknown-only, or empty framework lists expand to every capable framework;\n * frameworks without a marketplace concept produce no row.\n *\n * Claude Code carries a single deep link on the CLI's documented\n * `claude-cli://open?q=` handler, which opens a Claude Code terminal\n * session with the command pre-filled regardless of the user's editor.\n *\n * Copilot's CLI still has no URI scheme, but Copilot's *other* surface does:\n * VS Code 1.113 ships `vscode://chat-plugin/add-marketplace?ref=`, which\n * accepts a plain or base64 `owner/repo` and always shows a confirmation\n * dialog before registering the marketplace (it also dedupes against the\n * user's existing entries). So the Copilot row keeps its terminal command for\n * CLI users *and* gains editor launchers, mirroring how `mcp-config` already\n * maps `github-copilot` onto the VS Code stable/Insiders pair.\n */\nexport function getMarketplaceAddCommands(\n frameworks: string[],\n repoSlug: string,\n): MarketplaceAddCommand[] {\n const capable = resolveCapableFrameworks(\n frameworks,\n MARKETPLACE_CAPABLE_FRAMEWORKS,\n );\n const commands: MarketplaceAddCommand[] = [];\n for (const framework of capable) {\n if (framework === 'claude-code') {\n const command = `/plugin marketplace add ${repoSlug}`;\n commands.push({\n framework,\n command,\n deepLinks: [\n {\n label: 'Claude',\n href: `claude-cli://open?q=${encodeURIComponent(command)}`,\n framework,\n },\n ],\n });\n } else if (framework === 'github-copilot') {\n const ref = encodeURIComponent(repoSlug);\n commands.push({\n framework,\n command: `copilot plugin marketplace add ${repoSlug}`,\n deepLinks: [\n {\n label: 'VS Code',\n href: `vscode://chat-plugin/add-marketplace?ref=${ref}`,\n framework,\n },\n {\n label: 'VS Code Insiders',\n href: `vscode-insiders://chat-plugin/add-marketplace?ref=${ref}`,\n framework,\n },\n ],\n });\n }\n }\n return commands;\n}\n\n/** The raw-file URL for a GitHub blob `source-location`; else `undefined`. */\nfunction getRawGithubFileUrl(\n sourceLocation: string | undefined,\n): string | undefined {\n if (!sourceLocation) {\n return undefined;\n }\n let url: URL;\n try {\n url = new URL(sourceLocation.replace(/^url:/, ''));\n } catch {\n return undefined;\n }\n if (url.hostname !== 'github.com') {\n return undefined;\n }\n const [owner, repo, marker, ref, ...path] = url.pathname\n .split('/')\n .filter(Boolean);\n if (!owner || !repo || marker !== 'blob' || !ref || path.length === 0) {\n return undefined;\n }\n return `https://raw.githubusercontent.com/${owner}/${repo}/${ref}/${path.join(\n '/',\n )}`;\n}\n\n/**\n * A launcher that opens an agent with an install prompt pre-filled. Neither\n * host auto-executes: the user reads the prompt and presses Enter. Claude Code\n * and Cursor are the two tools exposing a generic prompt URI — Copilot's\n * editor has purpose-built routes but no prompt handler, and Gemini has\n * neither (its `gemini.google.com/app?prompt=` link drives the web app, which\n * cannot write to a local workspace).\n *\n * Cursor truncates a deeplink at the first raw `&`, so the prompt must be\n * percent-encoded — `encodeURIComponent` handles that. Cursor also caps the\n * URL at ~8000 characters; these prompts are a URL plus a path, far under it.\n */\nfunction claudePromptLink(prompt: string): ResourceDeepLink {\n return {\n label: 'Claude',\n href: `claude-cli://open?q=${encodeURIComponent(prompt)}`,\n framework: 'claude-code',\n };\n}\n\nfunction cursorPromptLink(prompt: string): ResourceDeepLink {\n return {\n label: 'Cursor',\n href: `cursor://anysphere.cursor-deeplink/prompt?text=${encodeURIComponent(\n prompt,\n )}`,\n framework: 'cursor',\n };\n}\n\n/**\n * Frameworks with a one-click agent-install handler (Gemini has none).\n * OpenCode's Desktop app does register a real `opencode://` scheme, but every\n * route (`open-project`, `new-session`) requires an absolute local\n * `directory` param a web page cannot supply, so it's excluded here too.\n */\nexport const AGENT_LINK_CAPABLE_FRAMEWORKS = [\n 'claude-code',\n 'github-copilot',\n 'cursor',\n] as const;\n\n/** Hosts reachable by a generic prompt URI — the only route for skill/hook. */\nexport const PROMPT_LINK_CAPABLE_FRAMEWORKS = [\n 'claude-code',\n 'cursor',\n] as const;\n\n/**\n * The plain http(s) URL behind a `source-location`. Unlike\n * `getRawGithubFileUrl` this accepts **directory (`tree`) URLs**, which is what\n * a multi-file `skill` actually carries — a raw-file URL would resolve to\n * `undefined` for exactly the type that most needs a launcher.\n */\nfunction getSourceUrl(sourceLocation: string | undefined): string | undefined {\n if (!sourceLocation) {\n return undefined;\n }\n try {\n const url = new URL(sourceLocation.replace(/^url:/, ''));\n return url.protocol === 'http:' || url.protocol === 'https:'\n ? url.toString()\n : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * One-click launchers for the types with no purpose-built install route —\n * `skill` and `hook`. Both ride the generic prompt handlers, so the prompt\n * names the *host's own* install path and respects its install mode: a `merge`\n * target is asked to be merged into, never overwritten, so a launcher can\n * never cost the user their existing settings.\n *\n * Returns `[]` when the source URL cannot be derived, or for hosts with no\n * prompt route (Copilot, Gemini) — the path list and copy/download remain.\n */\nexport function getPromptInstallLinks(\n type: ResourceType,\n sourceLocation: string | undefined,\n name: string,\n frameworks: string[] = [],\n): ResourceDeepLink[] {\n return getInstallSteps(type, sourceLocation, name, frameworks)\n .map(step => step.link)\n .filter((link): link is ResourceDeepLink => !!link);\n}\n\n/**\n * Everything a single host needs to install a resource: where the body goes,\n * the prompt that puts it there, and a launcher when the host has a URI to\n * launch.\n *\n * `link` is absent for hosts with no prompt route — Copilot and Gemini. That\n * absence is why the step carries `prompt` as text: a host without a URI is\n * not a host without an install path, and the same instruction that a launcher\n * would pre-fill can be pasted into that agent by hand. Every declared\n * framework therefore gets something actionable, not a bare path.\n */\nexport interface ResourceInstallStep {\n framework: string;\n target: ResourceInstallTarget;\n /** The install instruction, ready to run in that host's agent. */\n prompt: string;\n /** One-click launcher, where the host exposes a generic prompt URI. */\n link?: ResourceDeepLink;\n}\n\nexport function getInstallSteps(\n type: ResourceType,\n sourceLocation: string | undefined,\n name: string,\n frameworks: string[] = [],\n): ResourceInstallStep[] {\n const sourceUrl = getSourceUrl(sourceLocation);\n if (!sourceUrl) {\n return [];\n }\n const label = RESOURCE_TYPE_REGISTRY[type].label.toLowerCase();\n const steps: ResourceInstallStep[] = [];\n for (const framework of expandInstallFrameworks(frameworks)) {\n const target = getResourceInstallTarget(type, framework, name);\n if (!target) {\n continue;\n }\n const prompt =\n target.mode === 'merge'\n ? `Install the \"${name}\" ${label}: fetch ${sourceUrl} and merge it into ${target.path}, keeping my existing settings intact.`\n : `Install the \"${name}\" ${label}: fetch ${sourceUrl} and save it to ${target.path}.`;\n let link: ResourceDeepLink | undefined;\n if (framework === 'claude-code') {\n link = claudePromptLink(prompt);\n } else if (framework === 'cursor') {\n link = cursorPromptLink(prompt);\n }\n steps.push({ framework, target, prompt, link });\n }\n return steps;\n}\n\n/** Frameworks with a one-click MCP-install handler (Gemini has none). */\nexport const MCP_LINK_CAPABLE_FRAMEWORKS = [\n 'claude-code',\n 'github-copilot',\n 'cursor',\n] as const;\n\n/**\n * One-click install links for an `agent` resource, restricted to the\n * resource's own compatible frameworks. VS Code stable and Insiders use the\n * native `chat-agent/install?url=` handler (the mechanism behind\n * awesome-copilot's Install buttons) and are Copilot's hosts, so they follow\n * `github-copilot`: VS Code downloads the file at `url` and asks the user\n * where to save it. Claude Code uses the `claude-cli://open?q=` handler with\n * an install prompt pre-filled to the convention path — reviewed and sent by\n * the user, never auto-executed. All derive from the GitHub blob URL in\n * `source-location`; anything else returns `[]` (copy/download fallback).\n */\nexport function getAgentInstallLinks(\n sourceLocation: string | undefined,\n name: string,\n frameworks: string[] = [],\n): ResourceDeepLink[] {\n const rawUrl = getRawGithubFileUrl(sourceLocation);\n if (!rawUrl) {\n return [];\n }\n const capable = resolveCapableFrameworks(\n frameworks,\n AGENT_LINK_CAPABLE_FRAMEWORKS,\n );\n const encodedRawUrl = encodeURIComponent(rawUrl);\n const installPrompt = (framework: string) => {\n const target = getResourceInstallTarget('agent', framework, name);\n return `Install this agent: fetch ${rawUrl} and save it to ${target?.path}`;\n };\n const links: ResourceDeepLink[] = [];\n for (const framework of capable) {\n if (framework === 'claude-code') {\n links.push(claudePromptLink(installPrompt('claude-code')));\n } else if (framework === 'cursor') {\n links.push(cursorPromptLink(installPrompt('cursor')));\n } else if (framework === 'github-copilot') {\n links.push({\n label: 'VS Code',\n href: `vscode:chat-agent/install?url=${encodedRawUrl}`,\n framework,\n });\n links.push({\n label: 'VS Code Insiders',\n href: `vscode-insiders:chat-agent/install?url=${encodedRawUrl}`,\n framework,\n });\n }\n }\n return links;\n}\n\n/**\n * One-click install links for an `mcp-config` resource, derived from its body —\n * the canonical `.mcp.json` snippet (spec §3.4). VS Code carries a native\n * `vscode:mcp/install?{json}` handler (Insiders scheme twin), Cursor a\n * documented `cursor://anysphere.cursor-deeplink/mcp/install` one, and\n * Claude Code gets a `claude-cli://open?q=` prompt around\n * `claude mcp add-json` — pre-filled, reviewed, never auto-executed.\n * Hosts follow the resource's own compatible frameworks: `all`/empty expand\n * to every capable host, anything else is intersected, so an mcp-config\n * declaring only Gemini (no handler) gets no links rather than every host's.\n * A missing, unparseable, or multi-server body returns `[]` (copy fallback) —\n * the body stays canonical, links are conveniences derived from it.\n */\nexport function getMcpInstallLinks(\n frameworks: string[],\n resourceName: string,\n bodyContent: string | undefined,\n): ResourceDeepLink[] {\n if (!bodyContent) {\n return [];\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(bodyContent);\n } catch {\n return [];\n }\n if (typeof parsed !== 'object' || parsed === null) {\n return [];\n }\n\n let serverName = resourceName;\n let config: Record<string, unknown>;\n const servers = (parsed as { mcpServers?: unknown }).mcpServers;\n if (servers !== undefined) {\n if (typeof servers !== 'object' || servers === null) {\n return [];\n }\n const entries = Object.entries(servers as Record<string, unknown>);\n if (\n entries.length !== 1 ||\n typeof entries[0][1] !== 'object' ||\n entries[0][1] === null\n ) {\n return [];\n }\n serverName = entries[0][0];\n config = entries[0][1] as Record<string, unknown>;\n } else if ('command' in parsed || 'url' in parsed) {\n config = parsed as Record<string, unknown>;\n } else {\n return [];\n }\n\n const capable = resolveCapableFrameworks(\n frameworks,\n MCP_LINK_CAPABLE_FRAMEWORKS,\n );\n\n const configJson = JSON.stringify(config);\n const links: ResourceDeepLink[] = [];\n for (const framework of capable) {\n if (framework === 'claude-code') {\n const prompt = encodeURIComponent(\n `Install this MCP config by running: claude mcp add-json ${serverName} '${configJson}'`,\n );\n links.push({\n label: 'Claude',\n href: `claude-cli://open?q=${prompt}`,\n framework,\n });\n } else if (framework === 'github-copilot') {\n const vsConfig = encodeURIComponent(\n JSON.stringify({ name: serverName, ...config }),\n );\n links.push({\n label: 'VS Code',\n href: `vscode:mcp/install?${vsConfig}`,\n framework,\n });\n links.push({\n label: 'VS Code Insiders',\n href: `vscode-insiders:mcp/install?${vsConfig}`,\n framework,\n });\n } else if (framework === 'cursor') {\n try {\n links.push({\n label: 'Cursor',\n href: `cursor://anysphere.cursor-deeplink/mcp/install?name=${encodeURIComponent(\n serverName,\n )}&config=${btoa(configJson)}`,\n framework,\n });\n } catch {\n // btoa rejects non-Latin1 config content — skip the Cursor link.\n }\n }\n }\n return links;\n}\n\n/**\n * Step two of the journey: how to install a plugin from the marketplace.\n * `marketplaceName` is the entity name, which the producer contract requires\n * to equal the `name` in `marketplace.json`.\n */\nexport function getMarketplaceInstallTemplate(marketplaceName: string): string {\n return `/plugin install <plugin>@${marketplaceName}`;\n}\n\n/**\n * The `.claude/settings.json` snippet a team commits so collaborators are\n * prompted to install the marketplace automatically (Claude Code).\n */\nexport function getMarketplaceTeamSnippet(\n marketplaceName: string,\n repoSlug: string,\n): string {\n return JSON.stringify(\n {\n extraKnownMarketplaces: {\n [marketplaceName]: { source: { source: 'github', repo: repoSlug } },\n },\n },\n null,\n 2,\n );\n}\n"],"names":[],"mappings":"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"}
|