add-skill-kit 3.2.3 → 3.2.5
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 +1 -1
- package/bin/lib/commands/help.js +0 -4
- package/bin/lib/commands/install.js +90 -9
- package/bin/lib/ui.js +1 -1
- package/lib/agent-cli/__tests__/adaptive_engine.test.js +190 -0
- package/lib/agent-cli/__tests__/integration/cross_script.test.js +222 -0
- package/lib/agent-cli/__tests__/integration/full_cycle.test.js +230 -0
- package/lib/agent-cli/__tests__/pattern_analyzer.test.js +173 -0
- package/lib/agent-cli/__tests__/pre_execution_check.test.js +167 -0
- package/lib/agent-cli/__tests__/skill_injector.test.js +191 -0
- package/lib/agent-cli/bin/agent.js +191 -0
- package/lib/agent-cli/dashboard/dashboard_server.js +340 -0
- package/lib/agent-cli/dashboard/index.html +538 -0
- package/lib/agent-cli/lib/audit.js +154 -0
- package/lib/agent-cli/lib/audit.test.js +100 -0
- package/lib/agent-cli/lib/auto-learn.js +319 -0
- package/lib/agent-cli/lib/auto_preview.py +148 -0
- package/lib/agent-cli/lib/backup.js +138 -0
- package/lib/agent-cli/lib/backup.test.js +78 -0
- package/lib/agent-cli/lib/checklist.py +222 -0
- package/lib/agent-cli/lib/cognitive-lesson.js +476 -0
- package/lib/agent-cli/lib/completion.js +149 -0
- package/lib/agent-cli/lib/config.js +35 -0
- package/lib/agent-cli/lib/eslint-fix.js +238 -0
- package/lib/agent-cli/lib/evolution-signal.js +215 -0
- package/lib/agent-cli/lib/export.js +86 -0
- package/lib/agent-cli/lib/export.test.js +65 -0
- package/lib/agent-cli/lib/fix.js +337 -0
- package/lib/agent-cli/lib/fix.test.js +80 -0
- package/lib/agent-cli/lib/gemini-export.js +83 -0
- package/lib/agent-cli/lib/generate-registry.js +42 -0
- package/lib/agent-cli/lib/hooks/install-hooks.js +152 -0
- package/lib/agent-cli/lib/hooks/lint-learn.js +172 -0
- package/lib/agent-cli/lib/ignore.js +116 -0
- package/lib/agent-cli/lib/ignore.test.js +58 -0
- package/lib/agent-cli/lib/init.js +124 -0
- package/lib/agent-cli/lib/learn.js +255 -0
- package/lib/agent-cli/lib/learn.test.js +70 -0
- package/lib/agent-cli/lib/migrate-to-v4.js +322 -0
- package/lib/agent-cli/lib/proposals.js +199 -0
- package/lib/agent-cli/lib/proposals.test.js +56 -0
- package/lib/agent-cli/lib/recall.js +820 -0
- package/lib/agent-cli/lib/recall.test.js +107 -0
- package/lib/agent-cli/lib/selfevolution-bridge.js +167 -0
- package/lib/agent-cli/lib/session_manager.py +120 -0
- package/lib/agent-cli/lib/settings.js +227 -0
- package/lib/agent-cli/lib/skill-learn.js +296 -0
- package/lib/agent-cli/lib/stats.js +132 -0
- package/lib/agent-cli/lib/stats.test.js +94 -0
- package/lib/agent-cli/lib/types.js +33 -0
- package/lib/agent-cli/lib/ui/audit-ui.js +146 -0
- package/lib/agent-cli/lib/ui/backup-ui.js +107 -0
- package/lib/agent-cli/lib/ui/clack-helpers.js +317 -0
- package/lib/agent-cli/lib/ui/common.js +83 -0
- package/lib/agent-cli/lib/ui/completion-ui.js +126 -0
- package/lib/agent-cli/lib/ui/custom-select.js +69 -0
- package/lib/agent-cli/lib/ui/dashboard-ui.js +222 -0
- package/lib/agent-cli/lib/ui/evolution-signals-ui.js +107 -0
- package/lib/agent-cli/lib/ui/export-ui.js +94 -0
- package/lib/agent-cli/lib/ui/fix-all-ui.js +191 -0
- package/lib/agent-cli/lib/ui/help-ui.js +49 -0
- package/lib/agent-cli/lib/ui/index.js +199 -0
- package/lib/agent-cli/lib/ui/init-ui.js +56 -0
- package/lib/agent-cli/lib/ui/knowledge-ui.js +55 -0
- package/lib/agent-cli/lib/ui/learn-ui.js +706 -0
- package/lib/agent-cli/lib/ui/lessons-ui.js +148 -0
- package/lib/agent-cli/lib/ui/pretty.js +145 -0
- package/lib/agent-cli/lib/ui/proposals-ui.js +99 -0
- package/lib/agent-cli/lib/ui/recall-ui.js +342 -0
- package/lib/agent-cli/lib/ui/routing-demo.js +79 -0
- package/lib/agent-cli/lib/ui/routing-ui.js +325 -0
- package/lib/agent-cli/lib/ui/settings-ui.js +381 -0
- package/lib/agent-cli/lib/ui/stats-ui.js +123 -0
- package/lib/agent-cli/lib/ui/watch-ui.js +236 -0
- package/lib/agent-cli/lib/verify_all.py +327 -0
- package/lib/agent-cli/lib/watcher.js +181 -0
- package/lib/agent-cli/lib/watcher.test.js +85 -0
- package/lib/agent-cli/package.json +51 -0
- package/lib/agent-cli/scripts/adaptive_engine.js +381 -0
- package/lib/agent-cli/scripts/dashboard_server.js +224 -0
- package/lib/agent-cli/scripts/error_sensor.js +565 -0
- package/lib/agent-cli/scripts/learn_from_failure.js +225 -0
- package/lib/agent-cli/scripts/pattern_analyzer.js +781 -0
- package/lib/agent-cli/scripts/pre_execution_check.js +623 -0
- package/lib/agent-cli/scripts/rule_sharing.js +374 -0
- package/lib/agent-cli/scripts/skill_injector.js +387 -0
- package/lib/agent-cli/scripts/success_sensor.js +500 -0
- package/lib/agent-cli/scripts/user_correction_sensor.js +426 -0
- package/lib/agent-cli/services/auto-learn-service.js +247 -0
- package/lib/agent-cli/src/MIGRATION.md +418 -0
- package/lib/agent-cli/src/README.md +367 -0
- package/lib/agent-cli/src/core/evolution/evolution-signal.js +42 -0
- package/lib/agent-cli/src/core/evolution/index.js +17 -0
- package/lib/agent-cli/src/core/evolution/review-gate.js +40 -0
- package/lib/agent-cli/src/core/evolution/signal-detector.js +137 -0
- package/lib/agent-cli/src/core/evolution/signal-queue.js +79 -0
- package/lib/agent-cli/src/core/evolution/threshold-checker.js +79 -0
- package/lib/agent-cli/src/core/index.js +15 -0
- package/lib/agent-cli/src/core/learning/cognitive-enhancer.js +282 -0
- package/lib/agent-cli/src/core/learning/index.js +12 -0
- package/lib/agent-cli/src/core/learning/lesson-synthesizer.js +83 -0
- package/lib/agent-cli/src/core/scanning/index.js +14 -0
- package/lib/agent-cli/src/data/index.js +13 -0
- package/lib/agent-cli/src/data/repositories/index.js +8 -0
- package/lib/agent-cli/src/data/repositories/lesson-repository.js +130 -0
- package/lib/agent-cli/src/data/repositories/signal-repository.js +119 -0
- package/lib/agent-cli/src/data/storage/index.js +8 -0
- package/lib/agent-cli/src/data/storage/json-storage.js +64 -0
- package/lib/agent-cli/src/data/storage/yaml-storage.js +66 -0
- package/lib/agent-cli/src/infrastructure/index.js +13 -0
- package/lib/agent-cli/src/presentation/formatters/skill-formatter.js +232 -0
- package/lib/agent-cli/src/services/export-service.js +162 -0
- package/lib/agent-cli/src/services/index.js +13 -0
- package/lib/agent-cli/src/services/learning-service.js +99 -0
- package/lib/agent-cli/types/index.d.ts +343 -0
- package/lib/agent-cli/utils/benchmark.js +269 -0
- package/lib/agent-cli/utils/logger.js +303 -0
- package/lib/agent-cli/utils/ml_patterns.js +300 -0
- package/lib/agent-cli/utils/recovery.js +312 -0
- package/lib/agent-cli/utils/telemetry.js +290 -0
- package/lib/agentskillskit-cli/README.md +21 -0
- package/{node_modules/agentskillskit-cli/bin → lib/agentskillskit-cli}/ag-smart.js +15 -15
- package/lib/agentskillskit-cli/package.json +51 -0
- package/package.json +19 -9
- /package/bin/{cli.js → kit.js} +0 -0
- /package/{node_modules/agentskillskit-cli → lib/agent-cli}/README.md +0 -0
|
@@ -0,0 +1,565 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Error Sensor - Auto-detect errors from multiple sources
|
|
4
|
+
*
|
|
5
|
+
* Part of FAANG-Grade Auto-Learn System Phase 1
|
|
6
|
+
*
|
|
7
|
+
* Sensors:
|
|
8
|
+
* - test: Parse vitest/jest output
|
|
9
|
+
* - build: Parse tsc/webpack errors
|
|
10
|
+
* - lint: Parse eslint warnings
|
|
11
|
+
* - runtime: Capture console.error/exceptions
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* node error_sensor.js --scan test
|
|
15
|
+
* node error_sensor.js --scan build
|
|
16
|
+
* node error_sensor.js --scan lint
|
|
17
|
+
* node error_sensor.js --scan all
|
|
18
|
+
* node error_sensor.js --watch
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import fs from 'fs';
|
|
22
|
+
import path from 'path';
|
|
23
|
+
import { execSync } from 'child_process';
|
|
24
|
+
import { fileURLToPath } from 'url';
|
|
25
|
+
|
|
26
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
27
|
+
const __dirname = path.dirname(__filename);
|
|
28
|
+
|
|
29
|
+
// Colors
|
|
30
|
+
const c = {
|
|
31
|
+
reset: '\x1b[0m',
|
|
32
|
+
red: '\x1b[31m',
|
|
33
|
+
green: '\x1b[32m',
|
|
34
|
+
yellow: '\x1b[33m',
|
|
35
|
+
blue: '\x1b[34m',
|
|
36
|
+
cyan: '\x1b[36m',
|
|
37
|
+
gray: '\x1b[90m',
|
|
38
|
+
bold: '\x1b[1m'
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// Find project root
|
|
42
|
+
function findProjectRoot() {
|
|
43
|
+
let current = process.cwd();
|
|
44
|
+
while (current !== path.dirname(current)) {
|
|
45
|
+
if (fs.existsSync(path.join(current, '.agent'))) {
|
|
46
|
+
return current;
|
|
47
|
+
}
|
|
48
|
+
current = path.dirname(current);
|
|
49
|
+
}
|
|
50
|
+
return process.cwd();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const projectRoot = findProjectRoot();
|
|
54
|
+
const knowledgePath = path.join(projectRoot, '.agent', 'knowledge');
|
|
55
|
+
const errorsPath = path.join(knowledgePath, 'detected-errors.json');
|
|
56
|
+
const lessonsPath = path.join(knowledgePath, 'lessons-learned.json');
|
|
57
|
+
|
|
58
|
+
// Ensure files exist
|
|
59
|
+
function ensureFiles() {
|
|
60
|
+
if (!fs.existsSync(knowledgePath)) {
|
|
61
|
+
fs.mkdirSync(knowledgePath, { recursive: true });
|
|
62
|
+
}
|
|
63
|
+
if (!fs.existsSync(errorsPath)) {
|
|
64
|
+
fs.writeFileSync(errorsPath, JSON.stringify({
|
|
65
|
+
_comment: "Auto-detected errors by error_sensor",
|
|
66
|
+
errors: [],
|
|
67
|
+
lastScan: null
|
|
68
|
+
}, null, 2));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Load detected errors
|
|
73
|
+
function loadErrors() {
|
|
74
|
+
ensureFiles();
|
|
75
|
+
try {
|
|
76
|
+
const data = JSON.parse(fs.readFileSync(errorsPath, 'utf8'));
|
|
77
|
+
return data.errors || [];
|
|
78
|
+
} catch {
|
|
79
|
+
return [];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Save detected errors
|
|
84
|
+
function saveErrors(errors) {
|
|
85
|
+
ensureFiles();
|
|
86
|
+
const data = {
|
|
87
|
+
_comment: "Auto-detected errors by error_sensor",
|
|
88
|
+
lastScan: new Date().toISOString(),
|
|
89
|
+
totalErrors: errors.length,
|
|
90
|
+
errors
|
|
91
|
+
};
|
|
92
|
+
fs.writeFileSync(errorsPath, JSON.stringify(data, null, 2));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Add error to collection
|
|
96
|
+
function addError(error) {
|
|
97
|
+
const errors = loadErrors();
|
|
98
|
+
|
|
99
|
+
// Check for duplicates (same type + message within last hour)
|
|
100
|
+
const oneHourAgo = Date.now() - 3600000;
|
|
101
|
+
const isDuplicate = errors.some(e =>
|
|
102
|
+
e.type === error.type &&
|
|
103
|
+
e.message === error.message &&
|
|
104
|
+
new Date(e.timestamp).getTime() > oneHourAgo
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
if (!isDuplicate) {
|
|
108
|
+
errors.push({
|
|
109
|
+
id: `ERR-${Date.now()}`,
|
|
110
|
+
...error,
|
|
111
|
+
timestamp: new Date().toISOString()
|
|
112
|
+
});
|
|
113
|
+
saveErrors(errors);
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// ==================== CONTEXT DETECTION ====================
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Detect project context from package.json and folder structure
|
|
123
|
+
*/
|
|
124
|
+
function detectProjectContext() {
|
|
125
|
+
const context = {
|
|
126
|
+
projectType: 'unknown',
|
|
127
|
+
framework: null,
|
|
128
|
+
language: 'javascript',
|
|
129
|
+
hasTypeScript: false,
|
|
130
|
+
hasTesting: false
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
const pkgPath = path.join(projectRoot, 'package.json');
|
|
135
|
+
if (fs.existsSync(pkgPath)) {
|
|
136
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
137
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
138
|
+
|
|
139
|
+
// Detect project type
|
|
140
|
+
if (deps['next']) {
|
|
141
|
+
context.projectType = 'nextjs';
|
|
142
|
+
context.framework = 'next';
|
|
143
|
+
} else if (deps['react-native'] || deps['expo']) {
|
|
144
|
+
context.projectType = 'react-native';
|
|
145
|
+
context.framework = 'react-native';
|
|
146
|
+
} else if (deps['react']) {
|
|
147
|
+
context.projectType = 'react';
|
|
148
|
+
context.framework = 'react';
|
|
149
|
+
} else if (deps['vue']) {
|
|
150
|
+
context.projectType = 'vue';
|
|
151
|
+
context.framework = 'vue';
|
|
152
|
+
} else if (deps['express'] || deps['fastify'] || deps['koa']) {
|
|
153
|
+
context.projectType = 'backend';
|
|
154
|
+
context.framework = deps['express'] ? 'express' : deps['fastify'] ? 'fastify' : 'koa';
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Detect TypeScript
|
|
158
|
+
if (deps['typescript'] || fs.existsSync(path.join(projectRoot, 'tsconfig.json'))) {
|
|
159
|
+
context.hasTypeScript = true;
|
|
160
|
+
context.language = 'typescript';
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Detect testing framework
|
|
164
|
+
if (deps['vitest'] || deps['jest'] || deps['mocha']) {
|
|
165
|
+
context.hasTesting = true;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
} catch { }
|
|
169
|
+
|
|
170
|
+
return context;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Detect file context from file path
|
|
175
|
+
*/
|
|
176
|
+
function detectFileContext(filePath) {
|
|
177
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
178
|
+
const dir = path.dirname(filePath);
|
|
179
|
+
const relativePath = path.relative(projectRoot, filePath);
|
|
180
|
+
|
|
181
|
+
const context = {
|
|
182
|
+
fileType: ext,
|
|
183
|
+
isTypeScript: ext === '.ts' || ext === '.tsx',
|
|
184
|
+
isTest: /\.(test|spec)\./i.test(filePath) || relativePath.includes('__tests__'),
|
|
185
|
+
isComponent: ext === '.tsx' || ext === '.jsx',
|
|
186
|
+
directory: relativePath.split(path.sep)[0] || 'root',
|
|
187
|
+
fullPath: relativePath
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
// Detect specific directories
|
|
191
|
+
if (relativePath.startsWith('src')) {
|
|
192
|
+
context.area = 'source';
|
|
193
|
+
} else if (relativePath.startsWith('lib')) {
|
|
194
|
+
context.area = 'library';
|
|
195
|
+
} else if (relativePath.startsWith('test') || relativePath.startsWith('__tests__')) {
|
|
196
|
+
context.area = 'test';
|
|
197
|
+
} else if (relativePath.startsWith('scripts')) {
|
|
198
|
+
context.area = 'scripts';
|
|
199
|
+
} else {
|
|
200
|
+
context.area = 'other';
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return context;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Add context to error object
|
|
208
|
+
*/
|
|
209
|
+
function addErrorWithContext(error) {
|
|
210
|
+
const projectContext = detectProjectContext();
|
|
211
|
+
const fileContext = error.file ? detectFileContext(error.file) : null;
|
|
212
|
+
|
|
213
|
+
const enrichedError = {
|
|
214
|
+
...error,
|
|
215
|
+
context: {
|
|
216
|
+
project: projectContext,
|
|
217
|
+
file: fileContext
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
return addError(enrichedError);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// ==================== SENSORS ====================
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Parse test output (vitest/jest)
|
|
228
|
+
*/
|
|
229
|
+
function scanTestErrors() {
|
|
230
|
+
const errors = [];
|
|
231
|
+
|
|
232
|
+
try {
|
|
233
|
+
// Try to run tests and capture output
|
|
234
|
+
const testOutput = execSync('npm test 2>&1', {
|
|
235
|
+
cwd: projectRoot,
|
|
236
|
+
encoding: 'utf8',
|
|
237
|
+
timeout: 60000
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
// Parse vitest output
|
|
241
|
+
const failedTests = testOutput.match(/FAIL\s+(.+)/g) || [];
|
|
242
|
+
const errorMessages = testOutput.match(/Error:\s*(.+)/g) || [];
|
|
243
|
+
const assertionFails = testOutput.match(/expect\(.+\)\.(.+)/g) || [];
|
|
244
|
+
|
|
245
|
+
for (const fail of failedTests) {
|
|
246
|
+
errors.push({
|
|
247
|
+
type: 'test',
|
|
248
|
+
source: 'vitest',
|
|
249
|
+
message: fail.trim(),
|
|
250
|
+
severity: 'HIGH',
|
|
251
|
+
raw: fail
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
for (const err of errorMessages) {
|
|
256
|
+
errors.push({
|
|
257
|
+
type: 'test',
|
|
258
|
+
source: 'vitest',
|
|
259
|
+
message: err.replace('Error:', '').trim(),
|
|
260
|
+
severity: 'HIGH',
|
|
261
|
+
raw: err
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
} catch (e) {
|
|
266
|
+
// Test command failed - parse error output
|
|
267
|
+
const output = e.stdout || e.stderr || '';
|
|
268
|
+
const lines = output.split('\n');
|
|
269
|
+
|
|
270
|
+
for (const line of lines) {
|
|
271
|
+
if (line.includes('FAIL') || line.includes('Error') || line.includes('✗')) {
|
|
272
|
+
errors.push({
|
|
273
|
+
type: 'test',
|
|
274
|
+
source: 'vitest',
|
|
275
|
+
message: line.trim(),
|
|
276
|
+
severity: 'HIGH',
|
|
277
|
+
raw: line
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return errors;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Parse build errors (TypeScript)
|
|
288
|
+
*/
|
|
289
|
+
function scanBuildErrors() {
|
|
290
|
+
const errors = [];
|
|
291
|
+
|
|
292
|
+
try {
|
|
293
|
+
execSync('npx tsc --noEmit 2>&1', {
|
|
294
|
+
cwd: projectRoot,
|
|
295
|
+
encoding: 'utf8',
|
|
296
|
+
timeout: 60000
|
|
297
|
+
});
|
|
298
|
+
} catch (e) {
|
|
299
|
+
const output = e.stdout || e.stderr || '';
|
|
300
|
+
// Parse TypeScript errors: file.ts(line,col): error TS1234: message
|
|
301
|
+
const tsErrors = output.match(/(.+\.tsx?)\((\d+),(\d+)\):\s*error\s+(TS\d+):\s*(.+)/g) || [];
|
|
302
|
+
|
|
303
|
+
for (const err of tsErrors) {
|
|
304
|
+
const match = err.match(/(.+\.tsx?)\((\d+),(\d+)\):\s*error\s+(TS\d+):\s*(.+)/);
|
|
305
|
+
if (match) {
|
|
306
|
+
errors.push({
|
|
307
|
+
type: 'build',
|
|
308
|
+
source: 'typescript',
|
|
309
|
+
file: match[1],
|
|
310
|
+
line: parseInt(match[2]),
|
|
311
|
+
code: match[4],
|
|
312
|
+
message: match[5],
|
|
313
|
+
severity: 'HIGH',
|
|
314
|
+
raw: err
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return errors;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Parse lint errors (ESLint)
|
|
325
|
+
*/
|
|
326
|
+
function scanLintErrors() {
|
|
327
|
+
const errors = [];
|
|
328
|
+
|
|
329
|
+
try {
|
|
330
|
+
execSync('npm run lint 2>&1', {
|
|
331
|
+
cwd: projectRoot,
|
|
332
|
+
encoding: 'utf8',
|
|
333
|
+
timeout: 60000
|
|
334
|
+
});
|
|
335
|
+
} catch (e) {
|
|
336
|
+
const output = e.stdout || e.stderr || '';
|
|
337
|
+
// Parse ESLint output: file.js:line:col error/warning message rule
|
|
338
|
+
const lintErrors = output.match(/(.+):(\d+):(\d+)\s+(error|warning)\s+(.+?)\s{2,}(.+)/g) || [];
|
|
339
|
+
|
|
340
|
+
for (const err of lintErrors) {
|
|
341
|
+
const match = err.match(/(.+):(\d+):(\d+)\s+(error|warning)\s+(.+?)\s{2,}(.+)/);
|
|
342
|
+
if (match) {
|
|
343
|
+
errors.push({
|
|
344
|
+
type: 'lint',
|
|
345
|
+
source: 'eslint',
|
|
346
|
+
file: match[1],
|
|
347
|
+
line: parseInt(match[2]),
|
|
348
|
+
level: match[4],
|
|
349
|
+
message: match[5],
|
|
350
|
+
rule: match[6],
|
|
351
|
+
severity: match[4] === 'error' ? 'HIGH' : 'MEDIUM',
|
|
352
|
+
raw: err
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return errors;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Scan for common code patterns that indicate errors
|
|
363
|
+
*/
|
|
364
|
+
function scanCodePatterns() {
|
|
365
|
+
const errors = [];
|
|
366
|
+
const srcDirs = ['src', 'lib', 'app', 'components', 'pages'];
|
|
367
|
+
|
|
368
|
+
for (const dir of srcDirs) {
|
|
369
|
+
const fullPath = path.join(projectRoot, dir);
|
|
370
|
+
if (!fs.existsSync(fullPath)) continue;
|
|
371
|
+
|
|
372
|
+
// Recursively scan files
|
|
373
|
+
const files = getAllFiles(fullPath, ['.js', '.ts', '.jsx', '.tsx']);
|
|
374
|
+
|
|
375
|
+
for (const file of files) {
|
|
376
|
+
const content = fs.readFileSync(file, 'utf8');
|
|
377
|
+
const lines = content.split('\n');
|
|
378
|
+
|
|
379
|
+
lines.forEach((line, idx) => {
|
|
380
|
+
// Detect console.error
|
|
381
|
+
if (line.includes('console.error')) {
|
|
382
|
+
errors.push({
|
|
383
|
+
type: 'pattern',
|
|
384
|
+
source: 'code-scan',
|
|
385
|
+
file: file,
|
|
386
|
+
line: idx + 1,
|
|
387
|
+
message: 'console.error detected',
|
|
388
|
+
severity: 'LOW',
|
|
389
|
+
raw: line.trim()
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// Detect TODO/FIXME with error keywords
|
|
394
|
+
if (/\/\/\s*(TODO|FIXME|BUG|HACK).*error/i.test(line)) {
|
|
395
|
+
errors.push({
|
|
396
|
+
type: 'pattern',
|
|
397
|
+
source: 'code-scan',
|
|
398
|
+
file: file,
|
|
399
|
+
line: idx + 1,
|
|
400
|
+
message: 'TODO/FIXME with error keyword',
|
|
401
|
+
severity: 'MEDIUM',
|
|
402
|
+
raw: line.trim()
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// Detect empty catch blocks
|
|
407
|
+
if (/catch\s*\([^)]*\)\s*{\s*}/.test(line)) {
|
|
408
|
+
errors.push({
|
|
409
|
+
type: 'pattern',
|
|
410
|
+
source: 'code-scan',
|
|
411
|
+
file: file,
|
|
412
|
+
line: idx + 1,
|
|
413
|
+
message: 'Empty catch block - errors silently swallowed',
|
|
414
|
+
severity: 'HIGH',
|
|
415
|
+
raw: line.trim()
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
return errors;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// Helper: Get all files recursively
|
|
426
|
+
function getAllFiles(dir, extensions) {
|
|
427
|
+
const files = [];
|
|
428
|
+
|
|
429
|
+
try {
|
|
430
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
431
|
+
|
|
432
|
+
for (const entry of entries) {
|
|
433
|
+
const fullPath = path.join(dir, entry.name);
|
|
434
|
+
|
|
435
|
+
if (entry.isDirectory() && !entry.name.startsWith('.') && entry.name !== 'node_modules') {
|
|
436
|
+
files.push(...getAllFiles(fullPath, extensions));
|
|
437
|
+
} else if (entry.isFile() && extensions.some(ext => entry.name.endsWith(ext))) {
|
|
438
|
+
files.push(fullPath);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
} catch {
|
|
442
|
+
// Ignore permission errors
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
return files;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// ==================== MAIN ====================
|
|
449
|
+
|
|
450
|
+
function runScan(type) {
|
|
451
|
+
console.log(`${c.cyan}🔍 Error Sensor - Scanning ${type}...${c.reset}\n`);
|
|
452
|
+
|
|
453
|
+
let allErrors = [];
|
|
454
|
+
|
|
455
|
+
if (type === 'all' || type === 'test') {
|
|
456
|
+
console.log(`${c.gray} Scanning test output...${c.reset}`);
|
|
457
|
+
const testErrors = scanTestErrors();
|
|
458
|
+
allErrors.push(...testErrors);
|
|
459
|
+
console.log(`${c.gray} Found ${testErrors.length} test errors${c.reset}`);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
if (type === 'all' || type === 'build') {
|
|
463
|
+
console.log(`${c.gray} Scanning build output...${c.reset}`);
|
|
464
|
+
const buildErrors = scanBuildErrors();
|
|
465
|
+
allErrors.push(...buildErrors);
|
|
466
|
+
console.log(`${c.gray} Found ${buildErrors.length} build errors${c.reset}`);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
if (type === 'all' || type === 'lint') {
|
|
470
|
+
console.log(`${c.gray} Scanning lint output...${c.reset}`);
|
|
471
|
+
const lintErrors = scanLintErrors();
|
|
472
|
+
allErrors.push(...lintErrors);
|
|
473
|
+
console.log(`${c.gray} Found ${lintErrors.length} lint errors${c.reset}`);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
if (type === 'all' || type === 'pattern') {
|
|
477
|
+
console.log(`${c.gray} Scanning code patterns...${c.reset}`);
|
|
478
|
+
const patternErrors = scanCodePatterns();
|
|
479
|
+
allErrors.push(...patternErrors);
|
|
480
|
+
console.log(`${c.gray} Found ${patternErrors.length} pattern issues${c.reset}`);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Save detected errors
|
|
484
|
+
let newCount = 0;
|
|
485
|
+
for (const error of allErrors) {
|
|
486
|
+
if (addError(error)) {
|
|
487
|
+
newCount++;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
console.log(`\n${c.cyan}════════════════════════════════════════${c.reset}`);
|
|
492
|
+
console.log(`${c.bold}Scan Complete${c.reset}`);
|
|
493
|
+
console.log(` Total detected: ${allErrors.length}`);
|
|
494
|
+
console.log(` New errors: ${c.yellow}${newCount}${c.reset}`);
|
|
495
|
+
console.log(` Saved to: ${c.gray}${errorsPath}${c.reset}`);
|
|
496
|
+
console.log(`${c.cyan}════════════════════════════════════════${c.reset}`);
|
|
497
|
+
|
|
498
|
+
return allErrors;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function showStats() {
|
|
502
|
+
const errors = loadErrors();
|
|
503
|
+
|
|
504
|
+
console.log(`${c.cyan}╔════════════════════════════════════════╗${c.reset}`);
|
|
505
|
+
console.log(`${c.cyan}║${c.reset} 📊 Error Sensor Statistics ${c.cyan}║${c.reset}`);
|
|
506
|
+
console.log(`${c.cyan}╚════════════════════════════════════════╝${c.reset}\n`);
|
|
507
|
+
|
|
508
|
+
// Group by type
|
|
509
|
+
const byType = {};
|
|
510
|
+
const bySeverity = {};
|
|
511
|
+
|
|
512
|
+
for (const err of errors) {
|
|
513
|
+
byType[err.type] = (byType[err.type] || 0) + 1;
|
|
514
|
+
bySeverity[err.severity] = (bySeverity[err.severity] || 0) + 1;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
console.log(`${c.bold}By Type:${c.reset}`);
|
|
518
|
+
for (const [type, count] of Object.entries(byType)) {
|
|
519
|
+
console.log(` ${type}: ${count}`);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
console.log(`\n${c.bold}By Severity:${c.reset}`);
|
|
523
|
+
for (const [sev, count] of Object.entries(bySeverity)) {
|
|
524
|
+
const color = { CRITICAL: c.red, HIGH: c.yellow, MEDIUM: c.blue, LOW: c.gray }[sev] || c.gray;
|
|
525
|
+
console.log(` ${color}${sev}${c.reset}: ${count}`);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
console.log(`\n${c.gray}Total errors tracked: ${errors.length}${c.reset}`);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// Parse CLI args
|
|
532
|
+
const args = process.argv.slice(2);
|
|
533
|
+
|
|
534
|
+
if (args.includes('--scan') || args.includes('-s')) {
|
|
535
|
+
const idx = args.findIndex(a => a === '--scan' || a === '-s');
|
|
536
|
+
const type = args[idx + 1] || 'all';
|
|
537
|
+
runScan(type);
|
|
538
|
+
} else if (args.includes('--stats')) {
|
|
539
|
+
showStats();
|
|
540
|
+
} else if (args.includes('--clear')) {
|
|
541
|
+
saveErrors([]);
|
|
542
|
+
console.log(`${c.green}✓ Cleared all detected errors${c.reset}`);
|
|
543
|
+
} else {
|
|
544
|
+
console.log(`${c.cyan}error_sensor - Auto-detect errors from test/build/lint${c.reset}
|
|
545
|
+
|
|
546
|
+
${c.bold}Usage:${c.reset}
|
|
547
|
+
node error_sensor.js --scan <type> Scan for errors
|
|
548
|
+
node error_sensor.js --stats Show error statistics
|
|
549
|
+
node error_sensor.js --clear Clear recorded errors
|
|
550
|
+
|
|
551
|
+
${c.bold}Scan types:${c.reset}
|
|
552
|
+
test Scan test output (vitest/jest)
|
|
553
|
+
build Scan TypeScript errors
|
|
554
|
+
lint Scan ESLint errors
|
|
555
|
+
pattern Scan code for error patterns
|
|
556
|
+
all Scan all sources (default)
|
|
557
|
+
|
|
558
|
+
${c.bold}Examples:${c.reset}
|
|
559
|
+
node error_sensor.js --scan all
|
|
560
|
+
node error_sensor.js --scan test
|
|
561
|
+
node error_sensor.js --stats
|
|
562
|
+
`);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
export { runScan, scanTestErrors, scanBuildErrors, scanLintErrors, scanCodePatterns, loadErrors };
|