@theihtisham/agent-shadow-brain 1.1.0 → 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.
- package/README.md +73 -237
- package/dist/brain/auto-update.d.ts +9 -0
- package/dist/brain/auto-update.d.ts.map +1 -0
- package/dist/brain/auto-update.js +59 -0
- package/dist/brain/auto-update.js.map +1 -0
- package/dist/brain/code-metrics.d.ts +18 -0
- package/dist/brain/code-metrics.d.ts.map +1 -0
- package/dist/brain/code-metrics.js +224 -0
- package/dist/brain/code-metrics.js.map +1 -0
- package/dist/brain/custom-rules.d.ts +14 -0
- package/dist/brain/custom-rules.d.ts.map +1 -0
- package/dist/brain/custom-rules.js +108 -0
- package/dist/brain/custom-rules.js.map +1 -0
- package/dist/brain/framework-presets.d.ts +34 -0
- package/dist/brain/framework-presets.d.ts.map +1 -0
- package/dist/brain/framework-presets.js +556 -0
- package/dist/brain/framework-presets.js.map +1 -0
- package/dist/brain/health-score.d.ts +42 -0
- package/dist/brain/health-score.d.ts.map +1 -0
- package/dist/brain/health-score.js +257 -0
- package/dist/brain/health-score.js.map +1 -0
- package/dist/brain/notifier.d.ts +26 -0
- package/dist/brain/notifier.d.ts.map +1 -0
- package/dist/brain/notifier.js +151 -0
- package/dist/brain/notifier.js.map +1 -0
- package/dist/brain/orchestrator.d.ts +64 -1
- package/dist/brain/orchestrator.d.ts.map +1 -1
- package/dist/brain/orchestrator.js +239 -3
- package/dist/brain/orchestrator.js.map +1 -1
- package/dist/brain/pr-generator.d.ts +19 -0
- package/dist/brain/pr-generator.d.ts.map +1 -0
- package/dist/brain/pr-generator.js +199 -0
- package/dist/brain/pr-generator.js.map +1 -0
- package/dist/brain/project-config.d.ts +14 -0
- package/dist/brain/project-config.d.ts.map +1 -0
- package/dist/brain/project-config.js +121 -0
- package/dist/brain/project-config.js.map +1 -0
- package/dist/brain/report-generator.d.ts +20 -0
- package/dist/brain/report-generator.d.ts.map +1 -0
- package/dist/brain/report-generator.js +386 -0
- package/dist/brain/report-generator.js.map +1 -0
- package/dist/brain/smart-fix.d.ts +24 -0
- package/dist/brain/smart-fix.d.ts.map +1 -0
- package/dist/brain/smart-fix.js +276 -0
- package/dist/brain/smart-fix.js.map +1 -0
- package/dist/brain/vuln-scanner.d.ts +16 -0
- package/dist/brain/vuln-scanner.d.ts.map +1 -0
- package/dist/brain/vuln-scanner.js +279 -0
- package/dist/brain/vuln-scanner.js.map +1 -0
- package/dist/cli.js +560 -57
- package/dist/cli.js.map +1 -1
- package/dist/dashboard/server.d.ts +22 -0
- package/dist/dashboard/server.d.ts.map +1 -0
- package/dist/dashboard/server.js +502 -0
- package/dist/dashboard/server.js.map +1 -0
- package/dist/index.d.ts +19 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -1
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +92 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +88 -77
package/README.md
CHANGED
|
@@ -1,237 +1,73 @@
|
|
|
1
|
-
# Agent Shadow Brain
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
-
|
|
73
|
-
-
|
|
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":"AAAA,uFAAuF;AAGvF,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,MAAM,YAAY,GAA2B;IAC3C,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY;IACpF,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAC3E,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO;IAC3E,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK;IACvE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY;IACtD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAChE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IACjE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ;CACtD,CAAC;AAEF,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC;IAC1B,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ;IAClE,aAAa,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM;IAC7D,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS;CAChE,CAAC,CAAC;AAEH,MAAM,OAAO,iBAAiB;IAK5B,YAAY,UAAkB,EAAE,IAAgE;QAC9F,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,YAAY,GAAG,IAAI,EAAE,YAAY,IAAI,EAAE,CAAC;QAC7C,IAAI,CAAC,mBAAmB,GAAG,IAAI,EAAE,mBAAmB,IAAI,EAAE,CAAC;IAC7D,CAAC;IAED,OAAO,CAAC,OAAsB;QAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5C,MAAM,SAAS,GAAyE,EAAE,CAAC;QAC3F,MAAM,SAAS,GAA2B,EAAE,CAAC;QAC7C,MAAM,YAAY,GAA2C,EAAE,CAAC;QAChE,MAAM,kBAAkB,GAAmE,EAAE,CAAC;QAE9F,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,IAAI,UAAU,GAAG,CAAC,CAAC;QAEnB,KAAK,MAAM,QAAQ,IAAI,KAAK,EAAE,CAAC;YAC7B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YACnC,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC;YAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;YAEzD,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YAE3C,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;gBACnD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAClC,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC;gBAE/B,iBAAiB;gBACjB,IAAI,aAAa,GAAG,CAAC,CAAC;gBACtB,IAAI,gBAAgB,GAAG,CAAC,CAAC;gBACzB,IAAI,cAAc,GAAG,CAAC,CAAC;gBAEvB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;oBACzB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;oBAC5B,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC;wBAAC,cAAc,EAAE,CAAC;wBAAC,SAAS;oBAAC,CAAC;oBACnD,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC;wBAC/E,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;wBACtF,gBAAgB,EAAE,CAAC;oBACrB,CAAC;yBAAM,CAAC;wBACN,aAAa,EAAE,CAAC;oBAClB,CAAC;gBACH,CAAC;gBAED,UAAU,IAAI,SAAS,CAAC;gBACxB,SAAS,IAAI,aAAa,CAAC;gBAC3B,YAAY,IAAI,gBAAgB,CAAC;gBACjC,UAAU,IAAI,cAAc,CAAC;gBAE7B,uBAAuB;gBACvB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;oBAAE,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;gBAC9E,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;gBACxB,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,SAAS,CAAC;gBAEnC,sBAAsB;gBACtB,YAAY,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;gBAEvD,qCAAqC;gBACrC,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;oBAC/E,MAAM,UAAU,GAAG,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;oBACpD,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;oBAC/C,IAAI,UAAU,IAAI,IAAI,CAAC,mBAAmB,EAAE,CAAC;wBAC3C,kBAAkB,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC;oBACpE,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,MAAM,CAAC,CAAC,+BAA+B,CAAC,CAAC;QAC7C,CAAC;QAED,wBAAwB;QACxB,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;YAC5C,IAAI,CAAC,UAAU,GAAG,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACrF,CAAC;QAED,qBAAqB;QACrB,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;QAC/C,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC;QAE/D,OAAO;YACL,UAAU,EAAE,KAAK,CAAC,MAAM;YACxB,UAAU;YACV,SAAS;YACT,YAAY;YACZ,UAAU;YACV,SAAS;YACT,YAAY,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;YACvC,kBAAkB,EAAE,kBAAkB,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;YACnD,SAAS;YACT,WAAW,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YACzE,SAAS,EAAE,IAAI,IAAI,EAAE;SACtB,CAAC;IACJ,CAAC;IAEO,OAAO,CAAC,GAAW,EAAE,KAAK,GAAG,CAAC;QACpC,IAAI,KAAK,GAAG,CAAC;YAAE,OAAO,EAAE,CAAC;QACzB,MAAM,KAAK,GAAa,EAAE,CAAC;QAE3B,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;YAC7D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAC5B,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc;oBAAE,SAAS;gBAE1E,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;gBAE5C,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;oBACxB,IAAI,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;wBAAE,SAAS;oBAC1C,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;wBAAE,SAAS;oBAChE,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;gBACnD,CAAC;qBAAM,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;oBAC1B,oBAAoB;oBACpB,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;oBACrC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ;wBAClE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM;wBAC7D,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;wBAC5E,SAAS;oBACX,CAAC;oBACD,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBACvB,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC;QAElC,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,kBAAkB,CAAC,OAAe;QACxC,0DAA0D;QAC1D,MAAM,gBAAgB,GAAG;YACvB,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY;YAChD,WAAW,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO;YAClD,OAAO,EAAE,YAAY;SACtB,CAAC;QACF,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,KAAK,MAAM,OAAO,IAAI,gBAAgB,EAAE,CAAC;YACvC,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACvC,IAAI,OAAO;gBAAE,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;QAC5C,CAAC;QACD,OAAO,UAAU,CAAC;IACpB,CAAC;IAEO,cAAc,CAAC,OAAe;QACpC,MAAM,QAAQ,GAAG;YACf,iBAAiB;YACjB,yDAAyD;YACzD,yCAAyC;YACzC,YAAY;YACZ,aAAa;YACb,WAAW;YACX,0BAA0B;YAC1B,2BAA2B;SAC5B,CAAC;QACF,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACvC,IAAI,OAAO;gBAAE,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;QACvC,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,aAAa,CAAC,OAAoB;QAChC,IAAI,GAAG,GAAG,sBAAsB,OAAO,CAAC,UAAU,WAAW,OAAO,CAAC,UAAU,CAAC,cAAc,EAAE,UAAU,CAAC;QAC3G,GAAG,IAAI,KAAK,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC;QAEjC,GAAG,IAAI,iBAAiB,OAAO,CAAC,SAAS,CAAC,cAAc,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC;QACjF,GAAG,IAAI,iBAAiB,OAAO,CAAC,YAAY,CAAC,cAAc,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC;QACpF,GAAG,IAAI,iBAAiB,OAAO,CAAC,UAAU,CAAC,cAAc,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC;QAClF,GAAG,IAAI,iBAAiB,OAAO,CAAC,WAAW,CAAC,cAAc,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC;QAEnF,GAAG,IAAI,kBAAkB,CAAC;QAC1B,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC;aAClD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;aACvC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACf,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,WAAW,EAAE,CAAC;YACvC,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACxH,GAAG,IAAI,OAAO,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,GAAG,IAAI,IAAI,CAAC,UAAU,MAAM,IAAI,CAAC,KAAK,WAAW,CAAC;QACrF,CAAC;QAED,IAAI,OAAO,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpC,GAAG,IAAI,sBAAsB,CAAC;YAC9B,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;gBACjD,GAAG,IAAI,OAAO,CAAC,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,IAAI,CAAC;YAC1E,CAAC;QACH,CAAC;QAED,IAAI,OAAO,CAAC,kBAAkB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1C,GAAG,IAAI,6BAA6B,IAAI,CAAC,mBAAmB,MAAM,CAAC;YACnE,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;gBACvD,GAAG,IAAI,kBAAkB,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,eAAe,CAAC,CAAC,IAAI,IAAI,CAAC;YACrG,CAAC;QACH,CAAC;QAED,OAAO,GAAG,CAAC;IACb,CAAC;IAED,UAAU,CAAC,OAAoB;QAC7B,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC1C,CAAC;IAED,UAAU,CAAC,OAAoB;QAC7B,IAAI,EAAE,GAAG,oBAAoB,CAAC;QAC9B,EAAE,IAAI,iCAAiC,CAAC;QACxC,EAAE,IAAI,mBAAmB,OAAO,CAAC,UAAU,MAAM,CAAC;QAClD,EAAE,IAAI,mBAAmB,OAAO,CAAC,UAAU,CAAC,cAAc,EAAE,MAAM,CAAC;QACnE,EAAE,IAAI,kBAAkB,OAAO,CAAC,SAAS,CAAC,cAAc,EAAE,MAAM,CAAC;QACjE,EAAE,IAAI,qBAAqB,OAAO,CAAC,YAAY,CAAC,cAAc,EAAE,MAAM,CAAC;QACvE,EAAE,IAAI,qBAAqB,OAAO,CAAC,WAAW,cAAc,CAAC;QAE7D,EAAE,IAAI,uEAAuE,CAAC;QAC9E,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;YAClH,EAAE,IAAI,KAAK,IAAI,MAAM,IAAI,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,MAAM,IAAI,CAAC,UAAU,OAAO,CAAC;QAC/F,CAAC;QAED,IAAI,OAAO,CAAC,kBAAkB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1C,EAAE,IAAI,gFAAgF,CAAC;YACvF,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC;gBAC3C,EAAE,IAAI,KAAK,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,UAAU,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC;YAC7D,CAAC;QACH,CAAC;QAED,OAAO,EAAE,CAAC;IACZ,CAAC;CACF"}
|