@theihtisham/agent-shadow-brain 5.0.0 → 5.1.1
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 +575 -292
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +1 -0
- package/dist/adapters/index.js.map +1 -1
- package/dist/brain/auto-setup.d.ts +54 -0
- package/dist/brain/auto-setup.d.ts.map +1 -0
- package/dist/brain/auto-setup.js +660 -0
- package/dist/brain/auto-setup.js.map +1 -0
- package/dist/brain/brain-portability.d.ts +81 -0
- package/dist/brain/brain-portability.d.ts.map +1 -0
- package/dist/brain/brain-portability.js +329 -0
- package/dist/brain/brain-portability.js.map +1 -0
- package/dist/brain/code-dna.d.ts +70 -0
- package/dist/brain/code-dna.d.ts.map +1 -0
- package/dist/brain/code-dna.js +611 -0
- package/dist/brain/code-dna.js.map +1 -0
- package/dist/brain/fine-tuning-engine.d.ts +99 -0
- package/dist/brain/fine-tuning-engine.d.ts.map +1 -0
- package/dist/brain/fine-tuning-engine.js +681 -0
- package/dist/brain/fine-tuning-engine.js.map +1 -0
- package/dist/brain/intent-engine.d.ts +64 -0
- package/dist/brain/intent-engine.d.ts.map +1 -0
- package/dist/brain/intent-engine.js +374 -0
- package/dist/brain/intent-engine.js.map +1 -0
- package/dist/brain/lsp-server.d.ts +62 -0
- package/dist/brain/lsp-server.d.ts.map +1 -0
- package/dist/brain/lsp-server.js +480 -0
- package/dist/brain/lsp-server.js.map +1 -0
- package/dist/brain/mcp-server.d.ts +12 -0
- package/dist/brain/mcp-server.d.ts.map +1 -1
- package/dist/brain/mcp-server.js +396 -37
- package/dist/brain/mcp-server.js.map +1 -1
- package/dist/brain/orchestrator.d.ts +13 -0
- package/dist/brain/orchestrator.d.ts.map +1 -1
- package/dist/brain/orchestrator.js +25 -1
- package/dist/brain/orchestrator.js.map +1 -1
- package/dist/brain/plugin-system.d.ts +97 -0
- package/dist/brain/plugin-system.d.ts.map +1 -0
- package/dist/brain/plugin-system.js +404 -0
- package/dist/brain/plugin-system.js.map +1 -0
- package/dist/brain/smart-cache.d.ts +100 -0
- package/dist/brain/smart-cache.d.ts.map +1 -0
- package/dist/brain/smart-cache.js +417 -0
- package/dist/brain/smart-cache.js.map +1 -0
- package/dist/brain/temporal-intelligence.d.ts +89 -0
- package/dist/brain/temporal-intelligence.d.ts.map +1 -0
- package/dist/brain/temporal-intelligence.js +378 -0
- package/dist/brain/temporal-intelligence.js.map +1 -0
- package/dist/cli.js +444 -3
- package/dist/cli.js.map +1 -1
- package/dist/dashboard/server.d.ts +4 -0
- package/dist/dashboard/server.d.ts.map +1 -1
- package/dist/dashboard/server.js +453 -330
- package/dist/dashboard/server.js.map +1 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -1
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +284 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +28 -4
|
@@ -0,0 +1,660 @@
|
|
|
1
|
+
// src/brain/auto-setup.ts — Zero-Config Auto-Setup Engine
|
|
2
|
+
// Detects project type, AI tools, languages, frameworks on install
|
|
3
|
+
// v5.0.1 — Infinite Intelligence Edition
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
/** AI tool config file patterns to detect */
|
|
7
|
+
const AI_TOOL_PATTERNS = [
|
|
8
|
+
{ name: 'Claude Code', files: ['.claude/CLAUDE.md', '.claude/settings.json'], tool: 'claude-code' },
|
|
9
|
+
{ name: 'Cursor', files: ['.cursorrules', '.cursor/rules', '.cursor/mcp.json'], tool: 'cursor' },
|
|
10
|
+
{ name: 'Kilo Code', files: ['.kilocode/rules', '.kilocode/settings.json'], tool: 'kilo-code' },
|
|
11
|
+
{ name: 'Cline', files: ['.clinerules', '.cline/settings.json'], tool: 'cline' },
|
|
12
|
+
{ name: 'OpenCode', files: ['.opencode/rules', '.opencode/settings.json'], tool: 'opencode' },
|
|
13
|
+
{ name: 'Codex', files: ['.codex/config.json', '.codex/rules'], tool: 'codex' },
|
|
14
|
+
{ name: 'Aider', files: ['.aider.conf.yml', '.aiderignore'], tool: 'aider' },
|
|
15
|
+
{ name: 'Windsurf', files: ['.windsurfrules', '.windsurf/rules'], tool: 'windsurf' },
|
|
16
|
+
];
|
|
17
|
+
/** Framework detection from package.json dependencies */
|
|
18
|
+
const FRAMEWORK_DETECTORS = {
|
|
19
|
+
'react': (d) => 'react' in d,
|
|
20
|
+
'next.js': (d) => 'next' in d,
|
|
21
|
+
'vue': (d) => 'vue' in d,
|
|
22
|
+
'nuxt': (d) => 'nuxt' in d,
|
|
23
|
+
'angular': (d) => '@angular/core' in d,
|
|
24
|
+
'svelte': (d) => 'svelte' in d,
|
|
25
|
+
'astro': (d) => 'astro' in d,
|
|
26
|
+
'express': (d) => 'express' in d,
|
|
27
|
+
'nestjs': (d) => '@nestjs/core' in d,
|
|
28
|
+
'fastify': (d) => 'fastify' in d,
|
|
29
|
+
'django': () => false, // detected by file existence
|
|
30
|
+
'flask': () => false,
|
|
31
|
+
'fastapi': () => false,
|
|
32
|
+
'spring-boot': () => false,
|
|
33
|
+
'rails': () => false,
|
|
34
|
+
'gin': () => false,
|
|
35
|
+
'actix': () => false,
|
|
36
|
+
'flutter': (d) => 'flutter' in d || 'flutter_test' in d,
|
|
37
|
+
'react-native': (d) => 'react-native' in d,
|
|
38
|
+
'expo': (d) => 'expo' in d,
|
|
39
|
+
'electron': (d) => 'electron' in d,
|
|
40
|
+
'tauri': () => false,
|
|
41
|
+
'three.js': (d) => 'three' in d,
|
|
42
|
+
'unity': () => false,
|
|
43
|
+
'unreal': () => false,
|
|
44
|
+
};
|
|
45
|
+
/** Language detection from file extensions */
|
|
46
|
+
const LANGUAGE_EXTENSIONS = {
|
|
47
|
+
'typescript': ['.ts', '.tsx', '.mts', '.cts'],
|
|
48
|
+
'javascript': ['.js', '.jsx', '.mjs', '.cjs'],
|
|
49
|
+
'python': ['.py', '.pyi', '.ipynb'],
|
|
50
|
+
'rust': ['.rs'],
|
|
51
|
+
'go': ['.go'],
|
|
52
|
+
'java': ['.java'],
|
|
53
|
+
'kotlin': ['.kt', '.kts'],
|
|
54
|
+
'swift': ['.swift'],
|
|
55
|
+
'c#': ['.cs'],
|
|
56
|
+
'c++': ['.cpp', '.cxx', '.cc', '.hpp'],
|
|
57
|
+
'c': ['.c', '.h'],
|
|
58
|
+
'ruby': ['.rb'],
|
|
59
|
+
'php': ['.php'],
|
|
60
|
+
'dart': ['.dart'],
|
|
61
|
+
'scala': ['.scala'],
|
|
62
|
+
'elixir': ['.ex', '.exs'],
|
|
63
|
+
'haskell': ['.hs'],
|
|
64
|
+
'lua': ['.lua'],
|
|
65
|
+
'shell': ['.sh', '.bash', '.zsh'],
|
|
66
|
+
'sql': ['.sql'],
|
|
67
|
+
'html': ['.html', '.htm'],
|
|
68
|
+
'css': ['.css', '.scss', '.sass', '.less'],
|
|
69
|
+
'vue': ['.vue'],
|
|
70
|
+
'svelte': ['.svelte'],
|
|
71
|
+
};
|
|
72
|
+
/** Test framework detection */
|
|
73
|
+
const TEST_DETECTORS = {
|
|
74
|
+
'vitest': (d) => 'vitest' in d,
|
|
75
|
+
'jest': (d) => 'jest' in d || '@jest/core' in d,
|
|
76
|
+
'mocha': (d) => 'mocha' in d,
|
|
77
|
+
'pytest': () => false,
|
|
78
|
+
'unittest': () => false,
|
|
79
|
+
'cypress': (d) => 'cypress' in d,
|
|
80
|
+
'playwright': (d) => '@playwright/test' in d || 'playwright' in d,
|
|
81
|
+
'testing-library': (d) => '@testing-library/react' in d || '@testing-library/vue' in d,
|
|
82
|
+
'ava': (d) => 'ava' in d,
|
|
83
|
+
'tap': (d) => 'tap' in d,
|
|
84
|
+
'jasmine': (d) => 'jasmine' in d,
|
|
85
|
+
'karma': (d) => 'karma' in d,
|
|
86
|
+
'pytorch-test': () => false,
|
|
87
|
+
'junit': () => false,
|
|
88
|
+
};
|
|
89
|
+
/** CI/CD detection */
|
|
90
|
+
const CICD_FILES = {
|
|
91
|
+
'github-actions': ['.github/workflows'],
|
|
92
|
+
'gitlab-ci': ['.gitlab-ci.yml'],
|
|
93
|
+
'jenkins': ['Jenkinsfile'],
|
|
94
|
+
'circleci': ['.circleci/config.yml'],
|
|
95
|
+
'travis-ci': ['.travis.yml'],
|
|
96
|
+
'azure-pipelines': ['azure-pipelines.yml', '.azure-pipelines.yml'],
|
|
97
|
+
'bitbucket-pipelines': ['bitbucket-pipelines.yml'],
|
|
98
|
+
'drone': ['.drone.yml'],
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* AutoSetup — zero-configuration project detection engine.
|
|
102
|
+
*
|
|
103
|
+
* Scans the project directory on install and automatically:
|
|
104
|
+
* 1. Detects languages, frameworks, build tools
|
|
105
|
+
* 2. Discovers AI coding tools already configured
|
|
106
|
+
* 3. Identifies test frameworks, linters, formatters
|
|
107
|
+
* 4. Checks for CI/CD, Git, Docker
|
|
108
|
+
* 5. Generates optimal BrainConfig with sensible defaults
|
|
109
|
+
* 6. Installs MCP integration for detected AI tools
|
|
110
|
+
*/
|
|
111
|
+
export class AutoSetup {
|
|
112
|
+
constructor(projectDir) {
|
|
113
|
+
this.projectDir = projectDir || process.cwd();
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Run full auto-detection and configuration.
|
|
117
|
+
* Call this from postinstall or `shadow-brain start`.
|
|
118
|
+
*/
|
|
119
|
+
async detect() {
|
|
120
|
+
const languages = this.detectLanguages();
|
|
121
|
+
const packageJson = this.readPackageJson();
|
|
122
|
+
const deps = this.extractDependencies(packageJson);
|
|
123
|
+
const frameworks = this.detectFrameworks(deps);
|
|
124
|
+
const buildTools = this.detectBuildTools(deps, packageJson);
|
|
125
|
+
const packageManager = this.detectPackageManager();
|
|
126
|
+
const aiTools = this.detectAITools();
|
|
127
|
+
const testFrameworks = this.detectTestFrameworks(deps);
|
|
128
|
+
const linters = this.detectLinters();
|
|
129
|
+
const formatters = this.detectFormatters(deps);
|
|
130
|
+
const cicd = this.detectCICD();
|
|
131
|
+
const hasGit = this.detectGit();
|
|
132
|
+
const hasDocker = this.detectDocker();
|
|
133
|
+
const config = this.generateConfig({
|
|
134
|
+
languages,
|
|
135
|
+
frameworks,
|
|
136
|
+
buildTools,
|
|
137
|
+
packageManager,
|
|
138
|
+
aiTools,
|
|
139
|
+
testFrameworks,
|
|
140
|
+
hasGit,
|
|
141
|
+
hasDocker,
|
|
142
|
+
});
|
|
143
|
+
return {
|
|
144
|
+
projectDir: this.projectDir,
|
|
145
|
+
projectName: this.getProjectName(packageJson),
|
|
146
|
+
projectType: this.inferProjectType(frameworks, languages),
|
|
147
|
+
languages,
|
|
148
|
+
frameworks,
|
|
149
|
+
buildTools,
|
|
150
|
+
packageManager,
|
|
151
|
+
aiTools,
|
|
152
|
+
testFrameworks,
|
|
153
|
+
linters,
|
|
154
|
+
formatters,
|
|
155
|
+
cicd,
|
|
156
|
+
hasGit,
|
|
157
|
+
hasDocker,
|
|
158
|
+
config,
|
|
159
|
+
timestamp: new Date(),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Install MCP integration files for detected AI tools.
|
|
164
|
+
*/
|
|
165
|
+
async installMCPForTools(result) {
|
|
166
|
+
const installed = [];
|
|
167
|
+
for (const tool of result.aiTools) {
|
|
168
|
+
if (!tool.detected)
|
|
169
|
+
continue;
|
|
170
|
+
try {
|
|
171
|
+
switch (tool.name) {
|
|
172
|
+
case 'Claude Code':
|
|
173
|
+
await this.installClaudeMCP();
|
|
174
|
+
installed.push('Claude Code');
|
|
175
|
+
break;
|
|
176
|
+
case 'Cursor':
|
|
177
|
+
await this.installCursorMCP();
|
|
178
|
+
installed.push('Cursor');
|
|
179
|
+
break;
|
|
180
|
+
case 'Kilo Code':
|
|
181
|
+
await this.installKiloCodeMCP();
|
|
182
|
+
installed.push('Kilo Code');
|
|
183
|
+
break;
|
|
184
|
+
case 'Cline':
|
|
185
|
+
await this.installClineMCP();
|
|
186
|
+
installed.push('Cline');
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
// Non-blocking — tool may not support MCP injection
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return installed;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Install git hooks for pre-commit/pre-push.
|
|
198
|
+
*/
|
|
199
|
+
async installGitHooks() {
|
|
200
|
+
const gitDir = path.join(this.projectDir, '.git');
|
|
201
|
+
if (!fs.existsSync(gitDir))
|
|
202
|
+
return false;
|
|
203
|
+
const hooksDir = path.join(gitDir, 'hooks');
|
|
204
|
+
if (!fs.existsSync(hooksDir)) {
|
|
205
|
+
fs.mkdirSync(hooksDir, { recursive: true });
|
|
206
|
+
}
|
|
207
|
+
// Pre-commit hook
|
|
208
|
+
const preCommit = path.join(hooksDir, 'pre-commit');
|
|
209
|
+
const preCommitContent = `#!/bin/sh
|
|
210
|
+
# Agent Shadow Brain — Auto-installed pre-commit hook
|
|
211
|
+
npx shadow-brain scan --staged 2>/dev/null || true
|
|
212
|
+
`;
|
|
213
|
+
fs.writeFileSync(preCommit, preCommitContent, { mode: 0o755 });
|
|
214
|
+
// Pre-push hook
|
|
215
|
+
const prePush = path.join(hooksDir, 'pre-push');
|
|
216
|
+
const prePushContent = `#!/bin/sh
|
|
217
|
+
# Agent Shadow Brain — Auto-installed pre-push hook
|
|
218
|
+
npx shadow-brain health 2>/dev/null || true
|
|
219
|
+
`;
|
|
220
|
+
fs.writeFileSync(prePush, prePushContent, { mode: 0o755 });
|
|
221
|
+
return true;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Generate a summary string for CLI display.
|
|
225
|
+
*/
|
|
226
|
+
getSummary(result) {
|
|
227
|
+
const lines = [];
|
|
228
|
+
lines.push(` Project: ${result.projectName} (${result.projectType})`);
|
|
229
|
+
lines.push(` Languages: ${result.languages.join(', ') || 'none detected'}`);
|
|
230
|
+
lines.push(` Frameworks: ${result.frameworks.join(', ') || 'none detected'}`);
|
|
231
|
+
lines.push(` Package Manager: ${result.packageManager}`);
|
|
232
|
+
lines.push(` Build Tools: ${result.buildTools.join(', ') || 'none detected'}`);
|
|
233
|
+
lines.push(` Test Frameworks: ${result.testFrameworks.join(', ') || 'none detected'}`);
|
|
234
|
+
lines.push(` AI Tools: ${result.aiTools.filter(t => t.detected).map(t => t.name).join(', ') || 'none detected'}`);
|
|
235
|
+
lines.push(` CI/CD: ${result.cicd.join(', ') || 'none detected'}`);
|
|
236
|
+
lines.push(` Git: ${result.hasGit ? 'yes' : 'no'}`);
|
|
237
|
+
lines.push(` Docker: ${result.hasDocker ? 'yes' : 'no'}`);
|
|
238
|
+
return lines.join('\n');
|
|
239
|
+
}
|
|
240
|
+
// ── Detection Methods ──────────────────────────────────────────────────────
|
|
241
|
+
detectLanguages() {
|
|
242
|
+
const detected = new Set();
|
|
243
|
+
const extensions = new Set();
|
|
244
|
+
const walkDir = (dir, depth = 0) => {
|
|
245
|
+
if (depth > 3)
|
|
246
|
+
return;
|
|
247
|
+
try {
|
|
248
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
249
|
+
for (const entry of entries) {
|
|
250
|
+
if (entry.name.startsWith('.') || entry.name === 'node_modules' || entry.name === 'dist' || entry.name === 'build' || entry.name === '.git')
|
|
251
|
+
continue;
|
|
252
|
+
const fullPath = path.join(dir, entry.name);
|
|
253
|
+
if (entry.isDirectory()) {
|
|
254
|
+
walkDir(fullPath, depth + 1);
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
const ext = path.extname(entry.name).toLowerCase();
|
|
258
|
+
if (ext)
|
|
259
|
+
extensions.add(ext);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
catch {
|
|
264
|
+
// Permission denied, skip
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
walkDir(this.projectDir);
|
|
268
|
+
for (const [language, exts] of Object.entries(LANGUAGE_EXTENSIONS)) {
|
|
269
|
+
for (const ext of exts) {
|
|
270
|
+
if (extensions.has(ext)) {
|
|
271
|
+
detected.add(language);
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return Array.from(detected);
|
|
277
|
+
}
|
|
278
|
+
readPackageJson() {
|
|
279
|
+
const pkgPath = path.join(this.projectDir, 'package.json');
|
|
280
|
+
if (!fs.existsSync(pkgPath))
|
|
281
|
+
return null;
|
|
282
|
+
try {
|
|
283
|
+
return JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
284
|
+
}
|
|
285
|
+
catch {
|
|
286
|
+
return null;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
extractDependencies(pkg) {
|
|
290
|
+
if (!pkg)
|
|
291
|
+
return {};
|
|
292
|
+
const deps = {};
|
|
293
|
+
const depFields = ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies'];
|
|
294
|
+
for (const field of depFields) {
|
|
295
|
+
const fieldDeps = pkg[field];
|
|
296
|
+
if (fieldDeps && typeof fieldDeps === 'object') {
|
|
297
|
+
Object.assign(deps, fieldDeps);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return deps;
|
|
301
|
+
}
|
|
302
|
+
detectFrameworks(deps) {
|
|
303
|
+
const detected = [];
|
|
304
|
+
for (const [framework, detector] of Object.entries(FRAMEWORK_DETECTORS)) {
|
|
305
|
+
try {
|
|
306
|
+
if (detector(deps)) {
|
|
307
|
+
detected.push(framework);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
catch {
|
|
311
|
+
// Skip
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
// File-based framework detection
|
|
315
|
+
if (fs.existsSync(path.join(this.projectDir, 'manage.py')))
|
|
316
|
+
detected.push('django');
|
|
317
|
+
if (fs.existsSync(path.join(this.projectDir, 'app.py')) || fs.existsSync(path.join(this.projectDir, 'requirements.txt'))) {
|
|
318
|
+
if (fs.existsSync(path.join(this.projectDir, 'requirements.txt'))) {
|
|
319
|
+
const reqs = fs.readFileSync(path.join(this.projectDir, 'requirements.txt'), 'utf-8').toLowerCase();
|
|
320
|
+
if (reqs.includes('flask'))
|
|
321
|
+
detected.push('flask');
|
|
322
|
+
if (reqs.includes('fastapi'))
|
|
323
|
+
detected.push('fastapi');
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
if (fs.existsSync(path.join(this.projectDir, 'pom.xml')))
|
|
327
|
+
detected.push('spring-boot');
|
|
328
|
+
if (fs.existsSync(path.join(this.projectDir, 'Gemfile')))
|
|
329
|
+
detected.push('rails');
|
|
330
|
+
if (fs.existsSync(path.join(this.projectDir, 'go.mod')))
|
|
331
|
+
detected.push('gin');
|
|
332
|
+
if (fs.existsSync(path.join(this.projectDir, 'Cargo.toml')))
|
|
333
|
+
detected.push('actix');
|
|
334
|
+
if (fs.existsSync(path.join(this.projectDir, 'src-tauri')))
|
|
335
|
+
detected.push('tauri');
|
|
336
|
+
if (fs.existsSync(path.join(this.projectDir, 'Assets')) && fs.existsSync(path.join(this.projectDir, 'ProjectSettings')))
|
|
337
|
+
detected.push('unity');
|
|
338
|
+
return [...new Set(detected)];
|
|
339
|
+
}
|
|
340
|
+
detectBuildTools(deps, pkg) {
|
|
341
|
+
const detected = new Set();
|
|
342
|
+
if (deps['webpack'])
|
|
343
|
+
detected.add('webpack');
|
|
344
|
+
if (deps['vite'])
|
|
345
|
+
detected.add('vite');
|
|
346
|
+
if (deps['esbuild'])
|
|
347
|
+
detected.add('esbuild');
|
|
348
|
+
if (deps['rollup'])
|
|
349
|
+
detected.add('rollup');
|
|
350
|
+
if (deps['parcel'])
|
|
351
|
+
detected.add('parcel');
|
|
352
|
+
if (deps['turbo'])
|
|
353
|
+
detected.add('turborepo');
|
|
354
|
+
if (deps['@nrwl/cli'] || deps['nx'])
|
|
355
|
+
detected.add('nx');
|
|
356
|
+
if (deps['typescript'])
|
|
357
|
+
detected.add('typescript');
|
|
358
|
+
if (deps['swc'] || deps['@swc/core'])
|
|
359
|
+
detected.add('swc');
|
|
360
|
+
if (deps['rspack'] || deps['@rspack/core'])
|
|
361
|
+
detected.add('rspack');
|
|
362
|
+
// From scripts
|
|
363
|
+
if (pkg && typeof pkg === 'object') {
|
|
364
|
+
const scripts = pkg.scripts;
|
|
365
|
+
if (scripts) {
|
|
366
|
+
for (const [, script] of Object.entries(scripts)) {
|
|
367
|
+
if (typeof script === 'string') {
|
|
368
|
+
if (script.includes('next build'))
|
|
369
|
+
detected.add('next.js-build');
|
|
370
|
+
if (script.includes('nuxt build'))
|
|
371
|
+
detected.add('nuxt-build');
|
|
372
|
+
if (script.includes('tsc'))
|
|
373
|
+
detected.add('tsc');
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
return Array.from(detected);
|
|
379
|
+
}
|
|
380
|
+
detectPackageManager() {
|
|
381
|
+
if (fs.existsSync(path.join(this.projectDir, 'pnpm-lock.yaml')))
|
|
382
|
+
return 'pnpm';
|
|
383
|
+
if (fs.existsSync(path.join(this.projectDir, 'bun.lockb')) || fs.existsSync(path.join(this.projectDir, 'bun.lock')))
|
|
384
|
+
return 'bun';
|
|
385
|
+
if (fs.existsSync(path.join(this.projectDir, 'yarn.lock')))
|
|
386
|
+
return 'yarn';
|
|
387
|
+
if (fs.existsSync(path.join(this.projectDir, 'package-lock.json')))
|
|
388
|
+
return 'npm';
|
|
389
|
+
return 'unknown';
|
|
390
|
+
}
|
|
391
|
+
detectAITools() {
|
|
392
|
+
const results = [];
|
|
393
|
+
for (const pattern of AI_TOOL_PATTERNS) {
|
|
394
|
+
let detected = false;
|
|
395
|
+
let foundPath = '';
|
|
396
|
+
for (const file of pattern.files) {
|
|
397
|
+
const fullPath = path.join(this.projectDir, file);
|
|
398
|
+
if (fs.existsSync(fullPath)) {
|
|
399
|
+
detected = true;
|
|
400
|
+
foundPath = file;
|
|
401
|
+
break;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
results.push({ name: pattern.name, path: foundPath, detected });
|
|
405
|
+
}
|
|
406
|
+
return results;
|
|
407
|
+
}
|
|
408
|
+
detectTestFrameworks(deps) {
|
|
409
|
+
const detected = [];
|
|
410
|
+
for (const [framework, detector] of Object.entries(TEST_DETECTORS)) {
|
|
411
|
+
try {
|
|
412
|
+
if (detector(deps))
|
|
413
|
+
detected.push(framework);
|
|
414
|
+
}
|
|
415
|
+
catch {
|
|
416
|
+
// Skip
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
// File-based detection
|
|
420
|
+
if (fs.existsSync(path.join(this.projectDir, 'pytest.ini')) || fs.existsSync(path.join(this.projectDir, 'setup.cfg')))
|
|
421
|
+
detected.push('pytest');
|
|
422
|
+
if (fs.existsSync(path.join(this.projectDir, 'phpunit.xml')))
|
|
423
|
+
detected.push('phpunit');
|
|
424
|
+
if (fs.existsSync(path.join(this.projectDir, 'jest.config.js')) || fs.existsSync(path.join(this.projectDir, 'jest.config.ts'))) {
|
|
425
|
+
if (!detected.includes('jest'))
|
|
426
|
+
detected.push('jest');
|
|
427
|
+
}
|
|
428
|
+
if (fs.existsSync(path.join(this.projectDir, 'vitest.config.ts')) || fs.existsSync(path.join(this.projectDir, 'vitest.config.js'))) {
|
|
429
|
+
if (!detected.includes('vitest'))
|
|
430
|
+
detected.push('vitest');
|
|
431
|
+
}
|
|
432
|
+
return [...new Set(detected)];
|
|
433
|
+
}
|
|
434
|
+
detectLinters() {
|
|
435
|
+
const detected = [];
|
|
436
|
+
if (fs.existsSync(path.join(this.projectDir, '.eslintrc.js')) || fs.existsSync(path.join(this.projectDir, '.eslintrc.json')) || fs.existsSync(path.join(this.projectDir, '.eslintrc.yml')) || fs.existsSync(path.join(this.projectDir, 'eslint.config.js')) || fs.existsSync(path.join(this.projectDir, 'eslint.config.mjs')))
|
|
437
|
+
detected.push('eslint');
|
|
438
|
+
if (fs.existsSync(path.join(this.projectDir, '.pylintrc')) || fs.existsSync(path.join(this.projectDir, 'pyproject.toml')))
|
|
439
|
+
detected.push('pylint');
|
|
440
|
+
if (fs.existsSync(path.join(this.projectDir, '.flake8')))
|
|
441
|
+
detected.push('flake8');
|
|
442
|
+
if (fs.existsSync(path.join(this.projectDir, '.rubocop.yml')))
|
|
443
|
+
detected.push('rubocop');
|
|
444
|
+
if (fs.existsSync(path.join(this.projectDir, '.golangci.yml')) || fs.existsSync(path.join(this.projectDir, '.golangci.yaml')))
|
|
445
|
+
detected.push('golangci-lint');
|
|
446
|
+
if (fs.existsSync(path.join(this.projectDir, '.clippy.toml')))
|
|
447
|
+
detected.push('clippy');
|
|
448
|
+
return detected;
|
|
449
|
+
}
|
|
450
|
+
detectFormatters(deps) {
|
|
451
|
+
const detected = [];
|
|
452
|
+
if (deps['prettier'] || fs.existsSync(path.join(this.projectDir, '.prettierrc')) || fs.existsSync(path.join(this.projectDir, '.prettierrc.js')))
|
|
453
|
+
detected.push('prettier');
|
|
454
|
+
if (fs.existsSync(path.join(this.projectDir, '.black')) || fs.existsSync(path.join(this.projectDir, 'pyproject.toml')))
|
|
455
|
+
detected.push('black');
|
|
456
|
+
if (fs.existsSync(path.join(this.projectDir, '.rustfmt.toml')))
|
|
457
|
+
detected.push('rustfmt');
|
|
458
|
+
if (deps['@biomejs/biome'] || fs.existsSync(path.join(this.projectDir, 'biome.json')))
|
|
459
|
+
detected.push('biome');
|
|
460
|
+
return detected;
|
|
461
|
+
}
|
|
462
|
+
detectCICD() {
|
|
463
|
+
const detected = [];
|
|
464
|
+
for (const [platform, files] of Object.entries(CICD_FILES)) {
|
|
465
|
+
for (const file of files) {
|
|
466
|
+
if (fs.existsSync(path.join(this.projectDir, file))) {
|
|
467
|
+
detected.push(platform);
|
|
468
|
+
break;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
return detected;
|
|
473
|
+
}
|
|
474
|
+
detectGit() {
|
|
475
|
+
return fs.existsSync(path.join(this.projectDir, '.git'));
|
|
476
|
+
}
|
|
477
|
+
detectDocker() {
|
|
478
|
+
return fs.existsSync(path.join(this.projectDir, 'Dockerfile')) || fs.existsSync(path.join(this.projectDir, 'docker-compose.yml')) || fs.existsSync(path.join(this.projectDir, 'docker-compose.yaml'));
|
|
479
|
+
}
|
|
480
|
+
// ── Config Generation ──────────────────────────────────────────────────────
|
|
481
|
+
generateConfig(ctx) {
|
|
482
|
+
const config = {
|
|
483
|
+
projectDir: this.projectDir,
|
|
484
|
+
};
|
|
485
|
+
// Store project name in config for reference
|
|
486
|
+
config.projectName = this.getProjectName(this.readPackageJson());
|
|
487
|
+
// Enable features based on detection
|
|
488
|
+
if (ctx.hasGit) {
|
|
489
|
+
config.gitEnabled = true;
|
|
490
|
+
}
|
|
491
|
+
// Set analysis depth based on project complexity
|
|
492
|
+
const complexity = ctx.frameworks.length + ctx.languages.length;
|
|
493
|
+
if (complexity > 5) {
|
|
494
|
+
config.analysisDepth = 'deep';
|
|
495
|
+
}
|
|
496
|
+
else if (complexity > 2) {
|
|
497
|
+
config.analysisDepth = 'standard';
|
|
498
|
+
}
|
|
499
|
+
else {
|
|
500
|
+
config.analysisDepth = 'quick';
|
|
501
|
+
}
|
|
502
|
+
return config;
|
|
503
|
+
}
|
|
504
|
+
inferProjectType(frameworks, languages) {
|
|
505
|
+
if (frameworks.includes('react-native') || frameworks.includes('expo') || frameworks.includes('flutter'))
|
|
506
|
+
return 'mobile';
|
|
507
|
+
if (frameworks.includes('electron') || frameworks.includes('tauri'))
|
|
508
|
+
return 'desktop';
|
|
509
|
+
if (frameworks.includes('unity'))
|
|
510
|
+
return 'game';
|
|
511
|
+
if (frameworks.includes('next.js') || frameworks.includes('nuxt') || frameworks.includes('astro') || frameworks.includes('angular') || frameworks.includes('svelte') || frameworks.includes('vue'))
|
|
512
|
+
return 'fullstack';
|
|
513
|
+
if (frameworks.includes('express') || frameworks.includes('nestjs') || frameworks.includes('fastify') || frameworks.includes('django') || frameworks.includes('flask') || frameworks.includes('fastapi') || frameworks.includes('spring-boot') || frameworks.includes('rails') || frameworks.includes('gin') || frameworks.includes('actix'))
|
|
514
|
+
return 'backend';
|
|
515
|
+
if (frameworks.includes('react') || frameworks.includes('vue') || frameworks.includes('angular') || frameworks.includes('svelte'))
|
|
516
|
+
return 'frontend';
|
|
517
|
+
if (frameworks.includes('three.js'))
|
|
518
|
+
return '3d-web';
|
|
519
|
+
if (languages.includes('rust') && !frameworks.length)
|
|
520
|
+
return 'systems';
|
|
521
|
+
if (languages.includes('go') && !frameworks.length)
|
|
522
|
+
return 'systems';
|
|
523
|
+
if (languages.includes('python') && !frameworks.length)
|
|
524
|
+
return 'data-science';
|
|
525
|
+
if (languages.includes('c++') || languages.includes('c'))
|
|
526
|
+
return 'systems';
|
|
527
|
+
return 'generic';
|
|
528
|
+
}
|
|
529
|
+
getProjectName(pkg) {
|
|
530
|
+
if (pkg && typeof pkg === 'object' && pkg.name && typeof pkg.name === 'string') {
|
|
531
|
+
return pkg.name.replace(/^@[^/]+\//, '');
|
|
532
|
+
}
|
|
533
|
+
return path.basename(this.projectDir);
|
|
534
|
+
}
|
|
535
|
+
// ── MCP Installation for AI Tools ──────────────────────────────────────────
|
|
536
|
+
async installClaudeMCP() {
|
|
537
|
+
const claudeDir = path.join(this.projectDir, '.claude');
|
|
538
|
+
const settingsPath = path.join(claudeDir, 'settings.json');
|
|
539
|
+
let settings = {};
|
|
540
|
+
if (fs.existsSync(settingsPath)) {
|
|
541
|
+
try {
|
|
542
|
+
settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
|
|
543
|
+
}
|
|
544
|
+
catch {
|
|
545
|
+
settings = {};
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
const mcpServers = (settings.mcpServers || {});
|
|
549
|
+
mcpServers['shadow-brain'] = {
|
|
550
|
+
command: 'npx',
|
|
551
|
+
args: ['-y', '@theihtisham/agent-shadow-brain', 'mcp'],
|
|
552
|
+
};
|
|
553
|
+
settings.mcpServers = mcpServers;
|
|
554
|
+
if (!fs.existsSync(claudeDir)) {
|
|
555
|
+
fs.mkdirSync(claudeDir, { recursive: true });
|
|
556
|
+
}
|
|
557
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
558
|
+
}
|
|
559
|
+
async installCursorMCP() {
|
|
560
|
+
const cursorDir = path.join(this.projectDir, '.cursor');
|
|
561
|
+
const mcpPath = path.join(cursorDir, 'mcp.json');
|
|
562
|
+
let mcpConfig = {};
|
|
563
|
+
if (fs.existsSync(mcpPath)) {
|
|
564
|
+
try {
|
|
565
|
+
mcpConfig = JSON.parse(fs.readFileSync(mcpPath, 'utf-8'));
|
|
566
|
+
}
|
|
567
|
+
catch {
|
|
568
|
+
mcpConfig = {};
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
const mcpServers = (mcpConfig.mcpServers || {});
|
|
572
|
+
mcpServers['shadow-brain'] = {
|
|
573
|
+
command: 'npx',
|
|
574
|
+
args: ['-y', '@theihtisham/agent-shadow-brain', 'mcp'],
|
|
575
|
+
};
|
|
576
|
+
mcpConfig.mcpServers = mcpServers;
|
|
577
|
+
if (!fs.existsSync(cursorDir)) {
|
|
578
|
+
fs.mkdirSync(cursorDir, { recursive: true });
|
|
579
|
+
}
|
|
580
|
+
fs.writeFileSync(mcpPath, JSON.stringify(mcpConfig, null, 2));
|
|
581
|
+
}
|
|
582
|
+
async installKiloCodeMCP() {
|
|
583
|
+
const kiloDir = path.join(this.projectDir, '.kilocode');
|
|
584
|
+
const settingsPath = path.join(kiloDir, 'settings.json');
|
|
585
|
+
let settings = {};
|
|
586
|
+
if (fs.existsSync(settingsPath)) {
|
|
587
|
+
try {
|
|
588
|
+
settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
|
|
589
|
+
}
|
|
590
|
+
catch {
|
|
591
|
+
settings = {};
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
const mcpServers = (settings.mcpServers || {});
|
|
595
|
+
mcpServers['shadow-brain'] = {
|
|
596
|
+
command: 'npx',
|
|
597
|
+
args: ['-y', '@theihtisham/agent-shadow-brain', 'mcp'],
|
|
598
|
+
};
|
|
599
|
+
settings.mcpServers = mcpServers;
|
|
600
|
+
if (!fs.existsSync(kiloDir)) {
|
|
601
|
+
fs.mkdirSync(kiloDir, { recursive: true });
|
|
602
|
+
}
|
|
603
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
604
|
+
}
|
|
605
|
+
async installClineMCP() {
|
|
606
|
+
const clineDir = path.join(this.projectDir, '.cline');
|
|
607
|
+
const settingsPath = path.join(clineDir, 'settings.json');
|
|
608
|
+
let settings = {};
|
|
609
|
+
if (fs.existsSync(settingsPath)) {
|
|
610
|
+
try {
|
|
611
|
+
settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
|
|
612
|
+
}
|
|
613
|
+
catch {
|
|
614
|
+
settings = {};
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
const mcpServers = (settings.mcpServers || {});
|
|
618
|
+
mcpServers['shadow-brain'] = {
|
|
619
|
+
command: 'npx',
|
|
620
|
+
args: ['-y', '@theihtisham/agent-shadow-brain', 'mcp'],
|
|
621
|
+
};
|
|
622
|
+
settings.mcpServers = mcpServers;
|
|
623
|
+
if (!fs.existsSync(clineDir)) {
|
|
624
|
+
fs.mkdirSync(clineDir, { recursive: true });
|
|
625
|
+
}
|
|
626
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
// ── Standalone postinstall runner ──────────────────────────────────────────
|
|
630
|
+
// Runs automatically after npm install to detect project and set up MCP
|
|
631
|
+
async function postinstall() {
|
|
632
|
+
try {
|
|
633
|
+
const setup = new AutoSetup();
|
|
634
|
+
const result = await setup.detect();
|
|
635
|
+
// Only install MCP for detected tools, silently
|
|
636
|
+
if (result.aiTools.some(t => t.detected)) {
|
|
637
|
+
await setup.installMCPForTools(result);
|
|
638
|
+
}
|
|
639
|
+
// Install git hooks if git repo detected
|
|
640
|
+
if (result.hasGit) {
|
|
641
|
+
await setup.installGitHooks();
|
|
642
|
+
}
|
|
643
|
+
// Output minimal setup info
|
|
644
|
+
console.log(`\n Shadow Brain v5.0.1 auto-configured for ${result.projectName} (${result.projectType})`);
|
|
645
|
+
if (result.aiTools.some(t => t.detected)) {
|
|
646
|
+
const tools = result.aiTools.filter(t => t.detected).map(t => t.name);
|
|
647
|
+
console.log(` AI tools detected: ${tools.join(', ')}`);
|
|
648
|
+
}
|
|
649
|
+
console.log(` Run: shadow-brain start\n`);
|
|
650
|
+
}
|
|
651
|
+
catch {
|
|
652
|
+
// Silent — never break npm install
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
// Run when executed directly (postinstall)
|
|
656
|
+
if (process.argv[1] &&
|
|
657
|
+
(process.argv[1].includes('auto-setup') || process.argv[1].includes('dist/brain/auto-setup'))) {
|
|
658
|
+
postinstall();
|
|
659
|
+
}
|
|
660
|
+
//# sourceMappingURL=auto-setup.js.map
|