@terasky/backstage-plugin-ai-rules 0.2.1 → 1.0.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.
@@ -0,0 +1,47 @@
1
+ import * as _backstage_catalog_model from '@backstage/catalog-model';
2
+ import * as React from 'react';
3
+ import * as _backstage_frontend_plugin_api from '@backstage/frontend-plugin-api';
4
+ import * as _backstage_plugin_catalog_react_alpha from '@backstage/plugin-catalog-react/alpha';
5
+
6
+ /** @alpha */
7
+ declare const aiRulesPlugin: _backstage_frontend_plugin_api.OverridableFrontendPlugin<{}, {}, {
8
+ "entity-content:ai-rules": _backstage_frontend_plugin_api.ExtensionDefinition<{
9
+ kind: "entity-content";
10
+ name: undefined;
11
+ config: {
12
+ path: string | undefined;
13
+ title: string | undefined;
14
+ filter: _backstage_plugin_catalog_react_alpha.EntityPredicate | undefined;
15
+ group: string | false | undefined;
16
+ };
17
+ configInput: {
18
+ filter?: _backstage_plugin_catalog_react_alpha.EntityPredicate | undefined;
19
+ title?: string | undefined;
20
+ path?: string | undefined;
21
+ group?: string | false | undefined;
22
+ };
23
+ output: _backstage_frontend_plugin_api.ExtensionDataRef<string, "core.routing.path", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<React.JSX.Element, "core.reactElement", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<_backstage_frontend_plugin_api.RouteRef<_backstage_frontend_plugin_api.AnyRouteRefParams>, "core.routing.ref", {
24
+ optional: true;
25
+ }> | _backstage_frontend_plugin_api.ExtensionDataRef<(entity: _backstage_catalog_model.Entity) => boolean, "catalog.entity-filter-function", {
26
+ optional: true;
27
+ }> | _backstage_frontend_plugin_api.ExtensionDataRef<string, "catalog.entity-filter-expression", {
28
+ optional: true;
29
+ }> | _backstage_frontend_plugin_api.ExtensionDataRef<string, "catalog.entity-content-title", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<string, "catalog.entity-content-group", {
30
+ optional: true;
31
+ }>;
32
+ inputs: {};
33
+ params: {
34
+ defaultPath?: [Error: `Use the 'path' param instead`];
35
+ path: string;
36
+ defaultTitle?: [Error: `Use the 'title' param instead`];
37
+ title: string;
38
+ defaultGroup?: [Error: `Use the 'group' param instead`];
39
+ group?: ("development" | "deployment" | "documentation" | "operation" | "overview" | "observability") | (string & {});
40
+ loader: () => Promise<JSX.Element>;
41
+ routeRef?: _backstage_frontend_plugin_api.RouteRef;
42
+ filter?: string | _backstage_plugin_catalog_react_alpha.EntityPredicate | ((entity: _backstage_catalog_model.Entity) => boolean);
43
+ };
44
+ }>;
45
+ }>;
46
+
47
+ export { aiRulesPlugin };
@@ -0,0 +1,54 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { createFrontendPlugin, ApiBlueprint, discoveryApiRef, identityApiRef } from '@backstage/frontend-plugin-api';
3
+ import { EntityContentBlueprint } from '@backstage/plugin-catalog-react/alpha';
4
+ import { isAIRulesAvailable } from './components/AiRulesComponent/AiRulesComponent.esm.js';
5
+ import { aiRulesApiRef } from './api/types.esm.js';
6
+ import { AiRulesClient } from './api/AiRulesClient.esm.js';
7
+
8
+ const aiRulesPlugin = createFrontendPlugin({
9
+ pluginId: "ai-rules",
10
+ extensions: [
11
+ EntityContentBlueprint.make({
12
+ params: {
13
+ path: "/ai-rules",
14
+ filter: isAIRulesAvailable,
15
+ title: "AI Rules",
16
+ loader: () => import('./components/AiRulesComponent/AiRulesComponent.esm.js').then((m) => /* @__PURE__ */ jsx(m.AIRulesComponent, {}))
17
+ },
18
+ disabled: true
19
+ }),
20
+ EntityContentBlueprint.make({
21
+ params: {
22
+ path: "/ai-instructions",
23
+ filter: isAIRulesAvailable,
24
+ title: "AI Instructions",
25
+ loader: () => import('./components/AiInstructionsComponent/AiInstructionsComponent.esm.js').then((m) => /* @__PURE__ */ jsx(m.AiInstructionsComponent, {}))
26
+ },
27
+ disabled: false
28
+ }),
29
+ EntityContentBlueprint.make({
30
+ params: {
31
+ path: "/mcp-servers",
32
+ filter: isAIRulesAvailable,
33
+ title: "MCP Servers",
34
+ loader: () => import('./components/MCPServersComponent/MCPServersComponent.esm.js').then((m) => /* @__PURE__ */ jsx(m.MCPServersComponent, {}))
35
+ },
36
+ disabled: true
37
+ }),
38
+ ApiBlueprint.make({
39
+ name: "aiRulesApi",
40
+ params: (defineParams) => defineParams({
41
+ api: aiRulesApiRef,
42
+ deps: {
43
+ discoveryApi: discoveryApiRef,
44
+ identityApi: identityApiRef
45
+ },
46
+ factory: ({ discoveryApi, identityApi }) => new AiRulesClient({ discoveryApi, identityApi })
47
+ }),
48
+ disabled: false
49
+ })
50
+ ]
51
+ });
52
+
53
+ export { aiRulesPlugin };
54
+ //# sourceMappingURL=alpha.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alpha.esm.js","sources":["../src/alpha.tsx"],"sourcesContent":["import {\n ApiBlueprint,\n createFrontendPlugin,\n discoveryApiRef,\n identityApiRef,\n} from '@backstage/frontend-plugin-api';\nimport { EntityContentBlueprint } from '@backstage/plugin-catalog-react/alpha';\nimport { isAIRulesAvailable } from './components/AiRulesComponent';\nimport { aiRulesApiRef, AiRulesClient } from './api';\n\n/** @alpha */\nexport const aiRulesPlugin = createFrontendPlugin({\n pluginId: 'ai-rules',\n extensions: [\n EntityContentBlueprint.make({\n params: {\n path: '/ai-rules',\n filter: isAIRulesAvailable,\n title: 'AI Rules',\n loader: () => import('./components/AiRulesComponent/AiRulesComponent').then(m => <m.AIRulesComponent />),\n },\n disabled: true,\n }),\n EntityContentBlueprint.make({\n params: {\n path: '/ai-instructions',\n filter: isAIRulesAvailable,\n title: 'AI Instructions',\n loader: () => import('./components/AiInstructionsComponent/AiInstructionsComponent').then(m => <m.AiInstructionsComponent />),\n },\n disabled: false,\n }),\n EntityContentBlueprint.make({\n params: {\n path: '/mcp-servers',\n filter: isAIRulesAvailable,\n title: 'MCP Servers',\n loader: () => import('./components/MCPServersComponent/MCPServersComponent').then(m => <m.MCPServersComponent />),\n },\n disabled: true,\n }),\n ApiBlueprint.make({\n name: 'aiRulesApi',\n params: defineParams => defineParams({\n api: aiRulesApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n identityApi: identityApiRef,\n },\n factory: ({ discoveryApi, identityApi }) => new AiRulesClient({ discoveryApi, identityApi }),\n }),\n disabled: false,\n }),\n ],\n});"],"names":[],"mappings":";;;;;;;AAWO,MAAM,gBAAgB,oBAAqB,CAAA;AAAA,EAChD,QAAU,EAAA,UAAA;AAAA,EACV,UAAY,EAAA;AAAA,IACV,uBAAuB,IAAK,CAAA;AAAA,MAC1B,MAAQ,EAAA;AAAA,QACN,IAAM,EAAA,WAAA;AAAA,QACN,MAAQ,EAAA,kBAAA;AAAA,QACR,KAAO,EAAA,UAAA;AAAA,QACP,MAAA,EAAQ,MAAM,OAAO,uDAAgD,CAAA,CAAE,IAAK,CAAA,CAAA,CAAA,qBAAM,GAAA,CAAA,CAAA,CAAE,gBAAF,EAAA,EAAmB,CAAE;AAAA,OACzG;AAAA,MACA,QAAU,EAAA;AAAA,KACX,CAAA;AAAA,IACD,uBAAuB,IAAK,CAAA;AAAA,MAC1B,MAAQ,EAAA;AAAA,QACN,IAAM,EAAA,kBAAA;AAAA,QACN,MAAQ,EAAA,kBAAA;AAAA,QACR,KAAO,EAAA,iBAAA;AAAA,QACP,MAAA,EAAQ,MAAM,OAAO,qEAA8D,CAAA,CAAE,IAAK,CAAA,CAAA,CAAA,qBAAM,GAAA,CAAA,CAAA,CAAE,uBAAF,EAAA,EAA0B,CAAE;AAAA,OAC9H;AAAA,MACA,QAAU,EAAA;AAAA,KACX,CAAA;AAAA,IACD,uBAAuB,IAAK,CAAA;AAAA,MAC1B,MAAQ,EAAA;AAAA,QACN,IAAM,EAAA,cAAA;AAAA,QACN,MAAQ,EAAA,kBAAA;AAAA,QACR,KAAO,EAAA,aAAA;AAAA,QACP,MAAA,EAAQ,MAAM,OAAO,6DAAsD,CAAA,CAAE,IAAK,CAAA,CAAA,CAAA,qBAAM,GAAA,CAAA,CAAA,CAAE,mBAAF,EAAA,EAAsB,CAAE;AAAA,OAClH;AAAA,MACA,QAAU,EAAA;AAAA,KACX,CAAA;AAAA,IACD,aAAa,IAAK,CAAA;AAAA,MAChB,IAAM,EAAA,YAAA;AAAA,MACN,MAAA,EAAQ,kBAAgB,YAAa,CAAA;AAAA,QACnC,GAAK,EAAA,aAAA;AAAA,QACL,IAAM,EAAA;AAAA,UACJ,YAAc,EAAA,eAAA;AAAA,UACd,WAAa,EAAA;AAAA,SACf;AAAA,QACA,OAAA,EAAS,CAAC,EAAE,YAAc,EAAA,WAAA,EAAkB,KAAA,IAAI,aAAc,CAAA,EAAE,YAAc,EAAA,WAAA,EAAa;AAAA,OAC5F,CAAA;AAAA,MACD,QAAU,EAAA;AAAA,KACX;AAAA;AAEL,CAAC;;;;"}
@@ -0,0 +1,47 @@
1
+ class AiRulesClient {
2
+ discoveryApi;
3
+ identityApi;
4
+ constructor(options) {
5
+ this.discoveryApi = options.discoveryApi;
6
+ this.identityApi = options.identityApi;
7
+ }
8
+ async getAuthHeaders() {
9
+ const { token } = await this.identityApi.getCredentials();
10
+ return {
11
+ "Authorization": `Bearer ${token}`
12
+ };
13
+ }
14
+ cleanGitUrl(url) {
15
+ return url.replace("url:", "").replace(/\/tree\/(?:main|master)\/.*$/, "");
16
+ }
17
+ async getAiRules(ruleTypes) {
18
+ const baseUrl = await this.discoveryApi.getBaseUrl("ai-rules");
19
+ const sourceLocation = window.location.pathname.split("/").includes("catalog") ? new URLSearchParams(window.location.search).get("sourceLocation") || "" : "";
20
+ const gitUrl = this.cleanGitUrl(sourceLocation);
21
+ const queryParams = new URLSearchParams({
22
+ gitUrl,
23
+ ruleTypes: ruleTypes.join(",")
24
+ });
25
+ const response = await fetch(`${baseUrl}/rules?${queryParams}`, {
26
+ headers: await this.getAuthHeaders()
27
+ });
28
+ if (!response.ok) {
29
+ throw new Error("Failed to fetch AI rules");
30
+ }
31
+ return await response.json();
32
+ }
33
+ async getMCPServers(gitUrl) {
34
+ const baseUrl = await this.discoveryApi.getBaseUrl("ai-rules");
35
+ const queryParams = new URLSearchParams({ gitUrl });
36
+ const response = await fetch(`${baseUrl}/mcp-servers?${queryParams}`, {
37
+ headers: await this.getAuthHeaders()
38
+ });
39
+ if (!response.ok) {
40
+ throw new Error("Failed to fetch MCP servers");
41
+ }
42
+ return await response.json();
43
+ }
44
+ }
45
+
46
+ export { AiRulesClient };
47
+ //# sourceMappingURL=AiRulesClient.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AiRulesClient.esm.js","sources":["../../src/api/AiRulesClient.ts"],"sourcesContent":["import { AiRulesApi } from './types';\nimport { AIRulesResponse } from '../types';\nimport { MCPServersResponse } from '../types/mcp';\n\n\nexport class AiRulesClient implements AiRulesApi {\n private readonly discoveryApi: { getBaseUrl: (pluginId: string) => Promise<string> };\n private readonly identityApi: { getCredentials(): Promise<{ token?: string }> };\n\n constructor(options: {\n discoveryApi: { getBaseUrl: (pluginId: string) => Promise<string> };\n identityApi: { getCredentials(): Promise<{ token?: string }> };\n }) {\n this.discoveryApi = options.discoveryApi;\n this.identityApi = options.identityApi;\n }\n\n private async getAuthHeaders(): Promise<HeadersInit> {\n const { token } = await this.identityApi.getCredentials();\n return {\n 'Authorization': `Bearer ${token}`,\n };\n }\n\n private cleanGitUrl(url: string): string {\n return url\n .replace('url:', '')\n .replace(/\\/tree\\/(?:main|master)\\/.*$/, '');\n }\n\n async getAiRules(ruleTypes: string[]): Promise<AIRulesResponse> {\n const baseUrl = await this.discoveryApi.getBaseUrl('ai-rules');\n const sourceLocation = window.location.pathname.split('/').includes('catalog')\n ? new URLSearchParams(window.location.search).get('sourceLocation') || ''\n : '';\n const gitUrl = this.cleanGitUrl(sourceLocation);\n \n const queryParams = new URLSearchParams({\n gitUrl,\n ruleTypes: ruleTypes.join(','),\n });\n\n const response = await fetch(`${baseUrl}/rules?${queryParams}`, {\n headers: await this.getAuthHeaders(),\n });\n if (!response.ok) {\n throw new Error('Failed to fetch AI rules');\n }\n return await response.json();\n }\n\n async getMCPServers(gitUrl: string): Promise<MCPServersResponse> {\n const baseUrl = await this.discoveryApi.getBaseUrl('ai-rules');\n const queryParams = new URLSearchParams({ gitUrl });\n\n const response = await fetch(`${baseUrl}/mcp-servers?${queryParams}`, {\n headers: await this.getAuthHeaders(),\n });\n if (!response.ok) {\n throw new Error('Failed to fetch MCP servers');\n }\n return await response.json();\n }\n}\n"],"names":[],"mappings":"AAKO,MAAM,aAAoC,CAAA;AAAA,EAC9B,YAAA;AAAA,EACA,WAAA;AAAA,EAEjB,YAAY,OAGT,EAAA;AACD,IAAA,IAAA,CAAK,eAAe,OAAQ,CAAA,YAAA;AAC5B,IAAA,IAAA,CAAK,cAAc,OAAQ,CAAA,WAAA;AAAA;AAC7B,EAEA,MAAc,cAAuC,GAAA;AACnD,IAAA,MAAM,EAAE,KAAM,EAAA,GAAI,MAAM,IAAA,CAAK,YAAY,cAAe,EAAA;AACxD,IAAO,OAAA;AAAA,MACL,eAAA,EAAiB,UAAU,KAAK,CAAA;AAAA,KAClC;AAAA;AACF,EAEQ,YAAY,GAAqB,EAAA;AACvC,IAAA,OAAO,IACJ,OAAQ,CAAA,MAAA,EAAQ,EAAE,CAClB,CAAA,OAAA,CAAQ,gCAAgC,EAAE,CAAA;AAAA;AAC/C,EAEA,MAAM,WAAW,SAA+C,EAAA;AAC9D,IAAA,MAAM,OAAU,GAAA,MAAM,IAAK,CAAA,YAAA,CAAa,WAAW,UAAU,CAAA;AAC7D,IAAA,MAAM,iBAAiB,MAAO,CAAA,QAAA,CAAS,SAAS,KAAM,CAAA,GAAG,EAAE,QAAS,CAAA,SAAS,IACzE,IAAI,eAAA,CAAgB,OAAO,QAAS,CAAA,MAAM,EAAE,GAAI,CAAA,gBAAgB,KAAK,EACrE,GAAA,EAAA;AACJ,IAAM,MAAA,MAAA,GAAS,IAAK,CAAA,WAAA,CAAY,cAAc,CAAA;AAE9C,IAAM,MAAA,WAAA,GAAc,IAAI,eAAgB,CAAA;AAAA,MACtC,MAAA;AAAA,MACA,SAAA,EAAW,SAAU,CAAA,IAAA,CAAK,GAAG;AAAA,KAC9B,CAAA;AAED,IAAA,MAAM,WAAW,MAAM,KAAA,CAAM,GAAG,OAAO,CAAA,OAAA,EAAU,WAAW,CAAI,CAAA,EAAA;AAAA,MAC9D,OAAA,EAAS,MAAM,IAAA,CAAK,cAAe;AAAA,KACpC,CAAA;AACD,IAAI,IAAA,CAAC,SAAS,EAAI,EAAA;AAChB,MAAM,MAAA,IAAI,MAAM,0BAA0B,CAAA;AAAA;AAE5C,IAAO,OAAA,MAAM,SAAS,IAAK,EAAA;AAAA;AAC7B,EAEA,MAAM,cAAc,MAA6C,EAAA;AAC/D,IAAA,MAAM,OAAU,GAAA,MAAM,IAAK,CAAA,YAAA,CAAa,WAAW,UAAU,CAAA;AAC7D,IAAA,MAAM,WAAc,GAAA,IAAI,eAAgB,CAAA,EAAE,QAAQ,CAAA;AAElD,IAAA,MAAM,WAAW,MAAM,KAAA,CAAM,GAAG,OAAO,CAAA,aAAA,EAAgB,WAAW,CAAI,CAAA,EAAA;AAAA,MACpE,OAAA,EAAS,MAAM,IAAA,CAAK,cAAe;AAAA,KACpC,CAAA;AACD,IAAI,IAAA,CAAC,SAAS,EAAI,EAAA;AAChB,MAAM,MAAA,IAAI,MAAM,6BAA6B,CAAA;AAAA;AAE/C,IAAO,OAAA,MAAM,SAAS,IAAK,EAAA;AAAA;AAE/B;;;;"}
@@ -0,0 +1,8 @@
1
+ import { createApiRef } from '@backstage/core-plugin-api';
2
+
3
+ const aiRulesApiRef = createApiRef({
4
+ id: "plugin.ai-rules.service"
5
+ });
6
+
7
+ export { aiRulesApiRef };
8
+ //# sourceMappingURL=types.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.esm.js","sources":["../../src/api/types.ts"],"sourcesContent":["import { AIRulesResponse } from '../types';\nimport { MCPServersResponse } from '../types/mcp';\n\nimport { createApiRef } from '@backstage/core-plugin-api';\n\nexport const aiRulesApiRef = createApiRef<AiRulesApi>({\n id: 'plugin.ai-rules.service',\n});\n\nexport interface AiRulesApi {\n getAiRules(ruleTypes: string[]): Promise<AIRulesResponse>;\n getMCPServers(gitUrl: string): Promise<MCPServersResponse>;\n}\n"],"names":[],"mappings":";;AAKO,MAAM,gBAAgB,YAAyB,CAAA;AAAA,EACpD,EAAI,EAAA;AACN,CAAC;;;;"}
@@ -0,0 +1,65 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useState } from 'react';
3
+ import { makeStyles } from '@material-ui/core/styles';
4
+ import { Tabs, Tab, Box } from '@material-ui/core';
5
+ import { AIRulesComponent } from '../AiRulesComponent/AiRulesComponent.esm.js';
6
+ import { MCPServersComponent } from '../MCPServersComponent/MCPServersComponent.esm.js';
7
+
8
+ function TabPanel(props) {
9
+ const { children, value, index, ...other } = props;
10
+ return /* @__PURE__ */ jsx(
11
+ "div",
12
+ {
13
+ role: "tabpanel",
14
+ hidden: value !== index,
15
+ id: `ai-instructions-tabpanel-${index}`,
16
+ "aria-labelledby": `ai-instructions-tab-${index}`,
17
+ ...other,
18
+ children: value === index && /* @__PURE__ */ jsx(Box, { children })
19
+ }
20
+ );
21
+ }
22
+ function a11yProps(index) {
23
+ return {
24
+ id: `ai-instructions-tab-${index}`,
25
+ "aria-controls": `ai-instructions-tabpanel-${index}`
26
+ };
27
+ }
28
+ const useStyles = makeStyles((theme) => ({
29
+ root: {
30
+ width: "100%",
31
+ backgroundColor: theme.palette.background.paper
32
+ },
33
+ tabPanel: {
34
+ padding: 0,
35
+ marginTop: theme.spacing(2)
36
+ }
37
+ }));
38
+ const AiInstructionsComponent = ({ title = "AI Instructions" }) => {
39
+ const styles = useStyles();
40
+ const [value, setValue] = useState(0);
41
+ const handleChange = (_event, newValue) => {
42
+ setValue(newValue);
43
+ };
44
+ return /* @__PURE__ */ jsxs("div", { className: styles.root, children: [
45
+ /* @__PURE__ */ jsxs(
46
+ Tabs,
47
+ {
48
+ value,
49
+ onChange: handleChange,
50
+ indicatorColor: "primary",
51
+ textColor: "primary",
52
+ variant: "fullWidth",
53
+ children: [
54
+ /* @__PURE__ */ jsx(Tab, { label: "Agent Rules", ...a11yProps(0) }),
55
+ /* @__PURE__ */ jsx(Tab, { label: "MCP Servers", ...a11yProps(1) })
56
+ ]
57
+ }
58
+ ),
59
+ /* @__PURE__ */ jsx(TabPanel, { value, index: 0, children: /* @__PURE__ */ jsx(Box, { className: styles.tabPanel, children: /* @__PURE__ */ jsx(AIRulesComponent, { title }) }) }),
60
+ /* @__PURE__ */ jsx(TabPanel, { value, index: 1, children: /* @__PURE__ */ jsx(Box, { className: styles.tabPanel, children: /* @__PURE__ */ jsx(MCPServersComponent, {}) }) })
61
+ ] });
62
+ };
63
+
64
+ export { AiInstructionsComponent };
65
+ //# sourceMappingURL=AiInstructionsComponent.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AiInstructionsComponent.esm.js","sources":["../../../src/components/AiInstructionsComponent/AiInstructionsComponent.tsx"],"sourcesContent":["import React, { useState } from 'react';\nimport { makeStyles } from '@material-ui/core/styles';\nimport {\n Tabs,\n Tab,\n Box,\n} from '@material-ui/core';\nimport { AIRulesComponent } from '../AiRulesComponent';\nimport { MCPServersComponent } from '../MCPServersComponent';\n\ninterface TabPanelProps {\n children?: React.ReactNode;\n index: number;\n value: number;\n}\n\nfunction TabPanel(props: TabPanelProps) {\n const { children, value, index, ...other } = props;\n\n return (\n <div\n role=\"tabpanel\"\n hidden={value !== index}\n id={`ai-instructions-tabpanel-${index}`}\n aria-labelledby={`ai-instructions-tab-${index}`}\n {...other}\n >\n {value === index && (\n <Box>\n {children}\n </Box>\n )}\n </div>\n );\n}\n\nfunction a11yProps(index: number) {\n return {\n id: `ai-instructions-tab-${index}`,\n 'aria-controls': `ai-instructions-tabpanel-${index}`,\n };\n}\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n width: '100%',\n backgroundColor: theme.palette.background.paper,\n },\n tabPanel: {\n padding: 0,\n marginTop: theme.spacing(2),\n },\n}));\n\nexport interface AiInstructionsComponentProps {\n title?: string;\n}\n\nexport const AiInstructionsComponent = ({ title = \"AI Instructions\" }: AiInstructionsComponentProps) => {\n const styles = useStyles();\n const [value, setValue] = useState(0);\n\n const handleChange = (_event: React.ChangeEvent<{}>, newValue: number) => {\n setValue(newValue);\n };\n\n return (\n <div className={styles.root}>\n <Tabs\n value={value}\n onChange={handleChange}\n indicatorColor=\"primary\"\n textColor=\"primary\"\n variant=\"fullWidth\"\n >\n <Tab label=\"Agent Rules\" {...a11yProps(0)} />\n <Tab label=\"MCP Servers\" {...a11yProps(1)} />\n </Tabs>\n <TabPanel value={value} index={0}>\n <Box className={styles.tabPanel}>\n <AIRulesComponent title={title} />\n </Box>\n </TabPanel>\n <TabPanel value={value} index={1}>\n <Box className={styles.tabPanel}>\n <MCPServersComponent />\n </Box>\n </TabPanel>\n </div>\n );\n};\n\n\n"],"names":[],"mappings":";;;;;;;AAgBA,SAAS,SAAS,KAAsB,EAAA;AACtC,EAAA,MAAM,EAAE,QAAU,EAAA,KAAA,EAAO,KAAO,EAAA,GAAG,OAAU,GAAA,KAAA;AAE7C,EACE,uBAAA,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,IAAK,EAAA,UAAA;AAAA,MACL,QAAQ,KAAU,KAAA,KAAA;AAAA,MAClB,EAAA,EAAI,4BAA4B,KAAK,CAAA,CAAA;AAAA,MACrC,iBAAA,EAAiB,uBAAuB,KAAK,CAAA,CAAA;AAAA,MAC5C,GAAG,KAAA;AAAA,MAEH,QAAU,EAAA,KAAA,KAAA,KAAA,oBACR,GAAA,CAAA,GAAA,EAAA,EACE,QACH,EAAA;AAAA;AAAA,GAEJ;AAEJ;AAEA,SAAS,UAAU,KAAe,EAAA;AAChC,EAAO,OAAA;AAAA,IACL,EAAA,EAAI,uBAAuB,KAAK,CAAA,CAAA;AAAA,IAChC,eAAA,EAAiB,4BAA4B,KAAK,CAAA;AAAA,GACpD;AACF;AAEA,MAAM,SAAA,GAAY,UAAW,CAAA,CAAC,KAAW,MAAA;AAAA,EACvC,IAAM,EAAA;AAAA,IACJ,KAAO,EAAA,MAAA;AAAA,IACP,eAAA,EAAiB,KAAM,CAAA,OAAA,CAAQ,UAAW,CAAA;AAAA,GAC5C;AAAA,EACA,QAAU,EAAA;AAAA,IACR,OAAS,EAAA,CAAA;AAAA,IACT,SAAA,EAAW,KAAM,CAAA,OAAA,CAAQ,CAAC;AAAA;AAE9B,CAAE,CAAA,CAAA;AAMK,MAAM,uBAA0B,GAAA,CAAC,EAAE,KAAA,GAAQ,mBAAsD,KAAA;AACtG,EAAA,MAAM,SAAS,SAAU,EAAA;AACzB,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAS,CAAC,CAAA;AAEpC,EAAM,MAAA,YAAA,GAAe,CAAC,MAAA,EAA+B,QAAqB,KAAA;AACxE,IAAA,QAAA,CAAS,QAAQ,CAAA;AAAA,GACnB;AAEA,EAAA,uBACG,IAAA,CAAA,KAAA,EAAA,EAAI,SAAW,EAAA,MAAA,CAAO,IACrB,EAAA,QAAA,EAAA;AAAA,oBAAA,IAAA;AAAA,MAAC,IAAA;AAAA,MAAA;AAAA,QACC,KAAA;AAAA,QACA,QAAU,EAAA,YAAA;AAAA,QACV,cAAe,EAAA,SAAA;AAAA,QACf,SAAU,EAAA,SAAA;AAAA,QACV,OAAQ,EAAA,WAAA;AAAA,QAER,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,OAAI,KAAM,EAAA,aAAA,EAAe,GAAG,SAAA,CAAU,CAAC,CAAG,EAAA,CAAA;AAAA,8BAC1C,GAAI,EAAA,EAAA,KAAA,EAAM,eAAe,GAAG,SAAA,CAAU,CAAC,CAAG,EAAA;AAAA;AAAA;AAAA,KAC7C;AAAA,oBACC,GAAA,CAAA,QAAA,EAAA,EAAS,KAAc,EAAA,KAAA,EAAO,GAC7B,QAAC,kBAAA,GAAA,CAAA,GAAA,EAAA,EAAI,SAAW,EAAA,MAAA,CAAO,QACrB,EAAA,QAAA,kBAAA,GAAA,CAAC,gBAAiB,EAAA,EAAA,KAAA,EAAc,GAClC,CACF,EAAA,CAAA;AAAA,oBACC,GAAA,CAAA,QAAA,EAAA,EAAS,KAAc,EAAA,KAAA,EAAO,CAC7B,EAAA,QAAA,kBAAA,GAAA,CAAC,GAAI,EAAA,EAAA,SAAA,EAAW,MAAO,CAAA,QAAA,EACrB,QAAC,kBAAA,GAAA,CAAA,mBAAA,EAAA,EAAoB,GACvB,CACF,EAAA;AAAA,GACF,EAAA,CAAA;AAEJ;;;;"}
@@ -230,27 +230,45 @@ const RuleComponent = ({ rule }) => {
230
230
  ] }) })
231
231
  ] });
232
232
  };
233
- const renderCopilotRule = (rule2) => /* @__PURE__ */ jsx(Card, { className: styles.ruleCard, children: /* @__PURE__ */ jsxs(CardContent, { children: [
234
- /* @__PURE__ */ jsxs("div", { className: styles.ruleHeader, children: [
235
- /* @__PURE__ */ jsxs("div", { className: styles.ruleHeaderContent, children: [
236
- /* @__PURE__ */ jsx(RuleTypeIcon, { type: rule2.type }),
237
- /* @__PURE__ */ jsxs(Typography, { variant: "h6", children: [
238
- "Copilot Rule #",
239
- rule2.order
233
+ const renderCopilotRule = (rule2) => {
234
+ const ruleNumber = rule2.order || (rule2.fileName.match(/Rule (\d+)/) || [])[1] || rule2.id.split("-").pop();
235
+ return /* @__PURE__ */ jsxs(Accordion, { className: styles.ruleCard, children: [
236
+ /* @__PURE__ */ jsx(AccordionSummary, { expandIcon: /* @__PURE__ */ jsx(ExpandMoreIcon, {}), children: /* @__PURE__ */ jsxs("div", { className: styles.ruleHeader, children: [
237
+ /* @__PURE__ */ jsxs("div", { className: styles.ruleHeaderContent, children: [
238
+ /* @__PURE__ */ jsx(RuleTypeIcon, { type: rule2.type }),
239
+ /* @__PURE__ */ jsx(Typography, { variant: "h6", children: rule2.title || `Copilot Rule #${ruleNumber}` }),
240
+ /* @__PURE__ */ jsx(Chip, { label: rule2.type, size: "small", className: styles.ruleType }),
241
+ rule2.applyTo && /* @__PURE__ */ jsx(
242
+ Chip,
243
+ {
244
+ label: `Applies to: ${rule2.applyTo}`,
245
+ size: "small",
246
+ variant: "outlined",
247
+ style: { marginLeft: 8 }
248
+ }
249
+ )
240
250
  ] }),
241
- /* @__PURE__ */ jsx(Chip, { label: rule2.type, size: "small", className: styles.ruleType })
242
- ] }),
243
- rule2.gitUrl && /* @__PURE__ */ jsx(Tooltip, { title: "Open file in repository", children: /* @__PURE__ */ jsx(
244
- IconButton,
245
- {
246
- size: "small",
247
- onClick: () => window.open(constructFileUrl(rule2.gitUrl, rule2.filePath), "_blank"),
248
- children: /* @__PURE__ */ jsx(LaunchIcon, { fontSize: "small" })
249
- }
250
- ) })
251
- ] }),
252
- /* @__PURE__ */ jsx("div", { className: styles.ruleContent, children: rule2.content })
253
- ] }) });
251
+ rule2.gitUrl && /* @__PURE__ */ jsx(Tooltip, { title: "Open file in repository", children: /* @__PURE__ */ jsx(
252
+ IconButton,
253
+ {
254
+ size: "small",
255
+ onClick: (e) => {
256
+ e.stopPropagation();
257
+ window.open(constructFileUrl(rule2.gitUrl, rule2.filePath), "_blank");
258
+ },
259
+ children: /* @__PURE__ */ jsx(LaunchIcon, { fontSize: "small" })
260
+ }
261
+ ) })
262
+ ] }) }),
263
+ /* @__PURE__ */ jsx(AccordionDetails, { children: /* @__PURE__ */ jsxs("div", { children: [
264
+ /* @__PURE__ */ jsxs("div", { className: styles.ruleMetadata, children: [
265
+ /* @__PURE__ */ jsx(Chip, { label: `Path: ${rule2.filePath}`, size: "small", variant: "outlined" }),
266
+ rule2.frontmatter && renderFrontmatter(theme, rule2.frontmatter)
267
+ ] }),
268
+ /* @__PURE__ */ jsx("div", { className: styles.ruleContent, children: /* @__PURE__ */ jsx(MarkdownContent, { content: rule2.content }) })
269
+ ] }) })
270
+ ] });
271
+ };
254
272
  const renderClineRule = (rule2) => /* @__PURE__ */ jsxs(Accordion, { className: styles.ruleCard, children: [
255
273
  /* @__PURE__ */ jsx(AccordionSummary, { expandIcon: /* @__PURE__ */ jsx(ExpandMoreIcon, {}), children: /* @__PURE__ */ jsxs("div", { className: styles.ruleHeader, children: [
256
274
  /* @__PURE__ */ jsxs("div", { className: styles.ruleHeaderContent, children: [
@@ -1 +1 @@
1
- {"version":3,"file":"AiRulesComponent.esm.js","sources":["../../../src/components/AiRulesComponent/AiRulesComponent.tsx"],"sourcesContent":["import { useAiRules } from '../../hooks/useAiRules';\nimport { InfoCard, Progress, EmptyState, MarkdownContent } from '@backstage/core-components';\nimport { Button, makeStyles, useTheme, Typography, Chip, Card, CardContent, Accordion, AccordionSummary, AccordionDetails, FormControlLabel, Checkbox, IconButton, Tooltip } from '@material-ui/core';\nimport { Entity } from '@backstage/catalog-model';\nimport ExpandMoreIcon from '@material-ui/icons/ExpandMore';\nimport CodeIcon from '@material-ui/icons/Code';\nimport LaunchIcon from '@material-ui/icons/Launch';\nimport { AIRuleType, AIRule, CursorRule, CopilotRule, ClineRule, ClaudeCodeRule } from '../../types';\nexport interface AIRulesComponentProps {\n title?: string;\n}\n\nexport const isAIRulesAvailable = (entity: Entity): boolean => {\n const sourceAnnotation = entity.metadata?.annotations?.['backstage.io/source-location'] || '';\n return sourceAnnotation.startsWith('url:');\n};\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n '& .MuiAccordion-root': {\n marginBottom: theme.spacing(1),\n '&:before': {\n display: 'none',\n },\n },\n },\n filterSection: {\n marginBottom: theme.spacing(2),\n padding: theme.spacing(2),\n backgroundColor: theme.palette.background.default,\n borderRadius: theme.shape.borderRadius,\n },\n ruleCard: {\n marginBottom: theme.spacing(1),\n border: `1px solid ${theme.palette.divider}`,\n },\n ruleHeader: {\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(1),\n width: '100%',\n },\n ruleHeaderContent: {\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(1),\n flex: 1,\n },\n ruleType: {\n textTransform: 'uppercase',\n fontWeight: 'bold',\n fontSize: '0.75rem',\n },\n ruleContent: {\n padding: theme.spacing(1),\n borderRadius: theme.shape.borderRadius,\n overflow: 'auto',\n maxHeight: '300px',\n '& > *': {\n backgroundColor: 'transparent !important',\n },\n },\n ruleMetadata: {\n display: 'flex',\n flexWrap: 'wrap',\n gap: theme.spacing(0.5),\n marginBottom: theme.spacing(1),\n },\n statsContainer: {\n display: 'flex',\n gap: theme.spacing(2),\n marginBottom: theme.spacing(2),\n },\n statCard: {\n minWidth: '120px',\n textAlign: 'center',\n },\n emptyStateIcon: {\n fontSize: '4rem',\n color: theme.palette.grey[400],\n },\n filterContainer: {\n display: 'flex',\n flexWrap: 'wrap',\n '& > *': {\n marginRight: theme.spacing(1),\n },\n },\n applyFilterButton: {\n marginTop: theme.spacing(1),\n },\n}));\n\nconst RuleTypeIcon = ({ type }: { type: AIRuleType }) => {\n const colors = {\n [AIRuleType.CURSOR]: '#0066CC',\n [AIRuleType.COPILOT]: '#6F42C1', \n [AIRuleType.CLINE]: '#28A745',\n [AIRuleType.CLAUDE_CODE]: '#FF6B35',\n };\n \n return <CodeIcon style={{ color: colors[type] }} />;\n};\n\nconst renderFrontmatter = (theme: any, frontmatter?: Record<string, any>) => {\n if (!frontmatter || Object.keys(frontmatter).length === 0) {\n return null;\n }\n\n // Filter out fields that are already displayed elsewhere (description, globs)\n const filteredEntries = Object.entries(frontmatter).filter(([key]) => \n !['description', 'globs'].includes(key)\n );\n\n if (filteredEntries.length === 0) {\n return null;\n }\n\n return (\n <div style={{ \n marginBottom: '16px', \n padding: '16px', \n backgroundColor: theme.palette.type === 'dark' ? 'rgba(255,255,255,0.05)' : 'rgba(0,0,0,0.05)', \n borderRadius: '8px',\n border: `1px solid ${theme.palette.type === 'dark' ? 'rgba(255,255,255,0.12)' : 'rgba(0,0,0,0.12)'}`\n }}>\n <Typography variant=\"subtitle2\" style={{ \n marginBottom: '12px', \n fontWeight: 'bold',\n color: theme.palette.text.secondary,\n textTransform: 'uppercase',\n letterSpacing: '0.5px'\n }}>\n Metadata\n </Typography>\n {filteredEntries.map(([key, value], index) => (\n <div key={key} style={{ marginBottom: index < filteredEntries.length - 1 ? '12px' : '0' }}>\n <Typography variant=\"body2\" style={{ \n fontWeight: 'bold',\n textTransform: 'capitalize',\n color: theme.palette.primary.main,\n marginBottom: '4px'\n }}>\n {key}:\n </Typography>\n <Typography variant=\"body2\" style={{ \n lineHeight: '1.5',\n marginLeft: '8px',\n color: theme.palette.text.primary\n }}>\n {Array.isArray(value) ? value.join(', ') : String(value)}\n </Typography>\n </div>\n ))}\n </div>\n );\n};\n\n// Helper function to parse cursor rule content manually\nconst parseCursorContent = (content: string) => {\n return manualParseFrontmatter(content);\n};\n\n// Manual frontmatter parsing as fallback\nconst manualParseFrontmatter = (content: string) => {\n // Check if content starts with ---\n if (!content.trim().startsWith('---')) {\n return {\n frontmatter: undefined,\n content: content\n };\n }\n\n try {\n // Split by lines\n const lines = content.split('\\n');\n let frontmatterEndIndex = -1;\n \n // Find the closing ---\n for (let i = 1; i < lines.length; i++) {\n if (lines[i].trim() === '---') {\n frontmatterEndIndex = i;\n break;\n }\n }\n \n if (frontmatterEndIndex === -1) {\n return {\n frontmatter: undefined,\n content: content\n };\n }\n \n // Extract frontmatter lines (between the --- markers)\n const frontmatterLines = lines.slice(1, frontmatterEndIndex);\n const contentLines = lines.slice(frontmatterEndIndex + 1);\n \n // Parse the YAML manually (simple key: value pairs)\n const frontmatter: Record<string, any> = {};\n for (const line of frontmatterLines) {\n const trimmedLine = line.trim();\n if (trimmedLine && trimmedLine.includes(':')) {\n const colonIndex = trimmedLine.indexOf(':');\n const key = trimmedLine.substring(0, colonIndex).trim();\n const value = trimmedLine.substring(colonIndex + 1).trim();\n frontmatter[key] = value;\n }\n }\n \n return {\n frontmatter: Object.keys(frontmatter).length > 0 ? frontmatter : undefined,\n content: contentLines.join('\\n').trim()\n };\n } catch (error) {\n return {\n frontmatter: undefined,\n content: content\n };\n }\n};\n\nconst constructFileUrl = (gitUrl: string, filePath: string): string => {\n // Remove trailing slashes from gitUrl\n const cleanGitUrl = gitUrl.replace(/\\/+$/, '');\n \n // For GitHub URLs, convert to blob view\n if (cleanGitUrl.includes('github.com')) {\n return `${cleanGitUrl}/blob/main/${filePath}`;\n }\n \n // For GitLab URLs, convert to blob view\n if (cleanGitUrl.includes('gitlab.com')) {\n return `${cleanGitUrl}/-/blob/main/${filePath}`;\n }\n \n // For other git providers, try generic blob URL\n return `${cleanGitUrl}/blob/main/${filePath}`;\n};\n\nconst RuleComponent = ({ rule }: { rule: AIRule }) => {\n const styles = useStyles();\n const theme = useTheme();\n \n const renderCursorRule = (rule: CursorRule) => {\n // Parse the raw content to extract frontmatter and clean content\n const { frontmatter, content } = parseCursorContent(rule.content);\n \n return (\n <Accordion className={styles.ruleCard}>\n <AccordionSummary expandIcon={<ExpandMoreIcon />}>\n <div className={styles.ruleHeader}>\n <div className={styles.ruleHeaderContent}>\n <RuleTypeIcon type={rule.type} />\n <Typography variant=\"h6\">{rule.fileName}</Typography>\n <Chip label={rule.type} size=\"small\" className={styles.ruleType} />\n {frontmatter?.description && (\n <Typography variant=\"body2\" style={{ marginLeft: 8, color: theme.palette.text.secondary }}>\n {frontmatter.description}\n </Typography>\n )}\n </div>\n {rule.gitUrl && (\n <Tooltip title=\"Open file in repository\">\n <IconButton\n size=\"small\"\n onClick={(e) => {\n e.stopPropagation();\n window.open(constructFileUrl(rule.gitUrl!, rule.filePath), '_blank');\n }}\n >\n <LaunchIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n )}\n </div>\n </AccordionSummary>\n <AccordionDetails>\n <div>\n <div className={styles.ruleMetadata}>\n <Chip label={`Path: ${rule.filePath}`} size=\"small\" variant=\"outlined\" />\n {frontmatter?.globs && (\n <Chip label={`Globs: ${Array.isArray(frontmatter.globs) ? frontmatter.globs.join(', ') : frontmatter.globs}`} size=\"small\" variant=\"outlined\" />\n )}\n </div>\n {renderFrontmatter(theme, frontmatter)}\n <div className={styles.ruleContent}>\n <MarkdownContent content={content} />\n </div>\n </div>\n </AccordionDetails>\n </Accordion>\n );\n };\n\n const renderCopilotRule = (rule: CopilotRule) => (\n <Card className={styles.ruleCard}>\n <CardContent>\n <div className={styles.ruleHeader}>\n <div className={styles.ruleHeaderContent}>\n <RuleTypeIcon type={rule.type} />\n <Typography variant=\"h6\">Copilot Rule #{rule.order}</Typography>\n <Chip label={rule.type} size=\"small\" className={styles.ruleType} />\n </div>\n {rule.gitUrl && (\n <Tooltip title=\"Open file in repository\">\n <IconButton\n size=\"small\"\n onClick={() => window.open(constructFileUrl(rule.gitUrl!, rule.filePath), '_blank')}\n >\n <LaunchIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n )}\n </div>\n <div className={styles.ruleContent}>\n {rule.content}\n </div>\n </CardContent>\n </Card>\n );\n\n const renderClineRule = (rule: ClineRule) => (\n <Accordion className={styles.ruleCard}>\n <AccordionSummary expandIcon={<ExpandMoreIcon />}>\n <div className={styles.ruleHeader}>\n <div className={styles.ruleHeaderContent}>\n <RuleTypeIcon type={rule.type} />\n <Typography variant=\"h6\">{rule.title || rule.fileName}</Typography>\n <Chip label={rule.type} size=\"small\" className={styles.ruleType} />\n </div>\n {rule.gitUrl && (\n <Tooltip title=\"Open file in repository\">\n <IconButton\n size=\"small\"\n onClick={(e) => {\n e.stopPropagation();\n window.open(constructFileUrl(rule.gitUrl!, rule.filePath), '_blank');\n }}\n >\n <LaunchIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n )}\n </div>\n </AccordionSummary>\n <AccordionDetails>\n <div>\n <div className={styles.ruleMetadata}>\n <Chip label={`Path: ${rule.filePath}`} size=\"small\" variant=\"outlined\" />\n </div>\n <div className={styles.ruleContent}>\n <MarkdownContent content={rule.content} />\n </div>\n </div>\n </AccordionDetails>\n </Accordion>\n );\n\n const renderClaudeCodeRule = (rule: ClaudeCodeRule) => (\n <Accordion className={styles.ruleCard}>\n <AccordionSummary expandIcon={<ExpandMoreIcon />}>\n <div className={styles.ruleHeader}>\n <div className={styles.ruleHeaderContent}>\n <RuleTypeIcon type={rule.type} />\n <Typography variant=\"h6\">{rule.title || rule.fileName}</Typography>\n <Chip label={rule.type} size=\"small\" className={styles.ruleType} />\n </div>\n {rule.gitUrl && (\n <Tooltip title=\"Open file in repository\">\n <IconButton\n size=\"small\"\n onClick={(e) => {\n e.stopPropagation();\n window.open(constructFileUrl(rule.gitUrl!, rule.filePath), '_blank');\n }}\n >\n <LaunchIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n )}\n </div>\n </AccordionSummary>\n <AccordionDetails>\n <div>\n <div className={styles.ruleMetadata}>\n <Chip label={`Path: ${rule.filePath}`} size=\"small\" variant=\"outlined\" />\n </div>\n <div className={styles.ruleContent}>\n <MarkdownContent content={rule.content} />\n </div>\n </div>\n </AccordionDetails>\n </Accordion>\n );\n\n switch (rule.type) {\n case AIRuleType.CURSOR:\n return renderCursorRule(rule as CursorRule);\n case AIRuleType.CLAUDE_CODE:\n return renderClaudeCodeRule(rule as ClaudeCodeRule);\n case AIRuleType.COPILOT:\n return renderCopilotRule(rule as CopilotRule);\n case AIRuleType.CLINE:\n return renderClineRule(rule as ClineRule);\n default:\n return null;\n }\n};\n\nexport const AIRulesComponent = ({ title = \"AI Coding Rules\" }: AIRulesComponentProps = {}) => {\n const { rulesByType, loading, error, hasGitUrl, totalRules, allowedRuleTypes, selectedRuleTypes, setSelectedRuleTypes, applyFilters, resetFilters, hasUnappliedChanges, hasSearched } = useAiRules();\n const styles = useStyles();\n \n // Define the desired rendering order\n const ruleTypeDisplayOrder = [AIRuleType.CURSOR, AIRuleType.CLAUDE_CODE, AIRuleType.COPILOT, AIRuleType.CLINE];\n \n // Helper function to format rule type names for display\n const formatRuleTypeName = (type: AIRuleType): string => {\n switch (type) {\n case AIRuleType.CURSOR:\n return 'Cursor';\n case AIRuleType.CLAUDE_CODE:\n return 'Claude Code';\n case AIRuleType.COPILOT:\n return 'Copilot';\n case AIRuleType.CLINE:\n return 'Cline';\n }\n };\n const handleTypeToggle = (type: AIRuleType, checked: boolean) => {\n const newTypes = checked \n ? [...selectedRuleTypes, type]\n : selectedRuleTypes.filter(t => t !== type);\n setSelectedRuleTypes(newTypes);\n };\n\n if (loading) {\n return (\n <InfoCard title={title}>\n <Progress />\n </InfoCard>\n );\n }\n\n if (!hasGitUrl) {\n return (\n <InfoCard title={title}>\n <EmptyState\n missing=\"content\"\n title=\"No Git Repository\"\n description=\"This component doesn't have a Git source URL configured.\"\n />\n </InfoCard>\n );\n }\n\n if (error) {\n return (\n <InfoCard title={title}>\n <EmptyState\n missing=\"content\"\n title=\"Error Loading Rules\"\n description={error}\n />\n </InfoCard>\n );\n }\n\n return (\n <InfoCard title={title} className={styles.root}>\n <div className={styles.filterSection}>\n <Typography variant=\"h6\" gutterBottom>\n Filter Rule Types\n </Typography>\n <div className={styles.filterContainer}>\n {allowedRuleTypes.map(type => (\n <FormControlLabel\n key={type}\n control={\n <Checkbox\n checked={selectedRuleTypes.includes(type)}\n onChange={(e) => handleTypeToggle(type, e.target.checked)}\n />\n }\n label={formatRuleTypeName(type)}\n />\n ))}\n </div>\n <div className={styles.applyFilterButton}>\n <Button\n variant=\"contained\"\n color=\"primary\"\n onClick={applyFilters}\n disabled={!hasUnappliedChanges}\n >\n Apply Filter\n </Button>\n {hasUnappliedChanges && (\n <Typography variant=\"body2\" color=\"textSecondary\" style={{ marginTop: 8 }}>\n You have unsaved filter changes. Click \"Apply Filter\" to update the results.\n </Typography>\n )}\n {!hasUnappliedChanges && selectedRuleTypes.length === 0 && (\n <Typography variant=\"body2\" color=\"textSecondary\" style={{ marginTop: 8 }}>\n Select at least one rule type to search for AI rules.\n </Typography>\n )}\n </div>\n </div>\n\n {hasSearched && totalRules === 0 ? (\n <EmptyState\n missing=\"content\"\n title=\"No AI Rules Found\"\n description=\"No AI rules were found in this repository for the selected rule types.\"\n action={\n <Button\n variant=\"outlined\"\n onClick={resetFilters}\n >\n Reset Filters\n </Button>\n }\n />\n ) : totalRules > 0 ? (\n <>\n <div className={styles.statsContainer}>\n <Card className={styles.statCard}>\n <CardContent>\n <Typography variant=\"h4\">{totalRules}</Typography>\n <Typography color=\"textSecondary\">Total Rules</Typography>\n </CardContent>\n </Card>\n {ruleTypeDisplayOrder.map(type => {\n const typeRules = rulesByType[type] || [];\n if (typeRules.length === 0) return null;\n return (\n <Card key={type} className={styles.statCard}>\n <CardContent>\n <Typography variant=\"h4\">{typeRules.length}</Typography>\n <Typography color=\"textSecondary\">{formatRuleTypeName(type)}</Typography>\n </CardContent>\n </Card>\n );\n })}\n </div>\n\n {ruleTypeDisplayOrder.map(type => {\n const typeRules = rulesByType[type] || [];\n if (typeRules.length === 0) return null;\n return (\n <div key={type}>\n <Typography variant=\"h5\" gutterBottom style={{ marginTop: 16 }}>\n {formatRuleTypeName(type)} Rules ({typeRules.length})\n </Typography>\n {typeRules.map(rule => (\n <RuleComponent key={rule.id} rule={rule} />\n ))}\n </div>\n );\n })}\n </>\n ) : (\n <div style={{ marginTop: 16 }}>\n <Typography variant=\"body1\" color=\"textSecondary\">\n Select rule types above and click \"Apply Filter\" to search for AI coding rules in this repository.\n </Typography>\n </div>\n )}\n </InfoCard>\n );\n};"],"names":["rule"],"mappings":"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"}
1
+ {"version":3,"file":"AiRulesComponent.esm.js","sources":["../../../src/components/AiRulesComponent/AiRulesComponent.tsx"],"sourcesContent":["import React from 'react';\nimport { useAiRules } from '../../hooks/useAiRules';\nimport { InfoCard, Progress, EmptyState, MarkdownContent } from '@backstage/core-components';\nimport { Button, makeStyles, useTheme, Typography, Chip, Card, CardContent, Accordion, AccordionSummary, AccordionDetails, FormControlLabel, Checkbox, IconButton, Tooltip } from '@material-ui/core';\nimport { Entity } from '@backstage/catalog-model';\nimport ExpandMoreIcon from '@material-ui/icons/ExpandMore';\nimport CodeIcon from '@material-ui/icons/Code';\nimport LaunchIcon from '@material-ui/icons/Launch';\nimport { AIRuleType, AIRule, CursorRule, CopilotRule, ClineRule, ClaudeCodeRule } from '../../types';\nexport interface AIRulesComponentProps {\n title?: string;\n}\n\nexport const isAIRulesAvailable = (entity: Entity): boolean => {\n const sourceAnnotation = entity.metadata?.annotations?.['backstage.io/source-location'] || '';\n return sourceAnnotation.startsWith('url:');\n};\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n '& .MuiAccordion-root': {\n marginBottom: theme.spacing(1),\n '&:before': {\n display: 'none',\n },\n },\n },\n filterSection: {\n marginBottom: theme.spacing(2),\n padding: theme.spacing(2),\n backgroundColor: theme.palette.background.default,\n borderRadius: theme.shape.borderRadius,\n },\n ruleCard: {\n marginBottom: theme.spacing(1),\n border: `1px solid ${theme.palette.divider}`,\n },\n ruleHeader: {\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(1),\n width: '100%',\n },\n ruleHeaderContent: {\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(1),\n flex: 1,\n },\n ruleType: {\n textTransform: 'uppercase',\n fontWeight: 'bold',\n fontSize: '0.75rem',\n },\n ruleContent: {\n padding: theme.spacing(1),\n borderRadius: theme.shape.borderRadius,\n overflow: 'auto',\n maxHeight: '300px',\n '& > *': {\n backgroundColor: 'transparent !important',\n },\n },\n ruleMetadata: {\n display: 'flex',\n flexWrap: 'wrap',\n gap: theme.spacing(0.5),\n marginBottom: theme.spacing(1),\n },\n statsContainer: {\n display: 'flex',\n gap: theme.spacing(2),\n marginBottom: theme.spacing(2),\n },\n statCard: {\n minWidth: '120px',\n textAlign: 'center',\n },\n emptyStateIcon: {\n fontSize: '4rem',\n color: theme.palette.grey[400],\n },\n filterContainer: {\n display: 'flex',\n flexWrap: 'wrap',\n '& > *': {\n marginRight: theme.spacing(1),\n },\n },\n applyFilterButton: {\n marginTop: theme.spacing(1),\n },\n}));\n\nconst RuleTypeIcon = ({ type }: { type: AIRuleType }) => {\n const colors = {\n [AIRuleType.CURSOR]: '#0066CC',\n [AIRuleType.COPILOT]: '#6F42C1', \n [AIRuleType.CLINE]: '#28A745',\n [AIRuleType.CLAUDE_CODE]: '#FF6B35',\n };\n \n return <CodeIcon style={{ color: colors[type] }} />;\n};\n\nconst renderFrontmatter = (theme: any, frontmatter?: Record<string, any>) => {\n if (!frontmatter || Object.keys(frontmatter).length === 0) {\n return null;\n }\n\n // Filter out fields that are already displayed elsewhere (description, globs)\n const filteredEntries = Object.entries(frontmatter).filter(([key]) => \n !['description', 'globs'].includes(key)\n );\n\n if (filteredEntries.length === 0) {\n return null;\n }\n\n return (\n <div style={{ \n marginBottom: '16px', \n padding: '16px', \n backgroundColor: theme.palette.type === 'dark' ? 'rgba(255,255,255,0.05)' : 'rgba(0,0,0,0.05)', \n borderRadius: '8px',\n border: `1px solid ${theme.palette.type === 'dark' ? 'rgba(255,255,255,0.12)' : 'rgba(0,0,0,0.12)'}`\n }}>\n <Typography variant=\"subtitle2\" style={{ \n marginBottom: '12px', \n fontWeight: 'bold',\n color: theme.palette.text.secondary,\n textTransform: 'uppercase',\n letterSpacing: '0.5px'\n }}>\n Metadata\n </Typography>\n {filteredEntries.map(([key, value], index) => (\n <div key={key} style={{ marginBottom: index < filteredEntries.length - 1 ? '12px' : '0' }}>\n <Typography variant=\"body2\" style={{ \n fontWeight: 'bold',\n textTransform: 'capitalize',\n color: theme.palette.primary.main,\n marginBottom: '4px'\n }}>\n {key}:\n </Typography>\n <Typography variant=\"body2\" style={{ \n lineHeight: '1.5',\n marginLeft: '8px',\n color: theme.palette.text.primary\n }}>\n {Array.isArray(value) ? value.join(', ') : String(value)}\n </Typography>\n </div>\n ))}\n </div>\n );\n};\n\n// Helper function to parse cursor rule content manually\nconst parseCursorContent = (content: string) => {\n return manualParseFrontmatter(content);\n};\n\n// Manual frontmatter parsing as fallback\nconst manualParseFrontmatter = (content: string) => {\n // Check if content starts with ---\n if (!content.trim().startsWith('---')) {\n return {\n frontmatter: undefined,\n content: content\n };\n }\n\n try {\n // Split by lines\n const lines = content.split('\\n');\n let frontmatterEndIndex = -1;\n \n // Find the closing ---\n for (let i = 1; i < lines.length; i++) {\n if (lines[i].trim() === '---') {\n frontmatterEndIndex = i;\n break;\n }\n }\n \n if (frontmatterEndIndex === -1) {\n return {\n frontmatter: undefined,\n content: content\n };\n }\n \n // Extract frontmatter lines (between the --- markers)\n const frontmatterLines = lines.slice(1, frontmatterEndIndex);\n const contentLines = lines.slice(frontmatterEndIndex + 1);\n \n // Parse the YAML manually (simple key: value pairs)\n const frontmatter: Record<string, any> = {};\n for (const line of frontmatterLines) {\n const trimmedLine = line.trim();\n if (trimmedLine && trimmedLine.includes(':')) {\n const colonIndex = trimmedLine.indexOf(':');\n const key = trimmedLine.substring(0, colonIndex).trim();\n const value = trimmedLine.substring(colonIndex + 1).trim();\n frontmatter[key] = value;\n }\n }\n \n return {\n frontmatter: Object.keys(frontmatter).length > 0 ? frontmatter : undefined,\n content: contentLines.join('\\n').trim()\n };\n } catch (error) {\n return {\n frontmatter: undefined,\n content: content\n };\n }\n};\n\nconst constructFileUrl = (gitUrl: string, filePath: string): string => {\n // Remove trailing slashes from gitUrl\n const cleanGitUrl = gitUrl.replace(/\\/+$/, '');\n \n // For GitHub URLs, convert to blob view\n if (cleanGitUrl.includes('github.com')) {\n return `${cleanGitUrl}/blob/main/${filePath}`;\n }\n \n // For GitLab URLs, convert to blob view\n if (cleanGitUrl.includes('gitlab.com')) {\n return `${cleanGitUrl}/-/blob/main/${filePath}`;\n }\n \n // For other git providers, try generic blob URL\n return `${cleanGitUrl}/blob/main/${filePath}`;\n};\n\nconst RuleComponent = ({ rule }: { rule: AIRule }) => {\n const styles = useStyles();\n const theme = useTheme();\n \n const renderCursorRule = (rule: CursorRule) => {\n // Parse the raw content to extract frontmatter and clean content\n const { frontmatter, content } = parseCursorContent(rule.content);\n \n return (\n <Accordion className={styles.ruleCard}>\n <AccordionSummary expandIcon={<ExpandMoreIcon />}>\n <div className={styles.ruleHeader}>\n <div className={styles.ruleHeaderContent}>\n <RuleTypeIcon type={rule.type} />\n <Typography variant=\"h6\">{rule.fileName}</Typography>\n <Chip label={rule.type} size=\"small\" className={styles.ruleType} />\n {frontmatter?.description && (\n <Typography variant=\"body2\" style={{ marginLeft: 8, color: theme.palette.text.secondary }}>\n {frontmatter.description}\n </Typography>\n )}\n </div>\n {rule.gitUrl && (\n <Tooltip title=\"Open file in repository\">\n <IconButton\n size=\"small\"\n onClick={(e) => {\n e.stopPropagation();\n window.open(constructFileUrl(rule.gitUrl!, rule.filePath), '_blank');\n }}\n >\n <LaunchIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n )}\n </div>\n </AccordionSummary>\n <AccordionDetails>\n <div>\n <div className={styles.ruleMetadata}>\n <Chip label={`Path: ${rule.filePath}`} size=\"small\" variant=\"outlined\" />\n {frontmatter?.globs && (\n <Chip label={`Globs: ${Array.isArray(frontmatter.globs) ? frontmatter.globs.join(', ') : frontmatter.globs}`} size=\"small\" variant=\"outlined\" />\n )}\n </div>\n {renderFrontmatter(theme, frontmatter)}\n <div className={styles.ruleContent}>\n <MarkdownContent content={content} />\n </div>\n </div>\n </AccordionDetails>\n </Accordion>\n );\n };\n\n const renderCopilotRule = (rule: CopilotRule) => {\n // Get rule number from either order (legacy) or extract from filename\n const ruleNumber = rule.order || (rule.fileName.match(/Rule (\\d+)/) || [])[1] || rule.id.split('-').pop();\n \n return (\n <Accordion className={styles.ruleCard}>\n <AccordionSummary expandIcon={<ExpandMoreIcon />}>\n <div className={styles.ruleHeader}>\n <div className={styles.ruleHeaderContent}>\n <RuleTypeIcon type={rule.type} />\n <Typography variant=\"h6\">\n {rule.title || `Copilot Rule #${ruleNumber}`}\n </Typography>\n <Chip label={rule.type} size=\"small\" className={styles.ruleType} />\n {rule.applyTo && (\n <Chip \n label={`Applies to: ${rule.applyTo}`} \n size=\"small\" \n variant=\"outlined\" \n style={{ marginLeft: 8 }}\n />\n )}\n </div>\n {rule.gitUrl && (\n <Tooltip title=\"Open file in repository\">\n <IconButton\n size=\"small\"\n onClick={(e) => {\n e.stopPropagation();\n window.open(constructFileUrl(rule.gitUrl!, rule.filePath), '_blank');\n }}\n >\n <LaunchIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n )}\n </div>\n </AccordionSummary>\n <AccordionDetails>\n <div>\n <div className={styles.ruleMetadata}>\n <Chip label={`Path: ${rule.filePath}`} size=\"small\" variant=\"outlined\" />\n {rule.frontmatter && renderFrontmatter(theme, rule.frontmatter)}\n </div>\n <div className={styles.ruleContent}>\n <MarkdownContent content={rule.content} />\n </div>\n </div>\n </AccordionDetails>\n </Accordion>\n );\n };\n\n const renderClineRule = (rule: ClineRule) => (\n <Accordion className={styles.ruleCard}>\n <AccordionSummary expandIcon={<ExpandMoreIcon />}>\n <div className={styles.ruleHeader}>\n <div className={styles.ruleHeaderContent}>\n <RuleTypeIcon type={rule.type} />\n <Typography variant=\"h6\">{rule.title || rule.fileName}</Typography>\n <Chip label={rule.type} size=\"small\" className={styles.ruleType} />\n </div>\n {rule.gitUrl && (\n <Tooltip title=\"Open file in repository\">\n <IconButton\n size=\"small\"\n onClick={(e) => {\n e.stopPropagation();\n window.open(constructFileUrl(rule.gitUrl!, rule.filePath), '_blank');\n }}\n >\n <LaunchIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n )}\n </div>\n </AccordionSummary>\n <AccordionDetails>\n <div>\n <div className={styles.ruleMetadata}>\n <Chip label={`Path: ${rule.filePath}`} size=\"small\" variant=\"outlined\" />\n </div>\n <div className={styles.ruleContent}>\n <MarkdownContent content={rule.content} />\n </div>\n </div>\n </AccordionDetails>\n </Accordion>\n );\n\n const renderClaudeCodeRule = (rule: ClaudeCodeRule) => (\n <Accordion className={styles.ruleCard}>\n <AccordionSummary expandIcon={<ExpandMoreIcon />}>\n <div className={styles.ruleHeader}>\n <div className={styles.ruleHeaderContent}>\n <RuleTypeIcon type={rule.type} />\n <Typography variant=\"h6\">{rule.title || rule.fileName}</Typography>\n <Chip label={rule.type} size=\"small\" className={styles.ruleType} />\n </div>\n {rule.gitUrl && (\n <Tooltip title=\"Open file in repository\">\n <IconButton\n size=\"small\"\n onClick={(e) => {\n e.stopPropagation();\n window.open(constructFileUrl(rule.gitUrl!, rule.filePath), '_blank');\n }}\n >\n <LaunchIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n )}\n </div>\n </AccordionSummary>\n <AccordionDetails>\n <div>\n <div className={styles.ruleMetadata}>\n <Chip label={`Path: ${rule.filePath}`} size=\"small\" variant=\"outlined\" />\n </div>\n <div className={styles.ruleContent}>\n <MarkdownContent content={rule.content} />\n </div>\n </div>\n </AccordionDetails>\n </Accordion>\n );\n\n switch (rule.type) {\n case AIRuleType.CURSOR:\n return renderCursorRule(rule as CursorRule);\n case AIRuleType.CLAUDE_CODE:\n return renderClaudeCodeRule(rule as ClaudeCodeRule);\n case AIRuleType.COPILOT:\n return renderCopilotRule(rule as CopilotRule);\n case AIRuleType.CLINE:\n return renderClineRule(rule as ClineRule);\n default:\n return null;\n }\n};\n\nexport const AIRulesComponent: React.FC<AIRulesComponentProps> = ({ title = \"AI Coding Rules\" } = {}) => {\n const { rulesByType, loading, error, hasGitUrl, totalRules, allowedRuleTypes, selectedRuleTypes, setSelectedRuleTypes, applyFilters, resetFilters, hasUnappliedChanges, hasSearched } = useAiRules();\n const styles = useStyles();\n \n // Define the desired rendering order\n const ruleTypeDisplayOrder = [AIRuleType.CURSOR, AIRuleType.CLAUDE_CODE, AIRuleType.COPILOT, AIRuleType.CLINE];\n \n // Helper function to format rule type names for display\n const formatRuleTypeName = (type: AIRuleType): string => {\n switch (type) {\n case AIRuleType.CURSOR:\n return 'Cursor';\n case AIRuleType.CLAUDE_CODE:\n return 'Claude Code';\n case AIRuleType.COPILOT:\n return 'Copilot';\n case AIRuleType.CLINE:\n return 'Cline';\n }\n };\n const handleTypeToggle = (type: AIRuleType, checked: boolean) => {\n const newTypes = checked \n ? [...selectedRuleTypes, type]\n : selectedRuleTypes.filter(t => t !== type);\n setSelectedRuleTypes(newTypes);\n };\n\n if (loading) {\n return (\n <InfoCard title={title}>\n <Progress />\n </InfoCard>\n );\n }\n\n if (!hasGitUrl) {\n return (\n <InfoCard title={title}>\n <EmptyState\n missing=\"content\"\n title=\"No Git Repository\"\n description=\"This component doesn't have a Git source URL configured.\"\n />\n </InfoCard>\n );\n }\n\n if (error) {\n return (\n <InfoCard title={title}>\n <EmptyState\n missing=\"content\"\n title=\"Error Loading Rules\"\n description={error}\n />\n </InfoCard>\n );\n }\n\n return (\n <InfoCard title={title} className={styles.root}>\n <div className={styles.filterSection}>\n <Typography variant=\"h6\" gutterBottom>\n Filter Rule Types\n </Typography>\n <div className={styles.filterContainer}>\n {allowedRuleTypes.map(type => (\n <FormControlLabel\n key={type}\n control={\n <Checkbox\n checked={selectedRuleTypes.includes(type)}\n onChange={(e) => handleTypeToggle(type, e.target.checked)}\n />\n }\n label={formatRuleTypeName(type)}\n />\n ))}\n </div>\n <div className={styles.applyFilterButton}>\n <Button\n variant=\"contained\"\n color=\"primary\"\n onClick={applyFilters}\n disabled={!hasUnappliedChanges}\n >\n Apply Filter\n </Button>\n {hasUnappliedChanges && (\n <Typography variant=\"body2\" color=\"textSecondary\" style={{ marginTop: 8 }}>\n You have unsaved filter changes. Click \"Apply Filter\" to update the results.\n </Typography>\n )}\n {!hasUnappliedChanges && selectedRuleTypes.length === 0 && (\n <Typography variant=\"body2\" color=\"textSecondary\" style={{ marginTop: 8 }}>\n Select at least one rule type to search for AI rules.\n </Typography>\n )}\n </div>\n </div>\n\n {hasSearched && totalRules === 0 ? (\n <EmptyState\n missing=\"content\"\n title=\"No AI Rules Found\"\n description=\"No AI rules were found in this repository for the selected rule types.\"\n action={\n <Button\n variant=\"outlined\"\n onClick={resetFilters}\n >\n Reset Filters\n </Button>\n }\n />\n ) : totalRules > 0 ? (\n <>\n <div className={styles.statsContainer}>\n <Card className={styles.statCard}>\n <CardContent>\n <Typography variant=\"h4\">{totalRules}</Typography>\n <Typography color=\"textSecondary\">Total Rules</Typography>\n </CardContent>\n </Card>\n {ruleTypeDisplayOrder.map(type => {\n const typeRules = rulesByType[type] || [];\n if (typeRules.length === 0) return null;\n return (\n <Card key={type} className={styles.statCard}>\n <CardContent>\n <Typography variant=\"h4\">{typeRules.length}</Typography>\n <Typography color=\"textSecondary\">{formatRuleTypeName(type)}</Typography>\n </CardContent>\n </Card>\n );\n })}\n </div>\n\n {ruleTypeDisplayOrder.map(type => {\n const typeRules = rulesByType[type] || [];\n if (typeRules.length === 0) return null;\n return (\n <div key={type}>\n <Typography variant=\"h5\" gutterBottom style={{ marginTop: 16 }}>\n {formatRuleTypeName(type)} Rules ({typeRules.length})\n </Typography>\n {typeRules.map(rule => (\n <RuleComponent key={rule.id} rule={rule} />\n ))}\n </div>\n );\n })}\n </>\n ) : (\n <div style={{ marginTop: 16 }}>\n <Typography variant=\"body1\" color=\"textSecondary\">\n Select rule types above and click \"Apply Filter\" to search for AI coding rules in this repository.\n </Typography>\n </div>\n )}\n </InfoCard>\n );\n};"],"names":["rule"],"mappings":"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"}
@@ -0,0 +1,236 @@
1
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
+ import React from 'react';
3
+ import { InfoCard, Progress, EmptyState, CodeSnippet } from '@backstage/core-components';
4
+ import { makeStyles, Accordion, AccordionSummary, Typography, Chip, AccordionDetails } from '@material-ui/core';
5
+ import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
6
+ import { useMCPServers } from '../../hooks/useMCPServers.esm.js';
7
+
8
+ const useStyles = makeStyles((theme) => ({
9
+ root: {
10
+ "& .MuiAccordion-root": {
11
+ marginBottom: theme.spacing(1),
12
+ "&:before": {
13
+ display: "none"
14
+ }
15
+ }
16
+ },
17
+ sourceAccordion: {
18
+ backgroundColor: theme.palette.background.default,
19
+ marginBottom: theme.spacing(2),
20
+ width: "100%",
21
+ "& .MuiAccordionSummary-root": {
22
+ borderBottom: `1px solid ${theme.palette.divider}`
23
+ },
24
+ "& .MuiAccordionDetails-root": {
25
+ padding: theme.spacing(2),
26
+ display: "flex",
27
+ flexDirection: "column",
28
+ gap: theme.spacing(2)
29
+ }
30
+ },
31
+ serversList: {
32
+ display: "flex",
33
+ flexDirection: "column",
34
+ gap: theme.spacing(2),
35
+ width: "100%"
36
+ },
37
+ serverAccordion: {
38
+ backgroundColor: theme.palette.background.paper,
39
+ width: "100%",
40
+ "& .MuiAccordionSummary-root": {
41
+ minHeight: "48px",
42
+ "&.Mui-expanded": {
43
+ minHeight: "48px"
44
+ }
45
+ },
46
+ "& .MuiAccordionSummary-content": {
47
+ margin: "12px 0",
48
+ "&.Mui-expanded": {
49
+ margin: "12px 0"
50
+ }
51
+ },
52
+ "& .MuiAccordionDetails-root": {
53
+ padding: theme.spacing(3)
54
+ }
55
+ },
56
+ envContainer: {
57
+ backgroundColor: theme.palette.background.default,
58
+ padding: theme.spacing(2),
59
+ borderRadius: theme.shape.borderRadius
60
+ },
61
+ envGrid: {
62
+ display: "grid",
63
+ gridTemplateColumns: "auto 1fr",
64
+ gap: theme.spacing(1),
65
+ alignItems: "center"
66
+ },
67
+ envKey: {
68
+ fontWeight: "bold",
69
+ color: theme.palette.text.secondary,
70
+ padding: theme.spacing(0.5, 1),
71
+ backgroundColor: theme.palette.background.paper,
72
+ borderRadius: theme.shape.borderRadius,
73
+ fontSize: "0.875rem"
74
+ },
75
+ envValue: {
76
+ wordBreak: "break-word",
77
+ padding: theme.spacing(0.5, 1),
78
+ backgroundColor: theme.palette.background.paper,
79
+ borderRadius: theme.shape.borderRadius,
80
+ fontSize: "0.875rem"
81
+ },
82
+ rawConfig: {
83
+ backgroundColor: theme.palette.background.default,
84
+ padding: theme.spacing(2),
85
+ borderRadius: theme.shape.borderRadius,
86
+ "& pre": {
87
+ margin: 0
88
+ }
89
+ },
90
+ sectionTitle: {
91
+ marginBottom: theme.spacing(1),
92
+ color: theme.palette.text.secondary,
93
+ fontWeight: 500
94
+ },
95
+ serverContent: {
96
+ display: "flex",
97
+ flexDirection: "column",
98
+ gap: theme.spacing(3),
99
+ width: "100%"
100
+ },
101
+ commandContainer: {
102
+ backgroundColor: theme.palette.background.default,
103
+ padding: theme.spacing(2),
104
+ borderRadius: theme.shape.borderRadius,
105
+ fontFamily: "monospace",
106
+ fontSize: "0.9rem",
107
+ overflowX: "auto",
108
+ whiteSpace: "pre"
109
+ },
110
+ detailsContainer: {
111
+ display: "grid",
112
+ gridTemplateColumns: "1fr 1fr",
113
+ gap: theme.spacing(3)
114
+ }
115
+ }));
116
+ const MCPServersComponent = ({ title = "MCP Servers" }) => {
117
+ const styles = useStyles();
118
+ const { servers, loading, error, hasGitUrl } = useMCPServers();
119
+ if (loading) {
120
+ return /* @__PURE__ */ jsx(InfoCard, { title, children: /* @__PURE__ */ jsx(Progress, {}) });
121
+ }
122
+ if (!hasGitUrl) {
123
+ return /* @__PURE__ */ jsx(InfoCard, { title, children: /* @__PURE__ */ jsx(
124
+ EmptyState,
125
+ {
126
+ missing: "content",
127
+ title: "No Git Repository",
128
+ description: "This component doesn't have a Git source URL configured."
129
+ }
130
+ ) });
131
+ }
132
+ if (error) {
133
+ return /* @__PURE__ */ jsx(InfoCard, { title, children: /* @__PURE__ */ jsx(
134
+ EmptyState,
135
+ {
136
+ missing: "content",
137
+ title: "Error Loading MCP Servers",
138
+ description: error
139
+ }
140
+ ) });
141
+ }
142
+ if (servers.length === 0) {
143
+ return /* @__PURE__ */ jsx(InfoCard, { title, children: /* @__PURE__ */ jsx(
144
+ EmptyState,
145
+ {
146
+ missing: "content",
147
+ title: "No MCP Servers Found",
148
+ description: "No MCP server configurations were found in this repository."
149
+ }
150
+ ) });
151
+ }
152
+ const serversBySource = servers.reduce((acc, server) => {
153
+ const source = server.source;
154
+ if (!acc[source]) {
155
+ acc[source] = [];
156
+ }
157
+ acc[source].push(server);
158
+ return acc;
159
+ }, {});
160
+ const formatSourceName = (source) => {
161
+ switch (source) {
162
+ case "vscode":
163
+ return "VSCode";
164
+ case "cursor":
165
+ return "Cursor";
166
+ case "claude":
167
+ return "Claude";
168
+ default:
169
+ return source;
170
+ }
171
+ };
172
+ return /* @__PURE__ */ jsx(InfoCard, { title, className: styles.root, children: Object.entries(serversBySource).map(([source, sourceServers]) => /* @__PURE__ */ jsxs(Accordion, { defaultExpanded: false, className: styles.sourceAccordion, children: [
173
+ /* @__PURE__ */ jsx(AccordionSummary, { expandIcon: /* @__PURE__ */ jsx(ExpandMoreIcon, {}), children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", width: "100%", gap: "16px" }, children: [
174
+ /* @__PURE__ */ jsxs(Typography, { variant: "h6", children: [
175
+ formatSourceName(source),
176
+ " MCP Servers"
177
+ ] }),
178
+ /* @__PURE__ */ jsx(
179
+ Chip,
180
+ {
181
+ label: `${sourceServers.length} server${sourceServers.length !== 1 ? "s" : ""}`,
182
+ size: "small",
183
+ color: "primary"
184
+ }
185
+ )
186
+ ] }) }),
187
+ /* @__PURE__ */ jsx(AccordionDetails, { children: /* @__PURE__ */ jsx("div", { className: styles.serversList, children: sourceServers.map((server) => /* @__PURE__ */ jsxs(Accordion, { className: styles.serverAccordion, children: [
188
+ /* @__PURE__ */ jsx(AccordionSummary, { expandIcon: /* @__PURE__ */ jsx(ExpandMoreIcon, {}), children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", width: "100%", gap: "16px" }, children: [
189
+ /* @__PURE__ */ jsx(Typography, { variant: "subtitle1", children: server.name }),
190
+ /* @__PURE__ */ jsx(
191
+ Chip,
192
+ {
193
+ label: server.type,
194
+ size: "small",
195
+ color: server.type === "local" ? "default" : "secondary",
196
+ variant: "outlined"
197
+ }
198
+ ),
199
+ server.config.command && /* @__PURE__ */ jsx(
200
+ Chip,
201
+ {
202
+ label: `${server.config.command}`,
203
+ size: "small",
204
+ variant: "outlined"
205
+ }
206
+ )
207
+ ] }) }),
208
+ /* @__PURE__ */ jsx(AccordionDetails, { children: /* @__PURE__ */ jsxs("div", { className: styles.serverContent, children: [
209
+ server.config.command && /* @__PURE__ */ jsxs("div", { children: [
210
+ /* @__PURE__ */ jsx(Typography, { variant: "subtitle2", className: styles.sectionTitle, children: "Command" }),
211
+ /* @__PURE__ */ jsxs("div", { className: styles.commandContainer, children: [
212
+ server.config.command,
213
+ " ",
214
+ server.config.args?.join(" ")
215
+ ] })
216
+ ] }),
217
+ /* @__PURE__ */ jsxs("div", { className: styles.detailsContainer, children: [
218
+ /* @__PURE__ */ jsx("div", { children: server.config.env && Object.keys(server.config.env).length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
219
+ /* @__PURE__ */ jsx(Typography, { variant: "subtitle2", className: styles.sectionTitle, children: "Environment Variables" }),
220
+ /* @__PURE__ */ jsx("div", { className: styles.envContainer, children: /* @__PURE__ */ jsx("div", { className: styles.envGrid, children: Object.entries(server.config.env).map(([key, value]) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
221
+ /* @__PURE__ */ jsx(Typography, { className: styles.envKey, children: key }),
222
+ /* @__PURE__ */ jsx(Typography, { className: styles.envValue, children: value })
223
+ ] }, key)) }) })
224
+ ] }) }),
225
+ /* @__PURE__ */ jsxs("div", { children: [
226
+ /* @__PURE__ */ jsx(Typography, { variant: "subtitle2", className: styles.sectionTitle, children: "Raw Configuration" }),
227
+ /* @__PURE__ */ jsx("div", { className: styles.rawConfig, children: /* @__PURE__ */ jsx(CodeSnippet, { text: server.rawConfig, language: "json" }) })
228
+ ] })
229
+ ] })
230
+ ] }) })
231
+ ] }, server.name)) }) })
232
+ ] }, source)) });
233
+ };
234
+
235
+ export { MCPServersComponent };
236
+ //# sourceMappingURL=MCPServersComponent.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MCPServersComponent.esm.js","sources":["../../../src/components/MCPServersComponent/MCPServersComponent.tsx"],"sourcesContent":["import React from 'react';\nimport {\n InfoCard,\n Progress,\n EmptyState,\n CodeSnippet,\n} from '@backstage/core-components';\nimport {\n makeStyles,\n Typography,\n Chip,\n Accordion,\n AccordionSummary,\n AccordionDetails,\n} from '@material-ui/core';\nimport { Theme } from '@material-ui/core/styles';\nimport ExpandMoreIcon from '@material-ui/icons/ExpandMore';\nimport { MCPServerInfo } from '../../types/mcp';\nimport { useMCPServers } from '../../hooks/useMCPServers';\n\nconst useStyles = makeStyles((theme: Theme) => ({\n root: {\n '& .MuiAccordion-root': {\n marginBottom: theme.spacing(1),\n '&:before': {\n display: 'none',\n },\n },\n },\n sourceAccordion: {\n backgroundColor: theme.palette.background.default,\n marginBottom: theme.spacing(2),\n width: '100%',\n '& .MuiAccordionSummary-root': {\n borderBottom: `1px solid ${theme.palette.divider}`,\n },\n '& .MuiAccordionDetails-root': {\n padding: theme.spacing(2),\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(2),\n },\n },\n serversList: {\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(2),\n width: '100%',\n },\n serverAccordion: {\n backgroundColor: theme.palette.background.paper,\n width: '100%',\n '& .MuiAccordionSummary-root': {\n minHeight: '48px',\n '&.Mui-expanded': {\n minHeight: '48px',\n },\n },\n '& .MuiAccordionSummary-content': {\n margin: '12px 0',\n '&.Mui-expanded': {\n margin: '12px 0',\n },\n },\n '& .MuiAccordionDetails-root': {\n padding: theme.spacing(3),\n },\n },\n envContainer: {\n backgroundColor: theme.palette.background.default,\n padding: theme.spacing(2),\n borderRadius: theme.shape.borderRadius,\n },\n envGrid: {\n display: 'grid',\n gridTemplateColumns: 'auto 1fr',\n gap: theme.spacing(1),\n alignItems: 'center',\n },\n envKey: {\n fontWeight: 'bold',\n color: theme.palette.text.secondary,\n padding: theme.spacing(0.5, 1),\n backgroundColor: theme.palette.background.paper,\n borderRadius: theme.shape.borderRadius,\n fontSize: '0.875rem',\n },\n envValue: {\n wordBreak: 'break-word',\n padding: theme.spacing(0.5, 1),\n backgroundColor: theme.palette.background.paper,\n borderRadius: theme.shape.borderRadius,\n fontSize: '0.875rem',\n },\n rawConfig: {\n backgroundColor: theme.palette.background.default,\n padding: theme.spacing(2),\n borderRadius: theme.shape.borderRadius,\n '& pre': {\n margin: 0,\n },\n },\n sectionTitle: {\n marginBottom: theme.spacing(1),\n color: theme.palette.text.secondary,\n fontWeight: 500,\n },\n serverContent: {\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(3),\n width: '100%',\n },\n commandContainer: {\n backgroundColor: theme.palette.background.default,\n padding: theme.spacing(2),\n borderRadius: theme.shape.borderRadius,\n fontFamily: 'monospace',\n fontSize: '0.9rem',\n overflowX: 'auto',\n whiteSpace: 'pre',\n },\n detailsContainer: {\n display: 'grid',\n gridTemplateColumns: '1fr 1fr',\n gap: theme.spacing(3),\n },\n}));\n\n\nexport interface MCPServersComponentProps {\n title?: string;\n}\n\nexport const MCPServersComponent = ({ title = \"MCP Servers\" }: MCPServersComponentProps) => {\n const styles = useStyles();\n const { servers, loading, error, hasGitUrl } = useMCPServers();\n\n if (loading) {\n return (\n <InfoCard title={title}>\n <Progress />\n </InfoCard>\n );\n }\n\n if (!hasGitUrl) {\n return (\n <InfoCard title={title}>\n <EmptyState\n missing=\"content\"\n title=\"No Git Repository\"\n description=\"This component doesn't have a Git source URL configured.\"\n />\n </InfoCard>\n );\n }\n\n if (error) {\n return (\n <InfoCard title={title}>\n <EmptyState\n missing=\"content\"\n title=\"Error Loading MCP Servers\"\n description={error}\n />\n </InfoCard>\n );\n }\n\n if (servers.length === 0) {\n return (\n <InfoCard title={title}>\n <EmptyState\n missing=\"content\"\n title=\"No MCP Servers Found\"\n description=\"No MCP server configurations were found in this repository.\"\n />\n </InfoCard>\n );\n }\n\n // Group servers by source\n const serversBySource = servers.reduce((acc, server) => {\n const source = server.source;\n if (!acc[source]) {\n acc[source] = [];\n }\n acc[source].push(server);\n return acc;\n }, {} as Record<string, MCPServerInfo[]>);\n\n const formatSourceName = (source: string) => {\n switch (source) {\n case 'vscode':\n return 'VSCode';\n case 'cursor':\n return 'Cursor';\n case 'claude':\n return 'Claude';\n default:\n return source;\n }\n };\n\n return (\n <InfoCard title={title} className={styles.root}>\n {Object.entries(serversBySource).map(([source, sourceServers]) => (\n <Accordion key={source} defaultExpanded={false} className={styles.sourceAccordion}>\n <AccordionSummary expandIcon={<ExpandMoreIcon />}>\n <div style={{ display: 'flex', alignItems: 'center', width: '100%', gap: '16px' }}>\n <Typography variant=\"h6\">\n {formatSourceName(source)} MCP Servers\n </Typography>\n <Chip\n label={`${sourceServers.length} server${sourceServers.length !== 1 ? 's' : ''}`}\n size=\"small\"\n color=\"primary\"\n />\n </div>\n </AccordionSummary>\n <AccordionDetails>\n <div className={styles.serversList}>\n {sourceServers.map((server) => (\n <Accordion key={server.name} className={styles.serverAccordion}>\n <AccordionSummary expandIcon={<ExpandMoreIcon />}>\n <div style={{ display: 'flex', alignItems: 'center', width: '100%', gap: '16px' }}>\n <Typography variant=\"subtitle1\">{server.name}</Typography>\n <Chip \n label={server.type} \n size=\"small\" \n color={server.type === 'local' ? 'default' : 'secondary'}\n variant=\"outlined\"\n />\n {server.config.command && (\n <Chip \n label={`${server.config.command}`}\n size=\"small\"\n variant=\"outlined\"\n />\n )}\n </div>\n </AccordionSummary>\n <AccordionDetails>\n <div className={styles.serverContent}>\n {server.config.command && (\n <div>\n <Typography variant=\"subtitle2\" className={styles.sectionTitle}>Command</Typography>\n <div className={styles.commandContainer}>\n {server.config.command} {server.config.args?.join(' ')}\n </div>\n </div>\n )}\n <div className={styles.detailsContainer}>\n <div>\n {server.config.env && Object.keys(server.config.env).length > 0 && (\n <>\n <Typography variant=\"subtitle2\" className={styles.sectionTitle}>Environment Variables</Typography>\n <div className={styles.envContainer}>\n <div className={styles.envGrid}>\n {Object.entries(server.config.env).map(([key, value]) => (\n <React.Fragment key={key}>\n <Typography className={styles.envKey}>{key}</Typography>\n <Typography className={styles.envValue}>{value}</Typography>\n </React.Fragment>\n ))}\n </div>\n </div>\n </>\n )}\n </div>\n <div>\n <Typography variant=\"subtitle2\" className={styles.sectionTitle}>Raw Configuration</Typography>\n <div className={styles.rawConfig}>\n <CodeSnippet text={server.rawConfig} language=\"json\" />\n </div>\n </div>\n </div>\n </div>\n </AccordionDetails>\n </Accordion>\n ))}\n </div>\n </AccordionDetails>\n </Accordion>\n ))}\n </InfoCard>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ import { useApi } from '@backstage/core-plugin-api';
2
+ import { useState, useCallback, useEffect } from 'react';
3
+ import { aiRulesApiRef } from '../api/types.esm.js';
4
+ import { useEntity } from '@backstage/plugin-catalog-react';
5
+
6
+ const useMCPServers = () => {
7
+ const api = useApi(aiRulesApiRef);
8
+ const { entity } = useEntity();
9
+ const [loading, setLoading] = useState(false);
10
+ const [error, setError] = useState();
11
+ const [servers, setServers] = useState([]);
12
+ const [hasGitUrl, setHasGitUrl] = useState(true);
13
+ const sourceLocation = entity.metadata?.annotations?.["backstage.io/source-location"];
14
+ const fetchServers = useCallback(async () => {
15
+ if (!sourceLocation) {
16
+ setHasGitUrl(false);
17
+ return;
18
+ }
19
+ try {
20
+ setLoading(true);
21
+ setError(void 0);
22
+ const gitUrl = sourceLocation.replace("url:", "").replace(/\/tree\/(?:main|master)\/.*$/, "");
23
+ const response = await api.getMCPServers(gitUrl);
24
+ setServers(response.servers);
25
+ } catch (err) {
26
+ setError(err.message);
27
+ } finally {
28
+ setLoading(false);
29
+ }
30
+ }, [api, sourceLocation]);
31
+ useEffect(() => {
32
+ fetchServers();
33
+ }, [fetchServers]);
34
+ return {
35
+ loading,
36
+ error,
37
+ servers,
38
+ hasGitUrl,
39
+ refetch: fetchServers
40
+ };
41
+ };
42
+
43
+ export { useMCPServers };
44
+ //# sourceMappingURL=useMCPServers.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMCPServers.esm.js","sources":["../../src/hooks/useMCPServers.ts"],"sourcesContent":["import { useApi } from '@backstage/core-plugin-api';\nimport { useCallback, useEffect, useState } from 'react';\nimport { aiRulesApiRef } from '../api/types';\nimport type { AiRulesApi } from '../api/types';\nimport { MCPServerInfo } from '../types/mcp';\nimport { useEntity } from '@backstage/plugin-catalog-react';\n\nexport const useMCPServers = () => {\n const api = useApi(aiRulesApiRef) as AiRulesApi;\n const { entity } = useEntity();\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string>();\n const [servers, setServers] = useState<MCPServerInfo[]>([]);\n const [hasGitUrl, setHasGitUrl] = useState(true);\n\n const sourceLocation = entity.metadata?.annotations?.['backstage.io/source-location'];\n\n const fetchServers = useCallback(async () => {\n if (!sourceLocation) {\n setHasGitUrl(false);\n return;\n }\n\n try {\n setLoading(true);\n setError(undefined);\n // Clean up the Git URL - remove url: prefix and /tree/main/ or /tree/master/\n const gitUrl = sourceLocation\n .replace('url:', '')\n .replace(/\\/tree\\/(?:main|master)\\/.*$/, '');\n const response = await api.getMCPServers(gitUrl);\n setServers(response.servers);\n } catch (err) {\n setError((err as Error).message);\n } finally {\n setLoading(false);\n }\n }, [api, sourceLocation]);\n\n useEffect(() => {\n fetchServers();\n }, [fetchServers]);\n\n return {\n loading,\n error,\n servers,\n hasGitUrl,\n refetch: fetchServers,\n };\n};\n"],"names":[],"mappings":";;;;;AAOO,MAAM,gBAAgB,MAAM;AACjC,EAAM,MAAA,GAAA,GAAM,OAAO,aAAa,CAAA;AAChC,EAAM,MAAA,EAAE,MAAO,EAAA,GAAI,SAAU,EAAA;AAC7B,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,KAAK,CAAA;AAC5C,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,QAAiB,EAAA;AAC3C,EAAA,MAAM,CAAC,OAAS,EAAA,UAAU,CAAI,GAAA,QAAA,CAA0B,EAAE,CAAA;AAC1D,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAI,SAAS,IAAI,CAAA;AAE/C,EAAA,MAAM,cAAiB,GAAA,MAAA,CAAO,QAAU,EAAA,WAAA,GAAc,8BAA8B,CAAA;AAEpF,EAAM,MAAA,YAAA,GAAe,YAAY,YAAY;AAC3C,IAAA,IAAI,CAAC,cAAgB,EAAA;AACnB,MAAA,YAAA,CAAa,KAAK,CAAA;AAClB,MAAA;AAAA;AAGF,IAAI,IAAA;AACF,MAAA,UAAA,CAAW,IAAI,CAAA;AACf,MAAA,QAAA,CAAS,KAAS,CAAA,CAAA;AAElB,MAAM,MAAA,MAAA,GAAS,eACZ,OAAQ,CAAA,MAAA,EAAQ,EAAE,CAClB,CAAA,OAAA,CAAQ,gCAAgC,EAAE,CAAA;AAC7C,MAAA,MAAM,QAAW,GAAA,MAAM,GAAI,CAAA,aAAA,CAAc,MAAM,CAAA;AAC/C,MAAA,UAAA,CAAW,SAAS,OAAO,CAAA;AAAA,aACpB,GAAK,EAAA;AACZ,MAAA,QAAA,CAAU,IAAc,OAAO,CAAA;AAAA,KAC/B,SAAA;AACA,MAAA,UAAA,CAAW,KAAK,CAAA;AAAA;AAClB,GACC,EAAA,CAAC,GAAK,EAAA,cAAc,CAAC,CAAA;AAExB,EAAA,SAAA,CAAU,MAAM;AACd,IAAa,YAAA,EAAA;AAAA,GACf,EAAG,CAAC,YAAY,CAAC,CAAA;AAEjB,EAAO,OAAA;AAAA,IACL,OAAA;AAAA,IACA,KAAA;AAAA,IACA,OAAA;AAAA,IACA,SAAA;AAAA,IACA,OAAS,EAAA;AAAA,GACX;AACF;;;;"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,17 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
1
  import { Entity } from '@backstage/catalog-model';
3
2
  import * as _backstage_core_plugin_api from '@backstage/core-plugin-api';
3
+ import React__default from 'react';
4
+ import * as react_jsx_runtime from 'react/jsx-runtime';
5
+
6
+ interface AiInstructionsComponentProps {
7
+ title?: string;
8
+ }
9
+ declare const AiInstructionsComponent: ({ title }: AiInstructionsComponentProps) => react_jsx_runtime.JSX.Element;
10
+
11
+ interface MCPServersComponentProps {
12
+ title?: string;
13
+ }
14
+ declare const MCPServersComponent: ({ title }: MCPServersComponentProps) => react_jsx_runtime.JSX.Element;
4
15
 
5
16
  interface AIRulesComponentProps {
6
17
  title?: string;
@@ -10,7 +21,7 @@ declare const isAIRulesAvailable: (entity: Entity) => boolean;
10
21
  declare const aiRulesPlugin: _backstage_core_plugin_api.BackstagePlugin<{
11
22
  root: _backstage_core_plugin_api.RouteRef<undefined>;
12
23
  }, {}, {}>;
13
- declare const AIRulesComponent: ({ title }?: AIRulesComponentProps) => react_jsx_runtime.JSX.Element;
24
+ declare const AIRulesComponent: (props: any) => React__default.FunctionComponentElement<AIRulesComponentProps>;
14
25
 
15
26
  declare enum AIRuleType {
16
27
  CURSOR = "cursor",
@@ -37,7 +48,10 @@ interface CopilotRule {
37
48
  fileName: string;
38
49
  gitUrl?: string;
39
50
  content: string;
40
- order: number;
51
+ order?: number;
52
+ title?: string;
53
+ applyTo?: string;
54
+ frontmatter?: Record<string, any>;
41
55
  }
42
56
  interface ClineRule {
43
57
  type: AIRuleType.CLINE;
@@ -71,4 +85,48 @@ interface AIRulesConfig {
71
85
  allowedRuleTypes?: AIRuleType[];
72
86
  }
73
87
 
74
- export { type AIRule, AIRuleType, AIRulesComponent, type AIRulesComponentProps, type AIRulesConfig, type AIRulesResponse, type ClaudeCodeRule, type ClineRule, type CopilotRule, type CursorRule, aiRulesPlugin, isAIRulesAvailable };
88
+ interface MCPServerConfig {
89
+ type?: 'stdio' | 'remote';
90
+ command?: string;
91
+ args?: string[];
92
+ env?: Record<string, string>;
93
+ url?: string;
94
+ headers?: Record<string, string>;
95
+ }
96
+ interface MCPServerInfo {
97
+ name: string;
98
+ type: 'local' | 'remote';
99
+ config: MCPServerConfig;
100
+ source: 'cursor' | 'vscode' | 'claude';
101
+ rawConfig: string;
102
+ }
103
+ interface MCPServersResponse {
104
+ servers: MCPServerInfo[];
105
+ }
106
+
107
+ declare const aiRulesApiRef: _backstage_core_plugin_api.ApiRef<AiRulesApi>;
108
+ interface AiRulesApi {
109
+ getAiRules(ruleTypes: string[]): Promise<AIRulesResponse>;
110
+ getMCPServers(gitUrl: string): Promise<MCPServersResponse>;
111
+ }
112
+
113
+ declare class AiRulesClient implements AiRulesApi {
114
+ private readonly discoveryApi;
115
+ private readonly identityApi;
116
+ constructor(options: {
117
+ discoveryApi: {
118
+ getBaseUrl: (pluginId: string) => Promise<string>;
119
+ };
120
+ identityApi: {
121
+ getCredentials(): Promise<{
122
+ token?: string;
123
+ }>;
124
+ };
125
+ });
126
+ private getAuthHeaders;
127
+ private cleanGitUrl;
128
+ getAiRules(ruleTypes: string[]): Promise<AIRulesResponse>;
129
+ getMCPServers(gitUrl: string): Promise<MCPServersResponse>;
130
+ }
131
+
132
+ export { type AIRule, AIRuleType, AIRulesComponent, type AIRulesComponentProps, type AIRulesConfig, type AIRulesResponse, AiInstructionsComponent, type AiInstructionsComponentProps, type AiRulesApi, AiRulesClient, type ClaudeCodeRule, type ClineRule, type CopilotRule, type CursorRule, type MCPServerConfig, type MCPServerInfo, MCPServersComponent, type MCPServersComponentProps, type MCPServersResponse, aiRulesApiRef, aiRulesPlugin, isAIRulesAvailable };
package/dist/index.esm.js CHANGED
@@ -1,4 +1,8 @@
1
1
  export { AIRulesComponent, aiRulesPlugin } from './plugin.esm.js';
2
2
  export { AIRuleType } from './types.esm.js';
3
+ export { MCPServersComponent } from './components/MCPServersComponent/MCPServersComponent.esm.js';
4
+ export { AiInstructionsComponent } from './components/AiInstructionsComponent/AiInstructionsComponent.esm.js';
3
5
  export { isAIRulesAvailable } from './components/AiRulesComponent/AiRulesComponent.esm.js';
6
+ export { aiRulesApiRef } from './api/types.esm.js';
7
+ export { AiRulesClient } from './api/AiRulesClient.esm.js';
4
8
  //# sourceMappingURL=index.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
1
+ {"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;"}
@@ -1,5 +1,6 @@
1
1
  import { createPlugin, createComponentExtension } from '@backstage/core-plugin-api';
2
2
  import { rootRouteRef } from './routes.esm.js';
3
+ import React from 'react';
3
4
 
4
5
  const aiRulesPlugin = createPlugin({
5
6
  id: "ai-rules",
@@ -11,7 +12,23 @@ const AIRulesComponent = aiRulesPlugin.provide(
11
12
  createComponentExtension({
12
13
  name: "AIRulesComponent",
13
14
  component: {
14
- lazy: () => import('./components/AiRulesComponent/AiRulesComponent.esm.js').then((m) => m.AIRulesComponent)
15
+ lazy: () => import('./components/AiRulesComponent/AiRulesComponent.esm.js').then((m) => m.AIRulesComponent).then((Component) => (props) => React.createElement(Component, props))
16
+ }
17
+ })
18
+ );
19
+ aiRulesPlugin.provide(
20
+ createComponentExtension({
21
+ name: "MCPServersComponent",
22
+ component: {
23
+ lazy: () => import('./components/MCPServersComponent/MCPServersComponent.esm.js').then((m) => m.MCPServersComponent).then((Component) => (props) => React.createElement(Component, props))
24
+ }
25
+ })
26
+ );
27
+ aiRulesPlugin.provide(
28
+ createComponentExtension({
29
+ name: "AiInstructionsComponent",
30
+ component: {
31
+ lazy: () => import('./components/AiInstructionsComponent/AiInstructionsComponent.esm.js').then((m) => m.AiInstructionsComponent).then((Component) => (props) => React.createElement(Component, props))
15
32
  }
16
33
  })
17
34
  );
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.esm.js","sources":["../src/plugin.ts"],"sourcesContent":["import { createPlugin, createComponentExtension } from '@backstage/core-plugin-api';\nimport { rootRouteRef } from './routes';\n\nexport const aiRulesPlugin = createPlugin({\n id: 'ai-rules',\n routes: {\n root: rootRouteRef,\n },\n});\n\nexport const AIRulesComponent = aiRulesPlugin.provide(\n createComponentExtension({\n name: 'AIRulesComponent',\n component: {\n lazy: () => import('./components/AiRulesComponent/AiRulesComponent').then(m => m.AIRulesComponent),\n },\n }),\n);"],"names":[],"mappings":";;;AAGO,MAAM,gBAAgB,YAAa,CAAA;AAAA,EACxC,EAAI,EAAA,UAAA;AAAA,EACJ,MAAQ,EAAA;AAAA,IACN,IAAM,EAAA;AAAA;AAEV,CAAC;AAEM,MAAM,mBAAmB,aAAc,CAAA,OAAA;AAAA,EAC5C,wBAAyB,CAAA;AAAA,IACvB,IAAM,EAAA,kBAAA;AAAA,IACN,SAAW,EAAA;AAAA,MACT,IAAA,EAAM,MAAM,OAAO,uDAAgD,EAAE,IAAK,CAAA,CAAA,CAAA,KAAK,EAAE,gBAAgB;AAAA;AACnG,GACD;AACH;;;;"}
1
+ {"version":3,"file":"plugin.esm.js","sources":["../src/plugin.ts"],"sourcesContent":["import { createPlugin, createComponentExtension } from '@backstage/core-plugin-api';\nimport { rootRouteRef } from './routes';\nimport React from 'react';\n\nexport const aiRulesPlugin = createPlugin({\n id: 'ai-rules',\n routes: {\n root: rootRouteRef,\n },\n});\n\nexport const AIRulesComponent = aiRulesPlugin.provide(\n createComponentExtension({\n name: 'AIRulesComponent',\n component: {\n lazy: () => import('./components/AiRulesComponent/AiRulesComponent').then(m => m.AIRulesComponent)\n .then(Component => (props: any) => React.createElement(Component, props)),\n },\n }),\n);\n\nexport const MCPServersComponent = aiRulesPlugin.provide(\n createComponentExtension({\n name: 'MCPServersComponent',\n component: {\n lazy: () => import('./components/MCPServersComponent/MCPServersComponent').then(m => m.MCPServersComponent)\n .then(Component => (props: any) => React.createElement(Component, props)),\n },\n }),\n);\n\nexport const AiInstructionsComponent = aiRulesPlugin.provide(\n createComponentExtension({\n name: 'AiInstructionsComponent',\n component: {\n lazy: () => import('./components/AiInstructionsComponent/AiInstructionsComponent').then(m => m.AiInstructionsComponent)\n .then(Component => (props: any) => React.createElement(Component, props)),\n },\n }),\n);"],"names":[],"mappings":";;;;AAIO,MAAM,gBAAgB,YAAa,CAAA;AAAA,EACxC,EAAI,EAAA,UAAA;AAAA,EACJ,MAAQ,EAAA;AAAA,IACN,IAAM,EAAA;AAAA;AAEV,CAAC;AAEM,MAAM,mBAAmB,aAAc,CAAA,OAAA;AAAA,EAC5C,wBAAyB,CAAA;AAAA,IACvB,IAAM,EAAA,kBAAA;AAAA,IACN,SAAW,EAAA;AAAA,MACT,MAAM,MAAM,OAAO,uDAAgD,CAAE,CAAA,IAAA,CAAK,OAAK,CAAE,CAAA,gBAAgB,CAC9F,CAAA,IAAA,CAAK,eAAa,CAAC,KAAA,KAAe,MAAM,aAAc,CAAA,SAAA,EAAW,KAAK,CAAC;AAAA;AAC5E,GACD;AACH;AAEmC,aAAc,CAAA,OAAA;AAAA,EAC/C,wBAAyB,CAAA;AAAA,IACvB,IAAM,EAAA,qBAAA;AAAA,IACN,SAAW,EAAA;AAAA,MACT,MAAM,MAAM,OAAO,6DAAsD,CAAE,CAAA,IAAA,CAAK,OAAK,CAAE,CAAA,mBAAmB,CACvG,CAAA,IAAA,CAAK,eAAa,CAAC,KAAA,KAAe,MAAM,aAAc,CAAA,SAAA,EAAW,KAAK,CAAC;AAAA;AAC5E,GACD;AACH;AAEuC,aAAc,CAAA,OAAA;AAAA,EACnD,wBAAyB,CAAA;AAAA,IACvB,IAAM,EAAA,yBAAA;AAAA,IACN,SAAW,EAAA;AAAA,MACT,MAAM,MAAM,OAAO,qEAA8D,CAAE,CAAA,IAAA,CAAK,OAAK,CAAE,CAAA,uBAAuB,CACnH,CAAA,IAAA,CAAK,eAAa,CAAC,KAAA,KAAe,MAAM,aAAc,CAAA,SAAA,EAAW,KAAK,CAAC;AAAA;AAC5E,GACD;AACH;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.esm.js","sources":["../src/types.ts"],"sourcesContent":["export enum AIRuleType {\n CURSOR = 'cursor',\n COPILOT = 'copilot', \n CLINE = 'cline',\n CLAUDE_CODE = 'claude-code',\n}\n\nexport interface CursorRule {\n type: AIRuleType.CURSOR;\n id: string;\n filePath: string;\n fileName: string;\n gitUrl?: string;\n description?: string;\n globs?: string[];\n alwaysApply?: boolean;\n frontmatter?: Record<string, any>;\n content: string;\n}\n\nexport interface CopilotRule {\n type: AIRuleType.COPILOT;\n id: string;\n filePath: string;\n fileName: string;\n gitUrl?: string;\n content: string;\n order: number; // Position in the file\n}\n\nexport interface ClineRule {\n type: AIRuleType.CLINE;\n id: string;\n filePath: string;\n fileName: string;\n gitUrl?: string;\n content: string;\n title?: string;\n sections?: Array<{\n title: string;\n content: string;\n }>;\n}\n\nexport interface ClaudeCodeRule {\n type: AIRuleType.CLAUDE_CODE;\n id: string;\n filePath: string;\n fileName: string;\n gitUrl?: string;\n content: string;\n title?: string;\n}\n\nexport type AIRule = CursorRule | CopilotRule | ClineRule | ClaudeCodeRule;\n\nexport interface AIRulesResponse {\n rules: AIRule[];\n totalCount: number;\n ruleTypes: AIRuleType[];\n}\n\nexport interface AIRulesConfig {\n allowedRuleTypes?: AIRuleType[];\n}"],"names":["AIRuleType"],"mappings":"AAAY,IAAA,UAAA,qBAAAA,WAAL,KAAA;AACL,EAAAA,YAAA,QAAS,CAAA,GAAA,QAAA;AACT,EAAAA,YAAA,SAAU,CAAA,GAAA,SAAA;AACV,EAAAA,YAAA,OAAQ,CAAA,GAAA,OAAA;AACR,EAAAA,YAAA,aAAc,CAAA,GAAA,aAAA;AAJJ,EAAAA,OAAAA,WAAAA;AAAA,CAAA,EAAA,UAAA,IAAA,EAAA;;;;"}
1
+ {"version":3,"file":"types.esm.js","sources":["../src/types.ts"],"sourcesContent":["export enum AIRuleType {\n CURSOR = 'cursor',\n COPILOT = 'copilot', \n CLINE = 'cline',\n CLAUDE_CODE = 'claude-code',\n}\n\nexport interface CursorRule {\n type: AIRuleType.CURSOR;\n id: string;\n filePath: string;\n fileName: string;\n gitUrl?: string;\n description?: string;\n globs?: string[];\n alwaysApply?: boolean;\n frontmatter?: Record<string, any>;\n content: string;\n}\n\nexport interface CopilotRule {\n type: AIRuleType.COPILOT;\n id: string;\n filePath: string;\n fileName: string;\n gitUrl?: string;\n content: string;\n order?: number; // Position in the file (legacy)\n title?: string;\n applyTo?: string;\n frontmatter?: Record<string, any>;\n}\n\nexport interface ClineRule {\n type: AIRuleType.CLINE;\n id: string;\n filePath: string;\n fileName: string;\n gitUrl?: string;\n content: string;\n title?: string;\n sections?: Array<{\n title: string;\n content: string;\n }>;\n}\n\nexport interface ClaudeCodeRule {\n type: AIRuleType.CLAUDE_CODE;\n id: string;\n filePath: string;\n fileName: string;\n gitUrl?: string;\n content: string;\n title?: string;\n}\n\nexport type AIRule = CursorRule | CopilotRule | ClineRule | ClaudeCodeRule;\n\nexport interface AIRulesResponse {\n rules: AIRule[];\n totalCount: number;\n ruleTypes: AIRuleType[];\n}\n\nexport interface AIRulesConfig {\n allowedRuleTypes?: AIRuleType[];\n}"],"names":["AIRuleType"],"mappings":"AAAY,IAAA,UAAA,qBAAAA,WAAL,KAAA;AACL,EAAAA,YAAA,QAAS,CAAA,GAAA,QAAA;AACT,EAAAA,YAAA,SAAU,CAAA,GAAA,SAAA;AACV,EAAAA,YAAA,OAAQ,CAAA,GAAA,OAAA;AACR,EAAAA,YAAA,aAAc,CAAA,GAAA,aAAA;AAJJ,EAAAA,OAAAA,WAAAA;AAAA,CAAA,EAAA,UAAA,IAAA,EAAA;;;;"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@terasky/backstage-plugin-ai-rules",
3
3
  "description": "AI Rules Visualizer Plugin for Backstage",
4
- "version": "0.2.1",
4
+ "version": "1.0.0",
5
5
  "main": "dist/index.esm.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "license": "Apache-2.0",
@@ -39,6 +39,7 @@
39
39
  "@backstage/catalog-model": "^1.7.5",
40
40
  "@backstage/core-components": "^0.17.5",
41
41
  "@backstage/core-plugin-api": "^1.10.9",
42
+ "@backstage/frontend-plugin-api": "^0.11.0",
42
43
  "@backstage/plugin-catalog-react": "^1.20.1",
43
44
  "@backstage/theme": "^0.6.8",
44
45
  "@material-ui/core": "^4.12.4",
@@ -71,8 +72,24 @@
71
72
  "copilot",
72
73
  "cline"
73
74
  ],
75
+ "exports": {
76
+ ".": {
77
+ "import": "./dist/index.esm.js",
78
+ "types": "./dist/index.d.ts",
79
+ "default": "./dist/index.esm.js"
80
+ },
81
+ "./alpha": {
82
+ "import": "./dist/alpha.esm.js",
83
+ "types": "./dist/alpha.d.ts",
84
+ "default": "./dist/alpha.esm.js"
85
+ },
86
+ "./package.json": "./package.json"
87
+ },
74
88
  "typesVersions": {
75
89
  "*": {
90
+ "alpha": [
91
+ "dist/alpha.d.ts"
92
+ ],
76
93
  "package.json": [
77
94
  "package.json"
78
95
  ]