devbonzai 2.2.201 → 2.2.203
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "devbonzai",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.203",
|
|
4
4
|
"description": "Quickly set up a local file server in any repository for browser-based file access",
|
|
5
5
|
"main": "cli.js",
|
|
6
6
|
"bin": {
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"author": "",
|
|
23
23
|
"license": "ISC",
|
|
24
24
|
"dependencies": {
|
|
25
|
+
"@anthropic-ai/sdk": "^0.52.0",
|
|
25
26
|
"express": "^4.18.2",
|
|
26
27
|
"cors": "^2.8.5",
|
|
27
28
|
"body-parser": "^1.20.2",
|
|
@@ -15,7 +15,8 @@ function indexHandler(req, res) {
|
|
|
15
15
|
'POST /prompt_agent': 'Execute cursor-agent command (body: {prompt})',
|
|
16
16
|
'POST /prompt_agent_stream': 'Execute cursor-agent with SSE streaming (body: {prompt})',
|
|
17
17
|
'POST /revert_job': 'Revert to a previous commit (body: {beforeCommit})',
|
|
18
|
-
'POST /shutdown': 'Gracefully shutdown the server'
|
|
18
|
+
'POST /shutdown': 'Gracefully shutdown the server',
|
|
19
|
+
'POST /scan_standards': 'Analyze codebase against architectural standards (body: {projectPath, standards, apiKey?})'
|
|
19
20
|
},
|
|
20
21
|
example: 'Try: /list or /read?path=README.md'
|
|
21
22
|
});
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const glob = require('glob');
|
|
4
|
+
const { Anthropic } = require('@anthropic-ai/sdk');
|
|
5
|
+
const { listAllFiles } = require('../utils/fileList');
|
|
6
|
+
const { getIgnorePatterns, shouldIgnore } = require('../utils/ignore');
|
|
7
|
+
|
|
8
|
+
// Hardcoded API key as fallback
|
|
9
|
+
const DEFAULT_API_KEY = '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';
|
|
10
|
+
|
|
11
|
+
module.exports = async function scanStandards(req, res) {
|
|
12
|
+
try {
|
|
13
|
+
const { projectPath, standards, apiKey } = req.body;
|
|
14
|
+
|
|
15
|
+
if (!projectPath || !standards) {
|
|
16
|
+
return res.status(400).json({ error: 'projectPath and standards required' });
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Use provided apiKey or fall back to default
|
|
20
|
+
const anthropicApiKey = apiKey || DEFAULT_API_KEY;
|
|
21
|
+
|
|
22
|
+
// Get file structure for context
|
|
23
|
+
const fileTree = getFileTree(projectPath);
|
|
24
|
+
|
|
25
|
+
// Sample a few key files for AI to analyze (don't send entire codebase)
|
|
26
|
+
const sampleFiles = getSampleFiles(projectPath, 10);
|
|
27
|
+
|
|
28
|
+
const anthropic = new Anthropic({ apiKey: anthropicApiKey });
|
|
29
|
+
|
|
30
|
+
const prompt = `You are analyzing a codebase for architectural violations.
|
|
31
|
+
|
|
32
|
+
PROJECT STRUCTURE:
|
|
33
|
+
${fileTree}
|
|
34
|
+
|
|
35
|
+
SAMPLE FILES:
|
|
36
|
+
${sampleFiles.map(f => `=== ${f.path} ===\n${f.content.substring(0, 500)}...\n`).join('\n')}
|
|
37
|
+
|
|
38
|
+
ARCHITECTURAL STANDARDS TO CHECK:
|
|
39
|
+
${Array.isArray(standards) ? standards.map((s, i) => `${i + 1}. ${s}`).join('\n') : standards}
|
|
40
|
+
|
|
41
|
+
Analyze the codebase and identify violations of these standards.
|
|
42
|
+
|
|
43
|
+
Respond ONLY with a JSON array of violations:
|
|
44
|
+
[
|
|
45
|
+
{
|
|
46
|
+
"rule": "Controllers should only handle HTTP requests",
|
|
47
|
+
"file": "src/controllers/UserController.ts",
|
|
48
|
+
"description": "Contains business logic and database queries",
|
|
49
|
+
"severity": "high"
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
If no violations found, return empty array: []`;
|
|
54
|
+
|
|
55
|
+
const message = await anthropic.messages.create({
|
|
56
|
+
model: 'claude-sonnet-4-20250514',
|
|
57
|
+
max_tokens: 4000,
|
|
58
|
+
messages: [{ role: 'user', content: prompt }]
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Parse AI response
|
|
62
|
+
const responseText = message.content[0].text;
|
|
63
|
+
const jsonMatch = responseText.match(/\[[\s\S]*\]/);
|
|
64
|
+
const violations = jsonMatch ? JSON.parse(jsonMatch[0]) : [];
|
|
65
|
+
|
|
66
|
+
res.json({
|
|
67
|
+
violations,
|
|
68
|
+
tokensUsed: message.usage.input_tokens + message.usage.output_tokens,
|
|
69
|
+
cost: estimateCost(message.usage)
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
} catch (error) {
|
|
73
|
+
console.error('Standards scan error:', error);
|
|
74
|
+
res.status(500).json({ error: error.message });
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
function getFileTree(projectPath) {
|
|
79
|
+
try {
|
|
80
|
+
const files = listAllFiles(projectPath);
|
|
81
|
+
// Filter out virtual files (.function, .class, .method) for cleaner tree
|
|
82
|
+
const realFiles = files.filter(f =>
|
|
83
|
+
!f.endsWith('.function') &&
|
|
84
|
+
!f.endsWith('.class') &&
|
|
85
|
+
!f.endsWith('.method')
|
|
86
|
+
);
|
|
87
|
+
return realFiles.slice(0, 200).join('\n'); // Limit to 200 entries
|
|
88
|
+
} catch (e) {
|
|
89
|
+
console.error('Error getting file tree:', e);
|
|
90
|
+
return 'Unable to read file tree';
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function getSampleFiles(projectPath, limit = 10) {
|
|
95
|
+
const ignorePatterns = getIgnorePatterns();
|
|
96
|
+
|
|
97
|
+
// Common build/output directories to always ignore
|
|
98
|
+
const defaultIgnoreGlobs = [
|
|
99
|
+
'**/node_modules/**',
|
|
100
|
+
'**/dist/**',
|
|
101
|
+
'**/build/**',
|
|
102
|
+
'**/static/**',
|
|
103
|
+
'**/out/**',
|
|
104
|
+
'**/.next/**',
|
|
105
|
+
'**/*.min.js',
|
|
106
|
+
'**/*.bundle.js',
|
|
107
|
+
'**/*.chunk.js'
|
|
108
|
+
];
|
|
109
|
+
|
|
110
|
+
// Get representative files
|
|
111
|
+
const files = glob.sync('**/*.{js,ts,jsx,tsx,py,java,go}', {
|
|
112
|
+
cwd: projectPath,
|
|
113
|
+
nodir: true,
|
|
114
|
+
ignore: defaultIgnoreGlobs
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Filter using ignore patterns and sort by size, take top N
|
|
118
|
+
return files
|
|
119
|
+
.filter(f => !shouldIgnore(f, ignorePatterns))
|
|
120
|
+
.map(f => {
|
|
121
|
+
const fullPath = path.join(projectPath, f);
|
|
122
|
+
try {
|
|
123
|
+
const stat = fs.statSync(fullPath);
|
|
124
|
+
const content = fs.readFileSync(fullPath, 'utf8');
|
|
125
|
+
return {
|
|
126
|
+
path: f,
|
|
127
|
+
content,
|
|
128
|
+
size: stat.size
|
|
129
|
+
};
|
|
130
|
+
} catch (e) {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
})
|
|
134
|
+
.filter(Boolean)
|
|
135
|
+
.sort((a, b) => b.size - a.size)
|
|
136
|
+
.slice(0, limit);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function estimateCost(usage) {
|
|
140
|
+
// Claude Sonnet 4 pricing
|
|
141
|
+
const inputCost = (usage.input_tokens / 1000000) * 3.00;
|
|
142
|
+
const outputCost = (usage.output_tokens / 1000000) * 15.00;
|
|
143
|
+
return (inputCost + outputCost).toFixed(4);
|
|
144
|
+
}
|
|
145
|
+
|
package/templates/receiver.js
CHANGED
|
@@ -19,6 +19,7 @@ const promptAgentStreamHandler = require('./handlers/prompt_agent_stream');
|
|
|
19
19
|
const revertJobHandler = require('./handlers/revert_job');
|
|
20
20
|
const shutdownHandler = require('./handlers/shutdown');
|
|
21
21
|
const scanCodeQualityHandler = require('./handlers/scan_code_quality');
|
|
22
|
+
const scanStandardsHandler = require('./handlers/scan_standards');
|
|
22
23
|
|
|
23
24
|
const app = express();
|
|
24
25
|
|
|
@@ -41,6 +42,7 @@ app.post('/prompt_agent_stream', promptAgentStreamHandler);
|
|
|
41
42
|
app.post('/revert_job', revertJobHandler);
|
|
42
43
|
app.post('/shutdown', shutdownHandler);
|
|
43
44
|
app.post('/scan_code_quality', scanCodeQualityHandler);
|
|
45
|
+
app.post('/scan_standards', scanStandardsHandler);
|
|
44
46
|
|
|
45
47
|
const port = 3001;
|
|
46
48
|
app.listen(port, () => {
|