midas-mcp 2.6.0 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai.d.ts.map +1 -1
- package/dist/ai.js +13 -4
- package/dist/ai.js.map +1 -1
- package/dist/analyzer.d.ts.map +1 -1
- package/dist/analyzer.js +46 -13
- package/dist/analyzer.js.map +1 -1
- package/dist/context.d.ts +12 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +17 -2
- package/dist/context.js.map +1 -1
- package/dist/search.d.ts +51 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +258 -0
- package/dist/search.js.map +1 -0
- package/dist/techstack.d.ts +28 -0
- package/dist/techstack.d.ts.map +1 -0
- package/dist/techstack.js +215 -0
- package/dist/techstack.js.map +1 -0
- package/dist/tests/context.test.d.ts +2 -0
- package/dist/tests/context.test.d.ts.map +1 -0
- package/dist/tests/context.test.js +213 -0
- package/dist/tests/context.test.js.map +1 -0
- package/dist/tests/search.test.d.ts +2 -0
- package/dist/tests/search.test.d.ts.map +1 -0
- package/dist/tests/search.test.js +228 -0
- package/dist/tests/search.test.js.map +1 -0
- package/dist/tests/techstack.test.d.ts +2 -0
- package/dist/tests/techstack.test.d.ts.map +1 -0
- package/dist/tests/techstack.test.js +187 -0
- package/dist/tests/techstack.test.js.map +1 -0
- package/dist/tools/phase.d.ts +3 -0
- package/dist/tools/phase.d.ts.map +1 -1
- package/dist/tools/phase.js +19 -7
- package/dist/tools/phase.js.map +1 -1
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +20 -1
- package/dist/tui.js.map +1 -1
- package/package.json +1 -1
package/dist/search.js
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Semantic Search for Midas
|
|
3
|
+
*
|
|
4
|
+
* Simple keyword-based search with TF-IDF-like scoring.
|
|
5
|
+
* Can be upgraded to use embeddings when available.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync } from 'fs';
|
|
8
|
+
import { join } from 'path';
|
|
9
|
+
import { sanitizePath } from './security.js';
|
|
10
|
+
import { getJournalEntries } from './tools/journal.js';
|
|
11
|
+
const MIDAS_DIR = '.midas';
|
|
12
|
+
const INDEX_FILE = 'search-index.json';
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// KEYWORD EXTRACTION
|
|
15
|
+
// ============================================================================
|
|
16
|
+
const STOP_WORDS = new Set([
|
|
17
|
+
'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for', 'of',
|
|
18
|
+
'with', 'by', 'from', 'as', 'is', 'was', 'are', 'were', 'been', 'be',
|
|
19
|
+
'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'could', 'should',
|
|
20
|
+
'may', 'might', 'must', 'that', 'this', 'these', 'those', 'it', 'its',
|
|
21
|
+
'i', 'you', 'he', 'she', 'we', 'they', 'them', 'their', 'my', 'your',
|
|
22
|
+
'not', 'no', 'yes', 'if', 'then', 'else', 'when', 'while', 'so', 'than',
|
|
23
|
+
'just', 'only', 'also', 'very', 'too', 'more', 'most', 'some', 'any',
|
|
24
|
+
'all', 'each', 'every', 'both', 'few', 'many', 'much', 'other', 'such',
|
|
25
|
+
]);
|
|
26
|
+
function extractKeywords(text) {
|
|
27
|
+
// Tokenize and normalize
|
|
28
|
+
const words = text.toLowerCase()
|
|
29
|
+
.replace(/[^a-z0-9_\-\.]+/g, ' ')
|
|
30
|
+
.split(/\s+/)
|
|
31
|
+
.filter(w => w.length > 2 && !STOP_WORDS.has(w));
|
|
32
|
+
// Count frequencies
|
|
33
|
+
const freq = {};
|
|
34
|
+
for (const word of words) {
|
|
35
|
+
freq[word] = (freq[word] || 0) + 1;
|
|
36
|
+
}
|
|
37
|
+
// Return top keywords by frequency
|
|
38
|
+
return Object.entries(freq)
|
|
39
|
+
.sort((a, b) => b[1] - a[1])
|
|
40
|
+
.slice(0, 20)
|
|
41
|
+
.map(([word]) => word);
|
|
42
|
+
}
|
|
43
|
+
// ============================================================================
|
|
44
|
+
// INDEX MANAGEMENT
|
|
45
|
+
// ============================================================================
|
|
46
|
+
function getIndexPath(projectPath) {
|
|
47
|
+
return join(projectPath, MIDAS_DIR, INDEX_FILE);
|
|
48
|
+
}
|
|
49
|
+
function loadIndex(projectPath) {
|
|
50
|
+
const path = getIndexPath(projectPath);
|
|
51
|
+
if (existsSync(path)) {
|
|
52
|
+
try {
|
|
53
|
+
return JSON.parse(readFileSync(path, 'utf-8'));
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// Corrupted index
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return { chunks: [], keywords: {}, lastUpdated: 0 };
|
|
60
|
+
}
|
|
61
|
+
function saveIndex(projectPath, index) {
|
|
62
|
+
const dir = join(projectPath, MIDAS_DIR);
|
|
63
|
+
if (!existsSync(dir)) {
|
|
64
|
+
mkdirSync(dir, { recursive: true });
|
|
65
|
+
}
|
|
66
|
+
index.lastUpdated = Date.now();
|
|
67
|
+
writeFileSync(getIndexPath(projectPath), JSON.stringify(index, null, 2));
|
|
68
|
+
}
|
|
69
|
+
// ============================================================================
|
|
70
|
+
// INDEXING
|
|
71
|
+
// ============================================================================
|
|
72
|
+
/**
|
|
73
|
+
* Index journal entries for search
|
|
74
|
+
*/
|
|
75
|
+
export function indexJournalEntries(projectPath) {
|
|
76
|
+
const safePath = sanitizePath(projectPath);
|
|
77
|
+
const index = loadIndex(safePath);
|
|
78
|
+
const entries = getJournalEntries({ projectPath: safePath, limit: 100 });
|
|
79
|
+
// Remove old journal chunks
|
|
80
|
+
index.chunks = index.chunks.filter(c => c.type !== 'journal');
|
|
81
|
+
// Add new journal chunks
|
|
82
|
+
for (const entry of entries) {
|
|
83
|
+
const keywords = extractKeywords(entry.title + ' ' + entry.conversation);
|
|
84
|
+
index.chunks.push({
|
|
85
|
+
id: `journal-${entry.id}`,
|
|
86
|
+
type: 'journal',
|
|
87
|
+
source: entry.id,
|
|
88
|
+
content: entry.conversation.slice(0, 1000), // Limit content size
|
|
89
|
+
timestamp: new Date(entry.timestamp).getTime(),
|
|
90
|
+
keywords,
|
|
91
|
+
});
|
|
92
|
+
// Update keyword frequencies
|
|
93
|
+
for (const kw of keywords) {
|
|
94
|
+
index.keywords[kw] = (index.keywords[kw] || 0) + 1;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
saveIndex(safePath, index);
|
|
98
|
+
return entries.length;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Index code files for search
|
|
102
|
+
*/
|
|
103
|
+
export function indexCodeFiles(projectPath, maxFiles = 50) {
|
|
104
|
+
const safePath = sanitizePath(projectPath);
|
|
105
|
+
const index = loadIndex(safePath);
|
|
106
|
+
// Remove old code chunks
|
|
107
|
+
index.chunks = index.chunks.filter(c => c.type !== 'code');
|
|
108
|
+
const extensions = ['.ts', '.tsx', '.js', '.jsx', '.py', '.go', '.rs', '.swift', '.md'];
|
|
109
|
+
const ignore = ['node_modules', '.git', 'dist', 'build', '.next', '__pycache__', '.midas'];
|
|
110
|
+
let indexed = 0;
|
|
111
|
+
function scanDir(dir, depth = 0) {
|
|
112
|
+
if (depth > 3 || indexed >= maxFiles)
|
|
113
|
+
return;
|
|
114
|
+
try {
|
|
115
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
116
|
+
if (indexed >= maxFiles)
|
|
117
|
+
break;
|
|
118
|
+
if (entry.name.startsWith('.') || ignore.includes(entry.name))
|
|
119
|
+
continue;
|
|
120
|
+
const path = join(dir, entry.name);
|
|
121
|
+
if (entry.isDirectory()) {
|
|
122
|
+
scanDir(path, depth + 1);
|
|
123
|
+
}
|
|
124
|
+
else if (extensions.some(ext => entry.name.endsWith(ext))) {
|
|
125
|
+
try {
|
|
126
|
+
const content = readFileSync(path, 'utf-8').slice(0, 2000);
|
|
127
|
+
const keywords = extractKeywords(content);
|
|
128
|
+
const relativePath = path.replace(safePath + '/', '');
|
|
129
|
+
index.chunks.push({
|
|
130
|
+
id: `code-${relativePath}`,
|
|
131
|
+
type: 'code',
|
|
132
|
+
source: relativePath,
|
|
133
|
+
content: content.slice(0, 500),
|
|
134
|
+
timestamp: Date.now(),
|
|
135
|
+
keywords,
|
|
136
|
+
});
|
|
137
|
+
for (const kw of keywords) {
|
|
138
|
+
index.keywords[kw] = (index.keywords[kw] || 0) + 1;
|
|
139
|
+
}
|
|
140
|
+
indexed++;
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// Can't read file
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
// Can't read directory
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
scanDir(safePath);
|
|
153
|
+
saveIndex(safePath, index);
|
|
154
|
+
return indexed;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Add an error to the search index
|
|
158
|
+
*/
|
|
159
|
+
export function indexError(projectPath, error, file) {
|
|
160
|
+
const safePath = sanitizePath(projectPath);
|
|
161
|
+
const index = loadIndex(safePath);
|
|
162
|
+
const keywords = extractKeywords(error + ' ' + (file || ''));
|
|
163
|
+
index.chunks.push({
|
|
164
|
+
id: `error-${Date.now()}`,
|
|
165
|
+
type: 'error',
|
|
166
|
+
source: file || 'unknown',
|
|
167
|
+
content: error.slice(0, 500),
|
|
168
|
+
timestamp: Date.now(),
|
|
169
|
+
keywords,
|
|
170
|
+
});
|
|
171
|
+
for (const kw of keywords) {
|
|
172
|
+
index.keywords[kw] = (index.keywords[kw] || 0) + 1;
|
|
173
|
+
}
|
|
174
|
+
// Keep only recent errors (last 20)
|
|
175
|
+
const errorChunks = index.chunks.filter(c => c.type === 'error');
|
|
176
|
+
if (errorChunks.length > 20) {
|
|
177
|
+
const toRemove = errorChunks
|
|
178
|
+
.sort((a, b) => a.timestamp - b.timestamp)
|
|
179
|
+
.slice(0, errorChunks.length - 20)
|
|
180
|
+
.map(c => c.id);
|
|
181
|
+
index.chunks = index.chunks.filter(c => !toRemove.includes(c.id));
|
|
182
|
+
}
|
|
183
|
+
saveIndex(safePath, index);
|
|
184
|
+
}
|
|
185
|
+
// ============================================================================
|
|
186
|
+
// SEARCH
|
|
187
|
+
// ============================================================================
|
|
188
|
+
/**
|
|
189
|
+
* Search for relevant chunks
|
|
190
|
+
*/
|
|
191
|
+
export function search(projectPath, query, options = {}) {
|
|
192
|
+
const safePath = sanitizePath(projectPath);
|
|
193
|
+
const index = loadIndex(safePath);
|
|
194
|
+
const queryKeywords = extractKeywords(query);
|
|
195
|
+
if (queryKeywords.length === 0)
|
|
196
|
+
return [];
|
|
197
|
+
// Calculate TF-IDF-like scores
|
|
198
|
+
const totalDocs = index.chunks.length || 1;
|
|
199
|
+
const scored = [];
|
|
200
|
+
for (const chunk of index.chunks) {
|
|
201
|
+
// Filter by type
|
|
202
|
+
if (options.types && !options.types.includes(chunk.type))
|
|
203
|
+
continue;
|
|
204
|
+
// Calculate score
|
|
205
|
+
let score = 0;
|
|
206
|
+
for (const qk of queryKeywords) {
|
|
207
|
+
if (chunk.keywords.includes(qk)) {
|
|
208
|
+
// TF: keyword is present
|
|
209
|
+
const tf = 1;
|
|
210
|
+
// IDF: log(total docs / docs with this keyword)
|
|
211
|
+
const df = index.keywords[qk] || 1;
|
|
212
|
+
const idf = Math.log(totalDocs / df);
|
|
213
|
+
score += tf * idf;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (score > 0) {
|
|
217
|
+
scored.push({ ...chunk, score });
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
// Sort by score (descending) and recency
|
|
221
|
+
scored.sort((a, b) => {
|
|
222
|
+
const scoreDiff = (b.score || 0) - (a.score || 0);
|
|
223
|
+
if (Math.abs(scoreDiff) > 0.5)
|
|
224
|
+
return scoreDiff;
|
|
225
|
+
return b.timestamp - a.timestamp;
|
|
226
|
+
});
|
|
227
|
+
return scored.slice(0, options.limit || 10);
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Get search index stats
|
|
231
|
+
*/
|
|
232
|
+
export function getSearchStats(projectPath) {
|
|
233
|
+
const index = loadIndex(projectPath);
|
|
234
|
+
const byType = {};
|
|
235
|
+
for (const chunk of index.chunks) {
|
|
236
|
+
byType[chunk.type] = (byType[chunk.type] || 0) + 1;
|
|
237
|
+
}
|
|
238
|
+
return {
|
|
239
|
+
totalChunks: index.chunks.length,
|
|
240
|
+
byType,
|
|
241
|
+
totalKeywords: Object.keys(index.keywords).length,
|
|
242
|
+
lastUpdated: index.lastUpdated,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Rebuild the entire search index
|
|
247
|
+
*/
|
|
248
|
+
export function rebuildIndex(projectPath) {
|
|
249
|
+
const safePath = sanitizePath(projectPath);
|
|
250
|
+
// Clear existing index
|
|
251
|
+
const index = { chunks: [], keywords: {}, lastUpdated: Date.now() };
|
|
252
|
+
saveIndex(safePath, index);
|
|
253
|
+
// Re-index everything
|
|
254
|
+
const journal = indexJournalEntries(safePath);
|
|
255
|
+
const code = indexCodeFiles(safePath);
|
|
256
|
+
return { journal, code };
|
|
257
|
+
}
|
|
258
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tech Stack Detection and Project Rules Generation
|
|
3
|
+
*/
|
|
4
|
+
export interface TechStack {
|
|
5
|
+
language: 'typescript' | 'javascript' | 'python' | 'go' | 'rust' | 'swift' | 'unknown';
|
|
6
|
+
framework?: string;
|
|
7
|
+
runtime?: string;
|
|
8
|
+
hasTests: boolean;
|
|
9
|
+
hasDocs: boolean;
|
|
10
|
+
hasCI: boolean;
|
|
11
|
+
dependencies: string[];
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Detect tech stack from project files
|
|
15
|
+
*/
|
|
16
|
+
export declare function detectTechStack(projectPath: string): TechStack;
|
|
17
|
+
/**
|
|
18
|
+
* Generate project-specific .cursorrules based on tech stack
|
|
19
|
+
*/
|
|
20
|
+
export declare function generateCursorRules(projectPath: string, projectName: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* Write .cursorrules to project
|
|
23
|
+
*/
|
|
24
|
+
export declare function writeCursorRules(projectPath: string, projectName: string): {
|
|
25
|
+
success: boolean;
|
|
26
|
+
path: string;
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=techstack.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"techstack.d.ts","sourceRoot":"","sources":["../src/techstack.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,YAAY,GAAG,YAAY,GAAG,QAAQ,GAAG,IAAI,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;IACvF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CA+F9D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAgGpF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAQ7G"}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tech Stack Detection and Project Rules Generation
|
|
3
|
+
*/
|
|
4
|
+
import { existsSync, readFileSync, readdirSync, writeFileSync } from 'fs';
|
|
5
|
+
import { join } from 'path';
|
|
6
|
+
import { sanitizePath } from './security.js';
|
|
7
|
+
/**
|
|
8
|
+
* Detect tech stack from project files
|
|
9
|
+
*/
|
|
10
|
+
export function detectTechStack(projectPath) {
|
|
11
|
+
const safePath = sanitizePath(projectPath);
|
|
12
|
+
const stack = {
|
|
13
|
+
language: 'unknown',
|
|
14
|
+
hasTests: false,
|
|
15
|
+
hasDocs: false,
|
|
16
|
+
hasCI: false,
|
|
17
|
+
dependencies: [],
|
|
18
|
+
};
|
|
19
|
+
// Check for package.json (Node.js/JavaScript/TypeScript)
|
|
20
|
+
const pkgPath = join(safePath, 'package.json');
|
|
21
|
+
if (existsSync(pkgPath)) {
|
|
22
|
+
try {
|
|
23
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
24
|
+
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
25
|
+
stack.dependencies = Object.keys(allDeps).slice(0, 20);
|
|
26
|
+
// Detect TypeScript
|
|
27
|
+
if (allDeps.typescript || existsSync(join(safePath, 'tsconfig.json'))) {
|
|
28
|
+
stack.language = 'typescript';
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
stack.language = 'javascript';
|
|
32
|
+
}
|
|
33
|
+
// Detect framework
|
|
34
|
+
if (allDeps.next)
|
|
35
|
+
stack.framework = 'Next.js';
|
|
36
|
+
else if (allDeps.react)
|
|
37
|
+
stack.framework = 'React';
|
|
38
|
+
else if (allDeps.vue)
|
|
39
|
+
stack.framework = 'Vue';
|
|
40
|
+
else if (allDeps.svelte)
|
|
41
|
+
stack.framework = 'Svelte';
|
|
42
|
+
else if (allDeps.express)
|
|
43
|
+
stack.framework = 'Express';
|
|
44
|
+
else if (allDeps.fastify)
|
|
45
|
+
stack.framework = 'Fastify';
|
|
46
|
+
else if (allDeps['@hono/node-server'] || allDeps.hono)
|
|
47
|
+
stack.framework = 'Hono';
|
|
48
|
+
// Detect runtime
|
|
49
|
+
if (allDeps.bun)
|
|
50
|
+
stack.runtime = 'Bun';
|
|
51
|
+
else
|
|
52
|
+
stack.runtime = 'Node.js';
|
|
53
|
+
// Check for tests
|
|
54
|
+
if (pkg.scripts?.test && pkg.scripts.test !== 'echo "Error: no test specified" && exit 1') {
|
|
55
|
+
stack.hasTests = true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// Invalid package.json
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Check for Python
|
|
63
|
+
const reqPath = join(safePath, 'requirements.txt');
|
|
64
|
+
const pyprojectPath = join(safePath, 'pyproject.toml');
|
|
65
|
+
if (existsSync(reqPath) || existsSync(pyprojectPath)) {
|
|
66
|
+
stack.language = 'python';
|
|
67
|
+
if (existsSync(reqPath)) {
|
|
68
|
+
const reqs = readFileSync(reqPath, 'utf-8');
|
|
69
|
+
if (reqs.includes('fastapi'))
|
|
70
|
+
stack.framework = 'FastAPI';
|
|
71
|
+
else if (reqs.includes('django'))
|
|
72
|
+
stack.framework = 'Django';
|
|
73
|
+
else if (reqs.includes('flask'))
|
|
74
|
+
stack.framework = 'Flask';
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Check for Go
|
|
78
|
+
if (existsSync(join(safePath, 'go.mod'))) {
|
|
79
|
+
stack.language = 'go';
|
|
80
|
+
}
|
|
81
|
+
// Check for Rust
|
|
82
|
+
if (existsSync(join(safePath, 'Cargo.toml'))) {
|
|
83
|
+
stack.language = 'rust';
|
|
84
|
+
}
|
|
85
|
+
// Check for Swift
|
|
86
|
+
if (existsSync(join(safePath, 'Package.swift'))) {
|
|
87
|
+
stack.language = 'swift';
|
|
88
|
+
}
|
|
89
|
+
// Check for docs
|
|
90
|
+
stack.hasDocs = existsSync(join(safePath, 'docs')) || existsSync(join(safePath, 'README.md'));
|
|
91
|
+
// Check for CI
|
|
92
|
+
stack.hasCI = existsSync(join(safePath, '.github', 'workflows'));
|
|
93
|
+
// Check for tests (general)
|
|
94
|
+
if (!stack.hasTests) {
|
|
95
|
+
try {
|
|
96
|
+
const files = readdirSync(safePath, { withFileTypes: true });
|
|
97
|
+
stack.hasTests = files.some(f => f.name.includes('test') || f.name.includes('spec') || f.name === '__tests__');
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// Can't read directory
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return stack;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Generate project-specific .cursorrules based on tech stack
|
|
107
|
+
*/
|
|
108
|
+
export function generateCursorRules(projectPath, projectName) {
|
|
109
|
+
const stack = detectTechStack(projectPath);
|
|
110
|
+
const lines = [
|
|
111
|
+
`# Project: ${projectName}`,
|
|
112
|
+
'',
|
|
113
|
+
'# Golden Code Methodology',
|
|
114
|
+
'- Follow the 4 phases: EAGLE_SIGHT -> BUILD -> SHIP -> GROW',
|
|
115
|
+
'- Use the 7-step BUILD cycle: RULES -> INDEX -> READ -> RESEARCH -> IMPLEMENT -> TEST -> DEBUG',
|
|
116
|
+
'- When stuck: Use Tornado (research + logs + tests)',
|
|
117
|
+
'',
|
|
118
|
+
];
|
|
119
|
+
// Language-specific rules
|
|
120
|
+
if (stack.language === 'typescript') {
|
|
121
|
+
lines.push('# TypeScript Rules');
|
|
122
|
+
lines.push('- Use strict mode (strict: true in tsconfig)');
|
|
123
|
+
lines.push('- No `any` types - use `unknown` and narrow with type guards');
|
|
124
|
+
lines.push('- Explicit return types on exported functions');
|
|
125
|
+
lines.push('- Use `type` imports: `import type { X } from ...`');
|
|
126
|
+
lines.push('- Always use .js extension in ESM imports');
|
|
127
|
+
lines.push('');
|
|
128
|
+
}
|
|
129
|
+
else if (stack.language === 'javascript') {
|
|
130
|
+
lines.push('# JavaScript Rules');
|
|
131
|
+
lines.push('- Use ES modules (import/export)');
|
|
132
|
+
lines.push('- Prefer const over let, never use var');
|
|
133
|
+
lines.push('- Use async/await over raw promises');
|
|
134
|
+
lines.push('');
|
|
135
|
+
}
|
|
136
|
+
else if (stack.language === 'python') {
|
|
137
|
+
lines.push('# Python Rules');
|
|
138
|
+
lines.push('- Use type hints on all function signatures');
|
|
139
|
+
lines.push('- Follow PEP 8 style guide');
|
|
140
|
+
lines.push('- Use dataclasses or Pydantic for data structures');
|
|
141
|
+
lines.push('- Virtual environment required (venv or poetry)');
|
|
142
|
+
lines.push('');
|
|
143
|
+
}
|
|
144
|
+
else if (stack.language === 'go') {
|
|
145
|
+
lines.push('# Go Rules');
|
|
146
|
+
lines.push('- Follow effective Go patterns');
|
|
147
|
+
lines.push('- Handle all errors explicitly');
|
|
148
|
+
lines.push('- Use gofmt for formatting');
|
|
149
|
+
lines.push('- Prefer composition over inheritance');
|
|
150
|
+
lines.push('');
|
|
151
|
+
}
|
|
152
|
+
else if (stack.language === 'rust') {
|
|
153
|
+
lines.push('# Rust Rules');
|
|
154
|
+
lines.push('- Follow Rust API guidelines');
|
|
155
|
+
lines.push('- Handle all Results and Options');
|
|
156
|
+
lines.push('- Use clippy for linting');
|
|
157
|
+
lines.push('- Document public APIs');
|
|
158
|
+
lines.push('');
|
|
159
|
+
}
|
|
160
|
+
// Framework-specific rules
|
|
161
|
+
if (stack.framework) {
|
|
162
|
+
lines.push(`# ${stack.framework} Rules`);
|
|
163
|
+
if (stack.framework === 'Next.js') {
|
|
164
|
+
lines.push('- Use App Router (app/) over Pages Router');
|
|
165
|
+
lines.push('- Server Components by default, use "use client" sparingly');
|
|
166
|
+
lines.push('- Colocate components with their routes');
|
|
167
|
+
}
|
|
168
|
+
else if (stack.framework === 'React') {
|
|
169
|
+
lines.push('- Functional components with hooks');
|
|
170
|
+
lines.push('- Colocate state with components that need it');
|
|
171
|
+
lines.push('- Extract reusable logic to custom hooks');
|
|
172
|
+
}
|
|
173
|
+
else if (stack.framework === 'Express' || stack.framework === 'Fastify') {
|
|
174
|
+
lines.push('- Validate all request inputs');
|
|
175
|
+
lines.push('- Use middleware for cross-cutting concerns');
|
|
176
|
+
lines.push('- Centralized error handling');
|
|
177
|
+
}
|
|
178
|
+
lines.push('');
|
|
179
|
+
}
|
|
180
|
+
// Testing rules
|
|
181
|
+
lines.push('# Testing');
|
|
182
|
+
if (stack.hasTests) {
|
|
183
|
+
lines.push('- Run tests before committing: npm test');
|
|
184
|
+
lines.push('- Write tests for new features');
|
|
185
|
+
lines.push('- Test edge cases and error paths');
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
lines.push('- Set up testing framework');
|
|
189
|
+
lines.push('- Write tests for all business logic');
|
|
190
|
+
}
|
|
191
|
+
lines.push('');
|
|
192
|
+
// Security rules
|
|
193
|
+
lines.push('# Security');
|
|
194
|
+
lines.push('- Never commit API keys or secrets');
|
|
195
|
+
lines.push('- Validate and sanitize all user input');
|
|
196
|
+
lines.push('- Use environment variables for configuration');
|
|
197
|
+
lines.push('');
|
|
198
|
+
// Midas integration
|
|
199
|
+
lines.push('# Midas Integration');
|
|
200
|
+
lines.push('- Call midas_analyze at session start');
|
|
201
|
+
lines.push('- Call midas_journal_save after significant changes');
|
|
202
|
+
lines.push('- Call midas_tornado when stuck on the same error');
|
|
203
|
+
return lines.join('\n');
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Write .cursorrules to project
|
|
207
|
+
*/
|
|
208
|
+
export function writeCursorRules(projectPath, projectName) {
|
|
209
|
+
const safePath = sanitizePath(projectPath);
|
|
210
|
+
const rules = generateCursorRules(safePath, projectName);
|
|
211
|
+
const rulesPath = join(safePath, '.cursorrules');
|
|
212
|
+
writeFileSync(rulesPath, rules);
|
|
213
|
+
return { success: true, path: rulesPath };
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=techstack.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"techstack.js","sourceRoot":"","sources":["../src/techstack.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.test.d.ts","sourceRoot":"","sources":["../../src/tests/context.test.ts"],"names":[],"mappings":""}
|