@nospt/plugin-dev-ai-hub 1.0.0 → 1.0.2

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,49 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { useMemo } from 'react';
3
+ import { PrismLight } from 'react-syntax-highlighter';
4
+ import json from 'react-syntax-highlighter/dist/esm/languages/prism/json';
5
+
6
+ const SyntaxHighlighter = PrismLight;
7
+ PrismLight.registerLanguage("json", json);
8
+ const JSON_HIGHLIGHT_STYLE = {
9
+ 'code[class*="language-"]': {
10
+ color: "var(--bui-fg-primary)",
11
+ background: "none"
12
+ },
13
+ 'pre[class*="language-"]': {
14
+ color: "var(--bui-fg-primary)",
15
+ background: "none"
16
+ },
17
+ property: { color: "var(--bui-fg-announcement)" },
18
+ string: { color: "var(--bui-fg-warning)" },
19
+ number: { color: "var(--bui-fg-warning)" },
20
+ boolean: { color: "var(--bui-fg-warning)" },
21
+ null: { color: "var(--bui-fg-warning)" },
22
+ punctuation: { color: "var(--bui-fg-secondary)" },
23
+ operator: { color: "var(--bui-fg-secondary)" }
24
+ };
25
+ function JsonBody({ content, className }) {
26
+ const formatted = useMemo(() => {
27
+ try {
28
+ return JSON.stringify(JSON.parse(content), null, 2);
29
+ } catch {
30
+ return null;
31
+ }
32
+ }, [content]);
33
+ if (formatted === null) {
34
+ return /* @__PURE__ */ jsx("pre", { className, children: /* @__PURE__ */ jsx("code", { children: content }) });
35
+ }
36
+ return /* @__PURE__ */ jsx(
37
+ SyntaxHighlighter,
38
+ {
39
+ language: "json",
40
+ style: JSON_HIGHLIGHT_STYLE,
41
+ className,
42
+ customStyle: { margin: 0, padding: 0 },
43
+ children: formatted
44
+ }
45
+ );
46
+ }
47
+
48
+ export { JsonBody };
49
+ //# sourceMappingURL=JsonBody.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JsonBody.esm.js","sources":["../../../src/components/AiResourcesPage/JsonBody.tsx"],"sourcesContent":["import { useMemo } from 'react';\nimport {\n PrismLight,\n type SyntaxHighlighterProps,\n} from 'react-syntax-highlighter';\nimport json from 'react-syntax-highlighter/dist/esm/languages/prism/json';\n\n// react-syntax-highlighter's bundled @types/react (v19) doesn't structurally\n// match this repo's React 18 types, so the class component fails the JSX\n// element-type check as-is; recast to a plain function-component shape.\nconst SyntaxHighlighter =\n PrismLight as unknown as React.ComponentType<SyntaxHighlighterProps>;\n\nPrismLight.registerLanguage('json', json);\n\n/**\n * Token colours are drawn from the app's own `--bui-fg-*` tokens, not a\n * canned Prism theme — those ship a single hardcoded palette and would go\n * unreadable in whichever of light/dark mode they weren't built for. Reusing\n * the app's own tokens means highlighting follows the active theme for free.\n */\nconst JSON_HIGHLIGHT_STYLE = {\n 'code[class*=\"language-\"]': {\n color: 'var(--bui-fg-primary)',\n background: 'none',\n },\n 'pre[class*=\"language-\"]': {\n color: 'var(--bui-fg-primary)',\n background: 'none',\n },\n property: { color: 'var(--bui-fg-announcement)' },\n string: { color: 'var(--bui-fg-warning)' },\n number: { color: 'var(--bui-fg-warning)' },\n boolean: { color: 'var(--bui-fg-warning)' },\n null: { color: 'var(--bui-fg-warning)' },\n punctuation: { color: 'var(--bui-fg-secondary)' },\n operator: { color: 'var(--bui-fg-secondary)' },\n};\n\ninterface JsonBodyProps {\n content: string;\n className: string;\n}\n\n/**\n * Pretty-prints and syntax-highlights a JSON resource body (ADR-0014). Falls\n * back to the raw text, unhighlighted, when the content doesn't parse as\n * JSON — a malformed or foreign file must stay visible, not blank the panel.\n */\nexport function JsonBody({ content, className }: JsonBodyProps) {\n const formatted = useMemo(() => {\n try {\n return JSON.stringify(JSON.parse(content), null, 2);\n } catch {\n return null;\n }\n }, [content]);\n\n if (formatted === null) {\n return (\n <pre className={className}>\n <code>{content}</code>\n </pre>\n );\n }\n\n return (\n <SyntaxHighlighter\n language=\"json\"\n style={JSON_HIGHLIGHT_STYLE}\n className={className}\n customStyle={{ margin: 0, padding: 0 }}\n >\n {formatted}\n </SyntaxHighlighter>\n );\n}\n"],"names":[],"mappings":";;;;;AAUA,MAAM,iBAAA,GACJ,UAAA;AAEF,UAAA,CAAW,gBAAA,CAAiB,QAAQ,IAAI,CAAA;AAQxC,MAAM,oBAAA,GAAuB;AAAA,EAC3B,0BAAA,EAA4B;AAAA,IAC1B,KAAA,EAAO,uBAAA;AAAA,IACP,UAAA,EAAY;AAAA,GACd;AAAA,EACA,yBAAA,EAA2B;AAAA,IACzB,KAAA,EAAO,uBAAA;AAAA,IACP,UAAA,EAAY;AAAA,GACd;AAAA,EACA,QAAA,EAAU,EAAE,KAAA,EAAO,4BAAA,EAA6B;AAAA,EAChD,MAAA,EAAQ,EAAE,KAAA,EAAO,uBAAA,EAAwB;AAAA,EACzC,MAAA,EAAQ,EAAE,KAAA,EAAO,uBAAA,EAAwB;AAAA,EACzC,OAAA,EAAS,EAAE,KAAA,EAAO,uBAAA,EAAwB;AAAA,EAC1C,IAAA,EAAM,EAAE,KAAA,EAAO,uBAAA,EAAwB;AAAA,EACvC,WAAA,EAAa,EAAE,KAAA,EAAO,yBAAA,EAA0B;AAAA,EAChD,QAAA,EAAU,EAAE,KAAA,EAAO,yBAAA;AACrB,CAAA;AAYO,SAAS,QAAA,CAAS,EAAE,OAAA,EAAS,SAAA,EAAU,EAAkB;AAC9D,EAAA,MAAM,SAAA,GAAY,QAAQ,MAAM;AAC9B,IAAA,IAAI;AACF,MAAA,OAAO,KAAK,SAAA,CAAU,IAAA,CAAK,MAAM,OAAO,CAAA,EAAG,MAAM,CAAC,CAAA;AAAA,IACpD,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF,CAAA,EAAG,CAAC,OAAO,CAAC,CAAA;AAEZ,EAAA,IAAI,cAAc,IAAA,EAAM;AACtB,IAAA,2BACG,KAAA,EAAA,EAAI,SAAA,EACH,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAM,mBAAQ,CAAA,EACjB,CAAA;AAAA,EAEJ;AAEA,EAAA,uBACE,GAAA;AAAA,IAAC,iBAAA;AAAA,IAAA;AAAA,MACC,QAAA,EAAS,MAAA;AAAA,MACT,KAAA,EAAO,oBAAA;AAAA,MACP,SAAA;AAAA,MACA,WAAA,EAAa,EAAE,MAAA,EAAQ,CAAA,EAAG,SAAS,CAAA,EAAE;AAAA,MAEpC,QAAA,EAAA;AAAA;AAAA,GACH;AAEJ;;;;"}
@@ -9,6 +9,7 @@ import { getBodyShape, hasCopyableBody, hasDownloadableArtifact, isParseableEnti
9
9
  import { devAiHubResourceApiRef } from '../../api/DevAiHubResourceClient.esm.js';
10
10
  import { useResourceBody } from '../../hooks/useResourceBody.esm.js';
11
11
  import { useTelemetryCounts } from '../../hooks/useTelemetryCounts.esm.js';
12
+ import { JsonBody } from './JsonBody.esm.js';
12
13
  import { ToolIcon } from '../ToolIcon/ToolIcon.esm.js';
13
14
  import { ResourceInstallDialog } from './ResourceInstallDialog.esm.js';
14
15
  import { stripFrontmatter } from './stripFrontmatter.esm.js';
@@ -185,7 +186,13 @@ function ResourceDetailPanel({
185
186
  }
186
187
  )
187
188
  ] }),
188
- bodyState.body && bodyShape === "json" && /* @__PURE__ */ jsx("pre", { className: styles.codeBlock, children: /* @__PURE__ */ jsx("code", { children: bodyState.body.content }) }),
189
+ bodyState.body && bodyShape === "json" && /* @__PURE__ */ jsx(
190
+ JsonBody,
191
+ {
192
+ content: bodyState.body.content,
193
+ className: styles.codeBlock
194
+ }
195
+ ),
189
196
  bodyState.body && bodyShape === "markdown" && /* @__PURE__ */ jsx("div", { className: styles.markdown, children: /* @__PURE__ */ jsx(ReactMarkdown, { children: stripFrontmatter(bodyState.body.content) }) })
190
197
  ] }),
191
198
  resource.frameworks.length > 0 && /* @__PURE__ */ jsxs("div", { className: styles.section, children: [
@@ -1 +1 @@
1
- {"version":3,"file":"ResourceDetailPanel.esm.js","sources":["../../../src/components/AiResourcesPage/ResourceDetailPanel.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport ReactMarkdown from 'react-markdown';\nimport {\n Box,\n Button,\n ButtonIcon,\n Flex,\n Link,\n Skeleton,\n Text,\n} from '@backstage/ui';\nimport {\n RiCloseLine,\n RiDownloadLine,\n RiExternalLinkLine,\n RiEyeLine,\n RiFileCopyLine,\n RiInstallLine,\n} from '@remixicon/react';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { EntityRefLink } from '@backstage/plugin-catalog-react';\nimport {\n getBodyShape,\n hasCopyableBody,\n hasDownloadableArtifact,\n isParseableEntityRef,\n type FrameworkToken,\n type ResourceSummary,\n} from '@nospt/plugin-dev-ai-hub-common';\nimport { devAiHubResourceApiRef } from '../../api/DevAiHubResourceClient';\nimport { useResourceBody } from '../../hooks/useResourceBody';\nimport { useTelemetryCounts } from '../../hooks/useTelemetryCounts';\nimport { ToolIcon } from '../ToolIcon';\nimport { ResourceInstallDialog } from './ResourceInstallDialog';\nimport { stripFrontmatter } from './stripFrontmatter';\nimport { frameworkLabel, getTypeMeta } from './typeMeta';\nimport styles from './ResourceDetailPanel.module.css';\n\ninterface ResourceDetailPanelProps {\n resource: ResourceSummary | undefined;\n onClose: () => void;\n}\n\n/**\n * Metadata rows that name a catalog entity and should link there. Rendering\n * still falls back to plain text per-row when the value isn't a parseable\n * ref (`isParseableEntityRef`) — Owner isn't guaranteed parseable, since\n * `toResourceSummary` deliberately passes a malformed one through rather\n * than dropping the resource, and `EntityRefLink` throws on a ref it can't\n * parse. Entity ref is always valid (built with `stringifyEntityRef`), so it\n * always renders as a link.\n */\nconst ENTITY_REF_ROWS = new Set(['Owner', 'Entity ref']);\n\n/**\n * The detail drawer (legacy pattern, URL-param driven). Metadata renders from\n * the catalog `ResourceSummary`; the body is fetched lazily on open from the\n * body resolver (issue #30) and rendered by shape. Resources without a\n * source-location are browsable but not actionable — no action buttons.\n */\nexport function ResourceDetailPanel({\n resource: resourceProp,\n onClose,\n}: ResourceDetailPanelProps) {\n const isOpen = !!resourceProp;\n // The drawer slides out on close (issue: \"add some flowers\"), which needs\n // content to stay rendered during the exit transition — the `resource` prop\n // itself goes undefined the instant the URL param clears. `displayResource`\n // mirrors the last real resource and is only ever updated while one is\n // present, so the drawer keeps showing it while animating out instead of\n // blanking.\n const [displayResource, setDisplayResource] = useState(resourceProp);\n useEffect(() => {\n if (resourceProp) setDisplayResource(resourceProp);\n }, [resourceProp]);\n\n const api = useApi(devAiHubResourceApiRef);\n\n // A `view` is a deliberate look at one resource, so it is recorded here —\n // when the drawer opens — and not on card render, where merely loading the\n // page counted a view for every card in the grid. Keyed on the *live* prop,\n // not `displayResource`: that one stays set through the exit animation, and\n // closing must not count a second view.\n const openedRef = resourceProp?.entityRef;\n useEffect(() => {\n if (openedRef) api.track(openedRef, 'view');\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [openedRef]);\n\n const actionable = !!displayResource?.sourceLocation;\n const bodyState = useResourceBody(displayResource?.entityRef, actionable);\n const counts = useTelemetryCounts(displayResource?.entityRef);\n const [installOpen, setInstallOpen] = useState(false);\n const [copied, setCopied] = useState(false);\n\n if (!displayResource) return null;\n\n const resource = displayResource;\n const meta = getTypeMeta(resource.type);\n const bodyShape = getBodyShape(resource.type);\n\n const handleCopy = async () => {\n if (!bodyState.body) return;\n await navigator.clipboard.writeText(bodyState.body.content);\n api.track(resource.entityRef, 'copy');\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n };\n\n const handleDownload = () => {\n api.track(resource.entityRef, 'download');\n return api.downloadEntityBody(resource.entityRef);\n };\n\n const handleInstall = () => {\n api.track(resource.entityRef, 'install');\n setInstallOpen(true);\n };\n\n const metadataRows: [string, string | undefined][] = [\n ['Type', meta.label],\n ['Lifecycle', resource.lifecycle || undefined],\n ['Owner', resource.owner],\n ['Version', resource.version],\n ['Entity ref', resource.entityRef],\n ];\n\n return (\n <>\n <div\n className={styles.overlay}\n data-open={isOpen}\n onClick={onClose}\n role=\"presentation\"\n aria-hidden={!isOpen}\n />\n <div\n className={styles.drawer}\n data-open={isOpen}\n style={{ '--drawer-accent': meta.color } as React.CSSProperties}\n role=\"dialog\"\n aria-label={resource.title ?? resource.name}\n aria-hidden={!isOpen}\n >\n <Flex className={styles.header}>\n <div\n className={styles.iconBox}\n style={\n {\n '--card-accent': meta.color,\n '--card-accent-bg': meta.colorBg,\n } as React.CSSProperties\n }\n >\n <meta.Icon size={20} />\n </div>\n <Box className={styles.headerText}>\n <Text variant=\"title-small\" weight=\"bold\" as=\"h2\">\n {resource.title ?? resource.name}\n </Text>\n <Text\n variant=\"body-x-small\"\n style={{ color: meta.color, fontWeight: 600 }}\n >\n {meta.label}\n </Text>\n </Box>\n <ButtonIcon\n icon={<RiCloseLine />}\n variant=\"tertiary\"\n onClick={onClose}\n aria-label=\"Close\"\n />\n </Flex>\n\n <div className={styles.body}>\n {resource.description && (\n <Text variant=\"body-small\" as=\"p\">\n {resource.description}\n </Text>\n )}\n\n {(!!counts?.view || !!counts?.install) && (\n <div className={styles.statsRow}>\n {!!counts?.view && (\n <span className={styles.statItem}>\n <RiEyeLine size={14} /> {counts.view} views\n </span>\n )}\n {!!counts?.install && (\n <span className={styles.statItem}>\n <RiInstallLine size={14} /> {counts.install} installs\n </span>\n )}\n </div>\n )}\n\n {actionable && (\n <div className={styles.actions}>\n {hasCopyableBody(resource.type) && (\n <Button\n size=\"small\"\n variant=\"secondary\"\n iconStart={<RiFileCopyLine />}\n isDisabled={!bodyState.body}\n onPress={handleCopy}\n >\n {copied ? 'Copied!' : 'Copy'}\n </Button>\n )}\n {hasDownloadableArtifact(resource.type) && (\n <Button\n size=\"small\"\n variant=\"secondary\"\n iconStart={<RiDownloadLine />}\n onPress={handleDownload}\n >\n Download\n </Button>\n )}\n <Button\n size=\"small\"\n variant=\"primary\"\n iconStart={<RiInstallLine />}\n onPress={handleInstall}\n >\n Install\n </Button>\n </div>\n )}\n\n <div className={styles.section}>\n <Text variant=\"body-x-small\" color=\"secondary\" weight=\"bold\">\n Content\n </Text>\n {!actionable && (\n <Text variant=\"body-small\" as=\"p\" color=\"secondary\">\n No content location published for this resource.\n </Text>\n )}\n {actionable && bodyState.loading && (\n <div className={styles.bodyLoading}>\n <Skeleton width=\"100%\" height={14} />\n <Skeleton width=\"85%\" height={14} />\n <Skeleton width=\"60%\" height={14} />\n </div>\n )}\n {actionable && bodyState.error === 'not-found' && (\n <Text variant=\"body-small\" as=\"p\" color=\"secondary\">\n Content not available — it may have been removed, or you may not\n have access to it.\n </Text>\n )}\n {actionable && bodyState.error === 'upstream' && (\n <Flex align=\"center\" gap=\"2\">\n <Text variant=\"body-small\" as=\"p\" color=\"secondary\">\n Couldn’t fetch the content from its source.\n </Text>\n <Button\n size=\"small\"\n variant=\"tertiary\"\n onPress={bodyState.retry}\n >\n Retry\n </Button>\n </Flex>\n )}\n {bodyState.body && bodyShape === 'json' && (\n <pre className={styles.codeBlock}>\n <code>{bodyState.body.content}</code>\n </pre>\n )}\n {bodyState.body && bodyShape === 'markdown' && (\n <div className={styles.markdown}>\n <ReactMarkdown>\n {stripFrontmatter(bodyState.body.content)}\n </ReactMarkdown>\n </div>\n )}\n </div>\n\n {resource.frameworks.length > 0 && (\n <div className={styles.section}>\n <Text variant=\"body-x-small\" color=\"secondary\" weight=\"bold\">\n Works with\n </Text>\n <div className={styles.badges}>\n {resource.frameworks.map(f => (\n <span key={f} className={styles.frameworkBadge}>\n <ToolIcon tool={f as FrameworkToken} size={14} />\n {frameworkLabel(f)}\n </span>\n ))}\n </div>\n </div>\n )}\n\n {resource.tags.length > 0 && (\n <div className={styles.section}>\n <Text variant=\"body-x-small\" color=\"secondary\" weight=\"bold\">\n Tags\n </Text>\n <div className={styles.badges}>\n {resource.tags.map(t => (\n <span key={t} className={styles.tag}>\n #{t}\n </span>\n ))}\n </div>\n </div>\n )}\n\n <div className={styles.section}>\n <Text variant=\"body-x-small\" color=\"secondary\" weight=\"bold\">\n Metadata\n </Text>\n <dl className={styles.metaList}>\n {metadataRows\n .filter(([, v]) => v)\n .map(([k, v]) => (\n <div key={k} className={styles.metaRow}>\n <dt>{k}</dt>\n <dd>\n {ENTITY_REF_ROWS.has(k) && isParseableEntityRef(v!) ? (\n <EntityRefLink entityRef={v!}>{v}</EntityRefLink>\n ) : (\n v\n )}\n </dd>\n </div>\n ))}\n </dl>\n </div>\n\n {resource.sourceLocation && (\n <div className={styles.section}>\n <Link\n href={resource.sourceLocation.replace(/^url:/, '')}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n <span className={styles.sourceLinkContent}>\n <RiExternalLinkLine size={14} /> View source\n </span>\n </Link>\n </div>\n )}\n </div>\n </div>\n\n <ResourceInstallDialog\n resource={resource}\n body={bodyState.body}\n isOpen={installOpen}\n onOpenChange={setInstallOpen}\n />\n </>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ResourceDetailPanel.esm.js","sources":["../../../src/components/AiResourcesPage/ResourceDetailPanel.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport ReactMarkdown from 'react-markdown';\nimport {\n Box,\n Button,\n ButtonIcon,\n Flex,\n Link,\n Skeleton,\n Text,\n} from '@backstage/ui';\nimport {\n RiCloseLine,\n RiDownloadLine,\n RiExternalLinkLine,\n RiEyeLine,\n RiFileCopyLine,\n RiInstallLine,\n} from '@remixicon/react';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { EntityRefLink } from '@backstage/plugin-catalog-react';\nimport {\n getBodyShape,\n hasCopyableBody,\n hasDownloadableArtifact,\n isParseableEntityRef,\n type FrameworkToken,\n type ResourceSummary,\n} from '@nospt/plugin-dev-ai-hub-common';\nimport { devAiHubResourceApiRef } from '../../api/DevAiHubResourceClient';\nimport { useResourceBody } from '../../hooks/useResourceBody';\nimport { useTelemetryCounts } from '../../hooks/useTelemetryCounts';\nimport { JsonBody } from './JsonBody';\nimport { ToolIcon } from '../ToolIcon';\nimport { ResourceInstallDialog } from './ResourceInstallDialog';\nimport { stripFrontmatter } from './stripFrontmatter';\nimport { frameworkLabel, getTypeMeta } from './typeMeta';\nimport styles from './ResourceDetailPanel.module.css';\n\ninterface ResourceDetailPanelProps {\n resource: ResourceSummary | undefined;\n onClose: () => void;\n}\n\n/**\n * Metadata rows that name a catalog entity and should link there. Rendering\n * still falls back to plain text per-row when the value isn't a parseable\n * ref (`isParseableEntityRef`) — Owner isn't guaranteed parseable, since\n * `toResourceSummary` deliberately passes a malformed one through rather\n * than dropping the resource, and `EntityRefLink` throws on a ref it can't\n * parse. Entity ref is always valid (built with `stringifyEntityRef`), so it\n * always renders as a link.\n */\nconst ENTITY_REF_ROWS = new Set(['Owner', 'Entity ref']);\n\n/**\n * The detail drawer (legacy pattern, URL-param driven). Metadata renders from\n * the catalog `ResourceSummary`; the body is fetched lazily on open from the\n * body resolver (issue #30) and rendered by shape. Resources without a\n * source-location are browsable but not actionable — no action buttons.\n */\nexport function ResourceDetailPanel({\n resource: resourceProp,\n onClose,\n}: ResourceDetailPanelProps) {\n const isOpen = !!resourceProp;\n // The drawer slides out on close (issue: \"add some flowers\"), which needs\n // content to stay rendered during the exit transition — the `resource` prop\n // itself goes undefined the instant the URL param clears. `displayResource`\n // mirrors the last real resource and is only ever updated while one is\n // present, so the drawer keeps showing it while animating out instead of\n // blanking.\n const [displayResource, setDisplayResource] = useState(resourceProp);\n useEffect(() => {\n if (resourceProp) setDisplayResource(resourceProp);\n }, [resourceProp]);\n\n const api = useApi(devAiHubResourceApiRef);\n\n // A `view` is a deliberate look at one resource, so it is recorded here —\n // when the drawer opens — and not on card render, where merely loading the\n // page counted a view for every card in the grid. Keyed on the *live* prop,\n // not `displayResource`: that one stays set through the exit animation, and\n // closing must not count a second view.\n const openedRef = resourceProp?.entityRef;\n useEffect(() => {\n if (openedRef) api.track(openedRef, 'view');\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [openedRef]);\n\n const actionable = !!displayResource?.sourceLocation;\n const bodyState = useResourceBody(displayResource?.entityRef, actionable);\n const counts = useTelemetryCounts(displayResource?.entityRef);\n const [installOpen, setInstallOpen] = useState(false);\n const [copied, setCopied] = useState(false);\n\n if (!displayResource) return null;\n\n const resource = displayResource;\n const meta = getTypeMeta(resource.type);\n const bodyShape = getBodyShape(resource.type);\n\n const handleCopy = async () => {\n if (!bodyState.body) return;\n await navigator.clipboard.writeText(bodyState.body.content);\n api.track(resource.entityRef, 'copy');\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n };\n\n const handleDownload = () => {\n api.track(resource.entityRef, 'download');\n return api.downloadEntityBody(resource.entityRef);\n };\n\n const handleInstall = () => {\n api.track(resource.entityRef, 'install');\n setInstallOpen(true);\n };\n\n const metadataRows: [string, string | undefined][] = [\n ['Type', meta.label],\n ['Lifecycle', resource.lifecycle || undefined],\n ['Owner', resource.owner],\n ['Version', resource.version],\n ['Entity ref', resource.entityRef],\n ];\n\n return (\n <>\n <div\n className={styles.overlay}\n data-open={isOpen}\n onClick={onClose}\n role=\"presentation\"\n aria-hidden={!isOpen}\n />\n <div\n className={styles.drawer}\n data-open={isOpen}\n style={{ '--drawer-accent': meta.color } as React.CSSProperties}\n role=\"dialog\"\n aria-label={resource.title ?? resource.name}\n aria-hidden={!isOpen}\n >\n <Flex className={styles.header}>\n <div\n className={styles.iconBox}\n style={\n {\n '--card-accent': meta.color,\n '--card-accent-bg': meta.colorBg,\n } as React.CSSProperties\n }\n >\n <meta.Icon size={20} />\n </div>\n <Box className={styles.headerText}>\n <Text variant=\"title-small\" weight=\"bold\" as=\"h2\">\n {resource.title ?? resource.name}\n </Text>\n <Text\n variant=\"body-x-small\"\n style={{ color: meta.color, fontWeight: 600 }}\n >\n {meta.label}\n </Text>\n </Box>\n <ButtonIcon\n icon={<RiCloseLine />}\n variant=\"tertiary\"\n onClick={onClose}\n aria-label=\"Close\"\n />\n </Flex>\n\n <div className={styles.body}>\n {resource.description && (\n <Text variant=\"body-small\" as=\"p\">\n {resource.description}\n </Text>\n )}\n\n {(!!counts?.view || !!counts?.install) && (\n <div className={styles.statsRow}>\n {!!counts?.view && (\n <span className={styles.statItem}>\n <RiEyeLine size={14} /> {counts.view} views\n </span>\n )}\n {!!counts?.install && (\n <span className={styles.statItem}>\n <RiInstallLine size={14} /> {counts.install} installs\n </span>\n )}\n </div>\n )}\n\n {actionable && (\n <div className={styles.actions}>\n {hasCopyableBody(resource.type) && (\n <Button\n size=\"small\"\n variant=\"secondary\"\n iconStart={<RiFileCopyLine />}\n isDisabled={!bodyState.body}\n onPress={handleCopy}\n >\n {copied ? 'Copied!' : 'Copy'}\n </Button>\n )}\n {hasDownloadableArtifact(resource.type) && (\n <Button\n size=\"small\"\n variant=\"secondary\"\n iconStart={<RiDownloadLine />}\n onPress={handleDownload}\n >\n Download\n </Button>\n )}\n <Button\n size=\"small\"\n variant=\"primary\"\n iconStart={<RiInstallLine />}\n onPress={handleInstall}\n >\n Install\n </Button>\n </div>\n )}\n\n <div className={styles.section}>\n <Text variant=\"body-x-small\" color=\"secondary\" weight=\"bold\">\n Content\n </Text>\n {!actionable && (\n <Text variant=\"body-small\" as=\"p\" color=\"secondary\">\n No content location published for this resource.\n </Text>\n )}\n {actionable && bodyState.loading && (\n <div className={styles.bodyLoading}>\n <Skeleton width=\"100%\" height={14} />\n <Skeleton width=\"85%\" height={14} />\n <Skeleton width=\"60%\" height={14} />\n </div>\n )}\n {actionable && bodyState.error === 'not-found' && (\n <Text variant=\"body-small\" as=\"p\" color=\"secondary\">\n Content not available — it may have been removed, or you may not\n have access to it.\n </Text>\n )}\n {actionable && bodyState.error === 'upstream' && (\n <Flex align=\"center\" gap=\"2\">\n <Text variant=\"body-small\" as=\"p\" color=\"secondary\">\n Couldn’t fetch the content from its source.\n </Text>\n <Button\n size=\"small\"\n variant=\"tertiary\"\n onPress={bodyState.retry}\n >\n Retry\n </Button>\n </Flex>\n )}\n {bodyState.body && bodyShape === 'json' && (\n <JsonBody\n content={bodyState.body.content}\n className={styles.codeBlock}\n />\n )}\n {bodyState.body && bodyShape === 'markdown' && (\n <div className={styles.markdown}>\n <ReactMarkdown>\n {stripFrontmatter(bodyState.body.content)}\n </ReactMarkdown>\n </div>\n )}\n </div>\n\n {resource.frameworks.length > 0 && (\n <div className={styles.section}>\n <Text variant=\"body-x-small\" color=\"secondary\" weight=\"bold\">\n Works with\n </Text>\n <div className={styles.badges}>\n {resource.frameworks.map(f => (\n <span key={f} className={styles.frameworkBadge}>\n <ToolIcon tool={f as FrameworkToken} size={14} />\n {frameworkLabel(f)}\n </span>\n ))}\n </div>\n </div>\n )}\n\n {resource.tags.length > 0 && (\n <div className={styles.section}>\n <Text variant=\"body-x-small\" color=\"secondary\" weight=\"bold\">\n Tags\n </Text>\n <div className={styles.badges}>\n {resource.tags.map(t => (\n <span key={t} className={styles.tag}>\n #{t}\n </span>\n ))}\n </div>\n </div>\n )}\n\n <div className={styles.section}>\n <Text variant=\"body-x-small\" color=\"secondary\" weight=\"bold\">\n Metadata\n </Text>\n <dl className={styles.metaList}>\n {metadataRows\n .filter(([, v]) => v)\n .map(([k, v]) => (\n <div key={k} className={styles.metaRow}>\n <dt>{k}</dt>\n <dd>\n {ENTITY_REF_ROWS.has(k) && isParseableEntityRef(v!) ? (\n <EntityRefLink entityRef={v!}>{v}</EntityRefLink>\n ) : (\n v\n )}\n </dd>\n </div>\n ))}\n </dl>\n </div>\n\n {resource.sourceLocation && (\n <div className={styles.section}>\n <Link\n href={resource.sourceLocation.replace(/^url:/, '')}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n <span className={styles.sourceLinkContent}>\n <RiExternalLinkLine size={14} /> View source\n </span>\n </Link>\n </div>\n )}\n </div>\n </div>\n\n <ResourceInstallDialog\n resource={resource}\n body={bodyState.body}\n isOpen={installOpen}\n onOpenChange={setInstallOpen}\n />\n </>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -8,6 +8,7 @@ import { useApi } from '@backstage/core-plugin-api';
8
8
  import { getBodyShape, getMarketplaceRepoSlug, getMarketplaceAddCommands, getInstallSteps, expandInstallFrameworks, getResourceInstallTarget, hasCopyableBody, hasDownloadableArtifact, getAgentInstallLinks, getMcpInstallLinks, getMarketplaceInstallTemplate, getMarketplaceTeamSnippet } from '@nospt/plugin-dev-ai-hub-common';
9
9
  import { devAiHubResourceApiRef } from '../../api/DevAiHubResourceClient.esm.js';
10
10
  import { ToolIcon } from '../ToolIcon/ToolIcon.esm.js';
11
+ import { JsonBody } from './JsonBody.esm.js';
11
12
  import { frameworkLabel } from './typeMeta.esm.js';
12
13
  import styles from './ResourceInstallDialog.module.css.esm.js';
13
14
 
@@ -191,7 +192,7 @@ function ResourceInstallDialog({
191
192
  const marketplaceRepoSlug = resource.type === "marketplace" ? getMarketplaceRepoSlug(resource.sourceLocation) : void 0;
192
193
  const marketplaceAddCommands = marketplaceRepoSlug ? getMarketplaceAddCommands(resource.frameworks, marketplaceRepoSlug) : [];
193
194
  const hasMarketplaceJourney = marketplaceAddCommands.length > 0;
194
- const showBodyDoc = resource.type === "plugin" || resource.type === "marketplace" && !hasMarketplaceJourney;
195
+ const showBodyDoc = shape === "markdown" && (resource.type === "plugin" || resource.type === "marketplace" && !hasMarketplaceJourney);
195
196
  const usesPromptInstall = resource.type === "skill" || resource.type === "hook";
196
197
  const installSteps = usesPromptInstall ? getInstallSteps(
197
198
  resource.type,
@@ -240,7 +241,7 @@ function ResourceInstallDialog({
240
241
  ] }),
241
242
  /* @__PURE__ */ jsx(DialogBody, { children: /* @__PURE__ */ jsxs("div", { className: styles.content, children: [
242
243
  /* @__PURE__ */ jsx(Text, { variant: "body-small", as: "p", children: TYPE_HINTS[resource.type] }),
243
- body && shape === "json" && /* @__PURE__ */ jsx("pre", { className: styles.codeBlock, children: /* @__PURE__ */ jsx("code", { children: body.content }) }),
244
+ body && shape === "json" && /* @__PURE__ */ jsx(JsonBody, { content: body.content, className: styles.codeBlock }),
244
245
  hasMarketplaceJourney && marketplaceRepoSlug && /* @__PURE__ */ jsx(
245
246
  MarketplaceJourney,
246
247
  {
@@ -1 +1 @@
1
- {"version":3,"file":"ResourceInstallDialog.esm.js","sources":["../../../src/components/AiResourcesPage/ResourceInstallDialog.tsx"],"sourcesContent":["import { 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 { ToolIcon } from '../ToolIcon';\nimport { frameworkLabel } from './typeMeta';\nimport styles from './ResourceInstallDialog.module.css';\n\ninterface ResourceInstallDialogProps {\n resource: ResourceSummary;\n body?: ResourceBody;\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(resource: ResourceSummary, body?: ResourceBody) {\n if (resource.type === 'agent') {\n return getAgentInstallLinks(\n resource.sourceLocation,\n resource.name,\n resource.frameworks,\n );\n }\n if (resource.type === 'mcp-config') {\n return getMcpInstallLinks(\n resource.frameworks,\n resource.name,\n body?.content,\n );\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}: {\n resource: ResourceSummary;\n repoSlug: string;\n addCommands: MarketplaceAddCommand[];\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 >\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 isOpen,\n onOpenChange,\n}: ResourceInstallDialogProps) {\n const api = useApi(devAiHubResourceApiRef);\n const [copied, setCopied] = useState(false);\n const [downloadError, setDownloadError] = useState(false);\n\n const shape = getBodyShape(resource.type);\n const installLinks = getInstallLinks(resource, 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 = marketplaceRepoSlug\n ? getMarketplaceAddCommands(resource.frameworks, marketplaceRepoSlug)\n : [];\n const hasMarketplaceJourney = marketplaceAddCommands.length > 0;\n const showBodyDoc =\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 = usesPromptInstall\n ? getInstallSteps(\n resource.type,\n resource.sourceLocation,\n resource.name,\n resource.frameworks,\n )\n : [];\n const pathRows = expandInstallFrameworks(resource.frameworks)\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 const handleCopy = async () => {\n if (!body) return;\n await navigator.clipboard.writeText(body.content);\n api.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 api.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 {TYPE_HINTS[resource.type]}\n </Text>\n\n {body && shape === 'json' && (\n <pre className={styles.codeBlock}>\n <code>{body.content}</code>\n </pre>\n )}\n\n {hasMarketplaceJourney && marketplaceRepoSlug && (\n <MarketplaceJourney\n resource={resource}\n repoSlug={marketplaceRepoSlug}\n addCommands={marketplaceAddCommands}\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 api.track(\n resource.entityRef,\n 'install',\n framework,\n )\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 >\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 { 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 { ToolIcon } from '../ToolIcon';\nimport { JsonBody } from './JsonBody';\nimport { frameworkLabel } from './typeMeta';\nimport styles from './ResourceInstallDialog.module.css';\n\ninterface ResourceInstallDialogProps {\n resource: ResourceSummary;\n body?: ResourceBody;\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(resource: ResourceSummary, body?: ResourceBody) {\n if (resource.type === 'agent') {\n return getAgentInstallLinks(\n resource.sourceLocation,\n resource.name,\n resource.frameworks,\n );\n }\n if (resource.type === 'mcp-config') {\n return getMcpInstallLinks(\n resource.frameworks,\n resource.name,\n body?.content,\n );\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}: {\n resource: ResourceSummary;\n repoSlug: string;\n addCommands: MarketplaceAddCommand[];\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 >\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 isOpen,\n onOpenChange,\n}: ResourceInstallDialogProps) {\n const api = useApi(devAiHubResourceApiRef);\n const [copied, setCopied] = useState(false);\n const [downloadError, setDownloadError] = useState(false);\n\n const shape = getBodyShape(resource.type);\n const installLinks = getInstallLinks(resource, 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 = marketplaceRepoSlug\n ? getMarketplaceAddCommands(resource.frameworks, 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 = usesPromptInstall\n ? getInstallSteps(\n resource.type,\n resource.sourceLocation,\n resource.name,\n resource.frameworks,\n )\n : [];\n const pathRows = expandInstallFrameworks(resource.frameworks)\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 const handleCopy = async () => {\n if (!body) return;\n await navigator.clipboard.writeText(body.content);\n api.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 api.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 {TYPE_HINTS[resource.type]}\n </Text>\n\n {body && shape === 'json' && (\n <JsonBody content={body.content} className={styles.codeBlock} />\n )}\n\n {hasMarketplaceJourney && marketplaceRepoSlug && (\n <MarketplaceJourney\n resource={resource}\n repoSlug={marketplaceRepoSlug}\n addCommands={marketplaceAddCommands}\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 api.track(\n resource.entityRef,\n 'install',\n framework,\n )\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 >\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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nospt/plugin-dev-ai-hub",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Frontend plugin for Dev AI Hub",
5
5
  "license": "Apache-2.0",
6
6
  "main": "./dist/index.esm.js",
@@ -60,7 +60,7 @@
60
60
  "@backstage/frontend-plugin-api": "^0.17.0",
61
61
  "@backstage/plugin-catalog-react": "^3.0.0",
62
62
  "@backstage/ui": "^0.15.0",
63
- "@nospt/plugin-dev-ai-hub-common": "^1.0.0",
63
+ "@nospt/plugin-dev-ai-hub-common": "^1.0.2",
64
64
  "@remixicon/react": "^4.6.0",
65
65
  "react-markdown": "^9.0.0",
66
66
  "react-syntax-highlighter": "^16.1.1",