@theihtisham/agent-shadow-brain 1.1.1 → 1.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.
Files changed (42) hide show
  1. package/README.md +73 -237
  2. package/dist/brain/auto-update.d.ts +9 -0
  3. package/dist/brain/auto-update.d.ts.map +1 -0
  4. package/dist/brain/auto-update.js +59 -0
  5. package/dist/brain/auto-update.js.map +1 -0
  6. package/dist/brain/code-metrics.d.ts +18 -0
  7. package/dist/brain/code-metrics.d.ts.map +1 -0
  8. package/dist/brain/code-metrics.js +224 -0
  9. package/dist/brain/code-metrics.js.map +1 -0
  10. package/dist/brain/custom-rules.d.ts +14 -0
  11. package/dist/brain/custom-rules.d.ts.map +1 -0
  12. package/dist/brain/custom-rules.js +108 -0
  13. package/dist/brain/custom-rules.js.map +1 -0
  14. package/dist/brain/notifier.d.ts +26 -0
  15. package/dist/brain/notifier.d.ts.map +1 -0
  16. package/dist/brain/notifier.js +151 -0
  17. package/dist/brain/notifier.js.map +1 -0
  18. package/dist/brain/orchestrator.d.ts +38 -1
  19. package/dist/brain/orchestrator.d.ts.map +1 -1
  20. package/dist/brain/orchestrator.js +126 -0
  21. package/dist/brain/orchestrator.js.map +1 -1
  22. package/dist/brain/pr-generator.d.ts +19 -0
  23. package/dist/brain/pr-generator.d.ts.map +1 -0
  24. package/dist/brain/pr-generator.js +199 -0
  25. package/dist/brain/pr-generator.js.map +1 -0
  26. package/dist/brain/project-config.d.ts +14 -0
  27. package/dist/brain/project-config.d.ts.map +1 -0
  28. package/dist/brain/project-config.js +121 -0
  29. package/dist/brain/project-config.js.map +1 -0
  30. package/dist/brain/vuln-scanner.d.ts +16 -0
  31. package/dist/brain/vuln-scanner.d.ts.map +1 -0
  32. package/dist/brain/vuln-scanner.js +279 -0
  33. package/dist/brain/vuln-scanner.js.map +1 -0
  34. package/dist/cli.js +222 -2
  35. package/dist/cli.js.map +1 -1
  36. package/dist/index.d.ts +10 -1
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +8 -0
  39. package/dist/index.js.map +1 -1
  40. package/dist/types.d.ts +92 -0
  41. package/dist/types.d.ts.map +1 -1
  42. package/package.json +88 -77
package/README.md CHANGED
@@ -1,237 +1,73 @@
1
- # Agent Shadow Brain
2
-
3
- <div align="center">
4
- <img src="docs/images/banner.svg" alt="Agent Shadow Brain Banner" width="100%" />
5
- </div>
6
-
7
- <br/>
8
-
9
- <div align="center">
10
-
11
- [![npm version](https://img.shields.io/npm/v/@theihtisham/agent-shadow-brain.svg)](https://www.npmjs.com/package/@theihtisham/agent-shadow-brain)
12
- [![npm downloads](https://img.shields.io/npm/dm/@theihtisham/agent-shadow-brain.svg)](https://www.npmjs.com/package/@theihtisham/agent-shadow-brain)
13
- [![license](https://img.shields.io/npm/l/@theihtisham/agent-shadow-brain.svg)](https://github.com/theihtisham/agent-shadow-brain/blob/main/LICENSE)
14
- [![node](https://img.shields.io/node/v/@theihtisham/agent-shadow-brain.svg)](https://www.npmjs.com/package/@theihtisham/agent-shadow-brain)
15
-
16
- **A shadow AI brain that runs alongside your coding agent — watching, reviewing, and injecting intelligence in real-time.**
17
-
18
- Works with **Claude Code** · **Kilo Code** · **Cline** · **OpenCode** · **Codex CLI** · and more
19
-
20
- [Quick Start](#install) · [How It Works](#how-it-works) · [CLI Reference](#cli-reference) · [Personalities](#brain-personalities) · [API](#programmatic-api)
21
-
22
- </div>
23
-
24
- ---
25
-
26
- ## Install
27
-
28
- ```bash
29
- npm install -g @theihtisham/agent-shadow-brain
30
- ```
31
-
32
- Or use directly without installing:
33
-
34
- ```bash
35
- npx @theihtisham/agent-shadow-brain start .
36
- ```
37
-
38
- ### First-time setup
39
-
40
- ```bash
41
- shadow-brain setup
42
- ```
43
-
44
- Runs an interactive wizard to configure your LLM provider, personality, and review depth.
45
-
46
- ### Health check
47
-
48
- ```bash
49
- shadow-brain doctor
50
- ```
51
-
52
- Verifies your configuration, tests provider connectivity, and detects running agents.
53
-
54
- ---
55
-
56
- ## How It Works
57
-
58
- <div align="center">
59
- <img src="docs/images/architecture.svg" alt="Architecture Diagram" width="100%" />
60
- </div>
61
-
62
- Shadow Brain watches your project files and git activity in real-time, reads what your coding agent is doing, and uses an LLM (with a smart rule-based fallback) to generate insights. It then injects those insights directly into the agent's memory files so the agent picks them up automatically.
63
-
64
- **Pipeline:** `File/Git Watcher` → `Orchestrator (debounce)` → `Brain Analyzer (LLM + rules)` → `Personality Engine` → `Smart Injection into agent memory`
65
-
66
- ### Key Features
67
-
68
- - **Real-time monitoring** — watches file changes and git activity as they happen
69
- - **Multi-provider LLM** — supports Ollama (free/local), Anthropic, OpenAI, and OpenRouter
70
- - **Smart fallback** — 20+ rule-based patterns work without any LLM (secrets detection, SQL injection, N+1 queries, and more)
71
- - **6 brain personalities** — mentor, critic, architect, security, performance, or balanced
72
- - **Auto-injection** — insights go directly into your agent's memory/rules files
73
- - **5 agent adapters** — works with Claude Code, Kilo Code, Cline, OpenCode, and Codex
74
- - **3 review depths** — quick (4K), standard (8K), deep (16K tokens)
75
-
76
- ---
77
-
78
- ## CLI Reference
79
-
80
- ### `shadow-brain start [project-dir]`
81
-
82
- Start watching a project with a live terminal dashboard.
83
-
84
- ```bash
85
- shadow-brain start . # Watch current directory
86
- shadow-brain start . -p anthropic -k $API_KEY # Use Anthropic
87
- shadow-brain start . --personality security # Security-focused
88
- shadow-brain start . --depth deep # Deep analysis
89
- shadow-brain start . --agents claude-code,codex # Watch specific agents
90
- ```
91
-
92
- | Option | Description |
93
- |--------|-------------|
94
- | `-p, --provider` | LLM provider: `anthropic`, `openai`, `ollama`, `openrouter` |
95
- | `-m, --model` | LLM model name |
96
- | `-k, --api-key` | API key |
97
- | `--personality` | Brain personality (see below) |
98
- | `--depth` | Review depth: `quick`, `standard`, `deep` |
99
- | `--agents` | Comma-separated agent list |
100
- | `--no-inject` | Disable auto-injection |
101
-
102
- ### `shadow-brain review [project-dir]`
103
-
104
- One-shot project analysis without watch mode.
105
-
106
- ```bash
107
- shadow-brain review . # Text output (default)
108
- shadow-brain review . --output json # JSON output
109
- shadow-brain review . --output markdown # Markdown output
110
- shadow-brain review . --depth deep # Thorough analysis
111
- ```
112
-
113
- ### `shadow-brain inject <message>`
114
-
115
- Manually inject a message into agent memory.
116
-
117
- ```bash
118
- shadow-brain inject "Always use TypeScript strict mode"
119
- shadow-brain inject "Check for SQL injection" --type warning --priority high
120
- shadow-brain inject "Follow REST conventions" --agent claude-code
121
- ```
122
-
123
- ### `shadow-brain status`
124
-
125
- Show current configuration and detected agents.
126
-
127
- ### `shadow-brain config`
128
-
129
- Manage persistent configuration.
130
-
131
- ```bash
132
- shadow-brain config --list
133
- shadow-brain config provider openai
134
- shadow-brain config apiKey sk-xxx
135
- shadow-brain config personality architect
136
- shadow-brain config --reset
137
- ```
138
-
139
- ### `shadow-brain setup`
140
-
141
- Interactive setup wizard for first-time configuration.
142
-
143
- ### `shadow-brain doctor`
144
-
145
- Health check — verifies config, tests provider connectivity, detects agents.
146
-
147
- ---
148
-
149
- ## Supported Agents
150
-
151
- | Agent | Detection | Injection Target |
152
- |-------|-----------|-----------------|
153
- | **Claude Code** | `.claude/` directory, process | `.claude/memory/`, `.claude/rules/` |
154
- | **Kilo Code** | VS Code extension data, `.kilocode/` | `.kilocode/rules/`, `.kilocode/memory/` |
155
- | **Cline** | VS Code extension data, `.clinerules` | `.clinerules`, `.cline/memory/` |
156
- | **OpenCode** | `.opencode/`, `opencode.json`, process | `.opencode/rules/`, `AGENTS.md` |
157
- | **Codex CLI** | `.codex/`, `AGENTS.md`, process | `AGENTS.md` |
158
-
159
- ---
160
-
161
- ## Brain Personalities
162
-
163
- <div align="center">
164
- <img src="docs/images/personalities.svg" alt="Brain Personalities" width="100%" />
165
- </div>
166
-
167
- | Personality | Focus |
168
- |------------|-------|
169
- | `mentor` | Teaches and explains — code quality, best practices, learning tips |
170
- | `critic` | Thorough code reviews — bugs, logic errors, edge cases, dead code |
171
- | `architect` | Big-picture thinking — modularity, scalability, design patterns |
172
- | `security` | Paranoid about vulnerabilities — OWASP top 10, injection attacks, secret leaks |
173
- | `performance` | Optimization focused — N+1 queries, memory leaks, bundle size |
174
- | `balanced` | Mix of all perspectives (default) |
175
-
176
- ---
177
-
178
- ## Rule-Based Detection Patterns
179
-
180
- Even without an LLM configured, Shadow Brain detects **20+ code patterns**:
181
-
182
- **Security:** hardcoded secrets, API keys, private keys, SQL injection, XSS (dangerouslySetInnerHTML), eval/Function usage, .env file changes, database credential exposure
183
-
184
- **Code Quality:** large batch changes, deleted files, code changes without tests, missing .gitignore, missing tsconfig.json, framework mismatches, excessive console.log
185
-
186
- **Performance:** N+1 query patterns, synchronous file I/O, async/await in loops
187
-
188
- **Architecture:** multiple config file changes, database migrations, infrastructure/deployment files, API endpoint changes, lock file drift
189
-
190
- ---
191
-
192
- ## LLM Providers
193
-
194
- | Provider | Setup | Cost |
195
- |----------|-------|------|
196
- | **Ollama** (default) | `ollama serve` + `ollama pull llama3` | Free, local |
197
- | **Anthropic** | Set API key via `shadow-brain config apiKey sk-...` | Pay per token |
198
- | **OpenAI** | Set provider + API key | Pay per token |
199
- | **OpenRouter** | Set provider + API key | Pay per token |
200
-
201
- ---
202
-
203
- ## Programmatic API
204
-
205
- ```typescript
206
- import { Orchestrator, createAdapter, LLMClient, Analyzer, PromptBuilder } from '@theihtisham/agent-shadow-brain';
207
-
208
- const orchestrator = new Orchestrator({
209
- provider: 'ollama',
210
- projectDir: '/path/to/project',
211
- agents: ['claude-code'],
212
- watchMode: true,
213
- autoInject: true,
214
- reviewDepth: 'standard',
215
- brainPersonality: 'balanced',
216
- });
217
-
218
- orchestrator.on('insights', ({ insights }) => {
219
- console.log('Generated insights:', insights);
220
- });
221
-
222
- await orchestrator.start();
223
- ```
224
-
225
- ---
226
-
227
- ## Contributing
228
-
229
- 1. Fork the repository
230
- 2. Create your feature branch: `git checkout -b feature/my-feature`
231
- 3. Commit your changes: `git commit -m 'Add my feature'`
232
- 4. Push to the branch: `git push origin feature/my-feature`
233
- 5. Open a Pull Request
234
-
235
- ## License
236
-
237
- [MIT](LICENSE) © 2025 theihtisham
1
+ # Agent Shadow Brain
2
+
3
+ A shadow AI brain that runs alongside Claude Code, Kilo Code, Cline, OpenCode, and Codex — watching, reviewing, and injecting intelligence in real-time.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @theihtisham/agent-shadow-brain
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```typescript
14
+ import { } from '@theihtisham/agent-shadow-brain';
15
+ ```
16
+
17
+ ## Features
18
+
19
+ - Written in TypeScript with full type definitions
20
+ - Zero external dependencies (minimal footprint)
21
+ - Event-driven architecture
22
+ - Comprehensive test suite
23
+
24
+ ## API
25
+
26
+ ### Quick Start
27
+
28
+ ```typescript
29
+ import { } from '@theihtisham/agent-shadow-brain';
30
+
31
+ // Initialize and use the package
32
+ ```
33
+
34
+ ## Configuration
35
+
36
+ Configuration options and their defaults:
37
+
38
+ ```typescript
39
+ const config = {
40
+ // Add configuration options here
41
+ };
42
+ ```
43
+
44
+ ## Examples
45
+
46
+ See the `tests/` directory for usage examples.
47
+
48
+ ## Development
49
+
50
+ ```bash
51
+ # Install dependencies
52
+ npm install
53
+
54
+ # Build
55
+ npm run build
56
+
57
+ # Run tests
58
+ npm test
59
+
60
+ # Lint
61
+ npm run lint
62
+ ```
63
+
64
+ ## License
65
+
66
+ MIT License - see [LICENSE](LICENSE) for details.
67
+
68
+ ## Author
69
+
70
+ **ihtisham**
71
+
72
+ - GitHub: [https://github.com/theihtisham](https://github.com/theihtisham)
73
+ - npm: [@theihtisham](https://www.npmjs.com/~theihtisham)
@@ -0,0 +1,9 @@
1
+ export interface UpdateCheck {
2
+ current: string;
3
+ latest: string;
4
+ hasUpdate: boolean;
5
+ changelog?: string;
6
+ }
7
+ export declare function checkForUpdate(): Promise<UpdateCheck>;
8
+ export declare function formatUpdateNotice(check: UpdateCheck): string;
9
+ //# sourceMappingURL=auto-update.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-update.d.ts","sourceRoot":"","sources":["../../src/brain/auto-update.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,WAAW,CAAC,CAwC3D;AAYD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAG7D"}
@@ -0,0 +1,59 @@
1
+ // src/brain/auto-update.ts — Check for Shadow Brain updates
2
+ import * as https from 'https';
3
+ const CURRENT_VERSION = '1.2.0';
4
+ const PACKAGE_NAME = '@theihtisham/agent-shadow-brain';
5
+ export async function checkForUpdate() {
6
+ return new Promise((resolve) => {
7
+ const options = {
8
+ hostname: 'registry.npmjs.org',
9
+ path: `/${PACKAGE_NAME}/latest`,
10
+ method: 'GET',
11
+ headers: { 'Accept': 'application/json' },
12
+ timeout: 5000,
13
+ };
14
+ const req = https.request(options, (res) => {
15
+ let data = '';
16
+ res.on('data', (chunk) => { data += chunk; });
17
+ res.on('end', () => {
18
+ try {
19
+ const pkg = JSON.parse(data);
20
+ const latest = pkg.version || CURRENT_VERSION;
21
+ resolve({
22
+ current: CURRENT_VERSION,
23
+ latest,
24
+ hasUpdate: compareVersions(latest, CURRENT_VERSION) > 0,
25
+ changelog: pkg.description,
26
+ });
27
+ }
28
+ catch {
29
+ resolve({ current: CURRENT_VERSION, latest: CURRENT_VERSION, hasUpdate: false });
30
+ }
31
+ });
32
+ });
33
+ req.on('error', () => {
34
+ resolve({ current: CURRENT_VERSION, latest: CURRENT_VERSION, hasUpdate: false });
35
+ });
36
+ req.on('timeout', () => {
37
+ req.destroy();
38
+ resolve({ current: CURRENT_VERSION, latest: CURRENT_VERSION, hasUpdate: false });
39
+ });
40
+ req.end();
41
+ });
42
+ }
43
+ function compareVersions(a, b) {
44
+ const pa = a.split('.').map(Number);
45
+ const pb = b.split('.').map(Number);
46
+ for (let i = 0; i < 3; i++) {
47
+ if ((pa[i] || 0) > (pb[i] || 0))
48
+ return 1;
49
+ if ((pa[i] || 0) < (pb[i] || 0))
50
+ return -1;
51
+ }
52
+ return 0;
53
+ }
54
+ export function formatUpdateNotice(check) {
55
+ if (!check.hasUpdate)
56
+ return '';
57
+ return `\n A new version of Shadow Brain is available: ${check.latest} (current: ${check.current})\n Update: npm i -g ${PACKAGE_NAME}@latest\n`;
58
+ }
59
+ //# sourceMappingURL=auto-update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-update.js","sourceRoot":"","sources":["../../src/brain/auto-update.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import { CodeMetrics, FileChange } from '../types.js';
2
+ export declare class CodeMetricsEngine {
3
+ private projectDir;
4
+ private excludePaths;
5
+ private complexityThreshold;
6
+ constructor(projectDir: string, opts?: {
7
+ excludePaths?: string[];
8
+ complexityThreshold?: number;
9
+ });
10
+ compute(changes?: FileChange[]): CodeMetrics;
11
+ private walkDir;
12
+ private estimateComplexity;
13
+ private countFunctions;
14
+ formatConsole(metrics: CodeMetrics): string;
15
+ formatJSON(metrics: CodeMetrics): string;
16
+ toMarkdown(metrics: CodeMetrics): string;
17
+ }
18
+ //# sourceMappingURL=code-metrics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-metrics.d.ts","sourceRoot":"","sources":["../../src/brain/code-metrics.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAqBtD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,YAAY,CAAW;IAC/B,OAAO,CAAC,mBAAmB,CAAS;gBAExB,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,mBAAmB,CAAC,EAAE,MAAM,CAAA;KAAE;IAMhG,OAAO,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,GAAG,WAAW;IAwF5C,OAAO,CAAC,OAAO;IA+Bf,OAAO,CAAC,kBAAkB;IAe1B,OAAO,CAAC,cAAc;IAmBtB,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM;IAmC3C,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM;IAIxC,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM;CAuBzC"}
@@ -0,0 +1,224 @@
1
+ // src/brain/code-metrics.ts — Code metrics: LOC, complexity, language breakdown, churn
2
+ import * as fs from 'fs';
3
+ import * as path from 'path';
4
+ const LANGUAGE_MAP = {
5
+ '.ts': 'TypeScript', '.tsx': 'TypeScript', '.js': 'JavaScript', '.jsx': 'JavaScript',
6
+ '.py': 'Python', '.rb': 'Ruby', '.go': 'Go', '.rs': 'Rust', '.java': 'Java',
7
+ '.kt': 'Kotlin', '.swift': 'Swift', '.c': 'C', '.cpp': 'C++', '.h': 'C/C++',
8
+ '.cs': 'C#', '.php': 'PHP', '.scala': 'Scala', '.r': 'R', '.sql': 'SQL',
9
+ '.sh': 'Shell', '.bash': 'Shell', '.ps1': 'PowerShell',
10
+ '.html': 'HTML', '.css': 'CSS', '.scss': 'SCSS', '.less': 'LESS',
11
+ '.json': 'JSON', '.yaml': 'YAML', '.yml': 'YAML', '.toml': 'TOML',
12
+ '.md': 'Markdown', '.vue': 'Vue', '.svelte': 'Svelte',
13
+ };
14
+ const IGNORE_DIRS = new Set([
15
+ 'node_modules', '.git', 'dist', 'build', 'out', 'target', 'vendor',
16
+ '__pycache__', '.next', '.nuxt', 'coverage', '.cache', '.tox',
17
+ 'venv', '.venv', 'env', '.env', 'bin', 'obj', 'Pods', '.gradle',
18
+ ]);
19
+ export class CodeMetricsEngine {
20
+ constructor(projectDir, opts) {
21
+ this.projectDir = projectDir;
22
+ this.excludePaths = opts?.excludePaths || [];
23
+ this.complexityThreshold = opts?.complexityThreshold || 15;
24
+ }
25
+ compute(changes) {
26
+ const files = this.walkDir(this.projectDir);
27
+ const languages = {};
28
+ const fileTypes = {};
29
+ const largestFiles = [];
30
+ const complexityHotspots = [];
31
+ let totalLines = 0;
32
+ let codeLines = 0;
33
+ let commentLines = 0;
34
+ let blankLines = 0;
35
+ for (const filePath of files) {
36
+ const ext = path.extname(filePath);
37
+ const lang = LANGUAGE_MAP[ext] || 'Other';
38
+ const relPath = path.relative(this.projectDir, filePath);
39
+ fileTypes[ext] = (fileTypes[ext] || 0) + 1;
40
+ try {
41
+ const content = fs.readFileSync(filePath, 'utf-8');
42
+ const lines = content.split('\n');
43
+ const lineCount = lines.length;
44
+ // Classify lines
45
+ let fileCodeLines = 0;
46
+ let fileCommentLines = 0;
47
+ let fileBlankLines = 0;
48
+ for (const line of lines) {
49
+ const trimmed = line.trim();
50
+ if (trimmed === '') {
51
+ fileBlankLines++;
52
+ continue;
53
+ }
54
+ if (trimmed.startsWith('//') || trimmed.startsWith('#') || trimmed.startsWith('/*') ||
55
+ trimmed.startsWith('*') || trimmed.startsWith('"""') || trimmed.startsWith("'''")) {
56
+ fileCommentLines++;
57
+ }
58
+ else {
59
+ fileCodeLines++;
60
+ }
61
+ }
62
+ totalLines += lineCount;
63
+ codeLines += fileCodeLines;
64
+ commentLines += fileCommentLines;
65
+ blankLines += fileBlankLines;
66
+ // Track language stats
67
+ if (!languages[lang])
68
+ languages[lang] = { files: 0, lines: 0, percentage: 0 };
69
+ languages[lang].files++;
70
+ languages[lang].lines += lineCount;
71
+ // Track largest files
72
+ largestFiles.push({ path: relPath, lines: lineCount });
73
+ // Estimate complexity for code files
74
+ if (['.ts', '.tsx', '.js', '.jsx', '.py', '.go', '.java', '.rs'].includes(ext)) {
75
+ const complexity = this.estimateComplexity(content);
76
+ const functions = this.countFunctions(content);
77
+ if (complexity >= this.complexityThreshold) {
78
+ complexityHotspots.push({ path: relPath, complexity, functions });
79
+ }
80
+ }
81
+ }
82
+ catch { /* binary or unreadable file */ }
83
+ }
84
+ // Calculate percentages
85
+ for (const lang of Object.values(languages)) {
86
+ lang.percentage = totalLines > 0 ? Math.round((lang.lines / totalLines) * 100) : 0;
87
+ }
88
+ // Sort largest files
89
+ largestFiles.sort((a, b) => b.lines - a.lines);
90
+ complexityHotspots.sort((a, b) => b.complexity - a.complexity);
91
+ return {
92
+ totalFiles: files.length,
93
+ totalLines,
94
+ codeLines,
95
+ commentLines,
96
+ blankLines,
97
+ languages,
98
+ largestFiles: largestFiles.slice(0, 20),
99
+ complexityHotspots: complexityHotspots.slice(0, 10),
100
+ fileTypes,
101
+ avgFileSize: files.length > 0 ? Math.round(totalLines / files.length) : 0,
102
+ timestamp: new Date(),
103
+ };
104
+ }
105
+ walkDir(dir, depth = 0) {
106
+ if (depth > 6)
107
+ return [];
108
+ const files = [];
109
+ try {
110
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
111
+ for (const entry of entries) {
112
+ if (entry.name.startsWith('.') && entry.name !== '.env.example')
113
+ continue;
114
+ const fullPath = path.join(dir, entry.name);
115
+ if (entry.isDirectory()) {
116
+ if (IGNORE_DIRS.has(entry.name))
117
+ continue;
118
+ if (this.excludePaths.some(p => fullPath.includes(p)))
119
+ continue;
120
+ files.push(...this.walkDir(fullPath, depth + 1));
121
+ }
122
+ else if (entry.isFile()) {
123
+ // Skip binary files
124
+ const ext = path.extname(entry.name);
125
+ if (['.png', '.jpg', '.jpeg', '.gif', '.ico', '.svg', '.woff', '.woff2',
126
+ '.ttf', '.eot', '.mp3', '.mp4', '.zip', '.gz', '.tar', '.exe',
127
+ '.dll', '.so', '.dylib', '.pyc', '.class', '.o', '.obj'].includes(ext)) {
128
+ continue;
129
+ }
130
+ files.push(fullPath);
131
+ }
132
+ }
133
+ }
134
+ catch { /* permission error */ }
135
+ return files;
136
+ }
137
+ estimateComplexity(content) {
138
+ // Cyclomatic complexity estimation: count decision points
139
+ const decisionPatterns = [
140
+ /\bif\b/g, /\belse\b/g, /\bfor\b/g, /\bwhile\b/g,
141
+ /\bcase\b/g, /\bcatch\b/g, /&&/g, /\|\|/g, /\?\?/g,
142
+ /\?\./g, /\bawait\b/g,
143
+ ];
144
+ let complexity = 1;
145
+ for (const pattern of decisionPatterns) {
146
+ const matches = content.match(pattern);
147
+ if (matches)
148
+ complexity += matches.length;
149
+ }
150
+ return complexity;
151
+ }
152
+ countFunctions(content) {
153
+ const patterns = [
154
+ /function\s+\w+/g,
155
+ /const\s+\w+\s*=\s*(?:async\s+)?(?:\([^)]*\)|[^=])\s*=>/g,
156
+ /(?:async\s+)?\w+\s*\([^)]*\)\s*:\s*\w+/g,
157
+ /def\s+\w+/g,
158
+ /func\s+\w+/g,
159
+ /fn\s+\w+/g,
160
+ /public\s+\w+\s+\w+\s*\(/g,
161
+ /private\s+\w+\s+\w+\s*\(/g,
162
+ ];
163
+ let count = 0;
164
+ for (const pattern of patterns) {
165
+ const matches = content.match(pattern);
166
+ if (matches)
167
+ count += matches.length;
168
+ }
169
+ return count;
170
+ }
171
+ formatConsole(metrics) {
172
+ let out = `\n Code Metrics — ${metrics.totalFiles} files, ${metrics.totalLines.toLocaleString()} lines\n`;
173
+ out += ` ${'─'.repeat(55)}\n\n`;
174
+ out += ` Code: ${metrics.codeLines.toLocaleString().padStart(8)} lines\n`;
175
+ out += ` Comments: ${metrics.commentLines.toLocaleString().padStart(8)} lines\n`;
176
+ out += ` Blank: ${metrics.blankLines.toLocaleString().padStart(8)} lines\n`;
177
+ out += ` Avg/ file: ${metrics.avgFileSize.toLocaleString().padStart(8)} lines\n`;
178
+ out += `\n Languages:\n`;
179
+ const sortedLangs = Object.entries(metrics.languages)
180
+ .sort((a, b) => b[1].lines - a[1].lines)
181
+ .slice(0, 8);
182
+ for (const [lang, data] of sortedLangs) {
183
+ const bar = '█'.repeat(Math.round(data.percentage / 5)) + '░'.repeat(Math.max(0, 20 - Math.round(data.percentage / 5)));
184
+ out += ` ${lang.padEnd(12)} ${bar} ${data.percentage}% (${data.files} files)\n`;
185
+ }
186
+ if (metrics.largestFiles.length > 0) {
187
+ out += `\n Largest files:\n`;
188
+ for (const f of metrics.largestFiles.slice(0, 5)) {
189
+ out += ` ${f.lines.toLocaleString().padStart(6)} lines ${f.path}\n`;
190
+ }
191
+ }
192
+ if (metrics.complexityHotspots.length > 0) {
193
+ out += `\n Complexity hotspots (>${this.complexityThreshold}):\n`;
194
+ for (const f of metrics.complexityHotspots.slice(0, 5)) {
195
+ out += ` complexity ${String(f.complexity).padStart(4)} ${f.functions} functions ${f.path}\n`;
196
+ }
197
+ }
198
+ return out;
199
+ }
200
+ formatJSON(metrics) {
201
+ return JSON.stringify(metrics, null, 2);
202
+ }
203
+ toMarkdown(metrics) {
204
+ let md = `# Code Metrics\n\n`;
205
+ md += `| Metric | Value |\n|---|---|\n`;
206
+ md += `| Total files | ${metrics.totalFiles} |\n`;
207
+ md += `| Total lines | ${metrics.totalLines.toLocaleString()} |\n`;
208
+ md += `| Code lines | ${metrics.codeLines.toLocaleString()} |\n`;
209
+ md += `| Comment lines | ${metrics.commentLines.toLocaleString()} |\n`;
210
+ md += `| Avg file size | ${metrics.avgFileSize} lines |\n\n`;
211
+ md += `## Languages\n\n| Language | Files | Lines | % |\n|---|---|---|---|\n`;
212
+ for (const [lang, data] of Object.entries(metrics.languages).sort((a, b) => b[1].lines - a[1].lines).slice(0, 10)) {
213
+ md += `| ${lang} | ${data.files} | ${data.lines.toLocaleString()} | ${data.percentage}% |\n`;
214
+ }
215
+ if (metrics.complexityHotspots.length > 0) {
216
+ md += `\n## Complexity Hotspots\n\n| File | Complexity | Functions |\n|---|---|---|\n`;
217
+ for (const f of metrics.complexityHotspots) {
218
+ md += `| ${f.path} | ${f.complexity} | ${f.functions} |\n`;
219
+ }
220
+ }
221
+ return md;
222
+ }
223
+ }
224
+ //# sourceMappingURL=code-metrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-metrics.js","sourceRoot":"","sources":["../../src/brain/code-metrics.ts"],"names":[],"mappings":"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"}