@terasky/backstage-plugin-ai-rules 0.1.0 → 0.2.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/README.md +1 -1
- package/config.d.ts +10 -2
- package/dist/components/AiRulesComponent/AiRulesComponent.esm.js +106 -42
- package/dist/components/AiRulesComponent/AiRulesComponent.esm.js.map +1 -1
- package/dist/hooks/useAiRules.esm.js +48 -9
- package/dist/hooks/useAiRules.esm.js.map +1 -1
- package/dist/index.d.ts +13 -3
- package/dist/types.esm.js +1 -0
- package/dist/types.esm.js.map +1 -1
- package/package.json +10 -10
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Welcome to the AI Coding Rules plugin!
|
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@terasky/backstage-plugin-ai-rules)
|
|
6
6
|
|
|
7
|
-
The `AI Coding Rules` plugin for Backstage provides comprehensive visualization and management of AI coding rules from various sources like Cursor, GitHub Copilot, and
|
|
7
|
+
The `AI Coding Rules` plugin for Backstage provides comprehensive visualization and management of AI coding rules from various sources like Cursor, GitHub Copilot, Cline, and Claude Code. It enables teams to discover, view, and manage their AI coding guidelines directly within the Backstage interface, featuring modern UI with filtering capabilities, statistics overview, and expandable rule cards with metadata display.
|
|
8
8
|
|
|
9
9
|
For detailed docs go to https://terasky-oss.github.io/backstage-plugins/plugins/ai-rules-plugin/overview
|
|
10
10
|
|
package/config.d.ts
CHANGED
|
@@ -7,9 +7,17 @@ export interface Config {
|
|
|
7
7
|
aiRules?: {
|
|
8
8
|
/**
|
|
9
9
|
* Allowed rule types to search for in repositories
|
|
10
|
-
* Defaults to ["cursor", "copilot"] if not specified
|
|
10
|
+
* Defaults to ["cursor", "copilot", "cline", "claude-code"] if not specified
|
|
11
11
|
* @visibility frontend
|
|
12
12
|
*/
|
|
13
|
-
allowedRuleTypes: string[]; // e.g. ["cursor", "copilot", "cline"]
|
|
13
|
+
allowedRuleTypes: string[]; // e.g. ["cursor", "copilot", "cline", "claude-code"]
|
|
14
|
+
/**
|
|
15
|
+
* Default rule types to be pre-selected when the component loads
|
|
16
|
+
* If not provided, defaults to empty array (no rules pre-selected)
|
|
17
|
+
* If empty array, no rule types are pre-selected
|
|
18
|
+
* If specific array, those rule types are pre-selected
|
|
19
|
+
* @visibility frontend
|
|
20
|
+
*/
|
|
21
|
+
defaultRuleTypes?: string[]; // e.g. ["cursor", "copilot"]
|
|
14
22
|
}
|
|
15
23
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
1
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import { useAiRules } from '../../hooks/useAiRules.esm.js';
|
|
3
3
|
import { InfoCard, Progress, EmptyState, MarkdownContent } from '@backstage/core-components';
|
|
4
|
-
import { makeStyles,
|
|
4
|
+
import { makeStyles, Typography, FormControlLabel, Checkbox, Button, Card, CardContent, useTheme, Accordion, AccordionSummary, Chip, Tooltip, IconButton, AccordionDetails } from '@material-ui/core';
|
|
5
5
|
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
|
|
6
6
|
import CodeIcon from '@material-ui/icons/Code';
|
|
7
7
|
import LaunchIcon from '@material-ui/icons/Launch';
|
|
@@ -81,13 +81,17 @@ const useStyles = makeStyles((theme) => ({
|
|
|
81
81
|
"& > *": {
|
|
82
82
|
marginRight: theme.spacing(1)
|
|
83
83
|
}
|
|
84
|
+
},
|
|
85
|
+
applyFilterButton: {
|
|
86
|
+
marginTop: theme.spacing(1)
|
|
84
87
|
}
|
|
85
88
|
}));
|
|
86
89
|
const RuleTypeIcon = ({ type }) => {
|
|
87
90
|
const colors = {
|
|
88
91
|
[AIRuleType.CURSOR]: "#0066CC",
|
|
89
92
|
[AIRuleType.COPILOT]: "#6F42C1",
|
|
90
|
-
[AIRuleType.CLINE]: "#28A745"
|
|
93
|
+
[AIRuleType.CLINE]: "#28A745",
|
|
94
|
+
[AIRuleType.CLAUDE_CODE]: "#FF6B35"
|
|
91
95
|
};
|
|
92
96
|
return /* @__PURE__ */ jsx(CodeIcon, { style: { color: colors[type] } });
|
|
93
97
|
};
|
|
@@ -271,9 +275,35 @@ const RuleComponent = ({ rule }) => {
|
|
|
271
275
|
/* @__PURE__ */ jsx("div", { className: styles.ruleContent, children: /* @__PURE__ */ jsx(MarkdownContent, { content: rule2.content }) })
|
|
272
276
|
] }) })
|
|
273
277
|
] });
|
|
278
|
+
const renderClaudeCodeRule = (rule2) => /* @__PURE__ */ jsxs(Accordion, { className: styles.ruleCard, children: [
|
|
279
|
+
/* @__PURE__ */ jsx(AccordionSummary, { expandIcon: /* @__PURE__ */ jsx(ExpandMoreIcon, {}), children: /* @__PURE__ */ jsxs("div", { className: styles.ruleHeader, children: [
|
|
280
|
+
/* @__PURE__ */ jsxs("div", { className: styles.ruleHeaderContent, children: [
|
|
281
|
+
/* @__PURE__ */ jsx(RuleTypeIcon, { type: rule2.type }),
|
|
282
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h6", children: rule2.title || rule2.fileName }),
|
|
283
|
+
/* @__PURE__ */ jsx(Chip, { label: rule2.type, size: "small", className: styles.ruleType })
|
|
284
|
+
] }),
|
|
285
|
+
rule2.gitUrl && /* @__PURE__ */ jsx(Tooltip, { title: "Open file in repository", children: /* @__PURE__ */ jsx(
|
|
286
|
+
IconButton,
|
|
287
|
+
{
|
|
288
|
+
size: "small",
|
|
289
|
+
onClick: (e) => {
|
|
290
|
+
e.stopPropagation();
|
|
291
|
+
window.open(constructFileUrl(rule2.gitUrl, rule2.filePath), "_blank");
|
|
292
|
+
},
|
|
293
|
+
children: /* @__PURE__ */ jsx(LaunchIcon, { fontSize: "small" })
|
|
294
|
+
}
|
|
295
|
+
) })
|
|
296
|
+
] }) }),
|
|
297
|
+
/* @__PURE__ */ jsx(AccordionDetails, { children: /* @__PURE__ */ jsxs("div", { children: [
|
|
298
|
+
/* @__PURE__ */ jsx("div", { className: styles.ruleMetadata, children: /* @__PURE__ */ jsx(Chip, { label: `Path: ${rule2.filePath}`, size: "small", variant: "outlined" }) }),
|
|
299
|
+
/* @__PURE__ */ jsx("div", { className: styles.ruleContent, children: /* @__PURE__ */ jsx(MarkdownContent, { content: rule2.content }) })
|
|
300
|
+
] }) })
|
|
301
|
+
] });
|
|
274
302
|
switch (rule.type) {
|
|
275
303
|
case AIRuleType.CURSOR:
|
|
276
304
|
return renderCursorRule(rule);
|
|
305
|
+
case AIRuleType.CLAUDE_CODE:
|
|
306
|
+
return renderClaudeCodeRule(rule);
|
|
277
307
|
case AIRuleType.COPILOT:
|
|
278
308
|
return renderCopilotRule(rule);
|
|
279
309
|
case AIRuleType.CLINE:
|
|
@@ -283,8 +313,21 @@ const RuleComponent = ({ rule }) => {
|
|
|
283
313
|
}
|
|
284
314
|
};
|
|
285
315
|
const AIRulesComponent = ({ title = "AI Coding Rules" } = {}) => {
|
|
286
|
-
const { rulesByType, loading, error, hasGitUrl, totalRules, allowedRuleTypes, selectedRuleTypes, setSelectedRuleTypes } = useAiRules();
|
|
316
|
+
const { rulesByType, loading, error, hasGitUrl, totalRules, allowedRuleTypes, selectedRuleTypes, setSelectedRuleTypes, applyFilters, resetFilters, hasUnappliedChanges, hasSearched } = useAiRules();
|
|
287
317
|
const styles = useStyles();
|
|
318
|
+
const ruleTypeDisplayOrder = [AIRuleType.CURSOR, AIRuleType.CLAUDE_CODE, AIRuleType.COPILOT, AIRuleType.CLINE];
|
|
319
|
+
const formatRuleTypeName = (type) => {
|
|
320
|
+
switch (type) {
|
|
321
|
+
case AIRuleType.CURSOR:
|
|
322
|
+
return "Cursor";
|
|
323
|
+
case AIRuleType.CLAUDE_CODE:
|
|
324
|
+
return "Claude Code";
|
|
325
|
+
case AIRuleType.COPILOT:
|
|
326
|
+
return "Copilot";
|
|
327
|
+
case AIRuleType.CLINE:
|
|
328
|
+
return "Cline";
|
|
329
|
+
}
|
|
330
|
+
};
|
|
288
331
|
const handleTypeToggle = (type, checked) => {
|
|
289
332
|
const newTypes = checked ? [...selectedRuleTypes, type] : selectedRuleTypes.filter((t) => t !== type);
|
|
290
333
|
setSelectedRuleTypes(newTypes);
|
|
@@ -312,24 +355,6 @@ const AIRulesComponent = ({ title = "AI Coding Rules" } = {}) => {
|
|
|
312
355
|
}
|
|
313
356
|
) });
|
|
314
357
|
}
|
|
315
|
-
if (totalRules === 0) {
|
|
316
|
-
return /* @__PURE__ */ jsx(InfoCard, { title, children: /* @__PURE__ */ jsx(
|
|
317
|
-
EmptyState,
|
|
318
|
-
{
|
|
319
|
-
missing: "content",
|
|
320
|
-
title: "No AI Rules Found",
|
|
321
|
-
description: "No AI rules were found in this repository for the selected rule types.",
|
|
322
|
-
action: /* @__PURE__ */ jsx(
|
|
323
|
-
Button,
|
|
324
|
-
{
|
|
325
|
-
variant: "outlined",
|
|
326
|
-
onClick: () => setSelectedRuleTypes(allowedRuleTypes),
|
|
327
|
-
children: "Reset Filters"
|
|
328
|
-
}
|
|
329
|
-
)
|
|
330
|
-
}
|
|
331
|
-
) });
|
|
332
|
-
}
|
|
333
358
|
return /* @__PURE__ */ jsxs(InfoCard, { title, className: styles.root, children: [
|
|
334
359
|
/* @__PURE__ */ jsxs("div", { className: styles.filterSection, children: [
|
|
335
360
|
/* @__PURE__ */ jsx(Typography, { variant: "h6", gutterBottom: true, children: "Filter Rule Types" }),
|
|
@@ -343,30 +368,69 @@ const AIRulesComponent = ({ title = "AI Coding Rules" } = {}) => {
|
|
|
343
368
|
onChange: (e) => handleTypeToggle(type, e.target.checked)
|
|
344
369
|
}
|
|
345
370
|
),
|
|
346
|
-
label:
|
|
371
|
+
label: formatRuleTypeName(type)
|
|
347
372
|
},
|
|
348
373
|
type
|
|
349
|
-
)) })
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
374
|
+
)) }),
|
|
375
|
+
/* @__PURE__ */ jsxs("div", { className: styles.applyFilterButton, children: [
|
|
376
|
+
/* @__PURE__ */ jsx(
|
|
377
|
+
Button,
|
|
378
|
+
{
|
|
379
|
+
variant: "contained",
|
|
380
|
+
color: "primary",
|
|
381
|
+
onClick: applyFilters,
|
|
382
|
+
disabled: !hasUnappliedChanges,
|
|
383
|
+
children: "Apply Filter"
|
|
384
|
+
}
|
|
385
|
+
),
|
|
386
|
+
hasUnappliedChanges && /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "textSecondary", style: { marginTop: 8 }, children: 'You have unsaved filter changes. Click "Apply Filter" to update the results.' }),
|
|
387
|
+
!hasUnappliedChanges && selectedRuleTypes.length === 0 && /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "textSecondary", style: { marginTop: 8 }, children: "Select at least one rule type to search for AI rules." })
|
|
388
|
+
] })
|
|
360
389
|
] }),
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
"
|
|
390
|
+
hasSearched && totalRules === 0 ? /* @__PURE__ */ jsx(
|
|
391
|
+
EmptyState,
|
|
392
|
+
{
|
|
393
|
+
missing: "content",
|
|
394
|
+
title: "No AI Rules Found",
|
|
395
|
+
description: "No AI rules were found in this repository for the selected rule types.",
|
|
396
|
+
action: /* @__PURE__ */ jsx(
|
|
397
|
+
Button,
|
|
398
|
+
{
|
|
399
|
+
variant: "outlined",
|
|
400
|
+
onClick: resetFilters,
|
|
401
|
+
children: "Reset Filters"
|
|
402
|
+
}
|
|
403
|
+
)
|
|
404
|
+
}
|
|
405
|
+
) : totalRules > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
406
|
+
/* @__PURE__ */ jsxs("div", { className: styles.statsContainer, children: [
|
|
407
|
+
/* @__PURE__ */ jsx(Card, { className: styles.statCard, children: /* @__PURE__ */ jsxs(CardContent, { children: [
|
|
408
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h4", children: totalRules }),
|
|
409
|
+
/* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: "Total Rules" })
|
|
410
|
+
] }) }),
|
|
411
|
+
ruleTypeDisplayOrder.map((type) => {
|
|
412
|
+
const typeRules = rulesByType[type] || [];
|
|
413
|
+
if (typeRules.length === 0) return null;
|
|
414
|
+
return /* @__PURE__ */ jsx(Card, { className: styles.statCard, children: /* @__PURE__ */ jsxs(CardContent, { children: [
|
|
415
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h4", children: typeRules.length }),
|
|
416
|
+
/* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: formatRuleTypeName(type) })
|
|
417
|
+
] }) }, type);
|
|
418
|
+
})
|
|
367
419
|
] }),
|
|
368
|
-
|
|
369
|
-
|
|
420
|
+
ruleTypeDisplayOrder.map((type) => {
|
|
421
|
+
const typeRules = rulesByType[type] || [];
|
|
422
|
+
if (typeRules.length === 0) return null;
|
|
423
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
424
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "h5", gutterBottom: true, style: { marginTop: 16 }, children: [
|
|
425
|
+
formatRuleTypeName(type),
|
|
426
|
+
" Rules (",
|
|
427
|
+
typeRules.length,
|
|
428
|
+
")"
|
|
429
|
+
] }),
|
|
430
|
+
typeRules.map((rule) => /* @__PURE__ */ jsx(RuleComponent, { rule }, rule.id))
|
|
431
|
+
] }, type);
|
|
432
|
+
})
|
|
433
|
+
] }) : /* @__PURE__ */ jsx("div", { style: { marginTop: 16 }, children: /* @__PURE__ */ jsx(Typography, { variant: "body1", color: "textSecondary", children: 'Select rule types above and click "Apply Filter" to search for AI coding rules in this repository.' }) })
|
|
370
434
|
] });
|
|
371
435
|
};
|
|
372
436
|
|
|
@@ -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 } 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}));\n\nconst RuleTypeIcon = ({ type }: { type: AIRuleType }) => {\n const colors = {\n [AIRuleType.CURSOR]: '#0066CC',\n [AIRuleType.COPILOT]: '#6F42C1', \n [AIRuleType.CLINE]: '#28A745',\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 switch (rule.type) {\n case AIRuleType.CURSOR:\n return renderCursorRule(rule as CursorRule);\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 } = useAiRules();\n const styles = useStyles();\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 if (totalRules === 0) {\n return (\n <InfoCard title={title}>\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={() => setSelectedRuleTypes(allowedRuleTypes)}\n >\n Reset Filters\n </Button>\n }\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={type.charAt(0).toUpperCase() + type.slice(1)}\n />\n ))}\n </div>\n </div>\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 {Object.entries(rulesByType).map(([type, typeRules]) => (\n <Card key={type} className={styles.statCard}>\n <CardContent>\n <Typography variant=\"h4\">{typeRules.length}</Typography>\n <Typography color=\"textSecondary\">{type.charAt(0).toUpperCase() + type.slice(1)}</Typography>\n </CardContent>\n </Card>\n ))}\n </div>\n\n {Object.entries(rulesByType).map(([type, typeRules]) => (\n <div key={type}>\n <Typography variant=\"h5\" gutterBottom style={{ marginTop: 16 }}>\n {type.charAt(0).toUpperCase() + type.slice(1)} Rules ({typeRules.length})\n </Typography>\n {typeRules.map(rule => (\n <RuleComponent key={rule.id} rule={rule} />\n ))}\n </div>\n ))}\n </InfoCard>\n );\n};"],"names":["rule"],"mappings":";;;;;;;;;AAYa,MAAA,kBAAA,GAAqB,CAAC,MAA4B,KAAA;AAC7D,EAAA,MAAM,gBAAmB,GAAA,MAAA,CAAO,QAAU,EAAA,WAAA,GAAc,8BAA8B,CAAK,IAAA,EAAA;AAC3F,EAAO,OAAA,gBAAA,CAAiB,WAAW,MAAM,CAAA;AAC3C;AAEA,MAAM,SAAA,GAAY,UAAW,CAAA,CAAC,KAAW,MAAA;AAAA,EACvC,IAAM,EAAA;AAAA,IACJ,sBAAwB,EAAA;AAAA,MACtB,YAAA,EAAc,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,MAC7B,UAAY,EAAA;AAAA,QACV,OAAS,EAAA;AAAA;AACX;AACF,GACF;AAAA,EACA,aAAe,EAAA;AAAA,IACb,YAAA,EAAc,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,IAC7B,OAAA,EAAS,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,IACxB,eAAA,EAAiB,KAAM,CAAA,OAAA,CAAQ,UAAW,CAAA,OAAA;AAAA,IAC1C,YAAA,EAAc,MAAM,KAAM,CAAA;AAAA,GAC5B;AAAA,EACA,QAAU,EAAA;AAAA,IACR,YAAA,EAAc,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,IAC7B,MAAQ,EAAA,CAAA,UAAA,EAAa,KAAM,CAAA,OAAA,CAAQ,OAAO,CAAA;AAAA,GAC5C;AAAA,EACA,UAAY,EAAA;AAAA,IACV,OAAS,EAAA,MAAA;AAAA,IACT,UAAY,EAAA,QAAA;AAAA,IACZ,GAAA,EAAK,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,IACpB,KAAO,EAAA;AAAA,GACT;AAAA,EACA,iBAAmB,EAAA;AAAA,IACjB,OAAS,EAAA,MAAA;AAAA,IACT,UAAY,EAAA,QAAA;AAAA,IACZ,GAAA,EAAK,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,IACpB,IAAM,EAAA;AAAA,GACR;AAAA,EACA,QAAU,EAAA;AAAA,IACR,aAAe,EAAA,WAAA;AAAA,IACf,UAAY,EAAA,MAAA;AAAA,IACZ,QAAU,EAAA;AAAA,GACZ;AAAA,EACA,WAAa,EAAA;AAAA,IACX,OAAA,EAAS,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,IACxB,YAAA,EAAc,MAAM,KAAM,CAAA,YAAA;AAAA,IAC1B,QAAU,EAAA,MAAA;AAAA,IACV,SAAW,EAAA,OAAA;AAAA,IACX,OAAS,EAAA;AAAA,MACP,eAAiB,EAAA;AAAA;AACnB,GACF;AAAA,EACA,YAAc,EAAA;AAAA,IACZ,OAAS,EAAA,MAAA;AAAA,IACT,QAAU,EAAA,MAAA;AAAA,IACV,GAAA,EAAK,KAAM,CAAA,OAAA,CAAQ,GAAG,CAAA;AAAA,IACtB,YAAA,EAAc,KAAM,CAAA,OAAA,CAAQ,CAAC;AAAA,GAC/B;AAAA,EACA,cAAgB,EAAA;AAAA,IACd,OAAS,EAAA,MAAA;AAAA,IACT,GAAA,EAAK,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,IACpB,YAAA,EAAc,KAAM,CAAA,OAAA,CAAQ,CAAC;AAAA,GAC/B;AAAA,EACA,QAAU,EAAA;AAAA,IACR,QAAU,EAAA,OAAA;AAAA,IACV,SAAW,EAAA;AAAA,GACb;AAAA,EACA,cAAgB,EAAA;AAAA,IACd,QAAU,EAAA,MAAA;AAAA,IACV,KAAO,EAAA,KAAA,CAAM,OAAQ,CAAA,IAAA,CAAK,GAAG;AAAA,GAC/B;AAAA,EACA,eAAiB,EAAA;AAAA,IACf,OAAS,EAAA,MAAA;AAAA,IACT,QAAU,EAAA,MAAA;AAAA,IACV,OAAS,EAAA;AAAA,MACP,WAAA,EAAa,KAAM,CAAA,OAAA,CAAQ,CAAC;AAAA;AAC9B;AAEJ,CAAE,CAAA,CAAA;AAEF,MAAM,YAAe,GAAA,CAAC,EAAE,IAAA,EAAiC,KAAA;AACvD,EAAA,MAAM,MAAS,GAAA;AAAA,IACb,CAAC,UAAW,CAAA,MAAM,GAAG,SAAA;AAAA,IACrB,CAAC,UAAW,CAAA,OAAO,GAAG,SAAA;AAAA,IACtB,CAAC,UAAW,CAAA,KAAK,GAAG;AAAA,GACtB;AAEA,EAAO,uBAAA,GAAA,CAAC,YAAS,KAAO,EAAA,EAAE,OAAO,MAAO,CAAA,IAAI,GAAK,EAAA,CAAA;AACnD,CAAA;AAEA,MAAM,iBAAA,GAAoB,CAAC,KAAA,EAAY,WAAsC,KAAA;AAC3E,EAAA,IAAI,CAAC,WAAe,IAAA,MAAA,CAAO,KAAK,WAAW,CAAA,CAAE,WAAW,CAAG,EAAA;AACzD,IAAO,OAAA,IAAA;AAAA;AAIT,EAAA,MAAM,eAAkB,GAAA,MAAA,CAAO,OAAQ,CAAA,WAAW,CAAE,CAAA,MAAA;AAAA,IAAO,CAAC,CAAC,GAAG,CAC9D,KAAA,CAAC,CAAC,aAAe,EAAA,OAAO,CAAE,CAAA,QAAA,CAAS,GAAG;AAAA,GACxC;AAEA,EAAI,IAAA,eAAA,CAAgB,WAAW,CAAG,EAAA;AAChC,IAAO,OAAA,IAAA;AAAA;AAGT,EACE,uBAAA,IAAA,CAAC,SAAI,KAAO,EAAA;AAAA,IACV,YAAc,EAAA,MAAA;AAAA,IACd,OAAS,EAAA,MAAA;AAAA,IACT,eAAiB,EAAA,KAAA,CAAM,OAAQ,CAAA,IAAA,KAAS,SAAS,wBAA2B,GAAA,kBAAA;AAAA,IAC5E,YAAc,EAAA,KAAA;AAAA,IACd,QAAQ,CAAa,UAAA,EAAA,KAAA,CAAM,QAAQ,IAAS,KAAA,MAAA,GAAS,2BAA2B,kBAAkB,CAAA;AAAA,GAElG,EAAA,QAAA,EAAA;AAAA,oBAAC,GAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,WAAA,EAAY,KAAO,EAAA;AAAA,MACrC,YAAc,EAAA,MAAA;AAAA,MACd,UAAY,EAAA,MAAA;AAAA,MACZ,KAAA,EAAO,KAAM,CAAA,OAAA,CAAQ,IAAK,CAAA,SAAA;AAAA,MAC1B,aAAe,EAAA,WAAA;AAAA,MACf,aAAe,EAAA;AAAA,OACd,QAEH,EAAA,UAAA,EAAA,CAAA;AAAA,IACC,gBAAgB,GAAI,CAAA,CAAC,CAAC,GAAK,EAAA,KAAK,GAAG,KAClC,qBAAA,IAAA,CAAC,SAAc,KAAO,EAAA,EAAE,cAAc,KAAQ,GAAA,eAAA,CAAgB,SAAS,CAAI,GAAA,MAAA,GAAS,KAClF,EAAA,QAAA,EAAA;AAAA,sBAAC,IAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,OAAA,EAAQ,KAAO,EAAA;AAAA,QACjC,UAAY,EAAA,MAAA;AAAA,QACZ,aAAe,EAAA,YAAA;AAAA,QACf,KAAA,EAAO,KAAM,CAAA,OAAA,CAAQ,OAAQ,CAAA,IAAA;AAAA,QAC7B,YAAc,EAAA;AAAA,OAEb,EAAA,QAAA,EAAA;AAAA,QAAA,GAAA;AAAA,QAAI;AAAA,OACP,EAAA,CAAA;AAAA,sBACC,GAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,OAAA,EAAQ,KAAO,EAAA;AAAA,QACjC,UAAY,EAAA,KAAA;AAAA,QACZ,UAAY,EAAA,KAAA;AAAA,QACZ,KAAA,EAAO,KAAM,CAAA,OAAA,CAAQ,IAAK,CAAA;AAAA,OAC5B,EACG,QAAM,EAAA,KAAA,CAAA,OAAA,CAAQ,KAAK,CAAA,GAAI,KAAM,CAAA,IAAA,CAAK,IAAI,CAAA,GAAI,MAAO,CAAA,KAAK,CACzD,EAAA;AAAA,KAAA,EAAA,EAfQ,GAgBV,CACD;AAAA,GACH,EAAA,CAAA;AAEJ,CAAA;AAGA,MAAM,kBAAA,GAAqB,CAAC,OAAoB,KAAA;AAC9C,EAAA,OAAO,uBAAuB,OAAO,CAAA;AACvC,CAAA;AAGA,MAAM,sBAAA,GAAyB,CAAC,OAAoB,KAAA;AAElD,EAAA,IAAI,CAAC,OAAQ,CAAA,IAAA,EAAO,CAAA,UAAA,CAAW,KAAK,CAAG,EAAA;AACrC,IAAO,OAAA;AAAA,MACL,WAAa,EAAA,KAAA,CAAA;AAAA,MACb;AAAA,KACF;AAAA;AAGF,EAAI,IAAA;AAEF,IAAM,MAAA,KAAA,GAAQ,OAAQ,CAAA,KAAA,CAAM,IAAI,CAAA;AAChC,IAAA,IAAI,mBAAsB,GAAA,CAAA,CAAA;AAG1B,IAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,KAAA,CAAM,QAAQ,CAAK,EAAA,EAAA;AACrC,MAAA,IAAI,KAAM,CAAA,CAAC,CAAE,CAAA,IAAA,OAAW,KAAO,EAAA;AAC7B,QAAsB,mBAAA,GAAA,CAAA;AACtB,QAAA;AAAA;AACF;AAGF,IAAA,IAAI,wBAAwB,CAAI,CAAA,EAAA;AAC9B,MAAO,OAAA;AAAA,QACL,WAAa,EAAA,KAAA,CAAA;AAAA,QACb;AAAA,OACF;AAAA;AAIF,IAAA,MAAM,gBAAmB,GAAA,KAAA,CAAM,KAAM,CAAA,CAAA,EAAG,mBAAmB,CAAA;AAC3D,IAAA,MAAM,YAAe,GAAA,KAAA,CAAM,KAAM,CAAA,mBAAA,GAAsB,CAAC,CAAA;AAGxD,IAAA,MAAM,cAAmC,EAAC;AAC1C,IAAA,KAAA,MAAW,QAAQ,gBAAkB,EAAA;AACnC,MAAM,MAAA,WAAA,GAAc,KAAK,IAAK,EAAA;AAC9B,MAAA,IAAI,WAAe,IAAA,WAAA,CAAY,QAAS,CAAA,GAAG,CAAG,EAAA;AAC5C,QAAM,MAAA,UAAA,GAAa,WAAY,CAAA,OAAA,CAAQ,GAAG,CAAA;AAC1C,QAAA,MAAM,MAAM,WAAY,CAAA,SAAA,CAAU,CAAG,EAAA,UAAU,EAAE,IAAK,EAAA;AACtD,QAAA,MAAM,QAAQ,WAAY,CAAA,SAAA,CAAU,UAAa,GAAA,CAAC,EAAE,IAAK,EAAA;AACzD,QAAA,WAAA,CAAY,GAAG,CAAI,GAAA,KAAA;AAAA;AACrB;AAGF,IAAO,OAAA;AAAA,MACL,aAAa,MAAO,CAAA,IAAA,CAAK,WAAW,CAAE,CAAA,MAAA,GAAS,IAAI,WAAc,GAAA,KAAA,CAAA;AAAA,MACjE,OAAS,EAAA,YAAA,CAAa,IAAK,CAAA,IAAI,EAAE,IAAK;AAAA,KACxC;AAAA,WACO,KAAO,EAAA;AACd,IAAO,OAAA;AAAA,MACL,WAAa,EAAA,KAAA,CAAA;AAAA,MACb;AAAA,KACF;AAAA;AAEJ,CAAA;AAEA,MAAM,gBAAA,GAAmB,CAAC,MAAA,EAAgB,QAA6B,KAAA;AAErE,EAAA,MAAM,WAAc,GAAA,MAAA,CAAO,OAAQ,CAAA,MAAA,EAAQ,EAAE,CAAA;AAG7C,EAAI,IAAA,WAAA,CAAY,QAAS,CAAA,YAAY,CAAG,EAAA;AACtC,IAAO,OAAA,CAAA,EAAG,WAAW,CAAA,WAAA,EAAc,QAAQ,CAAA,CAAA;AAAA;AAI7C,EAAI,IAAA,WAAA,CAAY,QAAS,CAAA,YAAY,CAAG,EAAA;AACtC,IAAO,OAAA,CAAA,EAAG,WAAW,CAAA,aAAA,EAAgB,QAAQ,CAAA,CAAA;AAAA;AAI/C,EAAO,OAAA,CAAA,EAAG,WAAW,CAAA,WAAA,EAAc,QAAQ,CAAA,CAAA;AAC7C,CAAA;AAEA,MAAM,aAAgB,GAAA,CAAC,EAAE,IAAA,EAA6B,KAAA;AACpD,EAAA,MAAM,SAAS,SAAU,EAAA;AACzB,EAAA,MAAM,QAAQ,QAAS,EAAA;AAEvB,EAAM,MAAA,gBAAA,GAAmB,CAACA,KAAqB,KAAA;AAE7C,IAAA,MAAM,EAAE,WAAa,EAAA,OAAA,EAAY,GAAA,kBAAA,CAAmBA,MAAK,OAAO,CAAA;AAEhE,IAAA,uBACG,IAAA,CAAA,SAAA,EAAA,EAAU,SAAW,EAAA,MAAA,CAAO,QAC3B,EAAA,QAAA,EAAA;AAAA,sBAAC,GAAA,CAAA,gBAAA,EAAA,EAAiB,4BAAa,GAAA,CAAA,cAAA,EAAA,EAAe,GAC5C,QAAC,kBAAA,IAAA,CAAA,KAAA,EAAA,EAAI,SAAW,EAAA,MAAA,CAAO,UACrB,EAAA,QAAA,EAAA;AAAA,wBAAC,IAAA,CAAA,KAAA,EAAA,EAAI,SAAW,EAAA,MAAA,CAAO,iBACrB,EAAA,QAAA,EAAA;AAAA,0BAAC,GAAA,CAAA,YAAA,EAAA,EAAa,IAAMA,EAAAA,KAAAA,CAAK,IAAM,EAAA,CAAA;AAAA,8BAC9B,UAAW,EAAA,EAAA,OAAA,EAAQ,IAAM,EAAA,QAAA,EAAAA,MAAK,QAAS,EAAA,CAAA;AAAA,0BACxC,GAAA,CAAC,QAAK,KAAOA,EAAAA,KAAAA,CAAK,MAAM,IAAK,EAAA,OAAA,EAAQ,SAAW,EAAA,MAAA,CAAO,QAAU,EAAA,CAAA;AAAA,UAChE,aAAa,WACZ,oBAAA,GAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,SAAQ,KAAO,EAAA,EAAE,UAAY,EAAA,CAAA,EAAG,OAAO,KAAM,CAAA,OAAA,CAAQ,KAAK,SAAU,EAAA,EACrF,sBAAY,WACf,EAAA;AAAA,SAEJ,EAAA,CAAA;AAAA,QACCA,KAAK,CAAA,MAAA,oBACH,GAAA,CAAA,OAAA,EAAA,EAAQ,OAAM,yBACb,EAAA,QAAA,kBAAA,GAAA;AAAA,UAAC,UAAA;AAAA,UAAA;AAAA,YACC,IAAK,EAAA,OAAA;AAAA,YACL,OAAA,EAAS,CAAC,CAAM,KAAA;AACd,cAAA,CAAA,CAAE,eAAgB,EAAA;AAClB,cAAA,MAAA,CAAO,KAAK,gBAAiBA,CAAAA,KAAAA,CAAK,QAASA,KAAK,CAAA,QAAQ,GAAG,QAAQ,CAAA;AAAA,aACrE;AAAA,YAEA,QAAA,kBAAA,GAAA,CAAC,UAAW,EAAA,EAAA,QAAA,EAAS,OAAQ,EAAA;AAAA;AAAA,SAEjC,EAAA;AAAA,OAAA,EAEJ,CACF,EAAA,CAAA;AAAA,sBACA,GAAA,CAAC,gBACC,EAAA,EAAA,QAAA,kBAAA,IAAA,CAAC,KACC,EAAA,EAAA,QAAA,EAAA;AAAA,wBAAC,IAAA,CAAA,KAAA,EAAA,EAAI,SAAW,EAAA,MAAA,CAAO,YACrB,EAAA,QAAA,EAAA;AAAA,0BAAC,GAAA,CAAA,IAAA,EAAA,EAAK,OAAO,CAASA,MAAAA,EAAAA,KAAAA,CAAK,QAAQ,CAAI,CAAA,EAAA,IAAA,EAAK,OAAQ,EAAA,OAAA,EAAQ,UAAW,EAAA,CAAA;AAAA,UACtE,WAAA,EAAa,yBACX,GAAA,CAAA,IAAA,EAAA,EAAK,OAAO,CAAU,OAAA,EAAA,KAAA,CAAM,OAAQ,CAAA,WAAA,CAAY,KAAK,CAAA,GAAI,YAAY,KAAM,CAAA,IAAA,CAAK,IAAI,CAAI,GAAA,WAAA,CAAY,KAAK,CAAI,CAAA,EAAA,IAAA,EAAK,OAAQ,EAAA,OAAA,EAAQ,UAAW,EAAA;AAAA,SAElJ,EAAA,CAAA;AAAA,QACC,iBAAA,CAAkB,OAAO,WAAW,CAAA;AAAA,wBACrC,GAAA,CAAC,SAAI,SAAW,EAAA,MAAA,CAAO,aACrB,QAAC,kBAAA,GAAA,CAAA,eAAA,EAAA,EAAgB,SAAkB,CACrC,EAAA;AAAA,OAAA,EACF,CACF,EAAA;AAAA,KACF,EAAA,CAAA;AAAA,GAEJ;AAEA,EAAM,MAAA,iBAAA,GAAoB,CAACA,KACzB,qBAAA,GAAA,CAAC,QAAK,SAAW,EAAA,MAAA,CAAO,QACtB,EAAA,QAAA,kBAAA,IAAA,CAAC,WACC,EAAA,EAAA,QAAA,EAAA;AAAA,oBAAC,IAAA,CAAA,KAAA,EAAA,EAAI,SAAW,EAAA,MAAA,CAAO,UACrB,EAAA,QAAA,EAAA;AAAA,sBAAC,IAAA,CAAA,KAAA,EAAA,EAAI,SAAW,EAAA,MAAA,CAAO,iBACrB,EAAA,QAAA,EAAA;AAAA,wBAAC,GAAA,CAAA,YAAA,EAAA,EAAa,IAAMA,EAAAA,KAAAA,CAAK,IAAM,EAAA,CAAA;AAAA,wBAC/B,IAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,IAAK,EAAA,QAAA,EAAA;AAAA,UAAA,gBAAA;AAAA,UAAeA,KAAK,CAAA;AAAA,SAAM,EAAA,CAAA;AAAA,wBACnD,GAAA,CAAC,QAAK,KAAOA,EAAAA,KAAAA,CAAK,MAAM,IAAK,EAAA,OAAA,EAAQ,SAAW,EAAA,MAAA,CAAO,QAAU,EAAA;AAAA,OACnE,EAAA,CAAA;AAAA,MACCA,KAAK,CAAA,MAAA,oBACH,GAAA,CAAA,OAAA,EAAA,EAAQ,OAAM,yBACb,EAAA,QAAA,kBAAA,GAAA;AAAA,QAAC,UAAA;AAAA,QAAA;AAAA,UACC,IAAK,EAAA,OAAA;AAAA,UACL,OAAA,EAAS,MAAM,MAAA,CAAO,IAAK,CAAA,gBAAA,CAAiBA,MAAK,MAASA,EAAAA,KAAAA,CAAK,QAAQ,CAAA,EAAG,QAAQ,CAAA;AAAA,UAElF,QAAA,kBAAA,GAAA,CAAC,UAAW,EAAA,EAAA,QAAA,EAAS,OAAQ,EAAA;AAAA;AAAA,OAEjC,EAAA;AAAA,KAEJ,EAAA,CAAA;AAAA,wBACC,KAAI,EAAA,EAAA,SAAA,EAAW,OAAO,WACpB,EAAA,QAAA,EAAAA,MAAK,OACR,EAAA;AAAA,GAAA,EACF,CACF,EAAA,CAAA;AAGF,EAAA,MAAM,kBAAkB,CAACA,KAAAA,0BACtB,SAAU,EAAA,EAAA,SAAA,EAAW,OAAO,QAC3B,EAAA,QAAA,EAAA;AAAA,oBAAC,GAAA,CAAA,gBAAA,EAAA,EAAiB,4BAAa,GAAA,CAAA,cAAA,EAAA,EAAe,GAC5C,QAAC,kBAAA,IAAA,CAAA,KAAA,EAAA,EAAI,SAAW,EAAA,MAAA,CAAO,UACrB,EAAA,QAAA,EAAA;AAAA,sBAAC,IAAA,CAAA,KAAA,EAAA,EAAI,SAAW,EAAA,MAAA,CAAO,iBACrB,EAAA,QAAA,EAAA;AAAA,wBAAC,GAAA,CAAA,YAAA,EAAA,EAAa,IAAMA,EAAAA,KAAAA,CAAK,IAAM,EAAA,CAAA;AAAA,wBAC/B,GAAA,CAAC,cAAW,OAAQ,EAAA,IAAA,EAAM,UAAAA,KAAK,CAAA,KAAA,IAASA,MAAK,QAAS,EAAA,CAAA;AAAA,wBACtD,GAAA,CAAC,QAAK,KAAOA,EAAAA,KAAAA,CAAK,MAAM,IAAK,EAAA,OAAA,EAAQ,SAAW,EAAA,MAAA,CAAO,QAAU,EAAA;AAAA,OACnE,EAAA,CAAA;AAAA,MACCA,KAAK,CAAA,MAAA,oBACH,GAAA,CAAA,OAAA,EAAA,EAAQ,OAAM,yBACb,EAAA,QAAA,kBAAA,GAAA;AAAA,QAAC,UAAA;AAAA,QAAA;AAAA,UACC,IAAK,EAAA,OAAA;AAAA,UACL,OAAA,EAAS,CAAC,CAAM,KAAA;AACd,YAAA,CAAA,CAAE,eAAgB,EAAA;AAClB,YAAA,MAAA,CAAO,KAAK,gBAAiBA,CAAAA,KAAAA,CAAK,QAASA,KAAK,CAAA,QAAQ,GAAG,QAAQ,CAAA;AAAA,WACrE;AAAA,UAEA,QAAA,kBAAA,GAAA,CAAC,UAAW,EAAA,EAAA,QAAA,EAAS,OAAQ,EAAA;AAAA;AAAA,OAEjC,EAAA;AAAA,KAAA,EAEJ,CACF,EAAA,CAAA;AAAA,oBACA,GAAA,CAAC,gBACC,EAAA,EAAA,QAAA,kBAAA,IAAA,CAAC,KACC,EAAA,EAAA,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,KAAI,EAAA,EAAA,SAAA,EAAW,MAAO,CAAA,YAAA,EACrB,8BAAC,IAAK,EAAA,EAAA,KAAA,EAAO,CAASA,MAAAA,EAAAA,KAAAA,CAAK,QAAQ,CAAI,CAAA,EAAA,IAAA,EAAK,OAAQ,EAAA,OAAA,EAAQ,YAAW,CACzE,EAAA,CAAA;AAAA,sBACA,GAAA,CAAC,KAAI,EAAA,EAAA,SAAA,EAAW,MAAO,CAAA,WAAA,EACrB,8BAAC,eAAgB,EAAA,EAAA,OAAA,EAASA,KAAK,CAAA,OAAA,EAAS,CAC1C,EAAA;AAAA,KAAA,EACF,CACF,EAAA;AAAA,GACF,EAAA,CAAA;AAGF,EAAA,QAAQ,KAAK,IAAM;AAAA,IACjB,KAAK,UAAW,CAAA,MAAA;AACd,MAAA,OAAO,iBAAiB,IAAkB,CAAA;AAAA,IAC5C,KAAK,UAAW,CAAA,OAAA;AACd,MAAA,OAAO,kBAAkB,IAAmB,CAAA;AAAA,IAC9C,KAAK,UAAW,CAAA,KAAA;AACd,MAAA,OAAO,gBAAgB,IAAiB,CAAA;AAAA,IAC1C;AACE,MAAO,OAAA,IAAA;AAAA;AAEb,CAAA;AAEO,MAAM,mBAAmB,CAAC,EAAE,QAAQ,iBAAkB,EAAA,GAA2B,EAAO,KAAA;AAC7F,EAAM,MAAA,EAAE,WAAa,EAAA,OAAA,EAAS,KAAO,EAAA,SAAA,EAAW,YAAY,gBAAkB,EAAA,iBAAA,EAAmB,oBAAqB,EAAA,GAAI,UAAW,EAAA;AACrI,EAAA,MAAM,SAAS,SAAU,EAAA;AACzB,EAAM,MAAA,gBAAA,GAAmB,CAAC,IAAA,EAAkB,OAAqB,KAAA;AAC/D,IAAM,MAAA,QAAA,GAAW,OACb,GAAA,CAAC,GAAG,iBAAA,EAAmB,IAAI,CAAA,GAC3B,iBAAkB,CAAA,MAAA,CAAO,CAAK,CAAA,KAAA,CAAA,KAAM,IAAI,CAAA;AAC5C,IAAA,oBAAA,CAAqB,QAAQ,CAAA;AAAA,GAC/B;AAEA,EAAA,IAAI,OAAS,EAAA;AACX,IAAA,uBACG,GAAA,CAAA,QAAA,EAAA,EAAS,KACR,EAAA,QAAA,kBAAA,GAAA,CAAC,YAAS,CACZ,EAAA,CAAA;AAAA;AAIJ,EAAA,IAAI,CAAC,SAAW,EAAA;AACd,IACE,uBAAA,GAAA,CAAC,YAAS,KACR,EAAA,QAAA,kBAAA,GAAA;AAAA,MAAC,UAAA;AAAA,MAAA;AAAA,QACC,OAAQ,EAAA,SAAA;AAAA,QACR,KAAM,EAAA,mBAAA;AAAA,QACN,WAAY,EAAA;AAAA;AAAA,KAEhB,EAAA,CAAA;AAAA;AAIJ,EAAA,IAAI,KAAO,EAAA;AACT,IACE,uBAAA,GAAA,CAAC,YAAS,KACR,EAAA,QAAA,kBAAA,GAAA;AAAA,MAAC,UAAA;AAAA,MAAA;AAAA,QACC,OAAQ,EAAA,SAAA;AAAA,QACR,KAAM,EAAA,qBAAA;AAAA,QACN,WAAa,EAAA;AAAA;AAAA,KAEjB,EAAA,CAAA;AAAA;AAIJ,EAAA,IAAI,eAAe,CAAG,EAAA;AACpB,IACE,uBAAA,GAAA,CAAC,YAAS,KACR,EAAA,QAAA,kBAAA,GAAA;AAAA,MAAC,UAAA;AAAA,MAAA;AAAA,QACC,OAAQ,EAAA,SAAA;AAAA,QACR,KAAM,EAAA,mBAAA;AAAA,QACN,WAAY,EAAA,wEAAA;AAAA,QACZ,MACE,kBAAA,GAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,OAAQ,EAAA,UAAA;AAAA,YACR,OAAA,EAAS,MAAM,oBAAA,CAAqB,gBAAgB,CAAA;AAAA,YACrD,QAAA,EAAA;AAAA;AAAA;AAED;AAAA,KAGN,EAAA,CAAA;AAAA;AAIJ,EAAA,uBACG,IAAA,CAAA,QAAA,EAAA,EAAS,KAAc,EAAA,SAAA,EAAW,OAAO,IACxC,EAAA,QAAA,EAAA;AAAA,oBAAC,IAAA,CAAA,KAAA,EAAA,EAAI,SAAW,EAAA,MAAA,CAAO,aACrB,EAAA,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,IAAK,EAAA,YAAA,EAAY,MAAC,QAEtC,EAAA,mBAAA,EAAA,CAAA;AAAA,0BACC,KAAI,EAAA,EAAA,SAAA,EAAW,OAAO,eACpB,EAAA,QAAA,EAAA,gBAAA,CAAiB,IAAI,CACpB,IAAA,qBAAA,GAAA;AAAA,QAAC,gBAAA;AAAA,QAAA;AAAA,UAEC,OACE,kBAAA,GAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cACC,OAAA,EAAS,iBAAkB,CAAA,QAAA,CAAS,IAAI,CAAA;AAAA,cACxC,UAAU,CAAC,CAAA,KAAM,iBAAiB,IAAM,EAAA,CAAA,CAAE,OAAO,OAAO;AAAA;AAAA,WAC1D;AAAA,UAEF,KAAA,EAAO,KAAK,MAAO,CAAA,CAAC,EAAE,WAAY,EAAA,GAAI,IAAK,CAAA,KAAA,CAAM,CAAC;AAAA,SAAA;AAAA,QAP7C;AAAA,OASR,CACH,EAAA;AAAA,KACF,EAAA,CAAA;AAAA,oBAEC,IAAA,CAAA,KAAA,EAAA,EAAI,SAAW,EAAA,MAAA,CAAO,cACrB,EAAA,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,IAAK,EAAA,EAAA,SAAA,EAAW,MAAO,CAAA,QAAA,EACtB,+BAAC,WACC,EAAA,EAAA,QAAA,EAAA;AAAA,wBAAC,GAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,IAAA,EAAM,QAAW,EAAA,UAAA,EAAA,CAAA;AAAA,wBACpC,GAAA,CAAA,UAAA,EAAA,EAAW,KAAM,EAAA,eAAA,EAAgB,QAAW,EAAA,aAAA,EAAA;AAAA,OAAA,EAC/C,CACF,EAAA,CAAA;AAAA,MACC,OAAO,OAAQ,CAAA,WAAW,CAAE,CAAA,GAAA,CAAI,CAAC,CAAC,IAAA,EAAM,SAAS,CAAA,yBAC/C,IAAgB,EAAA,EAAA,SAAA,EAAW,MAAO,CAAA,QAAA,EACjC,+BAAC,WACC,EAAA,EAAA,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,IAAM,EAAA,QAAA,EAAA,SAAA,CAAU,MAAO,EAAA,CAAA;AAAA,wBAC1C,GAAA,CAAA,UAAA,EAAA,EAAW,KAAM,EAAA,eAAA,EAAiB,QAAK,EAAA,IAAA,CAAA,MAAA,CAAO,CAAC,CAAA,CAAE,WAAY,EAAA,GAAI,IAAK,CAAA,KAAA,CAAM,CAAC,CAAE,EAAA;AAAA,OAClF,EAAA,CAAA,EAAA,EAJS,IAKX,CACD;AAAA,KACH,EAAA,CAAA;AAAA,IAEC,MAAA,CAAO,OAAQ,CAAA,WAAW,CAAE,CAAA,GAAA,CAAI,CAAC,CAAC,IAAM,EAAA,SAAS,CAChD,qBAAA,IAAA,CAAC,KACC,EAAA,EAAA,QAAA,EAAA;AAAA,sBAAC,IAAA,CAAA,UAAA,EAAA,EAAW,SAAQ,IAAK,EAAA,YAAA,EAAY,MAAC,KAAO,EAAA,EAAE,SAAW,EAAA,EAAA,EACvD,EAAA,QAAA,EAAA;AAAA,QAAA,IAAA,CAAK,OAAO,CAAC,CAAA,CAAE,aAAgB,GAAA,IAAA,CAAK,MAAM,CAAC,CAAA;AAAA,QAAE,UAAA;AAAA,QAAS,SAAU,CAAA,MAAA;AAAA,QAAO;AAAA,OAC1E,EAAA,CAAA;AAAA,MACC,SAAA,CAAU,IAAI,CACb,IAAA,qBAAA,GAAA,CAAC,iBAA4B,IAAT,EAAA,EAAA,IAAA,CAAK,EAAgB,CAC1C;AAAA,KAAA,EAAA,EANO,IAOV,CACD;AAAA,GACH,EAAA,CAAA;AAEJ;;;;"}
|
|
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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"}
|
|
@@ -9,11 +9,22 @@ const useAiRules = () => {
|
|
|
9
9
|
const discoveryApi = useApi(discoveryApiRef);
|
|
10
10
|
const fetchApi = useApi(fetchApiRef);
|
|
11
11
|
const [rules, setRules] = useState([]);
|
|
12
|
-
const [loading, setLoading] = useState(
|
|
12
|
+
const [loading, setLoading] = useState(false);
|
|
13
13
|
const [error, setError] = useState(null);
|
|
14
14
|
const [selectedRuleTypes, setSelectedRuleTypes] = useState([]);
|
|
15
|
+
const [appliedRuleTypes, setAppliedRuleTypes] = useState([]);
|
|
16
|
+
const [initialized, setInitialized] = useState(false);
|
|
17
|
+
const [hasSearched, setHasSearched] = useState(false);
|
|
15
18
|
const allowedRuleTypes = useMemo(() => {
|
|
16
|
-
return configApi.getOptionalStringArray("aiRules.allowedRuleTypes") || [AIRuleType.CURSOR, AIRuleType.COPILOT];
|
|
19
|
+
return configApi.getOptionalStringArray("aiRules.allowedRuleTypes") || [AIRuleType.CURSOR, AIRuleType.COPILOT, AIRuleType.CLINE, AIRuleType.CLAUDE_CODE];
|
|
20
|
+
}, [configApi]);
|
|
21
|
+
const defaultRuleTypes = useMemo(() => {
|
|
22
|
+
const aiRulesConfig = configApi.getOptionalConfig("aiRules");
|
|
23
|
+
if (!aiRulesConfig) {
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
const configuredDefaults = configApi.getOptionalStringArray("aiRules.defaultRuleTypes");
|
|
27
|
+
return configuredDefaults !== void 0 ? configuredDefaults : [];
|
|
17
28
|
}, [configApi]);
|
|
18
29
|
const entityData = useMemo(() => {
|
|
19
30
|
const sourceAnnotation = entity.metadata?.annotations?.["backstage.io/source-location"] || "";
|
|
@@ -40,8 +51,14 @@ const useAiRules = () => {
|
|
|
40
51
|
};
|
|
41
52
|
}, [entity.kind, entity.metadata.namespace, entity.metadata.name, entity.metadata?.annotations?.["backstage.io/source-location"]]);
|
|
42
53
|
useEffect(() => {
|
|
43
|
-
|
|
44
|
-
|
|
54
|
+
const aiRulesConfig = configApi.getOptionalConfig("aiRules");
|
|
55
|
+
const configLoaded = aiRulesConfig !== void 0;
|
|
56
|
+
if (!initialized && allowedRuleTypes.length > 0 && configLoaded) {
|
|
57
|
+
setSelectedRuleTypes(defaultRuleTypes);
|
|
58
|
+
setAppliedRuleTypes(defaultRuleTypes);
|
|
59
|
+
setInitialized(true);
|
|
60
|
+
}
|
|
61
|
+
}, [defaultRuleTypes, allowedRuleTypes, initialized, configApi]);
|
|
45
62
|
const fetchAiRules = useCallback(async (ruleTypes) => {
|
|
46
63
|
if (!entityData.hasGitUrl || !entityData.gitUrl) {
|
|
47
64
|
setLoading(false);
|
|
@@ -50,19 +67,18 @@ const useAiRules = () => {
|
|
|
50
67
|
try {
|
|
51
68
|
setLoading(true);
|
|
52
69
|
setError(null);
|
|
70
|
+
setHasSearched(true);
|
|
53
71
|
const baseUrl = await discoveryApi.getBaseUrl("ai-rules");
|
|
54
72
|
const url = new URL(`${baseUrl}/rules`);
|
|
55
73
|
url.searchParams.append("gitUrl", entityData.gitUrl);
|
|
56
74
|
if (ruleTypes.length > 0) {
|
|
57
75
|
url.searchParams.append("ruleTypes", ruleTypes.join(","));
|
|
58
76
|
}
|
|
59
|
-
console.log("Fetching AI rules from:", url.toString());
|
|
60
77
|
const response = await fetchApi.fetch(url.toString());
|
|
61
78
|
if (!response.ok) {
|
|
62
79
|
throw new Error(`Failed to fetch AI rules: ${response.statusText}`);
|
|
63
80
|
}
|
|
64
81
|
const data = await response.json();
|
|
65
|
-
console.log("Received AI rules:", data);
|
|
66
82
|
setRules(data.rules);
|
|
67
83
|
} catch (err) {
|
|
68
84
|
const errorMessage = err instanceof Error ? err.message : "Unknown error occurred";
|
|
@@ -73,11 +89,28 @@ const useAiRules = () => {
|
|
|
73
89
|
setLoading(false);
|
|
74
90
|
}
|
|
75
91
|
}, [entityData.hasGitUrl, entityData.gitUrl, discoveryApi, fetchApi]);
|
|
76
|
-
|
|
92
|
+
const applyFilters = useCallback(() => {
|
|
93
|
+
setAppliedRuleTypes([...selectedRuleTypes]);
|
|
77
94
|
if (selectedRuleTypes.length > 0) {
|
|
78
95
|
fetchAiRules(selectedRuleTypes);
|
|
96
|
+
} else {
|
|
97
|
+
setRules([]);
|
|
98
|
+
setError(null);
|
|
99
|
+
setHasSearched(true);
|
|
100
|
+
}
|
|
101
|
+
}, [selectedRuleTypes, fetchAiRules]);
|
|
102
|
+
const resetFilters = useCallback(() => {
|
|
103
|
+
setSelectedRuleTypes(allowedRuleTypes);
|
|
104
|
+
setAppliedRuleTypes([...allowedRuleTypes]);
|
|
105
|
+
if (allowedRuleTypes.length > 0) {
|
|
106
|
+
fetchAiRules(allowedRuleTypes);
|
|
107
|
+
}
|
|
108
|
+
}, [allowedRuleTypes, fetchAiRules]);
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
if (appliedRuleTypes.length > 0) {
|
|
111
|
+
fetchAiRules(appliedRuleTypes);
|
|
79
112
|
}
|
|
80
|
-
}, [fetchAiRules,
|
|
113
|
+
}, [fetchAiRules, appliedRuleTypes]);
|
|
81
114
|
const rulesByType = useMemo(() => {
|
|
82
115
|
return rules.reduce((acc, rule) => {
|
|
83
116
|
if (!acc[rule.type]) {
|
|
@@ -95,9 +128,15 @@ const useAiRules = () => {
|
|
|
95
128
|
hasGitUrl: entityData.hasGitUrl,
|
|
96
129
|
componentName: entityData.name,
|
|
97
130
|
allowedRuleTypes,
|
|
131
|
+
defaultRuleTypes,
|
|
98
132
|
selectedRuleTypes,
|
|
99
133
|
setSelectedRuleTypes,
|
|
100
|
-
|
|
134
|
+
appliedRuleTypes,
|
|
135
|
+
applyFilters,
|
|
136
|
+
resetFilters,
|
|
137
|
+
totalRules: rules.length,
|
|
138
|
+
hasSearched,
|
|
139
|
+
hasUnappliedChanges: JSON.stringify(selectedRuleTypes.sort()) !== JSON.stringify(appliedRuleTypes.sort())
|
|
101
140
|
};
|
|
102
141
|
};
|
|
103
142
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAiRules.esm.js","sources":["../../src/hooks/useAiRules.ts"],"sourcesContent":["import { useEntity } from '@backstage/plugin-catalog-react';\nimport { AIRuleType, AIRulesResponse, AIRule } from '../types';\nimport { useState, useEffect, useMemo, useCallback } from 'react';\nimport { useApi, configApiRef, discoveryApiRef, fetchApiRef } from '@backstage/core-plugin-api';\n\nexport const useAiRules = () => {\n const { entity } = useEntity();\n const configApi = useApi(configApiRef);\n const discoveryApi = useApi(discoveryApiRef);\n const fetchApi = useApi(fetchApiRef);\n \n const [rules, setRules] = useState<AIRule[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [selectedRuleTypes, setSelectedRuleTypes] = useState<AIRuleType[]>([]);\n\n // Stabilize allowed rule types\n const allowedRuleTypes = useMemo(() => {\n return configApi.getOptionalStringArray('aiRules.allowedRuleTypes') as AIRuleType[] || [AIRuleType.CURSOR, AIRuleType.COPILOT];\n }, [configApi]);\n\n // Extract stable entity properties\n const entityData = useMemo(() => {\n const sourceAnnotation = entity.metadata?.annotations?.['backstage.io/source-location'] || '';\n const hasGitUrl = sourceAnnotation.startsWith('url:');\n \n let gitUrl = hasGitUrl ? sourceAnnotation.substring(4) : undefined;\n if (gitUrl) {\n // Remove trailing slashes and normalize URL\n gitUrl = gitUrl.replace(/\\/+$/, '');\n // Handle GitHub tree/blob URLs - extract base repo URL\n const treeMatch = gitUrl.match(/^(.+)\\/tree\\/([^/]+)(?:\\/(.+))?$/);\n const blobMatch = gitUrl.match(/^(.+)\\/blob\\/([^/]+)(?:\\/(.+))?$/);\n if (treeMatch) {\n gitUrl = treeMatch[1]; // Just the base repo URL\n }\n if (blobMatch) {\n gitUrl = blobMatch[1]; // Just the base repo URL \n }\n }\n\n return {\n kind: entity.kind,\n namespace: entity.metadata.namespace || 'default',\n name: entity.metadata.name,\n sourceAnnotation,\n hasGitUrl,\n gitUrl,\n };\n }, [entity.kind, entity.metadata.namespace, entity.metadata.name, entity.metadata?.annotations?.['backstage.io/source-location']]);\n\n // Initialize selected rule types only once\n useEffect(() => {\n setSelectedRuleTypes(allowedRuleTypes);\n }, []); // Empty dependency - only run once\n\n // Stable fetch function\n const fetchAiRules = useCallback(async (ruleTypes: AIRuleType[]) => {\n if (!entityData.hasGitUrl || !entityData.gitUrl) {\n setLoading(false);\n return;\n }\n\n try {\n setLoading(true);\n setError(null);\n \n const baseUrl = await discoveryApi.getBaseUrl('ai-rules');\n const url = new URL(`${baseUrl}/rules`);\n \n // Send the Git URL directly to the backend\n url.searchParams.append('gitUrl', entityData.gitUrl);\n if (ruleTypes.length > 0) {\n url.searchParams.append('ruleTypes', ruleTypes.join(','));\n }\n\n console.log('Fetching AI rules from:', url.toString());\n\n const response = await fetchApi.fetch(url.toString());\n if (!response.ok) {\n throw new Error(`Failed to fetch AI rules: ${response.statusText}`);\n }\n\n const data: AIRulesResponse = await response.json();\n console.log('Received AI rules:', data);\n setRules(data.rules);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';\n console.error('Error fetching AI rules:', errorMessage);\n setError(errorMessage);\n setRules([]);\n } finally {\n setLoading(false);\n }\n }, [entityData.hasGitUrl, entityData.gitUrl, discoveryApi, fetchApi]);\n\n // Fetch rules when dependencies change\n useEffect(() => {\n if (selectedRuleTypes.length > 0) {\n fetchAiRules(selectedRuleTypes);\n }\n }, [fetchAiRules, selectedRuleTypes]);\n\n const rulesByType = useMemo(() => {\n return rules.reduce((acc, rule) => {\n if (!acc[rule.type]) {\n acc[rule.type] = [];\n }\n acc[rule.type].push(rule);\n return acc;\n }, {} as Record<AIRuleType, AIRule[]>);\n }, [rules]);\n\n return {\n rules,\n rulesByType,\n loading,\n error,\n hasGitUrl: entityData.hasGitUrl,\n componentName: entityData.name,\n allowedRuleTypes,\n selectedRuleTypes,\n setSelectedRuleTypes,\n totalRules: rules.length,\n };\n};"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useAiRules.esm.js","sources":["../../src/hooks/useAiRules.ts"],"sourcesContent":["import { useEntity } from '@backstage/plugin-catalog-react';\nimport { AIRuleType, AIRulesResponse, AIRule } from '../types';\nimport { useState, useEffect, useMemo, useCallback } from 'react';\nimport { useApi, configApiRef, discoveryApiRef, fetchApiRef } from '@backstage/core-plugin-api';\n\nexport const useAiRules = () => {\n const { entity } = useEntity();\n const configApi = useApi(configApiRef);\n const discoveryApi = useApi(discoveryApiRef);\n const fetchApi = useApi(fetchApiRef);\n \n const [rules, setRules] = useState<AIRule[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [selectedRuleTypes, setSelectedRuleTypes] = useState<AIRuleType[]>([]);\n const [appliedRuleTypes, setAppliedRuleTypes] = useState<AIRuleType[]>([]);\n const [initialized, setInitialized] = useState(false);\n const [hasSearched, setHasSearched] = useState(false);\n\n // Stabilize allowed rule types\n const allowedRuleTypes = useMemo(() => {\n return configApi.getOptionalStringArray('aiRules.allowedRuleTypes') as AIRuleType[] || [AIRuleType.CURSOR, AIRuleType.COPILOT, AIRuleType.CLINE, AIRuleType.CLAUDE_CODE];\n }, [configApi]);\n\n // Stabilize default rule types\n const defaultRuleTypes = useMemo(() => {\n // Check if the config has the aiRules section at all\n const aiRulesConfig = configApi.getOptionalConfig('aiRules');\n if (!aiRulesConfig) {\n // Config not loaded yet or aiRules section doesn't exist, use empty array\n return [];\n }\n \n const configuredDefaults = configApi.getOptionalStringArray('aiRules.defaultRuleTypes') as AIRuleType[];\n \n // If defaultRuleTypes is explicitly configured (even as empty array), use that\n // If not configured at all, use empty array\n return configuredDefaults !== undefined ? configuredDefaults : [];\n }, [configApi]);\n\n // Extract stable entity properties\n const entityData = useMemo(() => {\n const sourceAnnotation = entity.metadata?.annotations?.['backstage.io/source-location'] || '';\n const hasGitUrl = sourceAnnotation.startsWith('url:');\n \n let gitUrl = hasGitUrl ? sourceAnnotation.substring(4) : undefined;\n if (gitUrl) {\n // Remove trailing slashes and normalize URL\n gitUrl = gitUrl.replace(/\\/+$/, '');\n // Handle GitHub tree/blob URLs - extract base repo URL\n const treeMatch = gitUrl.match(/^(.+)\\/tree\\/([^/]+)(?:\\/(.+))?$/);\n const blobMatch = gitUrl.match(/^(.+)\\/blob\\/([^/]+)(?:\\/(.+))?$/);\n if (treeMatch) {\n gitUrl = treeMatch[1]; // Just the base repo URL\n }\n if (blobMatch) {\n gitUrl = blobMatch[1]; // Just the base repo URL \n }\n }\n\n return {\n kind: entity.kind,\n namespace: entity.metadata.namespace || 'default',\n name: entity.metadata.name,\n sourceAnnotation,\n hasGitUrl,\n gitUrl,\n };\n }, [entity.kind, entity.metadata.namespace, entity.metadata.name, entity.metadata?.annotations?.['backstage.io/source-location']]);\n\n // Initialize selected and applied rule types when defaultRuleTypes is available\n useEffect(() => {\n // Check if config is loaded\n const aiRulesConfig = configApi.getOptionalConfig('aiRules');\n const configLoaded = aiRulesConfig !== undefined;\n \n if (!initialized && allowedRuleTypes.length > 0 && configLoaded) {\n setSelectedRuleTypes(defaultRuleTypes);\n setAppliedRuleTypes(defaultRuleTypes);\n setInitialized(true);\n }\n }, [defaultRuleTypes, allowedRuleTypes, initialized, configApi]);\n\n // Stable fetch function\n const fetchAiRules = useCallback(async (ruleTypes: AIRuleType[]) => {\n if (!entityData.hasGitUrl || !entityData.gitUrl) {\n setLoading(false);\n return;\n }\n\n try {\n setLoading(true);\n setError(null);\n setHasSearched(true);\n \n const baseUrl = await discoveryApi.getBaseUrl('ai-rules');\n const url = new URL(`${baseUrl}/rules`);\n \n // Send the Git URL directly to the backend\n url.searchParams.append('gitUrl', entityData.gitUrl);\n if (ruleTypes.length > 0) {\n url.searchParams.append('ruleTypes', ruleTypes.join(','));\n }\n\n const response = await fetchApi.fetch(url.toString());\n if (!response.ok) {\n throw new Error(`Failed to fetch AI rules: ${response.statusText}`);\n }\n\n const data: AIRulesResponse = await response.json();\n setRules(data.rules);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';\n console.error('Error fetching AI rules:', errorMessage);\n setError(errorMessage);\n setRules([]);\n } finally {\n setLoading(false);\n }\n }, [entityData.hasGitUrl, entityData.gitUrl, discoveryApi, fetchApi]);\n\n // Manual apply filter function\n const applyFilters = useCallback(() => {\n setAppliedRuleTypes([...selectedRuleTypes]);\n if (selectedRuleTypes.length > 0) {\n fetchAiRules(selectedRuleTypes);\n } else {\n // If no rule types selected, clear rules\n setRules([]);\n setError(null);\n setHasSearched(true);\n }\n }, [selectedRuleTypes, fetchAiRules]);\n\n // Reset filters to allowed rule types and apply immediately\n const resetFilters = useCallback(() => {\n setSelectedRuleTypes(allowedRuleTypes);\n setAppliedRuleTypes([...allowedRuleTypes]);\n if (allowedRuleTypes.length > 0) {\n fetchAiRules(allowedRuleTypes);\n }\n }, [allowedRuleTypes, fetchAiRules]);\n\n // Fetch rules when applied rule types change (triggered by applyFilters)\n useEffect(() => {\n if (appliedRuleTypes.length > 0) {\n fetchAiRules(appliedRuleTypes);\n }\n }, [fetchAiRules, appliedRuleTypes]);\n\n const rulesByType = useMemo(() => {\n return rules.reduce((acc, rule) => {\n if (!acc[rule.type]) {\n acc[rule.type] = [];\n }\n acc[rule.type].push(rule);\n return acc;\n }, {} as Record<AIRuleType, AIRule[]>);\n }, [rules]);\n\n return {\n rules,\n rulesByType,\n loading,\n error,\n hasGitUrl: entityData.hasGitUrl,\n componentName: entityData.name,\n allowedRuleTypes,\n defaultRuleTypes,\n selectedRuleTypes,\n setSelectedRuleTypes,\n appliedRuleTypes,\n applyFilters,\n resetFilters,\n totalRules: rules.length,\n hasSearched,\n hasUnappliedChanges: JSON.stringify(selectedRuleTypes.sort()) !== JSON.stringify(appliedRuleTypes.sort()),\n };\n};"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -15,7 +15,8 @@ declare const AIRulesComponent: ({ title }?: AIRulesComponentProps) => react_jsx
|
|
|
15
15
|
declare enum AIRuleType {
|
|
16
16
|
CURSOR = "cursor",
|
|
17
17
|
COPILOT = "copilot",
|
|
18
|
-
CLINE = "cline"
|
|
18
|
+
CLINE = "cline",
|
|
19
|
+
CLAUDE_CODE = "claude-code"
|
|
19
20
|
}
|
|
20
21
|
interface CursorRule {
|
|
21
22
|
type: AIRuleType.CURSOR;
|
|
@@ -51,7 +52,16 @@ interface ClineRule {
|
|
|
51
52
|
content: string;
|
|
52
53
|
}>;
|
|
53
54
|
}
|
|
54
|
-
|
|
55
|
+
interface ClaudeCodeRule {
|
|
56
|
+
type: AIRuleType.CLAUDE_CODE;
|
|
57
|
+
id: string;
|
|
58
|
+
filePath: string;
|
|
59
|
+
fileName: string;
|
|
60
|
+
gitUrl?: string;
|
|
61
|
+
content: string;
|
|
62
|
+
title?: string;
|
|
63
|
+
}
|
|
64
|
+
type AIRule = CursorRule | CopilotRule | ClineRule | ClaudeCodeRule;
|
|
55
65
|
interface AIRulesResponse {
|
|
56
66
|
rules: AIRule[];
|
|
57
67
|
totalCount: number;
|
|
@@ -61,4 +71,4 @@ interface AIRulesConfig {
|
|
|
61
71
|
allowedRuleTypes?: AIRuleType[];
|
|
62
72
|
}
|
|
63
73
|
|
|
64
|
-
export { type AIRule, AIRuleType, AIRulesComponent, type AIRulesComponentProps, type AIRulesConfig, type AIRulesResponse, type ClineRule, type CopilotRule, type CursorRule, aiRulesPlugin, isAIRulesAvailable };
|
|
74
|
+
export { type AIRule, AIRuleType, AIRulesComponent, type AIRulesComponentProps, type AIRulesConfig, type AIRulesResponse, type ClaudeCodeRule, type ClineRule, type CopilotRule, type CursorRule, aiRulesPlugin, isAIRulesAvailable };
|
package/dist/types.esm.js
CHANGED
package/dist/types.esm.js.map
CHANGED
|
@@ -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}\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 type AIRule = CursorRule | CopilotRule | ClineRule;\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;
|
|
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;;;;"}
|
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.
|
|
4
|
+
"version": "0.2.0",
|
|
5
5
|
"main": "dist/index.esm.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"license": "Apache-2.0",
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
"postpack": "backstage-cli package postpack"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@backstage/catalog-model": "^1.7.
|
|
40
|
-
"@backstage/core-components": "^0.17.
|
|
41
|
-
"@backstage/core-plugin-api": "^1.10.
|
|
42
|
-
"@backstage/plugin-catalog-react": "^1.19.
|
|
43
|
-
"@backstage/theme": "^0.6.
|
|
39
|
+
"@backstage/catalog-model": "^1.7.5",
|
|
40
|
+
"@backstage/core-components": "^0.17.4",
|
|
41
|
+
"@backstage/core-plugin-api": "^1.10.9",
|
|
42
|
+
"@backstage/plugin-catalog-react": "^1.19.1",
|
|
43
|
+
"@backstage/theme": "^0.6.7",
|
|
44
44
|
"@material-ui/core": "^4.12.4",
|
|
45
45
|
"@material-ui/icons": "^4.11.3",
|
|
46
46
|
"@material-ui/lab": "4.0.0-alpha.61"
|
|
@@ -49,10 +49,10 @@
|
|
|
49
49
|
"react": "^16.13.1 || ^17.0.0 || ^18.0.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@backstage/cli": "^0.33.
|
|
53
|
-
"@backstage/core-app-api": "^1.
|
|
54
|
-
"@backstage/dev-utils": "^1.1.
|
|
55
|
-
"@backstage/test-utils": "^1.7.
|
|
52
|
+
"@backstage/cli": "^0.33.1",
|
|
53
|
+
"@backstage/core-app-api": "^1.18.0",
|
|
54
|
+
"@backstage/dev-utils": "^1.1.12",
|
|
55
|
+
"@backstage/test-utils": "^1.7.10",
|
|
56
56
|
"@testing-library/jest-dom": "^6.0.0",
|
|
57
57
|
"@testing-library/react": "^14.0.0",
|
|
58
58
|
"@testing-library/user-event": "^14.0.0",
|