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,426 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* User Correction Sensor - Detect when user corrects AI-generated code
|
|
4
|
+
*
|
|
5
|
+
* Part of FAANG-Grade Auto-Learn System Phase 1
|
|
6
|
+
*
|
|
7
|
+
* Monitors git diff to detect:
|
|
8
|
+
* - Files modified shortly after AI generation
|
|
9
|
+
* - Common correction patterns
|
|
10
|
+
* - Import/path fixes
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* node user_correction_sensor.js --scan
|
|
14
|
+
* node user_correction_sensor.js --recent 1h
|
|
15
|
+
* node user_correction_sensor.js --stats
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import fs from 'fs';
|
|
19
|
+
import path from 'path';
|
|
20
|
+
import { execSync } from 'child_process';
|
|
21
|
+
import { fileURLToPath } from 'url';
|
|
22
|
+
|
|
23
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
24
|
+
const __dirname = path.dirname(__filename);
|
|
25
|
+
|
|
26
|
+
// Colors
|
|
27
|
+
const c = {
|
|
28
|
+
reset: '\x1b[0m',
|
|
29
|
+
red: '\x1b[31m',
|
|
30
|
+
green: '\x1b[32m',
|
|
31
|
+
yellow: '\x1b[33m',
|
|
32
|
+
blue: '\x1b[34m',
|
|
33
|
+
cyan: '\x1b[36m',
|
|
34
|
+
gray: '\x1b[90m',
|
|
35
|
+
bold: '\x1b[1m'
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// Find project root
|
|
39
|
+
function findProjectRoot() {
|
|
40
|
+
let current = process.cwd();
|
|
41
|
+
while (current !== path.dirname(current)) {
|
|
42
|
+
if (fs.existsSync(path.join(current, '.agent'))) {
|
|
43
|
+
return current;
|
|
44
|
+
}
|
|
45
|
+
current = path.dirname(current);
|
|
46
|
+
}
|
|
47
|
+
return process.cwd();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const projectRoot = findProjectRoot();
|
|
51
|
+
const knowledgePath = path.join(projectRoot, '.agent', 'knowledge');
|
|
52
|
+
const correctionsPath = path.join(knowledgePath, 'user-corrections.json');
|
|
53
|
+
|
|
54
|
+
// Ensure files exist
|
|
55
|
+
function ensureFiles() {
|
|
56
|
+
if (!fs.existsSync(knowledgePath)) {
|
|
57
|
+
fs.mkdirSync(knowledgePath, { recursive: true });
|
|
58
|
+
}
|
|
59
|
+
if (!fs.existsSync(correctionsPath)) {
|
|
60
|
+
fs.writeFileSync(correctionsPath, JSON.stringify({
|
|
61
|
+
_comment: "User corrections detected by correction_sensor",
|
|
62
|
+
corrections: [],
|
|
63
|
+
lastScan: null
|
|
64
|
+
}, null, 2));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Load corrections
|
|
69
|
+
function loadCorrections() {
|
|
70
|
+
ensureFiles();
|
|
71
|
+
try {
|
|
72
|
+
const data = JSON.parse(fs.readFileSync(correctionsPath, 'utf8'));
|
|
73
|
+
return data.corrections || [];
|
|
74
|
+
} catch {
|
|
75
|
+
return [];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Save corrections
|
|
80
|
+
function saveCorrections(corrections) {
|
|
81
|
+
ensureFiles();
|
|
82
|
+
const data = {
|
|
83
|
+
_comment: "User corrections detected by correction_sensor",
|
|
84
|
+
lastScan: new Date().toISOString(),
|
|
85
|
+
totalCorrections: corrections.length,
|
|
86
|
+
corrections
|
|
87
|
+
};
|
|
88
|
+
fs.writeFileSync(correctionsPath, JSON.stringify(data, null, 2));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Add correction
|
|
92
|
+
function addCorrection(correction) {
|
|
93
|
+
const corrections = loadCorrections();
|
|
94
|
+
|
|
95
|
+
// Check for duplicates
|
|
96
|
+
const isDuplicate = corrections.some(c =>
|
|
97
|
+
c.file === correction.file &&
|
|
98
|
+
c.pattern === correction.pattern
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
if (!isDuplicate) {
|
|
102
|
+
corrections.push({
|
|
103
|
+
id: `COR-${Date.now()}`,
|
|
104
|
+
...correction,
|
|
105
|
+
timestamp: new Date().toISOString()
|
|
106
|
+
});
|
|
107
|
+
saveCorrections(corrections);
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Common correction patterns to detect
|
|
114
|
+
const CORRECTION_PATTERNS = [
|
|
115
|
+
{
|
|
116
|
+
name: 'import_path_fix',
|
|
117
|
+
regex: /^[-+].*import.*from\s+['"](\.+\/|@)/,
|
|
118
|
+
description: 'Import path correction',
|
|
119
|
+
severity: 'HIGH'
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
name: 'type_annotation_fix',
|
|
123
|
+
regex: /^[-+].*:\s*(string|number|boolean|any|unknown|void)\b/,
|
|
124
|
+
description: 'Type annotation correction',
|
|
125
|
+
severity: 'MEDIUM'
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
name: 'null_check_added',
|
|
129
|
+
regex: /^\+.*(\?\.|!= null|!== null|\?\?)/,
|
|
130
|
+
description: 'Null check added',
|
|
131
|
+
severity: 'HIGH'
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
name: 'async_await_fix',
|
|
135
|
+
regex: /^[-+].*(async|await)\b/,
|
|
136
|
+
description: 'Async/await correction',
|
|
137
|
+
severity: 'HIGH'
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
name: 'variable_rename',
|
|
141
|
+
regex: /^-.*const\s+(\w+).*\n^\+.*const\s+(\w+)/m,
|
|
142
|
+
description: 'Variable renamed',
|
|
143
|
+
severity: 'MEDIUM'
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
name: 'error_handling_added',
|
|
147
|
+
regex: /^\+.*(try\s*{|catch\s*\(|\.catch\()/,
|
|
148
|
+
description: 'Error handling added',
|
|
149
|
+
severity: 'HIGH'
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
name: 'dependency_added',
|
|
153
|
+
regex: /^\+.*"[^"]+"\s*:\s*"[~^]?\d/,
|
|
154
|
+
description: 'Dependency added',
|
|
155
|
+
severity: 'MEDIUM'
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
name: 'condition_fix',
|
|
159
|
+
regex: /^[-+].*if\s*\(/,
|
|
160
|
+
description: 'Condition logic correction',
|
|
161
|
+
severity: 'HIGH'
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
name: 'return_value_fix',
|
|
165
|
+
regex: /^[-+].*return\s+/,
|
|
166
|
+
description: 'Return value correction',
|
|
167
|
+
severity: 'HIGH'
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
name: 'spelling_fix',
|
|
171
|
+
regex: /^-.*(\w+).*\n^\+.*\1[a-z]/i,
|
|
172
|
+
description: 'Spelling/typo fix',
|
|
173
|
+
severity: 'LOW'
|
|
174
|
+
}
|
|
175
|
+
];
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Get git diff from recent changes
|
|
179
|
+
*/
|
|
180
|
+
function getRecentDiff(since = '1 hour ago') {
|
|
181
|
+
try {
|
|
182
|
+
// Get diff of uncommitted changes
|
|
183
|
+
const staged = execSync('git diff --cached', {
|
|
184
|
+
cwd: projectRoot,
|
|
185
|
+
encoding: 'utf8',
|
|
186
|
+
maxBuffer: 10 * 1024 * 1024
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
const unstaged = execSync('git diff', {
|
|
190
|
+
cwd: projectRoot,
|
|
191
|
+
encoding: 'utf8',
|
|
192
|
+
maxBuffer: 10 * 1024 * 1024
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
return staged + '\n' + unstaged;
|
|
196
|
+
} catch {
|
|
197
|
+
return '';
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Parse diff and detect correction patterns
|
|
203
|
+
*/
|
|
204
|
+
function detectCorrections(diffOutput) {
|
|
205
|
+
const corrections = [];
|
|
206
|
+
const files = diffOutput.split(/^diff --git/m).slice(1);
|
|
207
|
+
|
|
208
|
+
for (const fileDiff of files) {
|
|
209
|
+
// Extract file name
|
|
210
|
+
const fileMatch = fileDiff.match(/a\/(.+)\s+b\//);
|
|
211
|
+
if (!fileMatch) continue;
|
|
212
|
+
|
|
213
|
+
const fileName = fileMatch[1];
|
|
214
|
+
|
|
215
|
+
// Skip non-code files
|
|
216
|
+
if (!/\.(js|ts|jsx|tsx|json|py|rb|go)$/.test(fileName)) continue;
|
|
217
|
+
|
|
218
|
+
// Get the actual diff content
|
|
219
|
+
const diffContent = fileDiff.split('\n').filter(l => l.startsWith('+') || l.startsWith('-'));
|
|
220
|
+
|
|
221
|
+
// Check each pattern
|
|
222
|
+
for (const pattern of CORRECTION_PATTERNS) {
|
|
223
|
+
for (const line of diffContent) {
|
|
224
|
+
if (pattern.regex.test(line)) {
|
|
225
|
+
corrections.push({
|
|
226
|
+
file: fileName,
|
|
227
|
+
pattern: pattern.name,
|
|
228
|
+
description: pattern.description,
|
|
229
|
+
severity: pattern.severity,
|
|
230
|
+
line: line.substring(0, 100), // Truncate for storage
|
|
231
|
+
category: categorizeCorrection(pattern.name)
|
|
232
|
+
});
|
|
233
|
+
break; // One match per pattern per file
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return corrections;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Categorize correction for pattern analysis
|
|
244
|
+
*/
|
|
245
|
+
function categorizeCorrection(patternName) {
|
|
246
|
+
const categories = {
|
|
247
|
+
import_path_fix: 'imports',
|
|
248
|
+
type_annotation_fix: 'types',
|
|
249
|
+
null_check_added: 'null-safety',
|
|
250
|
+
async_await_fix: 'async',
|
|
251
|
+
variable_rename: 'naming',
|
|
252
|
+
error_handling_added: 'error-handling',
|
|
253
|
+
dependency_added: 'dependencies',
|
|
254
|
+
condition_fix: 'logic',
|
|
255
|
+
return_value_fix: 'logic',
|
|
256
|
+
spelling_fix: 'typo'
|
|
257
|
+
};
|
|
258
|
+
return categories[patternName] || 'other';
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Analyze corrections to find patterns
|
|
263
|
+
*/
|
|
264
|
+
function analyzePatterns(corrections) {
|
|
265
|
+
const byCategory = {};
|
|
266
|
+
const byFile = {};
|
|
267
|
+
|
|
268
|
+
for (const corr of corrections) {
|
|
269
|
+
// By category
|
|
270
|
+
byCategory[corr.category] = (byCategory[corr.category] || 0) + 1;
|
|
271
|
+
|
|
272
|
+
// By file
|
|
273
|
+
const dir = path.dirname(corr.file);
|
|
274
|
+
byFile[dir] = (byFile[dir] || 0) + 1;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return {
|
|
278
|
+
byCategory,
|
|
279
|
+
byFile,
|
|
280
|
+
total: corrections.length,
|
|
281
|
+
topCategory: Object.entries(byCategory).sort((a, b) => b[1] - a[1])[0],
|
|
282
|
+
topDirectory: Object.entries(byFile).sort((a, b) => b[1] - a[1])[0]
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// ==================== MAIN ====================
|
|
287
|
+
|
|
288
|
+
function runScan() {
|
|
289
|
+
console.log(`${c.cyan}🔍 User Correction Sensor${c.reset}\n`);
|
|
290
|
+
console.log(`${c.gray}Scanning git diff for correction patterns...${c.reset}\n`);
|
|
291
|
+
|
|
292
|
+
const diff = getRecentDiff();
|
|
293
|
+
|
|
294
|
+
if (!diff.trim()) {
|
|
295
|
+
console.log(`${c.yellow}No uncommitted changes found.${c.reset}`);
|
|
296
|
+
console.log(`${c.gray}Tip: Make changes and run again before committing.${c.reset}`);
|
|
297
|
+
return [];
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const detected = detectCorrections(diff);
|
|
301
|
+
|
|
302
|
+
// Save new corrections
|
|
303
|
+
let newCount = 0;
|
|
304
|
+
for (const corr of detected) {
|
|
305
|
+
if (addCorrection(corr)) {
|
|
306
|
+
newCount++;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Display results
|
|
311
|
+
console.log(`${c.cyan}════════════════════════════════════════${c.reset}`);
|
|
312
|
+
console.log(`${c.bold}Scan Complete${c.reset}`);
|
|
313
|
+
console.log(` Patterns detected: ${detected.length}`);
|
|
314
|
+
console.log(` New corrections: ${c.yellow}${newCount}${c.reset}`);
|
|
315
|
+
console.log(`${c.cyan}════════════════════════════════════════${c.reset}\n`);
|
|
316
|
+
|
|
317
|
+
if (detected.length > 0) {
|
|
318
|
+
console.log(`${c.bold}Detected Corrections:${c.reset}`);
|
|
319
|
+
for (const corr of detected) {
|
|
320
|
+
const sevColor = { HIGH: c.yellow, MEDIUM: c.blue, LOW: c.gray }[corr.severity] || c.gray;
|
|
321
|
+
console.log(` ${sevColor}●${c.reset} ${corr.file}`);
|
|
322
|
+
console.log(` ${c.gray}${corr.description} (${corr.category})${c.reset}`);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return detected;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function showStats() {
|
|
330
|
+
const corrections = loadCorrections();
|
|
331
|
+
const analysis = analyzePatterns(corrections);
|
|
332
|
+
|
|
333
|
+
console.log(`${c.cyan}╔════════════════════════════════════════╗${c.reset}`);
|
|
334
|
+
console.log(`${c.cyan}║${c.reset} 📊 Correction Statistics ${c.cyan}║${c.reset}`);
|
|
335
|
+
console.log(`${c.cyan}╚════════════════════════════════════════╝${c.reset}\n`);
|
|
336
|
+
|
|
337
|
+
console.log(`${c.bold}By Category:${c.reset}`);
|
|
338
|
+
for (const [cat, count] of Object.entries(analysis.byCategory).sort((a, b) => b[1] - a[1])) {
|
|
339
|
+
const bar = '█'.repeat(Math.min(count, 20));
|
|
340
|
+
console.log(` ${cat.padEnd(15)} ${c.cyan}${bar}${c.reset} ${count}`);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
console.log(`\n${c.bold}Hot Directories (most corrections):${c.reset}`);
|
|
344
|
+
for (const [dir, count] of Object.entries(analysis.byFile).sort((a, b) => b[1] - a[1]).slice(0, 5)) {
|
|
345
|
+
console.log(` ${dir}: ${count}`);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
if (analysis.topCategory) {
|
|
349
|
+
console.log(`\n${c.yellow}⚠️ Most common issue: ${analysis.topCategory[0]} (${analysis.topCategory[1]} times)${c.reset}`);
|
|
350
|
+
console.log(`${c.gray} Consider creating a rule to prevent this pattern.${c.reset}`);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
console.log(`\n${c.gray}Total corrections tracked: ${corrections.length}${c.reset}`);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
function suggestLessons() {
|
|
357
|
+
const corrections = loadCorrections();
|
|
358
|
+
const analysis = analyzePatterns(corrections);
|
|
359
|
+
|
|
360
|
+
console.log(`${c.cyan}💡 Suggested Lessons${c.reset}\n`);
|
|
361
|
+
|
|
362
|
+
// Find patterns that occur 3+ times
|
|
363
|
+
const frequent = Object.entries(analysis.byCategory)
|
|
364
|
+
.filter(([_, count]) => count >= 3)
|
|
365
|
+
.sort((a, b) => b[1] - a[1]);
|
|
366
|
+
|
|
367
|
+
if (frequent.length === 0) {
|
|
368
|
+
console.log(`${c.gray}Not enough data yet. Keep coding and run again.${c.reset}`);
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
for (const [category, count] of frequent) {
|
|
373
|
+
console.log(`${c.bold}Pattern: ${category}${c.reset} (${count} occurrences)`);
|
|
374
|
+
|
|
375
|
+
const suggestions = {
|
|
376
|
+
'imports': 'Always use relative imports from project root. Check tsconfig paths.',
|
|
377
|
+
'types': 'Add explicit type annotations to function parameters and return types.',
|
|
378
|
+
'null-safety': 'Use optional chaining (?.) and nullish coalescing (??) operators.',
|
|
379
|
+
'async': 'Always use async/await pattern. Never mix callbacks and promises.',
|
|
380
|
+
'error-handling': 'Wrap async operations in try/catch. Never use empty catch blocks.',
|
|
381
|
+
'logic': 'Review conditional logic carefully. Add edge case tests.',
|
|
382
|
+
'naming': 'Follow naming conventions: camelCase for variables, PascalCase for types.'
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
console.log(` ${c.gray}Suggested rule: ${suggestions[category] || 'Review and document this pattern.'}${c.reset}\n`);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// Parse CLI args
|
|
390
|
+
const args = process.argv.slice(2);
|
|
391
|
+
|
|
392
|
+
if (args.includes('--scan') || args.includes('-s')) {
|
|
393
|
+
runScan();
|
|
394
|
+
} else if (args.includes('--stats')) {
|
|
395
|
+
showStats();
|
|
396
|
+
} else if (args.includes('--suggest')) {
|
|
397
|
+
suggestLessons();
|
|
398
|
+
} else if (args.includes('--clear')) {
|
|
399
|
+
saveCorrections([]);
|
|
400
|
+
console.log(`${c.green}✓ Cleared all corrections${c.reset}`);
|
|
401
|
+
} else {
|
|
402
|
+
console.log(`${c.cyan}user_correction_sensor - Detect AI code corrections${c.reset}
|
|
403
|
+
|
|
404
|
+
${c.bold}Usage:${c.reset}
|
|
405
|
+
node user_correction_sensor.js --scan Scan uncommitted changes
|
|
406
|
+
node user_correction_sensor.js --stats Show correction statistics
|
|
407
|
+
node user_correction_sensor.js --suggest Suggest lessons from patterns
|
|
408
|
+
node user_correction_sensor.js --clear Clear recorded corrections
|
|
409
|
+
|
|
410
|
+
${c.bold}What it detects:${c.reset}
|
|
411
|
+
• Import path corrections
|
|
412
|
+
• Type annotation fixes
|
|
413
|
+
• Added null checks
|
|
414
|
+
• Async/await corrections
|
|
415
|
+
• Error handling additions
|
|
416
|
+
• Logic/condition fixes
|
|
417
|
+
|
|
418
|
+
${c.bold}Example workflow:${c.reset}
|
|
419
|
+
1. AI generates code
|
|
420
|
+
2. User fixes issues
|
|
421
|
+
3. Run: node user_correction_sensor.js --scan
|
|
422
|
+
4. Patterns are recorded for analysis
|
|
423
|
+
`);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
export { runScan, detectCorrections, loadCorrections, analyzePatterns };
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-Learn Service
|
|
3
|
+
*
|
|
4
|
+
* Orchestrates all Auto-Learn scripts:
|
|
5
|
+
* - error_sensor.js
|
|
6
|
+
* - success_sensor.js
|
|
7
|
+
* - pattern_analyzer.js
|
|
8
|
+
* - pre_execution_check.js
|
|
9
|
+
* - adaptive_engine.js
|
|
10
|
+
* - skill_injector.js
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* import autoLearnService from './auto-learn-service.js';
|
|
14
|
+
* await autoLearnService.runFullCycle();
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { spawn } from 'child_process';
|
|
18
|
+
import path from 'path';
|
|
19
|
+
import { fileURLToPath } from 'url';
|
|
20
|
+
import fs from 'fs';
|
|
21
|
+
|
|
22
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
23
|
+
const __dirname = path.dirname(__filename);
|
|
24
|
+
|
|
25
|
+
// ==================== CONFIG ====================
|
|
26
|
+
|
|
27
|
+
const SCRIPTS_DIR = path.join(__dirname, '..', 'scripts');
|
|
28
|
+
|
|
29
|
+
const SCRIPTS = {
|
|
30
|
+
errorSensor: 'error_sensor.js',
|
|
31
|
+
successSensor: 'success_sensor.js',
|
|
32
|
+
patternAnalyzer: 'pattern_analyzer.js',
|
|
33
|
+
preExecutionCheck: 'pre_execution_check.js',
|
|
34
|
+
adaptiveEngine: 'adaptive_engine.js',
|
|
35
|
+
skillInjector: 'skill_injector.js',
|
|
36
|
+
ruleSharing: 'rule_sharing.js'
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// ==================== COLORS ====================
|
|
40
|
+
|
|
41
|
+
const c = {
|
|
42
|
+
reset: '\x1b[0m',
|
|
43
|
+
green: '\x1b[32m',
|
|
44
|
+
yellow: '\x1b[33m',
|
|
45
|
+
red: '\x1b[31m',
|
|
46
|
+
cyan: '\x1b[36m',
|
|
47
|
+
gray: '\x1b[90m'
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// ==================== RUNNER ====================
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Run a script and return result
|
|
54
|
+
* @param {string} scriptName - Script filename
|
|
55
|
+
* @param {string[]} args - Arguments
|
|
56
|
+
* @returns {Promise<{success: boolean, output: string}>}
|
|
57
|
+
*/
|
|
58
|
+
function runScript(scriptName, args = []) {
|
|
59
|
+
return new Promise((resolve) => {
|
|
60
|
+
const scriptPath = path.join(SCRIPTS_DIR, scriptName);
|
|
61
|
+
|
|
62
|
+
if (!fs.existsSync(scriptPath)) {
|
|
63
|
+
console.log(`${c.yellow}⚠️ Script not found: ${scriptName}${c.reset}`);
|
|
64
|
+
resolve({ success: false, output: 'Script not found' });
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
console.log(`${c.gray}▶ Running ${scriptName}...${c.reset}`);
|
|
69
|
+
|
|
70
|
+
const child = spawn('node', [scriptPath, ...args], {
|
|
71
|
+
cwd: process.cwd(),
|
|
72
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
let output = '';
|
|
76
|
+
|
|
77
|
+
child.stdout.on('data', (data) => {
|
|
78
|
+
output += data.toString();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
child.stderr.on('data', (data) => {
|
|
82
|
+
output += data.toString();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
child.on('close', (code) => {
|
|
86
|
+
if (code === 0) {
|
|
87
|
+
console.log(`${c.green}✓ ${scriptName} completed${c.reset}`);
|
|
88
|
+
resolve({ success: true, output });
|
|
89
|
+
} else {
|
|
90
|
+
console.log(`${c.red}✗ ${scriptName} failed (code ${code})${c.reset}`);
|
|
91
|
+
resolve({ success: false, output });
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
child.on('error', (err) => {
|
|
96
|
+
console.log(`${c.red}✗ ${scriptName} error: ${err.message}${c.reset}`);
|
|
97
|
+
resolve({ success: false, output: err.message });
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ==================== SERVICE FUNCTIONS ====================
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Run error sensor
|
|
106
|
+
*/
|
|
107
|
+
async function runErrorSensor() {
|
|
108
|
+
return runScript(SCRIPTS.errorSensor);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Run success sensor
|
|
113
|
+
*/
|
|
114
|
+
async function runSuccessSensor() {
|
|
115
|
+
return runScript(SCRIPTS.successSensor);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Run pattern analyzer
|
|
120
|
+
*/
|
|
121
|
+
async function runPatternAnalyzer() {
|
|
122
|
+
return runScript(SCRIPTS.patternAnalyzer);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Run pre-execution check
|
|
127
|
+
* @param {string} intent - User intent to check
|
|
128
|
+
*/
|
|
129
|
+
async function checkIntent(intent) {
|
|
130
|
+
return runScript(SCRIPTS.preExecutionCheck, [intent]);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Run adaptive engine
|
|
135
|
+
*/
|
|
136
|
+
async function runAdaptiveEngine() {
|
|
137
|
+
return runScript(SCRIPTS.adaptiveEngine);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Run skill injector
|
|
142
|
+
* @param {boolean} dryRun - Only simulate
|
|
143
|
+
*/
|
|
144
|
+
async function runSkillInjector(dryRun = true) {
|
|
145
|
+
const args = dryRun ? ['--dry-run'] : [];
|
|
146
|
+
return runScript(SCRIPTS.skillInjector, args);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Run rule sharing sync
|
|
151
|
+
*/
|
|
152
|
+
async function syncRules() {
|
|
153
|
+
return runScript(SCRIPTS.ruleSharing, ['--sync']);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ==================== FULL CYCLE ====================
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Run full Auto-Learn cycle
|
|
160
|
+
* @returns {Promise<{success: boolean, results: object}>}
|
|
161
|
+
*/
|
|
162
|
+
async function runFullCycle() {
|
|
163
|
+
console.log(`\n${c.cyan}╔════════════════════════════════════════╗${c.reset}`);
|
|
164
|
+
console.log(`${c.cyan}║${c.reset} 🧠 Auto-Learn Full Cycle ${c.cyan}║${c.reset}`);
|
|
165
|
+
console.log(`${c.cyan}╚════════════════════════════════════════╝${c.reset}\n`);
|
|
166
|
+
|
|
167
|
+
const results = {};
|
|
168
|
+
let allSuccess = true;
|
|
169
|
+
|
|
170
|
+
// Step 1: Scan for errors
|
|
171
|
+
console.log(`${c.cyan}[1/5]${c.reset} Scanning for errors...`);
|
|
172
|
+
results.errorSensor = await runErrorSensor();
|
|
173
|
+
if (!results.errorSensor.success) allSuccess = false;
|
|
174
|
+
|
|
175
|
+
// Step 2: Scan for successes
|
|
176
|
+
console.log(`\n${c.cyan}[2/5]${c.reset} Scanning for successes...`);
|
|
177
|
+
results.successSensor = await runSuccessSensor();
|
|
178
|
+
if (!results.successSensor.success) allSuccess = false;
|
|
179
|
+
|
|
180
|
+
// Step 3: Analyze patterns
|
|
181
|
+
console.log(`\n${c.cyan}[3/5]${c.reset} Analyzing patterns...`);
|
|
182
|
+
results.patternAnalyzer = await runPatternAnalyzer();
|
|
183
|
+
if (!results.patternAnalyzer.success) allSuccess = false;
|
|
184
|
+
|
|
185
|
+
// Step 4: Run adaptive engine
|
|
186
|
+
console.log(`\n${c.cyan}[4/5]${c.reset} Running adaptive engine...`);
|
|
187
|
+
results.adaptiveEngine = await runAdaptiveEngine();
|
|
188
|
+
if (!results.adaptiveEngine.success) allSuccess = false;
|
|
189
|
+
|
|
190
|
+
// Step 5: Check skill injection (dry run)
|
|
191
|
+
console.log(`\n${c.cyan}[5/5]${c.reset} Checking skill candidates...`);
|
|
192
|
+
results.skillInjector = await runSkillInjector(true);
|
|
193
|
+
|
|
194
|
+
// Summary
|
|
195
|
+
console.log(`\n${c.cyan}════════════════════════════════════════${c.reset}`);
|
|
196
|
+
if (allSuccess) {
|
|
197
|
+
console.log(`${c.green}✓ Auto-Learn cycle completed successfully!${c.reset}`);
|
|
198
|
+
} else {
|
|
199
|
+
console.log(`${c.yellow}⚠️ Auto-Learn cycle completed with some issues${c.reset}`);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return { success: allSuccess, results };
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Quick scan (errors + success only)
|
|
207
|
+
*/
|
|
208
|
+
async function quickScan() {
|
|
209
|
+
console.log(`${c.cyan}🔍 Quick Auto-Learn scan...${c.reset}\n`);
|
|
210
|
+
|
|
211
|
+
const errorResult = await runErrorSensor();
|
|
212
|
+
const successResult = await runSuccessSensor();
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
success: errorResult.success && successResult.success,
|
|
216
|
+
errors: errorResult,
|
|
217
|
+
successes: successResult
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// ==================== EXPORTS ====================
|
|
222
|
+
|
|
223
|
+
const autoLearnService = {
|
|
224
|
+
runErrorSensor,
|
|
225
|
+
runSuccessSensor,
|
|
226
|
+
runPatternAnalyzer,
|
|
227
|
+
checkIntent,
|
|
228
|
+
runAdaptiveEngine,
|
|
229
|
+
runSkillInjector,
|
|
230
|
+
syncRules,
|
|
231
|
+
runFullCycle,
|
|
232
|
+
quickScan
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
export {
|
|
236
|
+
runErrorSensor,
|
|
237
|
+
runSuccessSensor,
|
|
238
|
+
runPatternAnalyzer,
|
|
239
|
+
checkIntent,
|
|
240
|
+
runAdaptiveEngine,
|
|
241
|
+
runSkillInjector,
|
|
242
|
+
syncRules,
|
|
243
|
+
runFullCycle,
|
|
244
|
+
quickScan
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
export default autoLearnService;
|