@showcall/backstage-plugin-agent-catalog 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/AgentCatalogSidebarItem.esm.js +16 -0
- package/dist/components/AgentCatalogSidebarItem.esm.js.map +1 -0
- package/dist/components/AgentInfoCard.esm.js +87 -0
- package/dist/components/AgentInfoCard.esm.js.map +1 -0
- package/dist/components/FleetPage.esm.js +106 -0
- package/dist/components/FleetPage.esm.js.map +1 -0
- package/dist/index.d.ts +82 -0
- package/dist/index.esm.js +4 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/nav.esm.js +7 -0
- package/dist/nav.esm.js.map +1 -0
- package/dist/plugin.esm.js +30 -0
- package/dist/plugin.esm.js.map +1 -0
- package/package.json +64 -0
- package/src/index.ts +3 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { SidebarItem } from '@backstage/core-components';
|
|
3
|
+
import AndroidIcon from '@material-ui/icons/Android';
|
|
4
|
+
import { agentCatalogNavItem } from '../nav.esm.js';
|
|
5
|
+
|
|
6
|
+
const AgentCatalogSidebarItem = () => /* @__PURE__ */ jsx(
|
|
7
|
+
SidebarItem,
|
|
8
|
+
{
|
|
9
|
+
icon: AndroidIcon,
|
|
10
|
+
to: agentCatalogNavItem.path,
|
|
11
|
+
text: agentCatalogNavItem.title
|
|
12
|
+
}
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
export { AgentCatalogSidebarItem };
|
|
16
|
+
//# sourceMappingURL=AgentCatalogSidebarItem.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgentCatalogSidebarItem.esm.js","sources":["../../src/components/AgentCatalogSidebarItem.tsx"],"sourcesContent":["import { SidebarItem } from '@backstage/core-components';\nimport AndroidIcon from '@material-ui/icons/Android';\nimport { agentCatalogNavItem } from '../nav';\n\nexport const AgentCatalogSidebarItem = () => (\n <SidebarItem\n icon={AndroidIcon}\n to={agentCatalogNavItem.path}\n text={agentCatalogNavItem.title}\n />\n);\n"],"names":[],"mappings":";;;;;AAIO,MAAM,0BAA0B,sBACrC,GAAA;AAAA,EAAC,WAAA;AAAA,EAAA;AAAA,IACC,IAAA,EAAM,WAAA;AAAA,IACN,IAAI,mBAAA,CAAoB,IAAA;AAAA,IACxB,MAAM,mBAAA,CAAoB;AAAA;AAC5B;;;;"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
|
+
import { InfoCard } from '@backstage/core-components';
|
|
3
|
+
import { useEntity } from '@backstage/plugin-catalog-react';
|
|
4
|
+
import { Grid, Chip, Typography } from '@material-ui/core';
|
|
5
|
+
|
|
6
|
+
const A = "agentcatalog.io";
|
|
7
|
+
const Stat = ({ label, value }) => /* @__PURE__ */ jsxs(Grid, { item: true, xs: 4, children: [
|
|
8
|
+
/* @__PURE__ */ jsx(Typography, { variant: "overline", color: "textSecondary", component: "div", children: label }),
|
|
9
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h6", component: "div", children: value })
|
|
10
|
+
] });
|
|
11
|
+
const AgentInfoCard = () => {
|
|
12
|
+
const { entity } = useEntity();
|
|
13
|
+
const ann = entity.metadata.annotations ?? {};
|
|
14
|
+
const agent = entity.spec?.agent ?? {};
|
|
15
|
+
const requests = ann[`${A}/usage-requests`];
|
|
16
|
+
const tokens = ann[`${A}/usage-tokens`];
|
|
17
|
+
const cost = ann[`${A}/usage-cost-usd`];
|
|
18
|
+
const window = ann[`${A}/usage-window`] ?? "";
|
|
19
|
+
const lastActive = ann[`${A}/last-active`];
|
|
20
|
+
const reachable = ann[`${A}/reachable`];
|
|
21
|
+
const cardSource = ann[`${A}/card-source`];
|
|
22
|
+
const discovery = ann[`${A}/discovery`];
|
|
23
|
+
const runtime = ann[`${A}/runtime`];
|
|
24
|
+
const modelConfig = ann[`${A}/model-config`];
|
|
25
|
+
const image = ann[`${A}/image`];
|
|
26
|
+
const signals = ann[`${A}/heuristic-signals`];
|
|
27
|
+
const isHeuristic = discovery === "heuristic";
|
|
28
|
+
return /* @__PURE__ */ jsx(
|
|
29
|
+
InfoCard,
|
|
30
|
+
{
|
|
31
|
+
title: isHeuristic ? "LLM workload (heuristic finding)" : "Agent",
|
|
32
|
+
subheader: isHeuristic ? void 0 : `runtime: ${runtime ?? "unknown"}`,
|
|
33
|
+
children: /* @__PURE__ */ jsxs(Grid, { container: true, spacing: 2, children: [
|
|
34
|
+
/* @__PURE__ */ jsxs(Grid, { item: true, xs: 12, children: [
|
|
35
|
+
discovery && /* @__PURE__ */ jsx(Chip, { size: "small", variant: "outlined", label: `discovery: ${discovery}` }),
|
|
36
|
+
reachable && /* @__PURE__ */ jsx(
|
|
37
|
+
Chip,
|
|
38
|
+
{
|
|
39
|
+
size: "small",
|
|
40
|
+
label: reachable === "true" ? "reachable" : "unreachable",
|
|
41
|
+
style: {
|
|
42
|
+
backgroundColor: reachable === "true" ? "#1db95433" : "#e5484d33"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
),
|
|
46
|
+
cardSource && /* @__PURE__ */ jsx(Chip, { size: "small", variant: "outlined", label: `card: ${cardSource}` })
|
|
47
|
+
] }),
|
|
48
|
+
/* @__PURE__ */ jsx(Stat, { label: `Requests${window ? ` / ${window}` : ""}`, value: requests ?? "\u2014" }),
|
|
49
|
+
/* @__PURE__ */ jsx(Stat, { label: "Tokens", value: tokens ?? "\u2014" }),
|
|
50
|
+
/* @__PURE__ */ jsx(Stat, { label: "Last active", value: lastActive ?? "\u2014" }),
|
|
51
|
+
cost && /* @__PURE__ */ jsx(Stat, { label: `Cost / ${window}`, value: `$${cost}` }),
|
|
52
|
+
signals && /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsxs(Typography, { variant: "body2", color: "textSecondary", children: [
|
|
53
|
+
"Flagged because: ",
|
|
54
|
+
/* @__PURE__ */ jsx("code", { children: signals }),
|
|
55
|
+
". If this is a real agent, label its Service ",
|
|
56
|
+
/* @__PURE__ */ jsx("code", { children: 'agentcatalog.io/a2a: "true"' }),
|
|
57
|
+
"; if it's a false positive, label it ",
|
|
58
|
+
/* @__PURE__ */ jsx("code", { children: '"false"' }),
|
|
59
|
+
"."
|
|
60
|
+
] }) }),
|
|
61
|
+
(modelConfig || image) && /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsxs(Typography, { variant: "body2", color: "textSecondary", children: [
|
|
62
|
+
modelConfig && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
63
|
+
"model config: ",
|
|
64
|
+
/* @__PURE__ */ jsx("code", { children: modelConfig }),
|
|
65
|
+
" "
|
|
66
|
+
] }),
|
|
67
|
+
image && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
68
|
+
"image: ",
|
|
69
|
+
/* @__PURE__ */ jsx("code", { children: image })
|
|
70
|
+
] })
|
|
71
|
+
] }) }),
|
|
72
|
+
requests === void 0 && /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsxs(Typography, { variant: "body2", color: "textSecondary", children: [
|
|
73
|
+
"No per-agent usage: this agent has no gateway key alias. Issue it a key aliased ",
|
|
74
|
+
/* @__PURE__ */ jsxs("code", { children: [
|
|
75
|
+
String(agent.namespace ?? "ns"),
|
|
76
|
+
"/",
|
|
77
|
+
entity.metadata.title ?? entity.metadata.name
|
|
78
|
+
] }),
|
|
79
|
+
" to light up traction."
|
|
80
|
+
] }) })
|
|
81
|
+
] })
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export { AgentInfoCard };
|
|
87
|
+
//# sourceMappingURL=AgentInfoCard.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgentInfoCard.esm.js","sources":["../../src/components/AgentInfoCard.tsx"],"sourcesContent":["/**\n * Per-agent card for entity overview pages: traction + status at a glance,\n * so nobody needs the entity inspector to answer \"is this agent alive and\n * does anyone use it\".\n */\n\nimport type { ReactNode } from 'react';\nimport { InfoCard } from '@backstage/core-components';\nimport { useEntity } from '@backstage/plugin-catalog-react';\nimport { Chip, Grid, Typography } from '@material-ui/core';\n\nconst A = 'agentcatalog.io';\n\nconst Stat = ({ label, value }: { label: string; value: ReactNode }) => (\n <Grid item xs={4}>\n <Typography variant=\"overline\" color=\"textSecondary\" component=\"div\">\n {label}\n </Typography>\n <Typography variant=\"h6\" component=\"div\">\n {value}\n </Typography>\n </Grid>\n);\n\nexport const AgentInfoCard = () => {\n const { entity } = useEntity();\n const ann = entity.metadata.annotations ?? {};\n const agent = (entity.spec as { agent?: Record<string, unknown> })?.agent ?? {};\n\n const requests = ann[`${A}/usage-requests`];\n const tokens = ann[`${A}/usage-tokens`];\n const cost = ann[`${A}/usage-cost-usd`];\n const window = ann[`${A}/usage-window`] ?? '';\n const lastActive = ann[`${A}/last-active`];\n const reachable = ann[`${A}/reachable`];\n const cardSource = ann[`${A}/card-source`];\n const discovery = ann[`${A}/discovery`];\n const runtime = ann[`${A}/runtime`];\n const modelConfig = ann[`${A}/model-config`];\n const image = ann[`${A}/image`];\n const signals = ann[`${A}/heuristic-signals`];\n const isHeuristic = discovery === 'heuristic';\n\n return (\n <InfoCard\n title={isHeuristic ? 'LLM workload (heuristic finding)' : 'Agent'}\n subheader={isHeuristic ? undefined : `runtime: ${runtime ?? 'unknown'}`}\n >\n <Grid container spacing={2}>\n <Grid item xs={12}>\n {discovery && <Chip size=\"small\" variant=\"outlined\" label={`discovery: ${discovery}`} />}\n {reachable && (\n <Chip\n size=\"small\"\n label={reachable === 'true' ? 'reachable' : 'unreachable'}\n style={{\n backgroundColor: reachable === 'true' ? '#1db95433' : '#e5484d33',\n }}\n />\n )}\n {cardSource && <Chip size=\"small\" variant=\"outlined\" label={`card: ${cardSource}`} />}\n </Grid>\n\n <Stat label={`Requests${window ? ` / ${window}` : ''}`} value={requests ?? '—'} />\n <Stat label=\"Tokens\" value={tokens ?? '—'} />\n <Stat label=\"Last active\" value={lastActive ?? '—'} />\n {cost && <Stat label={`Cost / ${window}`} value={`$${cost}`} />}\n\n {signals && (\n <Grid item xs={12}>\n <Typography variant=\"body2\" color=\"textSecondary\">\n Flagged because: <code>{signals}</code>. If this is a real\n agent, label its Service <code>agentcatalog.io/a2a: \"true\"</code>;\n if it's a false positive, label it <code>\"false\"</code>.\n </Typography>\n </Grid>\n )}\n {(modelConfig || image) && (\n <Grid item xs={12}>\n <Typography variant=\"body2\" color=\"textSecondary\">\n {modelConfig && <>model config: <code>{modelConfig}</code> </>}\n {image && <>image: <code>{image}</code></>}\n </Typography>\n </Grid>\n )}\n {requests === undefined && (\n <Grid item xs={12}>\n <Typography variant=\"body2\" color=\"textSecondary\">\n No per-agent usage: this agent has no gateway key alias. Issue it\n a key aliased <code>{String(agent.namespace ?? 'ns')}/{entity.metadata.title ?? entity.metadata.name}</code> to\n light up traction.\n </Typography>\n </Grid>\n )}\n </Grid>\n </InfoCard>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
|
+
import { useState, useEffect } from 'react';
|
|
3
|
+
import { Page, Header, Content, ResponseErrorPanel, Progress, Table } from '@backstage/core-components';
|
|
4
|
+
import { useApi } from '@backstage/core-plugin-api';
|
|
5
|
+
import { catalogApiRef, EntityRefLink } from '@backstage/plugin-catalog-react';
|
|
6
|
+
import { Chip } from '@material-ui/core';
|
|
7
|
+
|
|
8
|
+
const A = "agentcatalog.io";
|
|
9
|
+
function toRow(entity) {
|
|
10
|
+
const ann = entity.metadata.annotations ?? {};
|
|
11
|
+
const requests = ann[`${A}/usage-requests`];
|
|
12
|
+
return {
|
|
13
|
+
entity,
|
|
14
|
+
name: entity.metadata.title ?? entity.metadata.name,
|
|
15
|
+
owner: String(entity.spec?.owner ?? "\u2014"),
|
|
16
|
+
runtime: ann[`${A}/runtime`] ?? "unknown",
|
|
17
|
+
discovery: ann[`${A}/discovery`] ?? "\u2014",
|
|
18
|
+
lifecycle: String(entity.spec?.lifecycle ?? "\u2014"),
|
|
19
|
+
reachable: ann[`${A}/reachable`] ?? "\u2014",
|
|
20
|
+
lastActive: ann[`${A}/last-active`] ?? "\u2014",
|
|
21
|
+
requests: requests !== void 0 ? Number(requests) : void 0,
|
|
22
|
+
window: ann[`${A}/usage-window`] ?? ""
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const columns = [
|
|
26
|
+
{
|
|
27
|
+
title: "Agent",
|
|
28
|
+
field: "name",
|
|
29
|
+
highlight: true,
|
|
30
|
+
render: (row) => /* @__PURE__ */ jsx(EntityRefLink, { entityRef: row.entity, title: row.name })
|
|
31
|
+
},
|
|
32
|
+
{ title: "Owner", field: "owner" },
|
|
33
|
+
{ title: "Runtime", field: "runtime" },
|
|
34
|
+
{
|
|
35
|
+
title: "Discovery",
|
|
36
|
+
field: "discovery",
|
|
37
|
+
render: (row) => /* @__PURE__ */ jsx(Chip, { label: row.discovery, size: "small", variant: "outlined" })
|
|
38
|
+
},
|
|
39
|
+
{ title: "Lifecycle", field: "lifecycle" },
|
|
40
|
+
{
|
|
41
|
+
title: "Reachable",
|
|
42
|
+
field: "reachable",
|
|
43
|
+
render: (row) => row.reachable === "\u2014" ? /* @__PURE__ */ jsx(Fragment, { children: "\u2014" }) : /* @__PURE__ */ jsx(
|
|
44
|
+
Chip,
|
|
45
|
+
{
|
|
46
|
+
label: row.reachable === "true" ? "yes" : "no",
|
|
47
|
+
size: "small",
|
|
48
|
+
style: {
|
|
49
|
+
backgroundColor: row.reachable === "true" ? "#1db95433" : "#e5484d33"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
)
|
|
53
|
+
},
|
|
54
|
+
{ title: "Last active", field: "lastActive" },
|
|
55
|
+
{
|
|
56
|
+
title: "Requests",
|
|
57
|
+
field: "requests",
|
|
58
|
+
type: "numeric",
|
|
59
|
+
render: (row) => row.requests !== void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
60
|
+
row.requests,
|
|
61
|
+
/* @__PURE__ */ jsxs("span", { style: { opacity: 0.6 }, children: [
|
|
62
|
+
" /",
|
|
63
|
+
row.window
|
|
64
|
+
] })
|
|
65
|
+
] }) : /* @__PURE__ */ jsx("span", { style: { opacity: 0.6 }, children: "no key alias" })
|
|
66
|
+
}
|
|
67
|
+
];
|
|
68
|
+
const FleetPage = () => {
|
|
69
|
+
const catalogApi = useApi(catalogApiRef);
|
|
70
|
+
const [rows, setRows] = useState();
|
|
71
|
+
const [error, setError] = useState();
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
catalogApi.getEntities({
|
|
74
|
+
// agents + multi-agent teams + honest heuristic findings
|
|
75
|
+
filter: {
|
|
76
|
+
kind: "Component",
|
|
77
|
+
"spec.type": ["ai-agent", "ai-agent-team", "llm-workload"]
|
|
78
|
+
}
|
|
79
|
+
}).then((res) => setRows(res.items.map(toRow))).catch(setError);
|
|
80
|
+
}, [catalogApi]);
|
|
81
|
+
return /* @__PURE__ */ jsxs(Page, { themeId: "tool", children: [
|
|
82
|
+
/* @__PURE__ */ jsx(
|
|
83
|
+
Header,
|
|
84
|
+
{
|
|
85
|
+
title: "AI Agents",
|
|
86
|
+
subtitle: "It's 10 PM. Do you know where your agents are?"
|
|
87
|
+
}
|
|
88
|
+
),
|
|
89
|
+
/* @__PURE__ */ jsxs(Content, { children: [
|
|
90
|
+
error && /* @__PURE__ */ jsx(ResponseErrorPanel, { error }),
|
|
91
|
+
!rows && !error && /* @__PURE__ */ jsx(Progress, {}),
|
|
92
|
+
rows && /* @__PURE__ */ jsx(
|
|
93
|
+
Table,
|
|
94
|
+
{
|
|
95
|
+
title: `Fleet (${rows.length})`,
|
|
96
|
+
options: { search: true, paging: false, padding: "dense" },
|
|
97
|
+
columns,
|
|
98
|
+
data: rows
|
|
99
|
+
}
|
|
100
|
+
)
|
|
101
|
+
] })
|
|
102
|
+
] });
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export { FleetPage };
|
|
106
|
+
//# sourceMappingURL=FleetPage.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FleetPage.esm.js","sources":["../../src/components/FleetPage.tsx"],"sourcesContent":["/**\n * The fleet view: every AI agent across all sources, one table.\n * \"It's 10 PM. Do you know where your agents are?\"\n */\n\nimport { useEffect, useState } from 'react';\nimport {\n Content,\n Header,\n Page,\n Progress,\n ResponseErrorPanel,\n Table,\n TableColumn,\n} from '@backstage/core-components';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { catalogApiRef, EntityRefLink } from '@backstage/plugin-catalog-react';\nimport type { Entity } from '@backstage/catalog-model';\nimport { Chip } from '@material-ui/core';\n\nconst A = 'agentcatalog.io';\n\ninterface AgentRow {\n entity: Entity;\n name: string;\n owner: string;\n runtime: string;\n discovery: string;\n lifecycle: string;\n reachable: string;\n lastActive: string;\n requests: number | undefined;\n window: string;\n}\n\nfunction toRow(entity: Entity): AgentRow {\n const ann = entity.metadata.annotations ?? {};\n const requests = ann[`${A}/usage-requests`];\n return {\n entity,\n name: entity.metadata.title ?? entity.metadata.name,\n owner: String(entity.spec?.owner ?? '—'),\n runtime: ann[`${A}/runtime`] ?? 'unknown',\n discovery: ann[`${A}/discovery`] ?? '—',\n lifecycle: String(entity.spec?.lifecycle ?? '—'),\n reachable: ann[`${A}/reachable`] ?? '—',\n lastActive: ann[`${A}/last-active`] ?? '—',\n requests: requests !== undefined ? Number(requests) : undefined,\n window: ann[`${A}/usage-window`] ?? '',\n };\n}\n\nconst columns: TableColumn<AgentRow>[] = [\n {\n title: 'Agent',\n field: 'name',\n highlight: true,\n render: row => <EntityRefLink entityRef={row.entity} title={row.name} />,\n },\n { title: 'Owner', field: 'owner' },\n { title: 'Runtime', field: 'runtime' },\n {\n title: 'Discovery',\n field: 'discovery',\n render: row => <Chip label={row.discovery} size=\"small\" variant=\"outlined\" />,\n },\n { title: 'Lifecycle', field: 'lifecycle' },\n {\n title: 'Reachable',\n field: 'reachable',\n render: row =>\n row.reachable === '—' ? (\n <>—</>\n ) : (\n <Chip\n label={row.reachable === 'true' ? 'yes' : 'no'}\n size=\"small\"\n style={{\n backgroundColor: row.reachable === 'true' ? '#1db95433' : '#e5484d33',\n }}\n />\n ),\n },\n { title: 'Last active', field: 'lastActive' },\n {\n title: 'Requests',\n field: 'requests',\n type: 'numeric',\n render: row =>\n row.requests !== undefined ? (\n <>\n {row.requests}\n <span style={{ opacity: 0.6 }}> /{row.window}</span>\n </>\n ) : (\n <span style={{ opacity: 0.6 }}>no key alias</span>\n ),\n },\n];\n\nexport const FleetPage = () => {\n const catalogApi = useApi(catalogApiRef);\n const [rows, setRows] = useState<AgentRow[] | undefined>();\n const [error, setError] = useState<Error | undefined>();\n\n useEffect(() => {\n catalogApi\n .getEntities({\n // agents + multi-agent teams + honest heuristic findings\n filter: {\n kind: 'Component',\n 'spec.type': ['ai-agent', 'ai-agent-team', 'llm-workload'],\n },\n })\n .then(res => setRows(res.items.map(toRow)))\n .catch(setError);\n }, [catalogApi]);\n\n return (\n <Page themeId=\"tool\">\n <Header\n title=\"AI Agents\"\n subtitle=\"It's 10 PM. Do you know where your agents are?\"\n />\n <Content>\n {error && <ResponseErrorPanel error={error} />}\n {!rows && !error && <Progress />}\n {rows && (\n <Table<AgentRow>\n title={`Fleet (${rows.length})`}\n options={{ search: true, paging: false, padding: 'dense' }}\n columns={columns}\n data={rows}\n />\n )}\n </Content>\n </Page>\n );\n};\n"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import * as _backstage_plugin_catalog_react_alpha from '@backstage/plugin-catalog-react/alpha';
|
|
2
|
+
import * as _backstage_frontend_plugin_api from '@backstage/frontend-plugin-api';
|
|
3
|
+
import * as react from 'react';
|
|
4
|
+
import * as _backstage_filter_predicates from '@backstage/filter-predicates';
|
|
5
|
+
import { Entity } from '@backstage/catalog-model';
|
|
6
|
+
|
|
7
|
+
declare const _default: _backstage_frontend_plugin_api.OverridableFrontendPlugin<{}, {}, {
|
|
8
|
+
"entity-card:agent-catalog/agent-info": _backstage_frontend_plugin_api.OverridableExtensionDefinition<{
|
|
9
|
+
kind: "entity-card";
|
|
10
|
+
name: "agent-info";
|
|
11
|
+
config: {
|
|
12
|
+
filter: _backstage_filter_predicates.FilterPredicate | undefined;
|
|
13
|
+
type: "content" | "info" | undefined;
|
|
14
|
+
};
|
|
15
|
+
configInput: {
|
|
16
|
+
filter?: _backstage_filter_predicates.FilterPredicate | undefined;
|
|
17
|
+
type?: "content" | "info" | undefined;
|
|
18
|
+
};
|
|
19
|
+
output: _backstage_frontend_plugin_api.ExtensionDataRef<react.JSX.Element, "core.reactElement", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<(entity: Entity) => boolean, "catalog.entity-filter-function", {
|
|
20
|
+
optional: true;
|
|
21
|
+
}> | _backstage_frontend_plugin_api.ExtensionDataRef<string, "catalog.entity-filter-expression", {
|
|
22
|
+
optional: true;
|
|
23
|
+
}> | _backstage_frontend_plugin_api.ExtensionDataRef<_backstage_plugin_catalog_react_alpha.EntityCardType, "catalog.entity-card-type", {
|
|
24
|
+
optional: true;
|
|
25
|
+
}>;
|
|
26
|
+
inputs: {};
|
|
27
|
+
params: {
|
|
28
|
+
loader: () => Promise<JSX.Element>;
|
|
29
|
+
filter?: string | _backstage_filter_predicates.FilterPredicate | ((entity: Entity) => boolean);
|
|
30
|
+
type?: _backstage_plugin_catalog_react_alpha.EntityCardType;
|
|
31
|
+
};
|
|
32
|
+
}>;
|
|
33
|
+
"page:agent-catalog": _backstage_frontend_plugin_api.OverridableExtensionDefinition<{
|
|
34
|
+
kind: "page";
|
|
35
|
+
name: undefined;
|
|
36
|
+
config: {
|
|
37
|
+
path: string | undefined;
|
|
38
|
+
title: string | undefined;
|
|
39
|
+
};
|
|
40
|
+
configInput: {
|
|
41
|
+
path?: string | undefined;
|
|
42
|
+
title?: string | undefined;
|
|
43
|
+
};
|
|
44
|
+
output: _backstage_frontend_plugin_api.ExtensionDataRef<string, "core.routing.path", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<_backstage_frontend_plugin_api.RouteRef<_backstage_frontend_plugin_api.AnyRouteRefParams>, "core.routing.ref", {
|
|
45
|
+
optional: true;
|
|
46
|
+
}> | _backstage_frontend_plugin_api.ExtensionDataRef<react.JSX.Element, "core.reactElement", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<string, "core.title", {
|
|
47
|
+
optional: true;
|
|
48
|
+
}> | _backstage_frontend_plugin_api.ExtensionDataRef<_backstage_frontend_plugin_api.IconElement, "core.icon", {
|
|
49
|
+
optional: true;
|
|
50
|
+
}>;
|
|
51
|
+
inputs: {
|
|
52
|
+
pages: _backstage_frontend_plugin_api.ExtensionInput<_backstage_frontend_plugin_api.ConfigurableExtensionDataRef<react.JSX.Element, "core.reactElement", {}> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<string, "core.routing.path", {}> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<_backstage_frontend_plugin_api.RouteRef<_backstage_frontend_plugin_api.AnyRouteRefParams>, "core.routing.ref", {
|
|
53
|
+
optional: true;
|
|
54
|
+
}> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<string, "core.title", {
|
|
55
|
+
optional: true;
|
|
56
|
+
}> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<_backstage_frontend_plugin_api.IconElement, "core.icon", {
|
|
57
|
+
optional: true;
|
|
58
|
+
}>, {
|
|
59
|
+
singleton: false;
|
|
60
|
+
optional: false;
|
|
61
|
+
internal: false;
|
|
62
|
+
}>;
|
|
63
|
+
};
|
|
64
|
+
params: {
|
|
65
|
+
path: string;
|
|
66
|
+
title?: string;
|
|
67
|
+
icon?: _backstage_frontend_plugin_api.IconElement;
|
|
68
|
+
loader?: () => Promise<react.JSX.Element>;
|
|
69
|
+
routeRef?: _backstage_frontend_plugin_api.RouteRef;
|
|
70
|
+
noHeader?: boolean;
|
|
71
|
+
};
|
|
72
|
+
}>;
|
|
73
|
+
}>;
|
|
74
|
+
|
|
75
|
+
declare const AgentCatalogSidebarItem: () => react.JSX.Element;
|
|
76
|
+
|
|
77
|
+
declare const agentCatalogNavItem: {
|
|
78
|
+
readonly path: "/agents";
|
|
79
|
+
readonly title: "Agents";
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export { AgentCatalogSidebarItem, agentCatalogNavItem, _default as default };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
|
package/dist/nav.esm.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nav.esm.js","sources":["../src/nav.ts"],"sourcesContent":["export const agentCatalogNavItem = {\n path: '/agents',\n title: 'Agents',\n} as const;\n"],"names":[],"mappings":"AAAO,MAAM,mBAAA,GAAsB;AAAA,EACjC,IAAA,EAAM,SAAA;AAAA,EACN,KAAA,EAAO;AACT;;;;"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { PageBlueprint, createFrontendPlugin } from '@backstage/frontend-plugin-api';
|
|
3
|
+
import { EntityCardBlueprint } from '@backstage/plugin-catalog-react/alpha';
|
|
4
|
+
import AndroidIcon from '@material-ui/icons/Android';
|
|
5
|
+
import { agentCatalogNavItem } from './nav.esm.js';
|
|
6
|
+
|
|
7
|
+
const agentFleetPage = PageBlueprint.make({
|
|
8
|
+
params: {
|
|
9
|
+
path: agentCatalogNavItem.path,
|
|
10
|
+
title: agentCatalogNavItem.title,
|
|
11
|
+
icon: /* @__PURE__ */ jsx(AndroidIcon, {}),
|
|
12
|
+
loader: () => import('./components/FleetPage.esm.js').then((m) => /* @__PURE__ */ jsx(m.FleetPage, {}))
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
const agentInfoCard = EntityCardBlueprint.make({
|
|
16
|
+
name: "agent-info",
|
|
17
|
+
params: {
|
|
18
|
+
filter: (entity) => entity.kind === "Component" && ["ai-agent", "ai-agent-team", "llm-workload"].includes(
|
|
19
|
+
entity.spec?.type ?? ""
|
|
20
|
+
),
|
|
21
|
+
loader: () => import('./components/AgentInfoCard.esm.js').then((m) => /* @__PURE__ */ jsx(m.AgentInfoCard, {}))
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
var plugin = createFrontendPlugin({
|
|
25
|
+
pluginId: "agent-catalog",
|
|
26
|
+
extensions: [agentFleetPage, agentInfoCard]
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
export { plugin as default };
|
|
30
|
+
//# sourceMappingURL=plugin.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.esm.js","sources":["../src/plugin.tsx"],"sourcesContent":["/**\n * agent-catalog frontend plugin (new frontend system).\n *\n * Two extensions, deliberately thin (see the roadmap's frontend scope):\n * - /agents: the fleet page — every AI agent across all sources\n * - an \"Agent\" info card on ai-agent Component pages (traction + status)\n *\n * Discovered automatically via `app.packages: all`; the fleet page's\n * title/icon surface it in the sidebar through the app's nav module.\n * Classic/custom sidebars can import AgentCatalogSidebarItem.\n */\n\nimport { PageBlueprint, createFrontendPlugin } from '@backstage/frontend-plugin-api';\nimport { EntityCardBlueprint } from '@backstage/plugin-catalog-react/alpha';\nimport type { Entity } from '@backstage/catalog-model';\nimport AndroidIcon from '@material-ui/icons/Android';\nimport { agentCatalogNavItem } from './nav';\n\nconst agentFleetPage = PageBlueprint.make({\n params: {\n path: agentCatalogNavItem.path,\n title: agentCatalogNavItem.title,\n icon: <AndroidIcon />,\n loader: () =>\n import('./components/FleetPage').then(m => <m.FleetPage />),\n },\n});\n\nconst agentInfoCard = EntityCardBlueprint.make({\n name: 'agent-info',\n params: {\n filter: (entity: Entity) =>\n entity.kind === 'Component' &&\n ['ai-agent', 'ai-agent-team', 'llm-workload'].includes(\n (entity.spec as { type?: string })?.type ?? '',\n ),\n loader: () =>\n import('./components/AgentInfoCard').then(m => <m.AgentInfoCard />),\n },\n});\n\nexport default createFrontendPlugin({\n pluginId: 'agent-catalog',\n extensions: [agentFleetPage, agentInfoCard],\n});\n"],"names":[],"mappings":";;;;;;AAkBA,MAAM,cAAA,GAAiB,cAAc,IAAA,CAAK;AAAA,EACxC,MAAA,EAAQ;AAAA,IACN,MAAM,mBAAA,CAAoB,IAAA;AAAA,IAC1B,OAAO,mBAAA,CAAoB,KAAA;AAAA,IAC3B,IAAA,sBAAO,WAAA,EAAA,EAAY,CAAA;AAAA,IACnB,MAAA,EAAQ,MACN,OAAO,+BAAwB,CAAA,CAAE,IAAA,CAAK,CAAA,CAAA,qBAAK,GAAA,CAAC,CAAA,CAAE,SAAA,EAAF,EAAY,CAAE;AAAA;AAEhE,CAAC,CAAA;AAED,MAAM,aAAA,GAAgB,oBAAoB,IAAA,CAAK;AAAA,EAC7C,IAAA,EAAM,YAAA;AAAA,EACN,MAAA,EAAQ;AAAA,IACN,MAAA,EAAQ,CAAC,MAAA,KACP,MAAA,CAAO,IAAA,KAAS,eAChB,CAAC,UAAA,EAAY,eAAA,EAAiB,cAAc,CAAA,CAAE,QAAA;AAAA,MAC3C,MAAA,CAAO,MAA4B,IAAA,IAAQ;AAAA,KAC9C;AAAA,IACF,MAAA,EAAQ,MACN,OAAO,mCAA4B,CAAA,CAAE,IAAA,CAAK,CAAA,CAAA,qBAAK,GAAA,CAAC,CAAA,CAAE,aAAA,EAAF,EAAgB,CAAE;AAAA;AAExE,CAAC,CAAA;AAED,aAAe,oBAAA,CAAqB;AAAA,EAClC,QAAA,EAAU,eAAA;AAAA,EACV,UAAA,EAAY,CAAC,cAAA,EAAgB,aAAa;AAC5C,CAAC,CAAA;;;;"}
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@showcall/backstage-plugin-agent-catalog",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Backstage frontend plugin: AI agent fleet view and per-agent traction/status cards",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"homepage": "https://github.com/Showcall/agent-catalog",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/Showcall/agent-catalog.git",
|
|
10
|
+
"directory": "plugins/plugin-agent-catalog"
|
|
11
|
+
},
|
|
12
|
+
"bugs": "https://github.com/Showcall/agent-catalog/issues",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"backstage",
|
|
15
|
+
"backstage-plugin",
|
|
16
|
+
"ai-agents",
|
|
17
|
+
"a2a",
|
|
18
|
+
"kagent",
|
|
19
|
+
"catalog"
|
|
20
|
+
],
|
|
21
|
+
"main": "src/index.ts",
|
|
22
|
+
"types": "src/index.ts",
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public",
|
|
25
|
+
"main": "dist/index.esm.js",
|
|
26
|
+
"module": "dist/index.esm.js",
|
|
27
|
+
"types": "dist/index.d.ts"
|
|
28
|
+
},
|
|
29
|
+
"backstage": {
|
|
30
|
+
"role": "frontend-plugin",
|
|
31
|
+
"pluginId": "agent-catalog"
|
|
32
|
+
},
|
|
33
|
+
"sideEffects": false,
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "backstage-cli package build",
|
|
36
|
+
"lint": "backstage-cli package lint",
|
|
37
|
+
"test": "backstage-cli package test"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@backstage/catalog-model": "^1.9.0",
|
|
41
|
+
"@backstage/core-components": "^0.18.11",
|
|
42
|
+
"@backstage/core-plugin-api": "^1.12.7",
|
|
43
|
+
"@backstage/frontend-plugin-api": "^0.17.2",
|
|
44
|
+
"@backstage/plugin-catalog-react": "^3.1.0",
|
|
45
|
+
"@material-ui/core": "^4.12.4",
|
|
46
|
+
"@material-ui/icons": "^4.11.3"
|
|
47
|
+
},
|
|
48
|
+
"peerDependencies": {
|
|
49
|
+
"react": "^17.0.0 || ^18.0.0",
|
|
50
|
+
"react-dom": "^17.0.0 || ^18.0.0",
|
|
51
|
+
"react-router-dom": "6.0.0-beta.0 || ^6.3.0"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@backstage/cli": "^0.36.3",
|
|
55
|
+
"@types/react": "^18.3.0",
|
|
56
|
+
"@types/react-dom": "^18.3.0",
|
|
57
|
+
"react": "^18.3.1",
|
|
58
|
+
"react-dom": "^18.3.1",
|
|
59
|
+
"react-router-dom": "^6.3.0"
|
|
60
|
+
},
|
|
61
|
+
"files": [
|
|
62
|
+
"dist"
|
|
63
|
+
]
|
|
64
|
+
}
|
package/src/index.ts
ADDED