@boshu2/vibe-check 2.3.0 → 2.4.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/.agents/plans/2025-12-29-complexity-driver-plan.md +225 -0
- package/.agents/plans/2025-12-29-complexity-drivers-plan.md +253 -0
- package/.agents/research/2025-12-29-complexity-driver-architecture.md +392 -0
- package/.agents/research/2025-12-29-complexity-drivers.md +227 -0
- package/.beads/issues.jsonl +12 -0
- package/CHANGELOG.md +27 -0
- package/README.md +71 -0
- package/dist/analyzers/complexity.d.ts +92 -0
- package/dist/analyzers/complexity.d.ts.map +1 -0
- package/dist/analyzers/complexity.js +79 -0
- package/dist/analyzers/complexity.js.map +1 -0
- package/dist/analyzers/modularity.d.ts +3 -1
- package/dist/analyzers/modularity.d.ts.map +1 -1
- package/dist/analyzers/modularity.js +32 -6
- package/dist/analyzers/modularity.js.map +1 -1
- package/dist/cli.js +2 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/driver.d.ts +18 -0
- package/dist/commands/driver.d.ts.map +1 -0
- package/dist/commands/driver.js +58 -0
- package/dist/commands/driver.js.map +1 -0
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +1 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/modularity.d.ts +2 -0
- package/dist/commands/modularity.d.ts.map +1 -1
- package/dist/commands/modularity.js +86 -7
- package/dist/commands/modularity.js.map +1 -1
- package/drivers/README.md +327 -0
- package/drivers/go.sh +131 -0
- package/drivers/java.sh +137 -0
- package/drivers/javascript.sh +134 -0
- package/drivers/php.sh +132 -0
- package/drivers/python.sh +90 -0
- package/drivers/rust.sh +132 -0
- package/package.json +1 -1
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
---
|
|
2
|
+
date: 2025-12-29
|
|
3
|
+
type: Research
|
|
4
|
+
topic: "Complexity Driver Architecture - Language-Agnostic Tool Integration"
|
|
5
|
+
tags: [research, architecture, complexity]
|
|
6
|
+
status: COMPLETE
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Research: Complexity Driver Architecture
|
|
10
|
+
|
|
11
|
+
**Created:** 2025-12-29
|
|
12
|
+
**Goal:** Design a plugin/driver system for language-specific complexity tools
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Executive Summary
|
|
17
|
+
|
|
18
|
+
vibe-check should remain language-agnostic while being able to incorporate complexity metrics from language-specific tools. This research proposes a "driver" architecture (similar to Linux device drivers) where thin wrapper scripts normalize output from various tools into a standard JSON schema.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Problem Statement
|
|
23
|
+
|
|
24
|
+
The modularity analyzer (`src/analyzers/modularity.ts`) currently uses heuristics like line count and pattern detection. Testing on a real codebase revealed:
|
|
25
|
+
|
|
26
|
+
| File | Lines | vibe-check Says | Actual Complexity (radon) |
|
|
27
|
+
|------|-------|-----------------|---------------------------|
|
|
28
|
+
| neo4j_store.py | 1,366 | "Too large" | Grade A (2.4) - FINE |
|
|
29
|
+
| sync.py | 1,117 | "Too large" | Grade C (17.7) - PROBLEM |
|
|
30
|
+
|
|
31
|
+
**Line count is a poor proxy.** A 1,000-line file of simple methods is fine; a 200-line file with nested conditionals is a nightmare.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Existing Complexity Tools by Language
|
|
36
|
+
|
|
37
|
+
| Language | Tool | Output Format | Installation |
|
|
38
|
+
|----------|------|---------------|--------------|
|
|
39
|
+
| **Python** | `radon` | JSON (`-j`) | `pip install radon` |
|
|
40
|
+
| **Python** | `xenon` | Exit codes + text | `pip install xenon` |
|
|
41
|
+
| **JS/TS** | `complexity-report` | JSON | `npm install complexity-report` |
|
|
42
|
+
| **JS/TS** | `es6-plato` | HTML/JSON | `npm install es6-plato` |
|
|
43
|
+
| **Go** | `gocyclo` | JSON (`-json`) | `go install github.com/fzipp/gocyclo` |
|
|
44
|
+
| **Go** | `gocognit` | Text | `go install github.com/uudashr/gocognit` |
|
|
45
|
+
| **Java** | `pmd` | XML/JSON | Download from PMD site |
|
|
46
|
+
| **C/C++** | `lizard` | JSON/CSV | `pip install lizard` |
|
|
47
|
+
| **Rust** | `cargo clippy` | Text (lint) | Built into Cargo |
|
|
48
|
+
| **Ruby** | `flog` | Text | `gem install flog` |
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Proposed Architecture
|
|
53
|
+
|
|
54
|
+
### Mental Model: Linux Driver Architecture
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
58
|
+
│ vibe-check (kernel) │
|
|
59
|
+
│ ─────────────────── │
|
|
60
|
+
│ • Git pattern analysis (existing) │
|
|
61
|
+
│ • Session detection (existing) │
|
|
62
|
+
│ • AI failure patterns (existing) │
|
|
63
|
+
│ • Modularity scoring (existing) │
|
|
64
|
+
│ • NEW: Reads .vibe-check/complexity.json if present │
|
|
65
|
+
│ • NEW: Merges complexity into modularity score │
|
|
66
|
+
└─────────────────────────────────────────────────────────────┘
|
|
67
|
+
▲
|
|
68
|
+
│ Standard JSON schema
|
|
69
|
+
│
|
|
70
|
+
┌─────────────────────┼─────────────────────┐
|
|
71
|
+
│ │ │
|
|
72
|
+
▼ ▼ ▼
|
|
73
|
+
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
|
|
74
|
+
│ driver-python │ │ driver-js │ │ driver-go │
|
|
75
|
+
│ ───────────── │ │ ───────────── │ │ ───────────── │
|
|
76
|
+
│ Wraps: radon │ │ Wraps: │ │ Wraps: │
|
|
77
|
+
│ Output: JSON │ │ complexity- │ │ gocyclo │
|
|
78
|
+
│ │ │ report │ │ │
|
|
79
|
+
└───────────────┘ └───────────────┘ └───────────────┘
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Standard Complexity Schema
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
interface ComplexityReport {
|
|
86
|
+
// Metadata
|
|
87
|
+
tool: string; // "radon", "complexity-report", "gocyclo"
|
|
88
|
+
language: string; // "python", "javascript", "go"
|
|
89
|
+
generatedAt: string; // ISO timestamp
|
|
90
|
+
|
|
91
|
+
// Per-file metrics
|
|
92
|
+
files: {
|
|
93
|
+
[filepath: string]: {
|
|
94
|
+
functions: FunctionComplexity[];
|
|
95
|
+
avgComplexity: number;
|
|
96
|
+
maxComplexity: number;
|
|
97
|
+
grade: 'A' | 'B' | 'C' | 'D' | 'E' | 'F';
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// Summary
|
|
102
|
+
summary: {
|
|
103
|
+
totalFiles: number;
|
|
104
|
+
totalFunctions: number;
|
|
105
|
+
avgComplexity: number;
|
|
106
|
+
gradeDistribution: Record<string, number>;
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
interface FunctionComplexity {
|
|
111
|
+
name: string;
|
|
112
|
+
complexity: number;
|
|
113
|
+
grade: 'A' | 'B' | 'C' | 'D' | 'E' | 'F';
|
|
114
|
+
line: number;
|
|
115
|
+
endLine?: number;
|
|
116
|
+
isMethod?: boolean;
|
|
117
|
+
className?: string;
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Grade Thresholds (Standardized)
|
|
122
|
+
|
|
123
|
+
All drivers should normalize to these grades:
|
|
124
|
+
|
|
125
|
+
| Grade | Complexity | Meaning |
|
|
126
|
+
|-------|------------|---------|
|
|
127
|
+
| A | 1-5 | Simple, low risk |
|
|
128
|
+
| B | 6-10 | Slightly complex, acceptable |
|
|
129
|
+
| C | 11-20 | Complex, consider refactoring |
|
|
130
|
+
| D | 21-30 | Very complex, refactor |
|
|
131
|
+
| E | 31-40 | Extremely complex, high risk |
|
|
132
|
+
| F | 41+ | Unmaintainable, must refactor |
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Driver Implementation
|
|
137
|
+
|
|
138
|
+
### Driver Contract
|
|
139
|
+
|
|
140
|
+
Each driver is a script that:
|
|
141
|
+
1. Takes a directory path as input
|
|
142
|
+
2. Runs the language-specific tool
|
|
143
|
+
3. Outputs JSON conforming to the standard schema
|
|
144
|
+
4. Exits 0 on success, non-zero on failure
|
|
145
|
+
|
|
146
|
+
### Example: Python Driver
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
#!/bin/bash
|
|
150
|
+
# drivers/python.sh
|
|
151
|
+
# Wraps radon to produce standard complexity JSON
|
|
152
|
+
|
|
153
|
+
set -euo pipefail
|
|
154
|
+
|
|
155
|
+
TARGET_DIR="${1:-.}"
|
|
156
|
+
|
|
157
|
+
# Check radon is installed
|
|
158
|
+
if ! command -v radon &> /dev/null; then
|
|
159
|
+
echo '{"error": "radon not installed. Run: pip install radon"}' >&2
|
|
160
|
+
exit 1
|
|
161
|
+
fi
|
|
162
|
+
|
|
163
|
+
# Run radon and transform output
|
|
164
|
+
radon cc "$TARGET_DIR" -j --total-average | jq '
|
|
165
|
+
{
|
|
166
|
+
tool: "radon",
|
|
167
|
+
language: "python",
|
|
168
|
+
generatedAt: (now | todate),
|
|
169
|
+
files: (to_entries | map({
|
|
170
|
+
key: .key,
|
|
171
|
+
value: {
|
|
172
|
+
functions: (.value | map({
|
|
173
|
+
name: .name,
|
|
174
|
+
complexity: .complexity,
|
|
175
|
+
grade: .rank,
|
|
176
|
+
line: .lineno,
|
|
177
|
+
endLine: .endline,
|
|
178
|
+
isMethod: .is_method,
|
|
179
|
+
className: .classname
|
|
180
|
+
})),
|
|
181
|
+
avgComplexity: ((.value | map(.complexity) | add) / (.value | length)),
|
|
182
|
+
maxComplexity: (.value | map(.complexity) | max),
|
|
183
|
+
grade: (
|
|
184
|
+
((.value | map(.complexity) | add) / (.value | length)) |
|
|
185
|
+
if . <= 5 then "A"
|
|
186
|
+
elif . <= 10 then "B"
|
|
187
|
+
elif . <= 20 then "C"
|
|
188
|
+
elif . <= 30 then "D"
|
|
189
|
+
elif . <= 40 then "E"
|
|
190
|
+
else "F"
|
|
191
|
+
end
|
|
192
|
+
)
|
|
193
|
+
}
|
|
194
|
+
}) | from_entries),
|
|
195
|
+
summary: {
|
|
196
|
+
totalFiles: (keys | length),
|
|
197
|
+
totalFunctions: ([.[]] | map(.functions | length) | add),
|
|
198
|
+
avgComplexity: ([.[]] | map(.avgComplexity) | add / length)
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
'
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Example: JavaScript Driver
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
#!/bin/bash
|
|
208
|
+
# drivers/javascript.sh
|
|
209
|
+
# Wraps complexity-report to produce standard complexity JSON
|
|
210
|
+
|
|
211
|
+
set -euo pipefail
|
|
212
|
+
|
|
213
|
+
TARGET_DIR="${1:-.}"
|
|
214
|
+
|
|
215
|
+
# Check tool is installed
|
|
216
|
+
if ! npx complexity-report --version &> /dev/null; then
|
|
217
|
+
echo '{"error": "complexity-report not installed"}' >&2
|
|
218
|
+
exit 1
|
|
219
|
+
fi
|
|
220
|
+
|
|
221
|
+
# Run and transform
|
|
222
|
+
npx complexity-report --format json "$TARGET_DIR" | jq '
|
|
223
|
+
{
|
|
224
|
+
tool: "complexity-report",
|
|
225
|
+
language: "javascript",
|
|
226
|
+
generatedAt: (now | todate),
|
|
227
|
+
files: # ... transform logic
|
|
228
|
+
}
|
|
229
|
+
'
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Integration with vibe-check
|
|
235
|
+
|
|
236
|
+
### Reading Complexity Data
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
// src/analyzers/complexity.ts
|
|
240
|
+
|
|
241
|
+
import * as fs from 'fs';
|
|
242
|
+
import * as path from 'path';
|
|
243
|
+
|
|
244
|
+
const COMPLEXITY_FILE = '.vibe-check/complexity.json';
|
|
245
|
+
|
|
246
|
+
export interface ComplexityData {
|
|
247
|
+
// ... schema from above
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export function loadComplexityData(rootDir: string): ComplexityData | null {
|
|
251
|
+
const filePath = path.join(rootDir, COMPLEXITY_FILE);
|
|
252
|
+
|
|
253
|
+
if (!fs.existsSync(filePath)) {
|
|
254
|
+
return null; // No complexity data available
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
try {
|
|
258
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
259
|
+
return JSON.parse(content);
|
|
260
|
+
} catch (e) {
|
|
261
|
+
console.warn(`Failed to parse ${COMPLEXITY_FILE}:`, e);
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export function getFileComplexity(
|
|
267
|
+
data: ComplexityData,
|
|
268
|
+
file: string
|
|
269
|
+
): { avgComplexity: number; grade: string } | null {
|
|
270
|
+
return data.files[file] || null;
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Enhancing Modularity Score
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
// In src/analyzers/modularity.ts, modify calculateScore()
|
|
278
|
+
|
|
279
|
+
function calculateScore(
|
|
280
|
+
lines: number,
|
|
281
|
+
pattern: FilePattern | null,
|
|
282
|
+
details: ModularityDetails,
|
|
283
|
+
content: string,
|
|
284
|
+
file: string,
|
|
285
|
+
complexityData?: ComplexityData // NEW parameter
|
|
286
|
+
): { score: number; flags: ModularityFlag[] } {
|
|
287
|
+
let score = 10;
|
|
288
|
+
const flags: ModularityFlag[] = [];
|
|
289
|
+
|
|
290
|
+
// ... existing logic ...
|
|
291
|
+
|
|
292
|
+
// NEW: Complexity-based scoring (if data available)
|
|
293
|
+
if (complexityData) {
|
|
294
|
+
const fileComplexity = getFileComplexity(complexityData, file);
|
|
295
|
+
if (fileComplexity) {
|
|
296
|
+
switch (fileComplexity.grade) {
|
|
297
|
+
case 'A':
|
|
298
|
+
case 'B':
|
|
299
|
+
score += 2; // Bonus for low complexity
|
|
300
|
+
break;
|
|
301
|
+
case 'C':
|
|
302
|
+
score -= 1;
|
|
303
|
+
flags.push('moderate-complexity');
|
|
304
|
+
break;
|
|
305
|
+
case 'D':
|
|
306
|
+
case 'E':
|
|
307
|
+
score -= 2;
|
|
308
|
+
flags.push('high-complexity');
|
|
309
|
+
break;
|
|
310
|
+
case 'F':
|
|
311
|
+
score -= 4;
|
|
312
|
+
flags.push('extreme-complexity');
|
|
313
|
+
break;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return { score: Math.max(0, Math.min(10, score)), flags };
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
## User Workflow
|
|
325
|
+
|
|
326
|
+
### CI Integration
|
|
327
|
+
|
|
328
|
+
```yaml
|
|
329
|
+
# .gitlab-ci.yml or .github/workflows/ci.yml
|
|
330
|
+
|
|
331
|
+
complexity-analysis:
|
|
332
|
+
script:
|
|
333
|
+
# Run appropriate driver for your language
|
|
334
|
+
- ./node_modules/.bin/vibe-check-driver-python services/ > .vibe-check/complexity.json
|
|
335
|
+
|
|
336
|
+
# Or if multi-language:
|
|
337
|
+
- vibe-check-driver-python backend/ >> .vibe-check/complexity.json
|
|
338
|
+
- vibe-check-driver-js frontend/ >> .vibe-check/complexity.json
|
|
339
|
+
|
|
340
|
+
# Then run vibe-check (will read complexity.json)
|
|
341
|
+
- vibe-check --format json > reports/vibe-report.json
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### Local Development
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
# Generate complexity data
|
|
348
|
+
vibe-check driver python ./src
|
|
349
|
+
|
|
350
|
+
# Run full analysis (reads complexity data automatically)
|
|
351
|
+
vibe-check
|
|
352
|
+
|
|
353
|
+
# Or one-liner
|
|
354
|
+
vibe-check --with-complexity python
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
## File Locations
|
|
360
|
+
|
|
361
|
+
| File | Purpose |
|
|
362
|
+
|------|---------|
|
|
363
|
+
| `.vibe-check/complexity.json` | Driver output (gitignored) |
|
|
364
|
+
| `drivers/python.sh` | Python driver script |
|
|
365
|
+
| `drivers/javascript.sh` | JavaScript driver script |
|
|
366
|
+
| `src/analyzers/complexity.ts` | Schema + loader |
|
|
367
|
+
| `src/analyzers/modularity.ts` | Enhanced scoring |
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
## Risks and Mitigations
|
|
372
|
+
|
|
373
|
+
| Risk | Likelihood | Impact | Mitigation |
|
|
374
|
+
|------|------------|--------|------------|
|
|
375
|
+
| Tool not installed | HIGH | LOW | Graceful degradation, clear error messages |
|
|
376
|
+
| Schema mismatch | MEDIUM | MEDIUM | Validate JSON against schema before use |
|
|
377
|
+
| Performance (large codebases) | MEDIUM | LOW | Cache results, run incrementally |
|
|
378
|
+
| Multiple languages | MEDIUM | LOW | Merge multiple driver outputs |
|
|
379
|
+
|
|
380
|
+
---
|
|
381
|
+
|
|
382
|
+
## Next Steps
|
|
383
|
+
|
|
384
|
+
1. Implement `src/analyzers/complexity.ts` (schema + loader)
|
|
385
|
+
2. Create `drivers/python.sh` wrapper
|
|
386
|
+
3. Modify `analyzeModularity()` to accept complexity data
|
|
387
|
+
4. Add `--with-complexity <lang>` CLI flag
|
|
388
|
+
5. Document in README.md
|
|
389
|
+
|
|
390
|
+
---
|
|
391
|
+
|
|
392
|
+
**Output:** .agents/research/2025-12-29-complexity-driver-architecture.md
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
---
|
|
2
|
+
date: 2025-12-29
|
|
3
|
+
type: Research
|
|
4
|
+
topic: "What complexity drivers should vibe-check support?"
|
|
5
|
+
tags: [research, drivers, complexity, languages, tooling]
|
|
6
|
+
status: COMPLETE
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Research: Complexity Drivers for vibe-check
|
|
10
|
+
|
|
11
|
+
**Created:** 2025-12-29
|
|
12
|
+
**Goal:** Determine which programming language drivers we should support for complexity analysis
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Executive Summary
|
|
17
|
+
|
|
18
|
+
vibe-check currently supports **Python, JavaScript/TypeScript, and Go** complexity drivers. Based on developer survey data and tool availability, we should prioritize adding **Rust**, **Java**, and **PHP** drivers. Ruby and C# are lower priority due to tooling complexity or enterprise focus.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Current State
|
|
23
|
+
|
|
24
|
+
### What Exists
|
|
25
|
+
|
|
26
|
+
Three drivers currently implemented:
|
|
27
|
+
|
|
28
|
+
| Driver | Tool | Status |
|
|
29
|
+
|--------|------|--------|
|
|
30
|
+
| `python.sh` | [radon](https://radon.readthedocs.io/) | ✅ Complete |
|
|
31
|
+
| `javascript.sh` | [cyclomatic-complexity](https://github.com/pilotpirxie/cyclomatic-complexity) | ✅ Complete |
|
|
32
|
+
| `go.sh` | [gocyclo](https://github.com/fzipp/gocyclo) | ✅ Complete |
|
|
33
|
+
|
|
34
|
+
### Key Files
|
|
35
|
+
|
|
36
|
+
| File | Purpose | Relevance |
|
|
37
|
+
|------|---------|-----------|
|
|
38
|
+
| `drivers/README.md` | Driver architecture docs | Template for new drivers |
|
|
39
|
+
| `src/analyzers/complexity.ts` | ComplexityReport schema | Must match output |
|
|
40
|
+
| `src/commands/driver.ts` | Driver execution | Hardcoded available list |
|
|
41
|
+
| `src/commands/modularity.ts` | Integration point | Uses driver output |
|
|
42
|
+
|
|
43
|
+
### Driver Contract
|
|
44
|
+
|
|
45
|
+
All drivers must output JSON matching `ComplexityReport` schema:
|
|
46
|
+
- Accept directory path as first argument
|
|
47
|
+
- Check tool availability, exit 1 with JSON error if missing
|
|
48
|
+
- Output valid JSON to stdout
|
|
49
|
+
- Exit 0 on success
|
|
50
|
+
- Handle empty directories gracefully
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Findings
|
|
55
|
+
|
|
56
|
+
### Finding 1: Language Popularity (2025 Data)
|
|
57
|
+
|
|
58
|
+
Based on [Stack Overflow 2025](https://survey.stackoverflow.co/2025/technology) and [TIOBE Index](https://www.techrepublic.com/article/news-tiobe-index-language-rankings/):
|
|
59
|
+
|
|
60
|
+
| Language | Stack Overflow 2025 | TIOBE Dec 2025 | Current Driver |
|
|
61
|
+
|----------|---------------------|----------------|----------------|
|
|
62
|
+
| JavaScript/TS | 66% usage | #6 | ✅ javascript.sh |
|
|
63
|
+
| Python | +7% growth | #1 (25.98%) | ✅ python.sh |
|
|
64
|
+
| Go | Growing | #8 | ✅ go.sh |
|
|
65
|
+
| **Rust** | 72% admired | #13 (rising) | ❌ None |
|
|
66
|
+
| **Java** | Enterprise staple | #4 | ❌ None |
|
|
67
|
+
| **C#** | Enterprise | #5 | ❌ None |
|
|
68
|
+
| **PHP** | Web backend | #16 | ❌ None |
|
|
69
|
+
| **Ruby** | Web (Rails) | #18 | ❌ None |
|
|
70
|
+
|
|
71
|
+
**Key insight:** We cover the top 3 general-purpose languages. Rust is the most admired language and rising fast.
|
|
72
|
+
|
|
73
|
+
### Finding 2: Available Complexity Tools
|
|
74
|
+
|
|
75
|
+
| Language | Tool | CLI | JSON Output | Install |
|
|
76
|
+
|----------|------|-----|-------------|---------|
|
|
77
|
+
| **Rust** | [rust-code-analysis](https://mozilla.github.io/rust-code-analysis/metrics.html) | ✅ | ✅ Native | `cargo install rust-code-analysis-cli` |
|
|
78
|
+
| **Java** | [PMD](https://pmd.github.io/pmd/pmd_rules_java_design.html) | ✅ | ✅ `-f json` | Download JAR |
|
|
79
|
+
| **C#** | [CCM](https://github.com/jonasblunck/ccm) | ✅ | XML only | NuGet |
|
|
80
|
+
| **PHP** | [PHPMD](https://phpmd.org/rules/codesize.html) | ✅ | ✅ Native | Composer |
|
|
81
|
+
| **Ruby** | [Saikuro](https://metricfu.github.io/Saikuro/) | ✅ | Text only | Gem |
|
|
82
|
+
|
|
83
|
+
### Finding 3: Implementation Complexity
|
|
84
|
+
|
|
85
|
+
| Language | Tool Quality | Output Parsing | Dependencies | Priority |
|
|
86
|
+
|----------|--------------|----------------|--------------|----------|
|
|
87
|
+
| **Rust** | Excellent (Mozilla) | Native JSON | Cargo | **P1** |
|
|
88
|
+
| **Java** | Good (PMD) | JSON via flag | JRE + JAR | P2 |
|
|
89
|
+
| **PHP** | Good (PHPMD) | Native JSON | PHP + Composer | P2 |
|
|
90
|
+
| **Ruby** | Fair (Saikuro) | Text → parse | Ruby + Gem | P3 |
|
|
91
|
+
| **C#** | Fair (CCM) | XML → parse | .NET SDK | P3 |
|
|
92
|
+
|
|
93
|
+
### Finding 4: Rust Tool Deep Dive
|
|
94
|
+
|
|
95
|
+
**rust-code-analysis** by Mozilla is ideal:
|
|
96
|
+
- Calculates Cyclomatic (CC) and Cognitive complexity
|
|
97
|
+
- Includes Halstead metrics
|
|
98
|
+
- Native JSON output
|
|
99
|
+
- Actively maintained
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
# Installation
|
|
103
|
+
cargo install rust-code-analysis-cli
|
|
104
|
+
|
|
105
|
+
# Usage with JSON output
|
|
106
|
+
rust-code-analysis-cli -m -O json -p /path/to/src
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Finding 5: Java Tool Options
|
|
110
|
+
|
|
111
|
+
**PMD** is the industry standard:
|
|
112
|
+
- Measures cyclomatic complexity
|
|
113
|
+
- JSON output with `-f json`
|
|
114
|
+
- Requires JRE (widely available)
|
|
115
|
+
- Well-documented
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# Usage
|
|
119
|
+
pmd check -d /path/to/src -R category/java/design.xml -f json
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Alternative:** Checkstyle has complexity checks but XML output only.
|
|
123
|
+
|
|
124
|
+
### Finding 6: PHP Tool Options
|
|
125
|
+
|
|
126
|
+
**PHPMD** (PHP Mess Detector) is the go-to:
|
|
127
|
+
- Direct cyclomatic complexity support
|
|
128
|
+
- JSON output built-in
|
|
129
|
+
- Easy to install via Composer
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# Usage
|
|
133
|
+
phpmd /path/to/src json codesize
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Constraints
|
|
139
|
+
|
|
140
|
+
| Constraint | Impact | Mitigation |
|
|
141
|
+
|------------|--------|------------|
|
|
142
|
+
| Tool availability | Users must install language tools | Document requirements clearly |
|
|
143
|
+
| JRE dependency (Java) | Heavy requirement | Note in docs, suggest alternatives |
|
|
144
|
+
| Output format variance | Different JSON structures | Transform in driver (like Go uses awk) |
|
|
145
|
+
| Platform compatibility | Some tools Unix-only | Test on macOS/Linux, note Windows limitations |
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Risks
|
|
150
|
+
|
|
151
|
+
| Risk | Likelihood | Impact | Mitigation |
|
|
152
|
+
|------|------------|--------|------------|
|
|
153
|
+
| Tool discontinued | Low | High | Choose well-maintained tools (Mozilla, PMD) |
|
|
154
|
+
| Breaking changes in tool output | Medium | Medium | Pin tool versions in docs |
|
|
155
|
+
| Installation friction | Medium | Medium | Provide clear install instructions |
|
|
156
|
+
| Windows compatibility | Low | Low | Focus on Unix first (developer primary platform) |
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Recommendation
|
|
161
|
+
|
|
162
|
+
### Immediate (P1)
|
|
163
|
+
|
|
164
|
+
**Add Rust driver** using `rust-code-analysis`:
|
|
165
|
+
- Most admired language, fastest growing
|
|
166
|
+
- Excellent Mozilla-backed tool
|
|
167
|
+
- Native JSON output (simplest implementation)
|
|
168
|
+
- Aligns with systems programming audience
|
|
169
|
+
|
|
170
|
+
### Near-term (P2)
|
|
171
|
+
|
|
172
|
+
**Add PHP driver** using PHPMD:
|
|
173
|
+
- Large web developer audience
|
|
174
|
+
- Native JSON output
|
|
175
|
+
- Easy Composer install
|
|
176
|
+
|
|
177
|
+
**Add Java driver** using PMD:
|
|
178
|
+
- Enterprise relevance
|
|
179
|
+
- JSON output via flag
|
|
180
|
+
- Well-documented
|
|
181
|
+
|
|
182
|
+
### Later (P3)
|
|
183
|
+
|
|
184
|
+
**Ruby** via Saikuro or Fukuzatsu - text parsing required
|
|
185
|
+
**C#** via CCM - XML output, .NET dependency
|
|
186
|
+
|
|
187
|
+
### Not Recommended
|
|
188
|
+
|
|
189
|
+
**Swift/Kotlin/Scala** - Niche audiences, tooling gaps
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Tool Comparison Matrix
|
|
194
|
+
|
|
195
|
+
| Language | Tool | JSON Native | Install Friction | Priority |
|
|
196
|
+
|----------|------|-------------|------------------|----------|
|
|
197
|
+
| Rust | rust-code-analysis | ✅ | Low (cargo) | **P1** |
|
|
198
|
+
| PHP | PHPMD | ✅ | Low (composer) | **P2** |
|
|
199
|
+
| Java | PMD | ✅ (flag) | Medium (JRE) | **P2** |
|
|
200
|
+
| Ruby | Saikuro | ❌ | Low (gem) | P3 |
|
|
201
|
+
| C# | CCM | ❌ | Medium (.NET) | P3 |
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Next Steps
|
|
206
|
+
|
|
207
|
+
1. Run `/plan` to create implementation plan for P1/P2 drivers
|
|
208
|
+
2. Start with Rust (simplest: native JSON, cargo install)
|
|
209
|
+
3. Add PHP and Java as follow-up work
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Sources
|
|
214
|
+
|
|
215
|
+
- [Stack Overflow Developer Survey 2025](https://survey.stackoverflow.co/2025/technology)
|
|
216
|
+
- [TIOBE Index December 2025](https://www.techrepublic.com/article/news-tiobe-index-language-rankings/)
|
|
217
|
+
- [rust-code-analysis metrics](https://mozilla.github.io/rust-code-analysis/metrics.html)
|
|
218
|
+
- [PMD Java Design Rules](https://pmd.github.io/pmd/pmd_rules_java_design.html)
|
|
219
|
+
- [PHPMD Code Size Rules](https://phpmd.org/rules/codesize.html)
|
|
220
|
+
- [gocyclo GitHub](https://github.com/fzipp/gocyclo)
|
|
221
|
+
- [cyclomatic-complexity npm](https://github.com/pilotpirxie/cyclomatic-complexity)
|
|
222
|
+
- [Checkstyle Cyclomatic Complexity](https://checkstyle.sourceforge.io/checks/metrics/cyclomaticcomplexity.html)
|
|
223
|
+
- [Saikuro Ruby Complexity](https://metricfu.github.io/Saikuro/)
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
**Output:** .agents/research/2025-12-29-complexity-drivers.md
|