@nospt/plugin-dev-ai-hub 1.1.2 → 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.
@@ -0,0 +1,9 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { UNSAFE_LocationContext } from 'react-router-dom';
3
+
4
+ function AppLaunchScope({ children }) {
5
+ return /* @__PURE__ */ jsx(UNSAFE_LocationContext.Provider, { value: null, children });
6
+ }
7
+
8
+ export { AppLaunchScope };
9
+ //# sourceMappingURL=AppLaunchScope.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AppLaunchScope.esm.js","sources":["../../../src/components/AiResourcesPage/AppLaunchScope.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { UNSAFE_LocationContext as LocationContext } from 'react-router-dom';\n\n/**\n * Scope for buttons that launch a local app through a custom-scheme deep link\n * (`vscode:`, `cursor://`, `claude-cli://`).\n *\n * `@backstage/ui` link components resolve every `href` through React Router\n * unless it is `http(s)://`, `//`, `mailto:` or `tel:`, and since\n * `@remix-run/router` 1.23.4 the router treats `vscode:…` as a route-relative\n * path — the button then points at `https://<backstage>/vscode:…`. BUI only\n * resolves when `useInRouterContext()` is true, so hiding the location\n * context here makes it pass the href through untouched; a custom-scheme\n * anchor is never same-origin, so React Aria leaves the click to the browser,\n * which hands it to the OS protocol handler.\n *\n * Nothing inside may rely on routing — wrap app launchers only.\n */\nexport function AppLaunchScope({ children }: { children: ReactNode }) {\n return (\n <LocationContext.Provider value={null as never}>\n {children}\n </LocationContext.Provider>\n );\n}\n"],"names":["LocationContext"],"mappings":";;;AAkBO,SAAS,cAAA,CAAe,EAAE,QAAA,EAAS,EAA4B;AACpE,EAAA,2BACGA,sBAAA,CAAgB,QAAA,EAAhB,EAAyB,KAAA,EAAO,MAC9B,QAAA,EACH,CAAA;AAEJ;;;;"}
@@ -9,6 +9,7 @@ import { getBodyShape, getMarketplaceRepoSlug, getMarketplaceAddCommands, getIns
9
9
  import { devAiHubResourceApiRef } from '../../api/DevAiHubResourceClient.esm.js';
10
10
  import { useTrackTelemetry } from '../../hooks/useTelemetryCounts.esm.js';
11
11
  import { ToolIcon } from '../ToolIcon/ToolIcon.esm.js';
12
+ import { AppLaunchScope } from './AppLaunchScope.esm.js';
12
13
  import { CollapsibleSection } from './CollapsibleSection.esm.js';
13
14
  import { JsonBody } from './JsonBody.esm.js';
14
15
  import { frameworkLabel } from './typeMeta.esm.js';
@@ -258,7 +259,7 @@ function ResourceInstallDialog({
258
259
  "Install ",
259
260
  resource.title ?? resource.name
260
261
  ] }),
261
- /* @__PURE__ */ jsx(DialogBody, { children: /* @__PURE__ */ jsxs("div", { className: styles.content, children: [
262
+ /* @__PURE__ */ jsx(DialogBody, { children: /* @__PURE__ */ jsx(AppLaunchScope, { children: /* @__PURE__ */ jsxs("div", { className: styles.content, children: [
262
263
  /* @__PURE__ */ jsx(Text, { variant: "body-small", as: "p", children: frameworksRestricted ? "No install path is available \u2014 none of the tools this resource supports are enabled for this Backstage. You can still copy or download the content below." : TYPE_HINTS[resource.type] }),
263
264
  body && shape === "json" && /* @__PURE__ */ jsx(CollapsibleSection, { label: "Content", children: /* @__PURE__ */ jsx(JsonBody, { content: body.content, className: styles.codeBlock }) }),
264
265
  hasMarketplaceJourney && marketplaceRepoSlug && /* @__PURE__ */ jsx(
@@ -299,7 +300,7 @@ function ResourceInstallDialog({
299
300
  );
300
301
  })() : (
301
302
  /* No prompt URI for this host — the same instruction,
302
- delivered by clipboard so the row is still actionable. */
303
+ delivered by clipboard so the row is still actionable. */
303
304
  /* @__PURE__ */ jsx(
304
305
  CopyPromptButton,
305
306
  {
@@ -374,7 +375,7 @@ function ResourceInstallDialog({
374
375
  )
375
376
  ] }),
376
377
  downloadError && /* @__PURE__ */ jsx(Text, { variant: "body-x-small", as: "p", children: "Download failed \u2014 the source may be unreachable. Try again or use \u201CView source\u201D." })
377
- ] }) })
378
+ ] }) }) })
378
379
  ]
379
380
  }
380
381
  );
@@ -1 +1 @@
1
- {"version":3,"file":"ResourceInstallDialog.esm.js","sources":["../../../src/components/AiResourcesPage/ResourceInstallDialog.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport ReactMarkdown from 'react-markdown';\nimport {\n Button,\n ButtonIcon,\n ButtonLink,\n Dialog,\n DialogBody,\n DialogHeader,\n Text,\n} from '@backstage/ui';\nimport {\n RiCheckLine,\n RiDownloadLine,\n RiExternalLinkLine,\n RiFileCopyLine,\n} from '@remixicon/react';\nimport { siClaude } from 'simple-icons';\nimport { useApi } from '@backstage/core-plugin-api';\nimport {\n expandInstallFrameworks,\n getAgentInstallLinks,\n getBodyShape,\n getMarketplaceAddCommands,\n getMcpInstallLinks,\n getMarketplaceInstallTemplate,\n getMarketplaceRepoSlug,\n getMarketplaceTeamSnippet,\n getInstallSteps,\n getResourceInstallTarget,\n hasCopyableBody,\n hasDownloadableArtifact,\n type FrameworkToken,\n type MarketplaceAddCommand,\n type ResourceInstallTarget,\n type ResourceSummary,\n} from '@nospt/plugin-dev-ai-hub-common';\nimport {\n devAiHubResourceApiRef,\n type ResourceBody,\n} from '../../api/DevAiHubResourceClient';\nimport { useTrackTelemetry } from '../../hooks/useTelemetryCounts';\nimport { ToolIcon } from '../ToolIcon';\nimport { CollapsibleSection } from './CollapsibleSection';\nimport { JsonBody } from './JsonBody';\nimport { frameworkLabel } from './typeMeta';\nimport styles from './ResourceInstallDialog.module.css';\n\ninterface ResourceInstallDialogProps {\n resource: ResourceSummary;\n body?: ResourceBody;\n /**\n * Whether the body is still being fetched. The mcp-config launchers are\n * derived from it, so the dialog-open telemetry fallback below must not\n * conclude \"no launcher\" while it is still in flight.\n */\n bodyLoading?: boolean;\n isOpen: boolean;\n onOpenChange: (open: boolean) => void;\n}\n\nconst TYPE_HINTS: Record<ResourceSummary['type'], string> = {\n skill:\n 'Download the skill (multi-file skills arrive as one zip) and extract it into the path for your framework.',\n agent:\n 'Download or copy the agent definition into the path for your framework.',\n hook: 'Register the hook definition at the path for your framework — most hosts merge it into a shared settings file.',\n 'mcp-config': 'Add this server entry to your MCP configuration file.',\n plugin:\n 'This plugin installs through its framework — follow the instructions below.',\n marketplace:\n 'Register this marketplace with your AI tool once, then install any of its plugins from it.',\n};\n\n/** The VS Code chevron mark (devicon's mono path), for a button's iconStart slot. */\nfunction VsCodeIcon() {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 128 128\"\n width={16}\n height={16}\n fill=\"currentColor\"\n aria-hidden\n >\n <path\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M90.767 127.126a7.968 7.968 0 0 0 6.35-.244l26.353-12.681a8 8 0 0 0 4.53-7.209V21.009a8 8 0 0 0-4.53-7.21L97.117 1.12a7.97 7.97 0 0 0-9.093 1.548l-50.45 46.026L15.6 32.013a5.328 5.328 0 0 0-6.807.302l-7.048 6.411a5.335 5.335 0 0 0-.006 7.888L20.796 64 1.74 81.387a5.336 5.336 0 0 0 .006 7.887l7.048 6.411a5.327 5.327 0 0 0 6.807.303l21.974-16.68 50.45 46.025a7.96 7.96 0 0 0 2.743 1.793Zm5.252-92.183L57.74 64l38.28 29.058V34.943Z\"\n />\n </svg>\n );\n}\n\n/** The Claude starburst, sized for a button's iconStart slot. */\nfunction ClaudeIcon() {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n width={16}\n height={16}\n fill=\"currentColor\"\n aria-hidden\n >\n <path d={siClaude.path} />\n </svg>\n );\n}\n\n/**\n * The one-click install links for the types with a *native* install route,\n * rendered once in the actions row. `skill` and `hook` are absent on purpose:\n * their launchers are per-host and live in their own rows, so returning them\n * here too would render every button twice.\n */\nfunction getInstallLinks(\n resource: ResourceSummary,\n frameworks: string[],\n body?: ResourceBody,\n) {\n if (resource.type === 'agent') {\n return getAgentInstallLinks(\n resource.sourceLocation,\n resource.name,\n frameworks,\n );\n }\n if (resource.type === 'mcp-config') {\n return getMcpInstallLinks(frameworks, resource.name, body?.content);\n }\n return [];\n}\n\n/** Brand styling for the known deep-link hosts, keyed by link label. */\nfunction launchBrand(label: string): {\n className?: string;\n icon: React.ReactElement;\n} {\n switch (label) {\n case 'Claude':\n return { className: styles.claudeLaunch, icon: <ClaudeIcon /> };\n case 'VS Code':\n return { className: styles.vscodeLaunch, icon: <VsCodeIcon /> };\n case 'VS Code Insiders':\n return { className: styles.insidersLaunch, icon: <VsCodeIcon /> };\n case 'Cursor':\n return {\n className: styles.cursorLaunch,\n icon: <ToolIcon tool=\"cursor\" branded={false} size={16} />,\n };\n default:\n return { icon: <RiExternalLinkLine /> };\n }\n}\n\n/**\n * Icon-only copy button for a single generated command (marketplace journey\n * rows); flashes a check mark as the copied feedback.\n */\nfunction CopyCommandButton({ text }: { text: string }) {\n const [copied, setCopied] = useState(false);\n return (\n <ButtonIcon\n size=\"small\"\n variant=\"tertiary\"\n icon={copied ? <RiCheckLine /> : <RiFileCopyLine />}\n aria-label={copied ? 'Copied' : 'Copy command'}\n onPress={async () => {\n await navigator.clipboard.writeText(text);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }}\n />\n );\n}\n\n/**\n * Clipboard fallback for a host with no prompt URI (Copilot, Gemini). It\n * carries the identical instruction a launcher would pre-fill, so the only\n * difference is the delivery — the user pastes it into their own agent.\n */\nfunction CopyPromptButton({ text, label }: { text: string; label: string }) {\n const [copied, setCopied] = useState(false);\n return (\n <Button\n size=\"small\"\n variant=\"secondary\"\n iconStart={copied ? <RiCheckLine /> : <RiFileCopyLine />}\n onPress={async () => {\n await navigator.clipboard.writeText(text);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }}\n >\n {copied ? 'Copied!' : `Copy prompt for ${label}`}\n </Button>\n );\n}\n\n/**\n * The two-step marketplace journey (ADR-0010): ① register the catalog with\n * the AI tool, ② install plugins from it — plus a team-distribution snippet.\n * Whether this can render at all is decided by the caller, which needs the\n * same answer to know if the body doc is still required as a fallback.\n */\nfunction MarketplaceJourney({\n resource,\n repoSlug,\n addCommands,\n onLaunch,\n}: {\n resource: ResourceSummary;\n repoSlug: string;\n addCommands: MarketplaceAddCommand[];\n /**\n * Records the `install`, with the launched host as `tool` (ADR-0011).\n * `framework` is optional on the published `ResourceDeepLink`; a generated\n * link always carries one, and an event without a `tool` is still a\n * truthful install.\n */\n onLaunch: (framework: string | undefined) => void;\n}) {\n return (\n <div className={styles.journey}>\n <Text variant=\"body-small\" as=\"p\" className={styles.stepTitle}>\n 1. Add the marketplace to your AI tool\n </Text>\n <dl className={styles.commandList}>\n {addCommands.map(({ framework, command, deepLinks }) => (\n <div key={framework} className={styles.commandRow}>\n <dt className={styles.commandLabel}>\n <ToolIcon tool={framework as FrameworkToken} size={16} />\n {frameworkLabel(framework)}\n </dt>\n <dd className={styles.commandCell}>\n <code>{command}</code>\n <CopyCommandButton text={command} />\n </dd>\n {deepLinks.length > 0 && (\n <dd className={styles.deepLinks}>\n {deepLinks.map(link => {\n const brand = launchBrand(link.label);\n return (\n <ButtonLink\n key={link.label}\n size=\"small\"\n variant=\"secondary\"\n className={brand.className}\n iconStart={brand.icon}\n href={link.href}\n onPress={() => onLaunch(link.framework)}\n >\n Add in {link.label}\n </ButtonLink>\n );\n })}\n </dd>\n )}\n </div>\n ))}\n </dl>\n\n <Text variant=\"body-small\" as=\"p\" className={styles.stepTitle}>\n 2. Install plugins from it\n </Text>\n <div className={styles.commandCell}>\n <code>{getMarketplaceInstallTemplate(resource.name)}</code>\n </div>\n\n <details className={styles.teamSection}>\n <summary>For teams: auto-install via project settings</summary>\n <Text variant=\"body-x-small\" as=\"p\">\n Commit this to your repository’s <code>.claude/settings.json</code>{' '}\n and collaborators are prompted to install the marketplace when they\n trust the folder.\n </Text>\n <pre className={styles.codeBlock}>\n <code>{getMarketplaceTeamSnippet(resource.name, repoSlug)}</code>\n </pre>\n <CopyCommandButton\n text={getMarketplaceTeamSnippet(resource.name, repoSlug)}\n />\n </details>\n </div>\n );\n}\n\n/**\n * Install guidance wired to the body resolver (issue #30): copy the body,\n * download the artifact (file or zip, ADR-0009), and per-framework install\n * paths. The body is canonical — nothing here is reconstructed from\n * annotations (CONTEXT.md: body).\n */\nexport function ResourceInstallDialog({\n resource,\n body,\n bodyLoading = false,\n isOpen,\n onOpenChange,\n}: ResourceInstallDialogProps) {\n const api = useApi(devAiHubResourceApiRef);\n const track = useTrackTelemetry();\n const [copied, setCopied] = useState(false);\n const [downloadError, setDownloadError] = useState(false);\n\n const shape = getBodyShape(resource.type);\n // The deployment allow-list removed every framework this resource declared.\n // An empty `frameworks` would otherwise fall back to the neutral `default`\n // path and every native launcher, re-exposing what the allow-list suppressed\n // — so skip all generated install content and say why. Copy/Download stay.\n const frameworksRestricted = !!resource.frameworksRestricted;\n // What install-path / launcher generation is scoped to: `installFrameworks`\n // when the backend inferred a scoped set (a bare resource under an active\n // allow-list), otherwise the declared-and-filtered `frameworks`. Badges\n // still read `frameworks` only.\n const installFrameworks = resource.installFrameworks ?? resource.frameworks;\n const installLinks = frameworksRestricted\n ? []\n : getInstallLinks(resource, installFrameworks, body);\n\n // A marketplace body doc repeats the generated journey almost verbatim —\n // same two steps, same commands — so rendering both doubles the dialog's\n // height to say one thing twice. The journey wins when it can be derived;\n // the body stays as ADR-0010's fallback for when the slug cannot be.\n const marketplaceRepoSlug =\n resource.type === 'marketplace'\n ? getMarketplaceRepoSlug(resource.sourceLocation)\n : undefined;\n const marketplaceAddCommands =\n marketplaceRepoSlug && !frameworksRestricted\n ? getMarketplaceAddCommands(installFrameworks, marketplaceRepoSlug)\n : [];\n const hasMarketplaceJourney = marketplaceAddCommands.length > 0;\n // plugin/marketplace bodies are the real manifest JSON (ADR-0014), so this\n // markdown fallback can only fire if shape is still 'markdown' — kept for\n // the (currently unreachable) case bodyShape ever becomes content-driven.\n const showBodyDoc =\n shape === 'markdown' &&\n (resource.type === 'plugin' ||\n (resource.type === 'marketplace' && !hasMarketplaceJourney));\n\n // skill/hook install by instructing the agent, so each host gets a row that\n // is actionable on its own: a launcher where the host has a prompt URI, a\n // copyable prompt where it does not. Other types keep the plain path list —\n // their launchers are native routes, rendered once in the actions row.\n const usesPromptInstall =\n resource.type === 'skill' || resource.type === 'hook';\n const installSteps =\n usesPromptInstall && !frameworksRestricted\n ? getInstallSteps(\n resource.type,\n resource.sourceLocation,\n resource.name,\n installFrameworks,\n )\n : [];\n const pathRows = frameworksRestricted\n ? []\n : expandInstallFrameworks(installFrameworks)\n .map(f => ({\n framework: f,\n target: getResourceInstallTarget(resource.type, f, resource.name),\n }))\n .filter(\n (row): row is { framework: string; target: ResourceInstallTarget } =>\n !!row.target,\n );\n const hasMergeTarget = (\n installSteps.length > 0\n ? installSteps.map(s => s.target)\n : pathRows.map(r => r.target)\n ).some(t => t.mode === 'merge');\n\n /**\n * Whether *this* dialog actually produced a launch button. Deliberately\n * per-resource, not per-type: a skill declaring only Copilot/Gemini, an\n * agent with no resolvable source URL, an unparseable or multi-server MCP\n * body, and a marketplace with no derivable repo slug all render a path and\n * no button, and ADR-0011 requires those to fall back to the dialog-open\n * signal rather than record nothing at all.\n */\n const hasLauncher =\n installLinks.length > 0 ||\n installSteps.some(step => step.link) ||\n marketplaceAddCommands.some(command => command.deepLinks.length > 0);\n\n /**\n * `mcp-config` alone derives its launchers from the body\n * (`getMcpInstallLinks`); every other type builds them from\n * `sourceLocation` and the declared frameworks. So only it may wait for the\n * fetch — for the rest the body is only ever Copy/Download material, and\n * waiting on it would drop the event entirely when the dialog is closed\n * before an unrelated request settles.\n */\n const awaitingMcpBody = resource.type === 'mcp-config' && bodyLoading;\n\n /**\n * The fallback arm of ADR-0011's \"record `install` at the most specific\n * point available\": with no launcher to wait for, opening the dialog is\n * that point.\n *\n * Skipped when the deployment allow-list left the resource with no install\n * path at all (post-dates this ADR): nothing is installable, so an\n * `install` event would claim something that cannot have happened.\n */\n useEffect(() => {\n if (!isOpen || frameworksRestricted || hasLauncher || awaitingMcpBody) {\n return;\n }\n track(resource.entityRef, 'install');\n // `awaitingMcpBody`, not the raw `bodyLoading`: for every other type the\n // body settling is unrelated to launcher availability, and depending on\n // it would re-run this effect after the event had already been recorded\n // — one install, counted twice.\n }, [\n isOpen,\n awaitingMcpBody,\n frameworksRestricted,\n hasLauncher,\n resource.entityRef,\n track,\n ]);\n\n const handleCopy = async () => {\n if (!body) return;\n await navigator.clipboard.writeText(body.content);\n track(resource.entityRef, 'copy');\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n };\n\n const handleDownload = async () => {\n setDownloadError(false);\n try {\n await api.downloadEntityBody(resource.entityRef);\n track(resource.entityRef, 'download');\n } catch {\n setDownloadError(true);\n }\n };\n\n return (\n <Dialog\n isOpen={isOpen}\n onOpenChange={onOpenChange}\n /* Size to the widest command line so generated commands stay unwrapped,\n clamped so prose-heavy bodies can't balloon the dialog. The height cap\n keeps a long fallback body scrolling inside the dialog rather than\n running off-screen — the install actions must always stay reachable. */\n style={{\n width: 'fit-content',\n minWidth: 'min(480px, calc(100vw - 3rem))',\n maxWidth: 'min(760px, calc(100vw - 3rem))',\n maxHeight: 'min(80vh, calc(100vh - 4rem))',\n }}\n >\n <DialogHeader>Install {resource.title ?? resource.name}</DialogHeader>\n <DialogBody>\n <div className={styles.content}>\n <Text variant=\"body-small\" as=\"p\">\n {frameworksRestricted\n ? 'No install path is available — none of the tools this resource ' +\n 'supports are enabled for this Backstage. You can still copy or ' +\n 'download the content below.'\n : TYPE_HINTS[resource.type]}\n </Text>\n\n {body && shape === 'json' && (\n <CollapsibleSection label=\"Content\">\n <JsonBody content={body.content} className={styles.codeBlock} />\n </CollapsibleSection>\n )}\n\n {hasMarketplaceJourney && marketplaceRepoSlug && (\n <MarketplaceJourney\n resource={resource}\n repoSlug={marketplaceRepoSlug}\n addCommands={marketplaceAddCommands}\n onLaunch={framework =>\n track(resource.entityRef, 'install', framework)\n }\n />\n )}\n\n {body && showBodyDoc && (\n <div className={styles.markdown}>\n <ReactMarkdown>{body.content}</ReactMarkdown>\n </div>\n )}\n\n {installSteps.length > 0 && (\n <dl className={styles.commandList}>\n {installSteps.map(({ framework, target, prompt, link }) => (\n <div key={framework} className={styles.commandRow}>\n <dt className={styles.commandLabel}>\n <ToolIcon tool={framework as FrameworkToken} size={16} />\n {frameworkLabel(framework)}\n </dt>\n <dd className={styles.pathRow}>\n <code>{target.path}</code>\n {target.mode === 'merge' && (\n <span className={styles.mergeBadge}>merge into</span>\n )}\n </dd>\n <dd className={styles.deepLinks}>\n {link ? (\n (() => {\n const brand = launchBrand(link.label);\n return (\n <ButtonLink\n size=\"small\"\n variant=\"secondary\"\n className={brand.className}\n iconStart={brand.icon}\n href={link.href}\n onPress={() =>\n track(resource.entityRef, 'install', framework)\n }\n >\n Install in {link.label}\n </ButtonLink>\n );\n })()\n ) : (\n /* No prompt URI for this host — the same instruction,\n delivered by clipboard so the row is still actionable. */\n <CopyPromptButton\n text={prompt}\n label={frameworkLabel(framework)}\n />\n )}\n </dd>\n </div>\n ))}\n </dl>\n )}\n\n {installSteps.length === 0 && pathRows.length > 0 && (\n <>\n <dl className={styles.pathList}>\n {pathRows.map(({ framework, target }) => (\n <div key={framework} className={styles.pathRow}>\n <dt>\n {framework === 'default'\n ? 'Any framework'\n : frameworkLabel(framework)}\n </dt>\n <dd>\n <code>{target.path}</code>\n {/* A merge target is a file the user already owns —\n flagged inline so the path is never mistaken for a\n drop-in destination to overwrite. */}\n {target.mode === 'merge' && (\n <span className={styles.mergeBadge}>merge into</span>\n )}\n </dd>\n </div>\n ))}\n </dl>\n {hasMergeTarget && (\n <Text\n variant=\"body-x-small\"\n as=\"p\"\n className={styles.mergeNote}\n >\n Paths marked <strong>merge into</strong> are shared\n configuration files. Add this entry to the existing file —\n replacing it discards your other settings.\n </Text>\n )}\n </>\n )}\n\n <div className={styles.actions}>\n {installLinks.map(link => {\n const brand = launchBrand(link.label);\n return (\n <ButtonLink\n key={link.label}\n size=\"small\"\n variant=\"secondary\"\n className={brand.className}\n iconStart={brand.icon}\n href={link.href}\n onPress={() =>\n track(resource.entityRef, 'install', link.framework)\n }\n >\n Install in {link.label}\n </ButtonLink>\n );\n })}\n {hasCopyableBody(resource.type) && (\n <Button\n size=\"small\"\n variant=\"secondary\"\n iconStart={<RiFileCopyLine />}\n isDisabled={!body}\n onPress={handleCopy}\n >\n {copied ? 'Copied!' : 'Copy content'}\n </Button>\n )}\n {hasDownloadableArtifact(resource.type) && (\n <Button\n size=\"small\"\n variant=\"primary\"\n iconStart={<RiDownloadLine />}\n onPress={handleDownload}\n >\n Download\n </Button>\n )}\n </div>\n {downloadError && (\n <Text variant=\"body-x-small\" as=\"p\">\n Download failed — the source may be unreachable. Try again or use\n “View source”.\n </Text>\n )}\n </div>\n </DialogBody>\n </Dialog>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ResourceInstallDialog.esm.js","sources":["../../../src/components/AiResourcesPage/ResourceInstallDialog.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport ReactMarkdown from 'react-markdown';\nimport {\n Button,\n ButtonIcon,\n ButtonLink,\n Dialog,\n DialogBody,\n DialogHeader,\n Text,\n} from '@backstage/ui';\nimport {\n RiCheckLine,\n RiDownloadLine,\n RiExternalLinkLine,\n RiFileCopyLine,\n} from '@remixicon/react';\nimport { siClaude } from 'simple-icons';\nimport { useApi } from '@backstage/core-plugin-api';\nimport {\n expandInstallFrameworks,\n getAgentInstallLinks,\n getBodyShape,\n getMarketplaceAddCommands,\n getMcpInstallLinks,\n getMarketplaceInstallTemplate,\n getMarketplaceRepoSlug,\n getMarketplaceTeamSnippet,\n getInstallSteps,\n getResourceInstallTarget,\n hasCopyableBody,\n hasDownloadableArtifact,\n type FrameworkToken,\n type MarketplaceAddCommand,\n type ResourceInstallTarget,\n type ResourceSummary,\n} from '@nospt/plugin-dev-ai-hub-common';\nimport {\n devAiHubResourceApiRef,\n type ResourceBody,\n} from '../../api/DevAiHubResourceClient';\nimport { useTrackTelemetry } from '../../hooks/useTelemetryCounts';\nimport { ToolIcon } from '../ToolIcon';\nimport { AppLaunchScope } from './AppLaunchScope';\nimport { CollapsibleSection } from './CollapsibleSection';\nimport { JsonBody } from './JsonBody';\nimport { frameworkLabel } from './typeMeta';\nimport styles from './ResourceInstallDialog.module.css';\n\ninterface ResourceInstallDialogProps {\n resource: ResourceSummary;\n body?: ResourceBody;\n /**\n * Whether the body is still being fetched. The mcp-config launchers are\n * derived from it, so the dialog-open telemetry fallback below must not\n * conclude \"no launcher\" while it is still in flight.\n */\n bodyLoading?: boolean;\n isOpen: boolean;\n onOpenChange: (open: boolean) => void;\n}\n\nconst TYPE_HINTS: Record<ResourceSummary['type'], string> = {\n skill:\n 'Download the skill (multi-file skills arrive as one zip) and extract it into the path for your framework.',\n agent:\n 'Download or copy the agent definition into the path for your framework.',\n hook: 'Register the hook definition at the path for your framework — most hosts merge it into a shared settings file.',\n 'mcp-config': 'Add this server entry to your MCP configuration file.',\n plugin:\n 'This plugin installs through its framework — follow the instructions below.',\n marketplace:\n 'Register this marketplace with your AI tool once, then install any of its plugins from it.',\n};\n\n/** The VS Code chevron mark (devicon's mono path), for a button's iconStart slot. */\nfunction VsCodeIcon() {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 128 128\"\n width={16}\n height={16}\n fill=\"currentColor\"\n aria-hidden\n >\n <path\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M90.767 127.126a7.968 7.968 0 0 0 6.35-.244l26.353-12.681a8 8 0 0 0 4.53-7.209V21.009a8 8 0 0 0-4.53-7.21L97.117 1.12a7.97 7.97 0 0 0-9.093 1.548l-50.45 46.026L15.6 32.013a5.328 5.328 0 0 0-6.807.302l-7.048 6.411a5.335 5.335 0 0 0-.006 7.888L20.796 64 1.74 81.387a5.336 5.336 0 0 0 .006 7.887l7.048 6.411a5.327 5.327 0 0 0 6.807.303l21.974-16.68 50.45 46.025a7.96 7.96 0 0 0 2.743 1.793Zm5.252-92.183L57.74 64l38.28 29.058V34.943Z\"\n />\n </svg>\n );\n}\n\n/** The Claude starburst, sized for a button's iconStart slot. */\nfunction ClaudeIcon() {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n width={16}\n height={16}\n fill=\"currentColor\"\n aria-hidden\n >\n <path d={siClaude.path} />\n </svg>\n );\n}\n\n/**\n * The one-click install links for the types with a *native* install route,\n * rendered once in the actions row. `skill` and `hook` are absent on purpose:\n * their launchers are per-host and live in their own rows, so returning them\n * here too would render every button twice.\n */\nfunction getInstallLinks(\n resource: ResourceSummary,\n frameworks: string[],\n body?: ResourceBody,\n) {\n if (resource.type === 'agent') {\n return getAgentInstallLinks(\n resource.sourceLocation,\n resource.name,\n frameworks,\n );\n }\n if (resource.type === 'mcp-config') {\n return getMcpInstallLinks(frameworks, resource.name, body?.content);\n }\n return [];\n}\n\n/** Brand styling for the known deep-link hosts, keyed by link label. */\nfunction launchBrand(label: string): {\n className?: string;\n icon: React.ReactElement;\n} {\n switch (label) {\n case 'Claude':\n return { className: styles.claudeLaunch, icon: <ClaudeIcon /> };\n case 'VS Code':\n return { className: styles.vscodeLaunch, icon: <VsCodeIcon /> };\n case 'VS Code Insiders':\n return { className: styles.insidersLaunch, icon: <VsCodeIcon /> };\n case 'Cursor':\n return {\n className: styles.cursorLaunch,\n icon: <ToolIcon tool=\"cursor\" branded={false} size={16} />,\n };\n default:\n return { icon: <RiExternalLinkLine /> };\n }\n}\n\n/**\n * Icon-only copy button for a single generated command (marketplace journey\n * rows); flashes a check mark as the copied feedback.\n */\nfunction CopyCommandButton({ text }: { text: string }) {\n const [copied, setCopied] = useState(false);\n return (\n <ButtonIcon\n size=\"small\"\n variant=\"tertiary\"\n icon={copied ? <RiCheckLine /> : <RiFileCopyLine />}\n aria-label={copied ? 'Copied' : 'Copy command'}\n onPress={async () => {\n await navigator.clipboard.writeText(text);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }}\n />\n );\n}\n\n/**\n * Clipboard fallback for a host with no prompt URI (Copilot, Gemini). It\n * carries the identical instruction a launcher would pre-fill, so the only\n * difference is the delivery — the user pastes it into their own agent.\n */\nfunction CopyPromptButton({ text, label }: { text: string; label: string }) {\n const [copied, setCopied] = useState(false);\n return (\n <Button\n size=\"small\"\n variant=\"secondary\"\n iconStart={copied ? <RiCheckLine /> : <RiFileCopyLine />}\n onPress={async () => {\n await navigator.clipboard.writeText(text);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }}\n >\n {copied ? 'Copied!' : `Copy prompt for ${label}`}\n </Button>\n );\n}\n\n/**\n * The two-step marketplace journey (ADR-0010): ① register the catalog with\n * the AI tool, ② install plugins from it — plus a team-distribution snippet.\n * Whether this can render at all is decided by the caller, which needs the\n * same answer to know if the body doc is still required as a fallback.\n */\nfunction MarketplaceJourney({\n resource,\n repoSlug,\n addCommands,\n onLaunch,\n}: {\n resource: ResourceSummary;\n repoSlug: string;\n addCommands: MarketplaceAddCommand[];\n /**\n * Records the `install`, with the launched host as `tool` (ADR-0011).\n * `framework` is optional on the published `ResourceDeepLink`; a generated\n * link always carries one, and an event without a `tool` is still a\n * truthful install.\n */\n onLaunch: (framework: string | undefined) => void;\n}) {\n return (\n <div className={styles.journey}>\n <Text variant=\"body-small\" as=\"p\" className={styles.stepTitle}>\n 1. Add the marketplace to your AI tool\n </Text>\n <dl className={styles.commandList}>\n {addCommands.map(({ framework, command, deepLinks }) => (\n <div key={framework} className={styles.commandRow}>\n <dt className={styles.commandLabel}>\n <ToolIcon tool={framework as FrameworkToken} size={16} />\n {frameworkLabel(framework)}\n </dt>\n <dd className={styles.commandCell}>\n <code>{command}</code>\n <CopyCommandButton text={command} />\n </dd>\n {deepLinks.length > 0 && (\n <dd className={styles.deepLinks}>\n {deepLinks.map(link => {\n const brand = launchBrand(link.label);\n return (\n <ButtonLink\n key={link.label}\n size=\"small\"\n variant=\"secondary\"\n className={brand.className}\n iconStart={brand.icon}\n href={link.href}\n onPress={() => onLaunch(link.framework)}\n >\n Add in {link.label}\n </ButtonLink>\n );\n })}\n </dd>\n )}\n </div>\n ))}\n </dl>\n\n <Text variant=\"body-small\" as=\"p\" className={styles.stepTitle}>\n 2. Install plugins from it\n </Text>\n <div className={styles.commandCell}>\n <code>{getMarketplaceInstallTemplate(resource.name)}</code>\n </div>\n\n <details className={styles.teamSection}>\n <summary>For teams: auto-install via project settings</summary>\n <Text variant=\"body-x-small\" as=\"p\">\n Commit this to your repository’s <code>.claude/settings.json</code>{' '}\n and collaborators are prompted to install the marketplace when they\n trust the folder.\n </Text>\n <pre className={styles.codeBlock}>\n <code>{getMarketplaceTeamSnippet(resource.name, repoSlug)}</code>\n </pre>\n <CopyCommandButton\n text={getMarketplaceTeamSnippet(resource.name, repoSlug)}\n />\n </details>\n </div>\n );\n}\n\n/**\n * Install guidance wired to the body resolver (issue #30): copy the body,\n * download the artifact (file or zip, ADR-0009), and per-framework install\n * paths. The body is canonical — nothing here is reconstructed from\n * annotations (CONTEXT.md: body).\n */\nexport function ResourceInstallDialog({\n resource,\n body,\n bodyLoading = false,\n isOpen,\n onOpenChange,\n}: ResourceInstallDialogProps) {\n const api = useApi(devAiHubResourceApiRef);\n const track = useTrackTelemetry();\n const [copied, setCopied] = useState(false);\n const [downloadError, setDownloadError] = useState(false);\n\n const shape = getBodyShape(resource.type);\n // The deployment allow-list removed every framework this resource declared.\n // An empty `frameworks` would otherwise fall back to the neutral `default`\n // path and every native launcher, re-exposing what the allow-list suppressed\n // — so skip all generated install content and say why. Copy/Download stay.\n const frameworksRestricted = !!resource.frameworksRestricted;\n // What install-path / launcher generation is scoped to: `installFrameworks`\n // when the backend inferred a scoped set (a bare resource under an active\n // allow-list), otherwise the declared-and-filtered `frameworks`. Badges\n // still read `frameworks` only.\n const installFrameworks = resource.installFrameworks ?? resource.frameworks;\n const installLinks = frameworksRestricted\n ? []\n : getInstallLinks(resource, installFrameworks, body);\n\n // A marketplace body doc repeats the generated journey almost verbatim —\n // same two steps, same commands — so rendering both doubles the dialog's\n // height to say one thing twice. The journey wins when it can be derived;\n // the body stays as ADR-0010's fallback for when the slug cannot be.\n const marketplaceRepoSlug =\n resource.type === 'marketplace'\n ? getMarketplaceRepoSlug(resource.sourceLocation)\n : undefined;\n const marketplaceAddCommands =\n marketplaceRepoSlug && !frameworksRestricted\n ? getMarketplaceAddCommands(installFrameworks, marketplaceRepoSlug)\n : [];\n const hasMarketplaceJourney = marketplaceAddCommands.length > 0;\n // plugin/marketplace bodies are the real manifest JSON (ADR-0014), so this\n // markdown fallback can only fire if shape is still 'markdown' — kept for\n // the (currently unreachable) case bodyShape ever becomes content-driven.\n const showBodyDoc =\n shape === 'markdown' &&\n (resource.type === 'plugin' ||\n (resource.type === 'marketplace' && !hasMarketplaceJourney));\n\n // skill/hook install by instructing the agent, so each host gets a row that\n // is actionable on its own: a launcher where the host has a prompt URI, a\n // copyable prompt where it does not. Other types keep the plain path list —\n // their launchers are native routes, rendered once in the actions row.\n const usesPromptInstall =\n resource.type === 'skill' || resource.type === 'hook';\n const installSteps =\n usesPromptInstall && !frameworksRestricted\n ? getInstallSteps(\n resource.type,\n resource.sourceLocation,\n resource.name,\n installFrameworks,\n )\n : [];\n const pathRows = frameworksRestricted\n ? []\n : expandInstallFrameworks(installFrameworks)\n .map(f => ({\n framework: f,\n target: getResourceInstallTarget(resource.type, f, resource.name),\n }))\n .filter(\n (row): row is { framework: string; target: ResourceInstallTarget } =>\n !!row.target,\n );\n const hasMergeTarget = (\n installSteps.length > 0\n ? installSteps.map(s => s.target)\n : pathRows.map(r => r.target)\n ).some(t => t.mode === 'merge');\n\n /**\n * Whether *this* dialog actually produced a launch button. Deliberately\n * per-resource, not per-type: a skill declaring only Copilot/Gemini, an\n * agent with no resolvable source URL, an unparseable or multi-server MCP\n * body, and a marketplace with no derivable repo slug all render a path and\n * no button, and ADR-0011 requires those to fall back to the dialog-open\n * signal rather than record nothing at all.\n */\n const hasLauncher =\n installLinks.length > 0 ||\n installSteps.some(step => step.link) ||\n marketplaceAddCommands.some(command => command.deepLinks.length > 0);\n\n /**\n * `mcp-config` alone derives its launchers from the body\n * (`getMcpInstallLinks`); every other type builds them from\n * `sourceLocation` and the declared frameworks. So only it may wait for the\n * fetch — for the rest the body is only ever Copy/Download material, and\n * waiting on it would drop the event entirely when the dialog is closed\n * before an unrelated request settles.\n */\n const awaitingMcpBody = resource.type === 'mcp-config' && bodyLoading;\n\n /**\n * The fallback arm of ADR-0011's \"record `install` at the most specific\n * point available\": with no launcher to wait for, opening the dialog is\n * that point.\n *\n * Skipped when the deployment allow-list left the resource with no install\n * path at all (post-dates this ADR): nothing is installable, so an\n * `install` event would claim something that cannot have happened.\n */\n useEffect(() => {\n if (!isOpen || frameworksRestricted || hasLauncher || awaitingMcpBody) {\n return;\n }\n track(resource.entityRef, 'install');\n // `awaitingMcpBody`, not the raw `bodyLoading`: for every other type the\n // body settling is unrelated to launcher availability, and depending on\n // it would re-run this effect after the event had already been recorded\n // — one install, counted twice.\n }, [\n isOpen,\n awaitingMcpBody,\n frameworksRestricted,\n hasLauncher,\n resource.entityRef,\n track,\n ]);\n\n const handleCopy = async () => {\n if (!body) return;\n await navigator.clipboard.writeText(body.content);\n track(resource.entityRef, 'copy');\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n };\n\n const handleDownload = async () => {\n setDownloadError(false);\n try {\n await api.downloadEntityBody(resource.entityRef);\n track(resource.entityRef, 'download');\n } catch {\n setDownloadError(true);\n }\n };\n\n return (\n <Dialog\n isOpen={isOpen}\n onOpenChange={onOpenChange}\n /* Size to the widest command line so generated commands stay unwrapped,\n clamped so prose-heavy bodies can't balloon the dialog. The height cap\n keeps a long fallback body scrolling inside the dialog rather than\n running off-screen — the install actions must always stay reachable. */\n style={{\n width: 'fit-content',\n minWidth: 'min(480px, calc(100vw - 3rem))',\n maxWidth: 'min(760px, calc(100vw - 3rem))',\n maxHeight: 'min(80vh, calc(100vh - 4rem))',\n }}\n >\n <DialogHeader>Install {resource.title ?? resource.name}</DialogHeader>\n <DialogBody>\n {/* Every launcher here is a custom-scheme deep link — keep the app's\n router from rewriting it (see AppLaunchScope). */}\n <AppLaunchScope>\n <div className={styles.content}>\n <Text variant=\"body-small\" as=\"p\">\n {frameworksRestricted\n ? 'No install path is available — none of the tools this resource ' +\n 'supports are enabled for this Backstage. You can still copy or ' +\n 'download the content below.'\n : TYPE_HINTS[resource.type]}\n </Text>\n\n {body && shape === 'json' && (\n <CollapsibleSection label=\"Content\">\n <JsonBody content={body.content} className={styles.codeBlock} />\n </CollapsibleSection>\n )}\n\n {hasMarketplaceJourney && marketplaceRepoSlug && (\n <MarketplaceJourney\n resource={resource}\n repoSlug={marketplaceRepoSlug}\n addCommands={marketplaceAddCommands}\n onLaunch={framework =>\n track(resource.entityRef, 'install', framework)\n }\n />\n )}\n\n {body && showBodyDoc && (\n <div className={styles.markdown}>\n <ReactMarkdown>{body.content}</ReactMarkdown>\n </div>\n )}\n\n {installSteps.length > 0 && (\n <dl className={styles.commandList}>\n {installSteps.map(({ framework, target, prompt, link }) => (\n <div key={framework} className={styles.commandRow}>\n <dt className={styles.commandLabel}>\n <ToolIcon tool={framework as FrameworkToken} size={16} />\n {frameworkLabel(framework)}\n </dt>\n <dd className={styles.pathRow}>\n <code>{target.path}</code>\n {target.mode === 'merge' && (\n <span className={styles.mergeBadge}>merge into</span>\n )}\n </dd>\n <dd className={styles.deepLinks}>\n {link ? (\n (() => {\n const brand = launchBrand(link.label);\n return (\n <ButtonLink\n size=\"small\"\n variant=\"secondary\"\n className={brand.className}\n iconStart={brand.icon}\n href={link.href}\n onPress={() =>\n track(resource.entityRef, 'install', framework)\n }\n >\n Install in {link.label}\n </ButtonLink>\n );\n })()\n ) : (\n /* No prompt URI for this host — the same instruction,\n delivered by clipboard so the row is still actionable. */\n <CopyPromptButton\n text={prompt}\n label={frameworkLabel(framework)}\n />\n )}\n </dd>\n </div>\n ))}\n </dl>\n )}\n\n {installSteps.length === 0 && pathRows.length > 0 && (\n <>\n <dl className={styles.pathList}>\n {pathRows.map(({ framework, target }) => (\n <div key={framework} className={styles.pathRow}>\n <dt>\n {framework === 'default'\n ? 'Any framework'\n : frameworkLabel(framework)}\n </dt>\n <dd>\n <code>{target.path}</code>\n {/* A merge target is a file the user already owns —\n flagged inline so the path is never mistaken for a\n drop-in destination to overwrite. */}\n {target.mode === 'merge' && (\n <span className={styles.mergeBadge}>merge into</span>\n )}\n </dd>\n </div>\n ))}\n </dl>\n {hasMergeTarget && (\n <Text\n variant=\"body-x-small\"\n as=\"p\"\n className={styles.mergeNote}\n >\n Paths marked <strong>merge into</strong> are shared\n configuration files. Add this entry to the existing file —\n replacing it discards your other settings.\n </Text>\n )}\n </>\n )}\n\n <div className={styles.actions}>\n {installLinks.map(link => {\n const brand = launchBrand(link.label);\n return (\n <ButtonLink\n key={link.label}\n size=\"small\"\n variant=\"secondary\"\n className={brand.className}\n iconStart={brand.icon}\n href={link.href}\n onPress={() =>\n track(resource.entityRef, 'install', link.framework)\n }\n >\n Install in {link.label}\n </ButtonLink>\n );\n })}\n {hasCopyableBody(resource.type) && (\n <Button\n size=\"small\"\n variant=\"secondary\"\n iconStart={<RiFileCopyLine />}\n isDisabled={!body}\n onPress={handleCopy}\n >\n {copied ? 'Copied!' : 'Copy content'}\n </Button>\n )}\n {hasDownloadableArtifact(resource.type) && (\n <Button\n size=\"small\"\n variant=\"primary\"\n iconStart={<RiDownloadLine />}\n onPress={handleDownload}\n >\n Download\n </Button>\n )}\n </div>\n {downloadError && (\n <Text variant=\"body-x-small\" as=\"p\">\n Download failed — the source may be unreachable. Try again or\n use “View source”.\n </Text>\n )}\n </div>\n </AppLaunchScope>\n </DialogBody>\n </Dialog>\n );\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nospt/plugin-dev-ai-hub",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
4
  "description": "Frontend plugin for Dev AI Hub",
5
5
  "license": "Apache-2.0",
6
6
  "main": "./dist/index.esm.js",
@@ -62,7 +62,7 @@
62
62
  "@backstage/frontend-plugin-api": "^0.18.0",
63
63
  "@backstage/plugin-catalog-react": "^3.2.2",
64
64
  "@backstage/ui": "^0.17.1",
65
- "@nospt/plugin-dev-ai-hub-common": "^1.1.2",
65
+ "@nospt/plugin-dev-ai-hub-common": "^1.1.3",
66
66
  "@remixicon/react": "^4.9.0",
67
67
  "react-markdown": "^9.0.0",
68
68
  "react-syntax-highlighter": "^16.1.1",