@stackguide/mcp-server 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.
- package/LICENSE +674 -0
- package/README.md +453 -0
- package/data/knowledge/python-django/architecture/architecture-patterns.md +201 -0
- package/data/knowledge/python-django/common-issues/common-issues.md +181 -0
- package/data/knowledge/python-django/patterns/drf-patterns.md +133 -0
- package/data/knowledge/react-node/architecture/node-architecture.md +257 -0
- package/data/knowledge/react-node/common-issues/common-issues.md +262 -0
- package/data/knowledge/react-node/patterns/react-patterns.md +244 -0
- package/data/rules/python-django/best-practices/django-best-practices.md +120 -0
- package/data/rules/python-django/coding-standards/django-standards.md +104 -0
- package/data/rules/python-django/security/security-guidelines.md +146 -0
- package/data/rules/react-node/best-practices/react-best-practices.md +195 -0
- package/data/rules/react-node/coding-standards/node-standards.md +192 -0
- package/data/rules/react-node/coding-standards/react-standards.md +155 -0
- package/data/rules/react-node/security/security-guidelines.md +228 -0
- package/dist/config/persistence.d.ts +15 -0
- package/dist/config/persistence.d.ts.map +1 -0
- package/dist/config/persistence.js +171 -0
- package/dist/config/persistence.js.map +1 -0
- package/dist/config/types.d.ts +47 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +116 -0
- package/dist/config/types.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1799 -0
- package/dist/index.js.map +1 -0
- package/dist/resources/knowledgeProvider.d.ts +10 -0
- package/dist/resources/knowledgeProvider.d.ts.map +1 -0
- package/dist/resources/knowledgeProvider.js +130 -0
- package/dist/resources/knowledgeProvider.js.map +1 -0
- package/dist/resources/rulesProvider.d.ts +10 -0
- package/dist/resources/rulesProvider.d.ts.map +1 -0
- package/dist/resources/rulesProvider.js +135 -0
- package/dist/resources/rulesProvider.js.map +1 -0
- package/dist/services/cursorDirectory.d.ts +55 -0
- package/dist/services/cursorDirectory.d.ts.map +1 -0
- package/dist/services/cursorDirectory.js +367 -0
- package/dist/services/cursorDirectory.js.map +1 -0
- package/dist/services/ruleManager.d.ts +18 -0
- package/dist/services/ruleManager.d.ts.map +1 -0
- package/dist/services/ruleManager.js +382 -0
- package/dist/services/ruleManager.js.map +1 -0
- package/dist/services/webDocumentation.d.ts +41 -0
- package/dist/services/webDocumentation.d.ts.map +1 -0
- package/dist/services/webDocumentation.js +237 -0
- package/dist/services/webDocumentation.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# React Coding Standards
|
|
2
|
+
|
|
3
|
+
Follow these coding standards when developing React applications.
|
|
4
|
+
|
|
5
|
+
## Project Structure
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
src/
|
|
9
|
+
├── components/ # Reusable UI components
|
|
10
|
+
│ ├── common/ # Generic components (Button, Input)
|
|
11
|
+
│ └── features/ # Feature-specific components
|
|
12
|
+
├── hooks/ # Custom React hooks
|
|
13
|
+
├── pages/ # Page components (routes)
|
|
14
|
+
├── services/ # API and external services
|
|
15
|
+
├── store/ # State management
|
|
16
|
+
├── types/ # TypeScript types/interfaces
|
|
17
|
+
├── utils/ # Utility functions
|
|
18
|
+
├── styles/ # Global styles
|
|
19
|
+
└── App.tsx
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Naming Conventions
|
|
23
|
+
|
|
24
|
+
- **Components**: PascalCase (e.g., `UserProfile.tsx`)
|
|
25
|
+
- **Hooks**: camelCase with "use" prefix (e.g., `useAuth.ts`)
|
|
26
|
+
- **Utilities**: camelCase (e.g., `formatDate.ts`)
|
|
27
|
+
- **Types**: PascalCase with descriptive suffix (e.g., `UserDTO`, `AuthState`)
|
|
28
|
+
- **Constants**: SCREAMING_SNAKE_CASE (e.g., `API_BASE_URL`)
|
|
29
|
+
|
|
30
|
+
## Component Patterns
|
|
31
|
+
|
|
32
|
+
### Functional Components with TypeScript
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
import { FC, useState, useCallback } from 'react';
|
|
36
|
+
|
|
37
|
+
interface UserCardProps {
|
|
38
|
+
user: User;
|
|
39
|
+
onSelect?: (userId: string) => void;
|
|
40
|
+
isSelected?: boolean;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const UserCard: FC<UserCardProps> = ({
|
|
44
|
+
user,
|
|
45
|
+
onSelect,
|
|
46
|
+
isSelected = false
|
|
47
|
+
}) => {
|
|
48
|
+
const handleClick = useCallback(() => {
|
|
49
|
+
onSelect?.(user.id);
|
|
50
|
+
}, [user.id, onSelect]);
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<div
|
|
54
|
+
className={`user-card ${isSelected ? 'selected' : ''}`}
|
|
55
|
+
onClick={handleClick}
|
|
56
|
+
>
|
|
57
|
+
<img src={user.avatar} alt={user.name} />
|
|
58
|
+
<h3>{user.name}</h3>
|
|
59
|
+
<p>{user.email}</p>
|
|
60
|
+
</div>
|
|
61
|
+
);
|
|
62
|
+
};
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Component Organization
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
// 1. Imports
|
|
69
|
+
import { FC, useState, useEffect } from 'react';
|
|
70
|
+
import { useQuery } from '@tanstack/react-query';
|
|
71
|
+
|
|
72
|
+
// 2. Types
|
|
73
|
+
interface Props {
|
|
74
|
+
id: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// 3. Constants
|
|
78
|
+
const REFRESH_INTERVAL = 5000;
|
|
79
|
+
|
|
80
|
+
// 4. Component
|
|
81
|
+
export const DataDisplay: FC<Props> = ({ id }) => {
|
|
82
|
+
// 4a. Hooks
|
|
83
|
+
const [isExpanded, setIsExpanded] = useState(false);
|
|
84
|
+
const { data, isLoading } = useQuery(['data', id], fetchData);
|
|
85
|
+
|
|
86
|
+
// 4b. Effects
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
// Effect logic
|
|
89
|
+
}, [id]);
|
|
90
|
+
|
|
91
|
+
// 4c. Handlers
|
|
92
|
+
const handleToggle = () => setIsExpanded(!isExpanded);
|
|
93
|
+
|
|
94
|
+
// 4d. Render helpers
|
|
95
|
+
const renderContent = () => {
|
|
96
|
+
if (isLoading) return <Spinner />;
|
|
97
|
+
return <DataContent data={data} />;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
// 4e. Return
|
|
101
|
+
return (
|
|
102
|
+
<div>
|
|
103
|
+
<button onClick={handleToggle}>Toggle</button>
|
|
104
|
+
{isExpanded && renderContent()}
|
|
105
|
+
</div>
|
|
106
|
+
);
|
|
107
|
+
};
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Import Order
|
|
111
|
+
|
|
112
|
+
1. React and React-related
|
|
113
|
+
2. Third-party libraries
|
|
114
|
+
3. Internal modules (absolute imports)
|
|
115
|
+
4. Relative imports
|
|
116
|
+
5. Styles
|
|
117
|
+
|
|
118
|
+
```tsx
|
|
119
|
+
import { useState, useEffect } from 'react';
|
|
120
|
+
import { useQuery } from '@tanstack/react-query';
|
|
121
|
+
import { motion } from 'framer-motion';
|
|
122
|
+
|
|
123
|
+
import { useAuth } from '@/hooks/useAuth';
|
|
124
|
+
import { apiClient } from '@/services/api';
|
|
125
|
+
|
|
126
|
+
import { UserCard } from './UserCard';
|
|
127
|
+
import { formatDate } from './utils';
|
|
128
|
+
|
|
129
|
+
import styles from './Dashboard.module.css';
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## TypeScript Best Practices
|
|
133
|
+
|
|
134
|
+
```tsx
|
|
135
|
+
// Use interfaces for props and public APIs
|
|
136
|
+
interface ButtonProps {
|
|
137
|
+
variant: 'primary' | 'secondary';
|
|
138
|
+
size?: 'sm' | 'md' | 'lg';
|
|
139
|
+
children: React.ReactNode;
|
|
140
|
+
onClick?: () => void;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Use type for unions and computed types
|
|
144
|
+
type ButtonSize = ButtonProps['size'];
|
|
145
|
+
type Status = 'idle' | 'loading' | 'success' | 'error';
|
|
146
|
+
|
|
147
|
+
// Avoid any - use unknown for truly unknown types
|
|
148
|
+
function parseResponse(data: unknown): User {
|
|
149
|
+
// Validate and type-guard
|
|
150
|
+
if (isUser(data)) {
|
|
151
|
+
return data;
|
|
152
|
+
}
|
|
153
|
+
throw new Error('Invalid user data');
|
|
154
|
+
}
|
|
155
|
+
```
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# React/Node Security Guidelines
|
|
2
|
+
|
|
3
|
+
Critical security practices for full-stack React and Node.js applications.
|
|
4
|
+
|
|
5
|
+
## Frontend Security
|
|
6
|
+
|
|
7
|
+
### XSS Prevention
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
// React auto-escapes by default
|
|
11
|
+
<div>{userInput}</div> // Safe
|
|
12
|
+
|
|
13
|
+
// DANGER: dangerouslySetInnerHTML
|
|
14
|
+
<div dangerouslySetInnerHTML={{ __html: userContent }} /> // Only with sanitization
|
|
15
|
+
|
|
16
|
+
// Sanitize if HTML is needed
|
|
17
|
+
import DOMPurify from 'dompurify';
|
|
18
|
+
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(userContent) }} />
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Secure Storage
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
// NEVER store sensitive data in localStorage
|
|
25
|
+
localStorage.setItem('token', jwt); // ❌ Vulnerable to XSS
|
|
26
|
+
|
|
27
|
+
// Use httpOnly cookies instead (set from server)
|
|
28
|
+
// Or use secure in-memory storage
|
|
29
|
+
class SecureStorage {
|
|
30
|
+
private token: string | null = null;
|
|
31
|
+
|
|
32
|
+
setToken(token: string) {
|
|
33
|
+
this.token = token;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
getToken() {
|
|
37
|
+
return this.token;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
clearToken() {
|
|
41
|
+
this.token = null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### URL Validation
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
// Validate URLs before navigation
|
|
50
|
+
function isSafeUrl(url: string): boolean {
|
|
51
|
+
try {
|
|
52
|
+
const parsed = new URL(url, window.location.origin);
|
|
53
|
+
return parsed.origin === window.location.origin;
|
|
54
|
+
} catch {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Prevent open redirects
|
|
60
|
+
const redirect = searchParams.get('redirect');
|
|
61
|
+
if (redirect && isSafeUrl(redirect)) {
|
|
62
|
+
navigate(redirect);
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Backend Security
|
|
67
|
+
|
|
68
|
+
### Input Validation
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
import { z } from 'zod';
|
|
72
|
+
|
|
73
|
+
const createUserSchema = z.object({
|
|
74
|
+
email: z.string().email().max(255),
|
|
75
|
+
password: z.string().min(8).max(128),
|
|
76
|
+
name: z.string().min(1).max(100).regex(/^[a-zA-Z\s]+$/)
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Middleware
|
|
80
|
+
export const validateBody = (schema: z.ZodSchema) => {
|
|
81
|
+
return (req: Request, res: Response, next: NextFunction) => {
|
|
82
|
+
const result = schema.safeParse(req.body);
|
|
83
|
+
if (!result.success) {
|
|
84
|
+
return res.status(400).json({
|
|
85
|
+
error: 'Validation failed',
|
|
86
|
+
details: result.error.format()
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
req.body = result.data; // Use validated data
|
|
90
|
+
next();
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### SQL Injection Prevention
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
// NEVER interpolate user input
|
|
99
|
+
const query = `SELECT * FROM users WHERE id = ${userId}`; // ❌
|
|
100
|
+
|
|
101
|
+
// Use parameterized queries
|
|
102
|
+
const user = await db.query('SELECT * FROM users WHERE id = $1', [userId]); // ✅
|
|
103
|
+
|
|
104
|
+
// With Prisma (safe by default)
|
|
105
|
+
const user = await prisma.user.findUnique({ where: { id: userId } });
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Authentication
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
// Password hashing
|
|
112
|
+
import bcrypt from 'bcrypt';
|
|
113
|
+
|
|
114
|
+
const SALT_ROUNDS = 12;
|
|
115
|
+
|
|
116
|
+
async function hashPassword(password: string): Promise<string> {
|
|
117
|
+
return bcrypt.hash(password, SALT_ROUNDS);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async function verifyPassword(password: string, hash: string): Promise<boolean> {
|
|
121
|
+
return bcrypt.compare(password, hash);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// JWT with rotation
|
|
125
|
+
import jwt from 'jsonwebtoken';
|
|
126
|
+
|
|
127
|
+
function generateTokens(userId: string) {
|
|
128
|
+
const accessToken = jwt.sign(
|
|
129
|
+
{ userId, type: 'access' },
|
|
130
|
+
config.JWT_SECRET,
|
|
131
|
+
{ expiresIn: '15m' } // Short-lived
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
const refreshToken = jwt.sign(
|
|
135
|
+
{ userId, type: 'refresh' },
|
|
136
|
+
config.JWT_REFRESH_SECRET,
|
|
137
|
+
{ expiresIn: '7d' }
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
return { accessToken, refreshToken };
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Rate Limiting
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
import rateLimit from 'express-rate-limit';
|
|
148
|
+
|
|
149
|
+
// General API limiter
|
|
150
|
+
const apiLimiter = rateLimit({
|
|
151
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
152
|
+
max: 100,
|
|
153
|
+
message: 'Too many requests, please try again later'
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// Strict limiter for auth endpoints
|
|
157
|
+
const authLimiter = rateLimit({
|
|
158
|
+
windowMs: 60 * 60 * 1000, // 1 hour
|
|
159
|
+
max: 5,
|
|
160
|
+
message: 'Too many login attempts'
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
app.use('/api/', apiLimiter);
|
|
164
|
+
app.use('/api/auth/login', authLimiter);
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Security Headers
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
import helmet from 'helmet';
|
|
171
|
+
|
|
172
|
+
app.use(helmet({
|
|
173
|
+
contentSecurityPolicy: {
|
|
174
|
+
directives: {
|
|
175
|
+
defaultSrc: ["'self'"],
|
|
176
|
+
scriptSrc: ["'self'"],
|
|
177
|
+
styleSrc: ["'self'", "'unsafe-inline'"],
|
|
178
|
+
imgSrc: ["'self'", "data:", "https:"],
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
hsts: {
|
|
182
|
+
maxAge: 31536000,
|
|
183
|
+
includeSubDomains: true
|
|
184
|
+
}
|
|
185
|
+
}));
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### CORS Configuration
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
import cors from 'cors';
|
|
192
|
+
|
|
193
|
+
const corsOptions = {
|
|
194
|
+
origin: (origin: string | undefined, callback: Function) => {
|
|
195
|
+
const allowedOrigins = ['https://yourdomain.com'];
|
|
196
|
+
if (!origin || allowedOrigins.includes(origin)) {
|
|
197
|
+
callback(null, true);
|
|
198
|
+
} else {
|
|
199
|
+
callback(new Error('Not allowed by CORS'));
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
credentials: true,
|
|
203
|
+
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
|
|
204
|
+
allowedHeaders: ['Content-Type', 'Authorization']
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
app.use(cors(corsOptions));
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Environment Secrets
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
// Never commit secrets
|
|
214
|
+
// .env.example (committed)
|
|
215
|
+
DATABASE_URL=
|
|
216
|
+
JWT_SECRET=
|
|
217
|
+
API_KEY=
|
|
218
|
+
|
|
219
|
+
// .env (gitignored)
|
|
220
|
+
DATABASE_URL=postgresql://...
|
|
221
|
+
JWT_SECRET=your-32-char-secret-here
|
|
222
|
+
API_KEY=sk-...
|
|
223
|
+
|
|
224
|
+
// Validate at startup
|
|
225
|
+
if (!process.env.JWT_SECRET || process.env.JWT_SECRET.length < 32) {
|
|
226
|
+
throw new Error('JWT_SECRET must be at least 32 characters');
|
|
227
|
+
}
|
|
228
|
+
```
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { UserConfiguration, ProjectType, Rule } from './types.js';
|
|
2
|
+
export declare function createConfiguration(name: string, projectType: ProjectType, selectedRules?: string[], selectedKnowledge?: string[]): UserConfiguration;
|
|
3
|
+
export declare function getAllConfigurations(): UserConfiguration[];
|
|
4
|
+
export declare function getConfigurationById(id: string): UserConfiguration | null;
|
|
5
|
+
export declare function getActiveConfiguration(): UserConfiguration | null;
|
|
6
|
+
export declare function setActiveConfiguration(id: string): UserConfiguration | null;
|
|
7
|
+
export declare function updateConfiguration(id: string, updates: Partial<Omit<UserConfiguration, 'id' | 'createdAt'>>): UserConfiguration | null;
|
|
8
|
+
export declare function deleteConfiguration(id: string): boolean;
|
|
9
|
+
export declare function addCustomRule(configId: string, rule: Omit<Rule, 'id'>): Rule | null;
|
|
10
|
+
export declare function updateSelectedRules(configId: string, ruleIds: string[]): boolean;
|
|
11
|
+
export declare function updateSelectedKnowledge(configId: string, knowledgeIds: string[]): boolean;
|
|
12
|
+
export declare function exportConfiguration(id: string): string | null;
|
|
13
|
+
export declare function importConfiguration(jsonString: string): UserConfiguration | null;
|
|
14
|
+
export declare function getConfigPath(): string;
|
|
15
|
+
//# sourceMappingURL=persistence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../../src/config/persistence.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAgDlE,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,WAAW,EACxB,aAAa,GAAE,MAAM,EAAO,EAC5B,iBAAiB,GAAE,MAAM,EAAO,GAC/B,iBAAiB,CAmBnB;AAGD,wBAAgB,oBAAoB,IAAI,iBAAiB,EAAE,CAG1D;AAGD,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAGzE;AAGD,wBAAgB,sBAAsB,IAAI,iBAAiB,GAAG,IAAI,CAIjE;AAGD,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAW3E;AAGD,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,iBAAiB,EAAE,IAAI,GAAG,WAAW,CAAC,CAAC,GAC5D,iBAAiB,GAAG,IAAI,CAc1B;AAGD,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAcvD;AAGD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI,CAgBnF;AAGD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAGhF;AAGD,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,OAAO,CAGzF;AAGD,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI7D;AAGD,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAoBhF;AAQD,wBAAgB,aAAa,IAAI,MAAM,CAEtC"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
|
|
2
|
+
import { homedir } from 'os';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
// Configuration directory
|
|
5
|
+
const CONFIG_DIR = join(homedir(), '.stackguide');
|
|
6
|
+
const CONFIG_FILE = join(CONFIG_DIR, 'config.json');
|
|
7
|
+
const CONFIGURATIONS_FILE = join(CONFIG_DIR, 'configurations.json');
|
|
8
|
+
// Ensure configuration directory exists
|
|
9
|
+
function ensureConfigDir() {
|
|
10
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
11
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
// Get storage
|
|
15
|
+
function getStorage() {
|
|
16
|
+
ensureConfigDir();
|
|
17
|
+
if (!existsSync(CONFIGURATIONS_FILE)) {
|
|
18
|
+
const defaultStorage = {
|
|
19
|
+
activeConfigurationId: null,
|
|
20
|
+
configurations: []
|
|
21
|
+
};
|
|
22
|
+
writeFileSync(CONFIGURATIONS_FILE, JSON.stringify(defaultStorage, null, 2));
|
|
23
|
+
return defaultStorage;
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
const data = readFileSync(CONFIGURATIONS_FILE, 'utf-8');
|
|
27
|
+
return JSON.parse(data);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return { activeConfigurationId: null, configurations: [] };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// Save storage
|
|
34
|
+
function saveStorage(storage) {
|
|
35
|
+
ensureConfigDir();
|
|
36
|
+
writeFileSync(CONFIGURATIONS_FILE, JSON.stringify(storage, null, 2));
|
|
37
|
+
}
|
|
38
|
+
// Create new configuration
|
|
39
|
+
export function createConfiguration(name, projectType, selectedRules = [], selectedKnowledge = []) {
|
|
40
|
+
const storage = getStorage();
|
|
41
|
+
const newConfig = {
|
|
42
|
+
id: generateId(),
|
|
43
|
+
name,
|
|
44
|
+
projectType,
|
|
45
|
+
selectedRules,
|
|
46
|
+
selectedKnowledge,
|
|
47
|
+
customRules: [],
|
|
48
|
+
createdAt: new Date().toISOString(),
|
|
49
|
+
updatedAt: new Date().toISOString()
|
|
50
|
+
};
|
|
51
|
+
storage.configurations.push(newConfig);
|
|
52
|
+
storage.activeConfigurationId = newConfig.id;
|
|
53
|
+
saveStorage(storage);
|
|
54
|
+
return newConfig;
|
|
55
|
+
}
|
|
56
|
+
// Get all configurations
|
|
57
|
+
export function getAllConfigurations() {
|
|
58
|
+
const storage = getStorage();
|
|
59
|
+
return storage.configurations;
|
|
60
|
+
}
|
|
61
|
+
// Get configuration by ID
|
|
62
|
+
export function getConfigurationById(id) {
|
|
63
|
+
const storage = getStorage();
|
|
64
|
+
return storage.configurations.find(c => c.id === id) || null;
|
|
65
|
+
}
|
|
66
|
+
// Get active configuration
|
|
67
|
+
export function getActiveConfiguration() {
|
|
68
|
+
const storage = getStorage();
|
|
69
|
+
if (!storage.activeConfigurationId)
|
|
70
|
+
return null;
|
|
71
|
+
return storage.configurations.find(c => c.id === storage.activeConfigurationId) || null;
|
|
72
|
+
}
|
|
73
|
+
// Set active configuration
|
|
74
|
+
export function setActiveConfiguration(id) {
|
|
75
|
+
const storage = getStorage();
|
|
76
|
+
const config = storage.configurations.find(c => c.id === id);
|
|
77
|
+
if (config) {
|
|
78
|
+
storage.activeConfigurationId = id;
|
|
79
|
+
saveStorage(storage);
|
|
80
|
+
return config;
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
// Update configuration
|
|
85
|
+
export function updateConfiguration(id, updates) {
|
|
86
|
+
const storage = getStorage();
|
|
87
|
+
const index = storage.configurations.findIndex(c => c.id === id);
|
|
88
|
+
if (index === -1)
|
|
89
|
+
return null;
|
|
90
|
+
storage.configurations[index] = {
|
|
91
|
+
...storage.configurations[index],
|
|
92
|
+
...updates,
|
|
93
|
+
updatedAt: new Date().toISOString()
|
|
94
|
+
};
|
|
95
|
+
saveStorage(storage);
|
|
96
|
+
return storage.configurations[index];
|
|
97
|
+
}
|
|
98
|
+
// Delete configuration
|
|
99
|
+
export function deleteConfiguration(id) {
|
|
100
|
+
const storage = getStorage();
|
|
101
|
+
const index = storage.configurations.findIndex(c => c.id === id);
|
|
102
|
+
if (index === -1)
|
|
103
|
+
return false;
|
|
104
|
+
storage.configurations.splice(index, 1);
|
|
105
|
+
if (storage.activeConfigurationId === id) {
|
|
106
|
+
storage.activeConfigurationId = storage.configurations[0]?.id || null;
|
|
107
|
+
}
|
|
108
|
+
saveStorage(storage);
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
// Add custom rule
|
|
112
|
+
export function addCustomRule(configId, rule) {
|
|
113
|
+
const storage = getStorage();
|
|
114
|
+
const config = storage.configurations.find(c => c.id === configId);
|
|
115
|
+
if (!config)
|
|
116
|
+
return null;
|
|
117
|
+
const newRule = {
|
|
118
|
+
...rule,
|
|
119
|
+
id: generateId()
|
|
120
|
+
};
|
|
121
|
+
config.customRules.push(newRule);
|
|
122
|
+
config.updatedAt = new Date().toISOString();
|
|
123
|
+
saveStorage(storage);
|
|
124
|
+
return newRule;
|
|
125
|
+
}
|
|
126
|
+
// Update selected rules
|
|
127
|
+
export function updateSelectedRules(configId, ruleIds) {
|
|
128
|
+
const config = updateConfiguration(configId, { selectedRules: ruleIds });
|
|
129
|
+
return config !== null;
|
|
130
|
+
}
|
|
131
|
+
// Update selected knowledge
|
|
132
|
+
export function updateSelectedKnowledge(configId, knowledgeIds) {
|
|
133
|
+
const config = updateConfiguration(configId, { selectedKnowledge: knowledgeIds });
|
|
134
|
+
return config !== null;
|
|
135
|
+
}
|
|
136
|
+
// Export configuration
|
|
137
|
+
export function exportConfiguration(id) {
|
|
138
|
+
const config = getConfigurationById(id);
|
|
139
|
+
if (!config)
|
|
140
|
+
return null;
|
|
141
|
+
return JSON.stringify(config, null, 2);
|
|
142
|
+
}
|
|
143
|
+
// Import configuration
|
|
144
|
+
export function importConfiguration(jsonString) {
|
|
145
|
+
try {
|
|
146
|
+
const imported = JSON.parse(jsonString);
|
|
147
|
+
const newConfig = {
|
|
148
|
+
...imported,
|
|
149
|
+
id: generateId(),
|
|
150
|
+
name: `${imported.name} (imported)`,
|
|
151
|
+
createdAt: new Date().toISOString(),
|
|
152
|
+
updatedAt: new Date().toISOString()
|
|
153
|
+
};
|
|
154
|
+
const storage = getStorage();
|
|
155
|
+
storage.configurations.push(newConfig);
|
|
156
|
+
saveStorage(storage);
|
|
157
|
+
return newConfig;
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// Generate unique ID
|
|
164
|
+
function generateId() {
|
|
165
|
+
return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
166
|
+
}
|
|
167
|
+
// Get configuration path
|
|
168
|
+
export function getConfigPath() {
|
|
169
|
+
return CONFIG_DIR;
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=persistence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persistence.js","sourceRoot":"","sources":["../../src/config/persistence.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export type ProjectType = 'python-django' | 'python-fastapi' | 'python-flask' | 'react-node' | 'react-typescript' | 'vue-node' | 'nextjs' | 'express' | 'nestjs' | 'laravel' | 'rails' | 'golang' | 'rust' | 'custom';
|
|
2
|
+
export interface ProjectInfo {
|
|
3
|
+
type: ProjectType;
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
languages: string[];
|
|
7
|
+
frameworks: string[];
|
|
8
|
+
detectionFiles: string[];
|
|
9
|
+
}
|
|
10
|
+
export interface Rule {
|
|
11
|
+
id: string;
|
|
12
|
+
name: string;
|
|
13
|
+
category: RuleCategory;
|
|
14
|
+
description: string;
|
|
15
|
+
content: string;
|
|
16
|
+
enabled: boolean;
|
|
17
|
+
priority: number;
|
|
18
|
+
}
|
|
19
|
+
export type RuleCategory = 'coding-standards' | 'best-practices' | 'security' | 'performance' | 'architecture' | 'testing' | 'documentation' | 'naming-conventions';
|
|
20
|
+
export interface KnowledgeFile {
|
|
21
|
+
id: string;
|
|
22
|
+
name: string;
|
|
23
|
+
path: string;
|
|
24
|
+
projectType: ProjectType;
|
|
25
|
+
category: KnowledgeCategory;
|
|
26
|
+
description: string;
|
|
27
|
+
content: string;
|
|
28
|
+
}
|
|
29
|
+
export type KnowledgeCategory = 'patterns' | 'common-issues' | 'architecture' | 'snippets' | 'workflows' | 'troubleshooting';
|
|
30
|
+
export interface UserConfiguration {
|
|
31
|
+
id: string;
|
|
32
|
+
name: string;
|
|
33
|
+
projectType: ProjectType;
|
|
34
|
+
selectedRules: string[];
|
|
35
|
+
selectedKnowledge: string[];
|
|
36
|
+
customRules: Rule[];
|
|
37
|
+
createdAt: string;
|
|
38
|
+
updatedAt: string;
|
|
39
|
+
}
|
|
40
|
+
export interface ServerState {
|
|
41
|
+
activeProjectType: ProjectType | null;
|
|
42
|
+
activeConfiguration: UserConfiguration | null;
|
|
43
|
+
loadedRules: Rule[];
|
|
44
|
+
loadedKnowledge: KnowledgeFile[];
|
|
45
|
+
}
|
|
46
|
+
export declare const SUPPORTED_PROJECTS: Record<ProjectType, ProjectInfo>;
|
|
47
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"AACA,MAAM,MAAM,WAAW,GACnB,eAAe,GACf,gBAAgB,GAChB,cAAc,GACd,YAAY,GACZ,kBAAkB,GAClB,UAAU,GACV,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,SAAS,GACT,OAAO,GACP,QAAQ,GACR,MAAM,GACN,QAAQ,CAAC;AAGb,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAGD,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,YAAY,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAGD,MAAM,MAAM,YAAY,GACpB,kBAAkB,GAClB,gBAAgB,GAChB,UAAU,GACV,aAAa,GACb,cAAc,GACd,SAAS,GACT,eAAe,GACf,oBAAoB,CAAC;AAGzB,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,WAAW,CAAC;IACzB,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB;AAGD,MAAM,MAAM,iBAAiB,GACzB,UAAU,GACV,eAAe,GACf,cAAc,GACd,UAAU,GACV,WAAW,GACX,iBAAiB,CAAC;AAGtB,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,WAAW,CAAC;IACzB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,WAAW,EAAE,IAAI,EAAE,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAGD,MAAM,WAAW,WAAW;IAC1B,iBAAiB,EAAE,WAAW,GAAG,IAAI,CAAC;IACtC,mBAAmB,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC9C,WAAW,EAAE,IAAI,EAAE,CAAC;IACpB,eAAe,EAAE,aAAa,EAAE,CAAC;CAClC;AAGD,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,WAAW,EAAE,WAAW,CAiH/D,CAAC"}
|