devbonzai 2.2.207 → 2.2.208
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/package.json +1 -1
- package/templates/handlers/scan_standards.js +172 -174
package/package.json
CHANGED
|
@@ -1,180 +1,178 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const glob = require('glob');
|
|
4
|
-
const { spawn } = require('child_process');
|
|
5
|
-
const { listAllFiles } = require('../utils/fileList');
|
|
6
|
-
const { getIgnorePatterns, shouldIgnore } = require('../utils/ignore');
|
|
7
|
-
|
|
8
1
|
module.exports = async function scanStandards(req, res) {
|
|
9
2
|
console.log('🔵 [scan_standards] Endpoint hit');
|
|
10
3
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
4
|
+
// Return sample response immediately
|
|
5
|
+
const violations = [
|
|
6
|
+
{
|
|
7
|
+
"rule": "React Best Practices",
|
|
8
|
+
"file": "src/App.js",
|
|
9
|
+
"description": "Component file exceeds 200 lines (701 lines). Components should be split into smaller, focused components.",
|
|
10
|
+
"severity": "high"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"rule": "React Best Practices",
|
|
14
|
+
"file": "src/components/StatusChecklistModal.js",
|
|
15
|
+
"description": "Component file exceeds 200 lines (1320 lines). Component should be split into smaller, focused components.",
|
|
16
|
+
"severity": "high"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"rule": "React Best Practices",
|
|
20
|
+
"file": "src/components/code/ElementsGenerator.js",
|
|
21
|
+
"description": "Component file exceeds 200 lines (1097 lines). Component should be split into smaller, focused components.",
|
|
22
|
+
"severity": "high"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"rule": "React Best Practices",
|
|
26
|
+
"file": "src/components/JobsSidebar.js",
|
|
27
|
+
"description": "Component file exceeds 200 lines (652 lines). Component should be split into smaller, focused components.",
|
|
28
|
+
"severity": "high"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"rule": "React Best Practices",
|
|
32
|
+
"file": "src/components/jobs/JobsSidebar.js",
|
|
33
|
+
"description": "Component file exceeds 200 lines (554 lines). Component should be split into smaller, focused components.",
|
|
34
|
+
"severity": "high"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"rule": "React Best Practices",
|
|
38
|
+
"file": "src/components/jobs/JobCard.js",
|
|
39
|
+
"description": "Component file exceeds 200 lines (514 lines). Component should be split into smaller, focused components.",
|
|
40
|
+
"severity": "high"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"rule": "React Best Practices",
|
|
44
|
+
"file": "src/components/UniversalNode.js",
|
|
45
|
+
"description": "Component file exceeds 200 lines (538 lines). Component should be split into smaller, focused components.",
|
|
46
|
+
"severity": "high"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"rule": "React Best Practices",
|
|
50
|
+
"file": "src/App.js",
|
|
51
|
+
"description": "Component contains data fetching directly (scanCodeQuality, scanStandards calls in useEffect). Data fetching should be in custom hooks, not components.",
|
|
52
|
+
"severity": "high"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"rule": "React Best Practices",
|
|
56
|
+
"file": "src/components/StatusChecklistModal.js",
|
|
57
|
+
"description": "Component contains data fetching directly (fetch calls to /analyze_prompt). Data fetching should be in custom hooks, not components.",
|
|
58
|
+
"severity": "high"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"rule": "React Best Practices",
|
|
62
|
+
"file": "src/components/code/ElementsGenerator.js",
|
|
63
|
+
"description": "Component contains data fetching directly (multiple fetch calls for delete, move, write operations). Data fetching should be in custom hooks, not components.",
|
|
64
|
+
"severity": "high"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"rule": "React Best Practices",
|
|
68
|
+
"file": "src/components/JobsSidebar.js",
|
|
69
|
+
"description": "Component contains data fetching directly (fetch calls to /analyze_prompt, /prompt_agent_stream, /revert_job). Data fetching should be in custom hooks, not components.",
|
|
70
|
+
"severity": "high"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"rule": "React Best Practices",
|
|
74
|
+
"file": "src/components/jobs/JobsSidebar.js",
|
|
75
|
+
"description": "Component contains data fetching directly (fetch calls to /analyze_prompt, /prompt_agent_stream, /revert_job). Data fetching should be in custom hooks, not components.",
|
|
76
|
+
"severity": "high"
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"rule": "React Best Practices",
|
|
80
|
+
"file": "src/components/FileList.js",
|
|
81
|
+
"description": "Component contains data fetching directly (fetch call to /list). Data fetching should be in custom hooks, not components.",
|
|
82
|
+
"severity": "medium"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"rule": "React Best Practices",
|
|
86
|
+
"file": "src/components/FileBrowser.js",
|
|
87
|
+
"description": "Component contains data fetching directly (fetch call to /read for line counts). Data fetching should be in custom hooks, not components.",
|
|
88
|
+
"severity": "medium"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"rule": "React Best Practices",
|
|
92
|
+
"file": "src/components/UniversalNode.js",
|
|
93
|
+
"description": "Component contains data fetching directly (fetch calls to /open-cursor and /read). Data fetching should be in custom hooks, not components.",
|
|
94
|
+
"severity": "medium"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"rule": "React Best Practices",
|
|
98
|
+
"file": "src/App.js",
|
|
99
|
+
"description": "Component contains business logic mixed with UI rendering (file operations, job management logic). Business logic should be in hooks or services, not components.",
|
|
100
|
+
"severity": "high"
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"rule": "React Best Practices",
|
|
104
|
+
"file": "src/components/StatusChecklistModal.js",
|
|
105
|
+
"description": "Component contains business logic mixed with UI rendering (job creation, fix operations). Business logic should be in hooks or services, not components.",
|
|
106
|
+
"severity": "high"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"rule": "React Best Practices",
|
|
110
|
+
"file": "src/components/code/ElementsGenerator.js",
|
|
111
|
+
"description": "Component contains business logic mixed with UI rendering (file operations, tree manipulation). Business logic should be in hooks or services, not components.",
|
|
112
|
+
"severity": "high"
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"rule": "React Best Practices",
|
|
116
|
+
"file": "src/components/JobsSidebar.js",
|
|
117
|
+
"description": "Component contains business logic mixed with UI rendering (job execution, state management). Business logic should be in hooks or services, not components.",
|
|
118
|
+
"severity": "high"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"rule": "React Best Practices",
|
|
122
|
+
"file": "src/App.js",
|
|
123
|
+
"description": "Props drilling detected - many props passed down multiple component levels (jobs, hoveredJobId, onJobsChange, etc.). Should use context for props beyond 2 levels.",
|
|
124
|
+
"severity": "medium"
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"rule": "Feature-Based Organization",
|
|
128
|
+
"file": "src/components/JobsSidebar.js",
|
|
129
|
+
"description": "Duplicate file exists: both src/components/JobsSidebar.js and src/components/jobs/JobsSidebar.js contain similar functionality. Feature folders should be self-contained with no duplicates.",
|
|
130
|
+
"severity": "medium"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"rule": "Clean Architecture",
|
|
134
|
+
"file": "src/App.js",
|
|
135
|
+
"description": "Business logic is not independent of frameworks - React components contain business logic that should be in framework-independent services.",
|
|
136
|
+
"severity": "high"
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"rule": "Clean Architecture",
|
|
140
|
+
"file": "src/components/StatusChecklistModal.js",
|
|
141
|
+
"description": "Business logic is not independent of frameworks - React component contains business logic that should be in framework-independent services.",
|
|
142
|
+
"severity": "high"
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"rule": "Clean Architecture",
|
|
146
|
+
"file": "src/components/code/ElementsGenerator.js",
|
|
147
|
+
"description": "Business logic is not independent of frameworks - React component contains business logic that should be in framework-independent services.",
|
|
148
|
+
"severity": "high"
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"rule": "Layered Architecture",
|
|
152
|
+
"file": "src/App.js",
|
|
153
|
+
"description": "Presentation layer contains data access (direct fetch calls). Data access should be in a separate data layer, not presentation layer.",
|
|
154
|
+
"severity": "high"
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"rule": "Layered Architecture",
|
|
158
|
+
"file": "src/components/StatusChecklistModal.js",
|
|
159
|
+
"description": "Presentation layer contains data access (direct fetch calls). Data access should be in a separate data layer, not presentation layer.",
|
|
160
|
+
"severity": "high"
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
"rule": "Layered Architecture",
|
|
164
|
+
"file": "src/components/code/ElementsGenerator.js",
|
|
165
|
+
"description": "Presentation layer contains data access (direct fetch calls). Data access should be in a separate data layer, not presentation layer.",
|
|
166
|
+
"severity": "high"
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"rule": "Layered Architecture",
|
|
170
|
+
"file": "src/components/JobsSidebar.js",
|
|
171
|
+
"description": "Presentation layer contains data access (direct fetch calls). Data access should be in a separate data layer, not presentation layer.",
|
|
172
|
+
"severity": "high"
|
|
19
173
|
}
|
|
20
|
-
|
|
21
|
-
// Get file structure for context
|
|
22
|
-
console.log('🔵 [scan_standards] Getting file tree...');
|
|
23
|
-
const fileTree = getFileTree(projectPath);
|
|
24
|
-
console.log('🔵 [scan_standards] File tree entries:', fileTree.split('\n').length);
|
|
25
|
-
|
|
26
|
-
// Sample a few key files for AI to analyze (don't send entire codebase)
|
|
27
|
-
console.log('🔵 [scan_standards] Getting sample files...');
|
|
28
|
-
const sampleFiles = getSampleFiles(projectPath, 10);
|
|
29
|
-
console.log('🔵 [scan_standards] Sample files found:', sampleFiles.length);
|
|
30
|
-
sampleFiles.forEach(f => console.log(' 📄', f.path, `(${f.size} bytes)`));
|
|
31
|
-
|
|
32
|
-
const prompt = `Analyze this codebase for architectural violations.
|
|
33
|
-
|
|
34
|
-
PROJECT STRUCTURE:
|
|
35
|
-
${fileTree}
|
|
36
|
-
|
|
37
|
-
SAMPLE FILES:
|
|
38
|
-
${sampleFiles.map(f => `=== ${f.path} ===\n${f.content.substring(0, 500)}...\n`).join('\n')}
|
|
39
|
-
|
|
40
|
-
STANDARDS TO CHECK:
|
|
41
|
-
${Array.isArray(standards) ? standards.map((s, i) => `${i + 1}. ${s}`).join('\n') : standards}
|
|
42
|
-
|
|
43
|
-
CRITICAL: Your response must be ONLY a valid JSON array. No markdown, no explanation, no summary text.
|
|
44
|
-
Start your response with [ and end with ]. Nothing else.
|
|
45
|
-
|
|
46
|
-
Output format:
|
|
47
|
-
[{"rule":"rule name","file":"path/to/file","description":"what violates it","severity":"high|medium|low"}]
|
|
48
|
-
|
|
49
|
-
Empty if no violations: []`;
|
|
50
|
-
|
|
51
|
-
console.log('🔵 [scan_standards] Prompt length:', prompt.length, 'chars');
|
|
52
|
-
|
|
53
|
-
// Use cursor-agent like prompt_agent does
|
|
54
|
-
const args = ['--print', '--force', '--workspace', projectPath, prompt];
|
|
55
|
-
console.log('🔵 [scan_standards] Spawning cursor-agent...');
|
|
56
|
-
|
|
57
|
-
const proc = spawn('cursor-agent', args, {
|
|
58
|
-
cwd: projectPath,
|
|
59
|
-
env: process.env,
|
|
60
|
-
stdio: ['ignore', 'pipe', 'pipe']
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
console.log('🔵 [scan_standards] Process spawned, PID:', proc.pid);
|
|
64
|
-
|
|
65
|
-
let stdout = '';
|
|
66
|
-
let stderr = '';
|
|
67
|
-
|
|
68
|
-
proc.stdout.on('data', (d) => {
|
|
69
|
-
const data = d.toString();
|
|
70
|
-
console.log('📤 [scan_standards] stdout chunk:', data.length, 'bytes');
|
|
71
|
-
stdout += data;
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
proc.stderr.on('data', (d) => {
|
|
75
|
-
const data = d.toString();
|
|
76
|
-
console.log('⚠️ [scan_standards] stderr chunk:', data.length, 'bytes');
|
|
77
|
-
stderr += data;
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
proc.on('error', (error) => {
|
|
81
|
-
console.error('❌ [scan_standards] Process error:', error.message);
|
|
82
|
-
return res.status(500).json({ error: error.message });
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
proc.on('close', (code) => {
|
|
86
|
-
console.log('🔵 [scan_standards] Process closed with code:', code);
|
|
87
|
-
console.log('🔵 [scan_standards] stdout total:', stdout.length, 'bytes');
|
|
88
|
-
console.log('🔵 [scan_standards] stderr total:', stderr.length, 'bytes');
|
|
89
|
-
|
|
90
|
-
if (code !== 0) {
|
|
91
|
-
console.error('❌ [scan_standards] Failed with code:', code);
|
|
92
|
-
console.error('❌ [scan_standards] stderr:', stderr);
|
|
93
|
-
return res.status(500).json({ error: `Process exited with code ${code}`, stderr });
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Parse AI response
|
|
97
|
-
console.log('🔵 [scan_standards] Parsing response...');
|
|
98
|
-
const jsonMatch = stdout.match(/\[[\s\S]*\]/);
|
|
99
|
-
|
|
100
|
-
if (!jsonMatch) {
|
|
101
|
-
console.log('⚠️ [scan_standards] No JSON array found in response');
|
|
102
|
-
console.log('⚠️ [scan_standards] Raw stdout:', stdout.substring(0, 500));
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
try {
|
|
106
|
-
const violations = jsonMatch ? JSON.parse(jsonMatch[0]) : [];
|
|
107
|
-
console.log('✅ [scan_standards] Found', violations.length, 'violations');
|
|
108
|
-
res.json({ violations });
|
|
109
|
-
} catch (parseError) {
|
|
110
|
-
console.error('❌ [scan_standards] JSON parse error:', parseError.message);
|
|
111
|
-
res.status(500).json({ error: 'Failed to parse response', raw: stdout });
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
} catch (error) {
|
|
116
|
-
console.error('❌ [scan_standards] Error:', error.message);
|
|
117
|
-
res.status(500).json({ error: error.message });
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
function getFileTree(projectPath) {
|
|
122
|
-
try {
|
|
123
|
-
const files = listAllFiles(projectPath);
|
|
124
|
-
// Filter out virtual files (.function, .class, .method) for cleaner tree
|
|
125
|
-
const realFiles = files.filter(f =>
|
|
126
|
-
!f.endsWith('.function') &&
|
|
127
|
-
!f.endsWith('.class') &&
|
|
128
|
-
!f.endsWith('.method')
|
|
129
|
-
);
|
|
130
|
-
return realFiles.slice(0, 200).join('\n'); // Limit to 200 entries
|
|
131
|
-
} catch (e) {
|
|
132
|
-
console.error('❌ [scan_standards] Error getting file tree:', e);
|
|
133
|
-
return 'Unable to read file tree';
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
function getSampleFiles(projectPath, limit = 10) {
|
|
138
|
-
const ignorePatterns = getIgnorePatterns();
|
|
139
|
-
|
|
140
|
-
// Common build/output directories to always ignore
|
|
141
|
-
const defaultIgnoreGlobs = [
|
|
142
|
-
'**/node_modules/**',
|
|
143
|
-
'**/dist/**',
|
|
144
|
-
'**/build/**',
|
|
145
|
-
'**/static/**',
|
|
146
|
-
'**/out/**',
|
|
147
|
-
'**/.next/**',
|
|
148
|
-
'**/*.min.js',
|
|
149
|
-
'**/*.bundle.js',
|
|
150
|
-
'**/*.chunk.js'
|
|
151
174
|
];
|
|
152
175
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
nodir: true,
|
|
157
|
-
ignore: defaultIgnoreGlobs
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
// Filter using ignore patterns and sort by size, take top N
|
|
161
|
-
return files
|
|
162
|
-
.filter(f => !shouldIgnore(f, ignorePatterns))
|
|
163
|
-
.map(f => {
|
|
164
|
-
const fullPath = path.join(projectPath, f);
|
|
165
|
-
try {
|
|
166
|
-
const stat = fs.statSync(fullPath);
|
|
167
|
-
const content = fs.readFileSync(fullPath, 'utf8');
|
|
168
|
-
return {
|
|
169
|
-
path: f,
|
|
170
|
-
content,
|
|
171
|
-
size: stat.size
|
|
172
|
-
};
|
|
173
|
-
} catch (e) {
|
|
174
|
-
return null;
|
|
175
|
-
}
|
|
176
|
-
})
|
|
177
|
-
.filter(Boolean)
|
|
178
|
-
.sort((a, b) => b.size - a.size)
|
|
179
|
-
.slice(0, limit);
|
|
180
|
-
}
|
|
176
|
+
console.log('✅ [scan_standards] Returning', violations.length, 'sample violations');
|
|
177
|
+
res.json({ violations });
|
|
178
|
+
};
|