add-skill-kit 3.2.4 → 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/{ag-smart.js → agent.js} +48 -15
- 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 +2 -2
- package/lib/agent-cli/lib/auto-learn.js +8 -8
- package/lib/agent-cli/lib/eslint-fix.js +1 -1
- package/lib/agent-cli/lib/fix.js +5 -5
- package/lib/agent-cli/lib/hooks/install-hooks.js +4 -4
- package/lib/agent-cli/lib/hooks/lint-learn.js +4 -4
- package/lib/agent-cli/lib/learn.js +10 -10
- package/lib/agent-cli/lib/recall.js +1 -1
- package/lib/agent-cli/lib/settings.js +24 -0
- package/lib/agent-cli/lib/skill-learn.js +2 -2
- package/lib/agent-cli/lib/stats.js +3 -3
- package/lib/agent-cli/lib/ui/dashboard-ui.js +103 -4
- package/lib/agent-cli/lib/ui/index.js +36 -6
- package/lib/agent-cli/lib/watcher.js +2 -2
- package/lib/agent-cli/package.json +4 -4
- 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/ag-smart.js +15 -15
- package/lib/agentskillskit-cli/package.json +3 -3
- package/package.json +11 -5
- /package/bin/{cli.js → kit.js} +0 -0
|
@@ -0,0 +1,623 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Pre-Execution Check - Prevent known errors before they happen
|
|
4
|
+
*
|
|
5
|
+
* Part of FAANG-Grade Auto-Learn System Phase 3
|
|
6
|
+
*
|
|
7
|
+
* Before AI writes code, this checks:
|
|
8
|
+
* - Active rules from lessons-learned
|
|
9
|
+
* - Auto-generated rules from pattern_analyzer
|
|
10
|
+
* - Known anti-patterns
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* node pre_execution_check.js --check "code intent description"
|
|
14
|
+
* node pre_execution_check.js --list-rules
|
|
15
|
+
* node pre_execution_check.js --approve RULE-ID
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import fs from 'fs';
|
|
19
|
+
import path from 'path';
|
|
20
|
+
import { fileURLToPath } from 'url';
|
|
21
|
+
|
|
22
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
23
|
+
const __dirname = path.dirname(__filename);
|
|
24
|
+
|
|
25
|
+
// Colors
|
|
26
|
+
const c = {
|
|
27
|
+
reset: '\x1b[0m',
|
|
28
|
+
red: '\x1b[31m',
|
|
29
|
+
green: '\x1b[32m',
|
|
30
|
+
yellow: '\x1b[33m',
|
|
31
|
+
blue: '\x1b[34m',
|
|
32
|
+
cyan: '\x1b[36m',
|
|
33
|
+
gray: '\x1b[90m',
|
|
34
|
+
bold: '\x1b[1m'
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// Find project root
|
|
38
|
+
function findProjectRoot() {
|
|
39
|
+
let current = process.cwd();
|
|
40
|
+
while (current !== path.dirname(current)) {
|
|
41
|
+
if (fs.existsSync(path.join(current, '.agent'))) {
|
|
42
|
+
return current;
|
|
43
|
+
}
|
|
44
|
+
current = path.dirname(current);
|
|
45
|
+
}
|
|
46
|
+
return process.cwd();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const projectRoot = findProjectRoot();
|
|
50
|
+
const knowledgePath = path.join(projectRoot, '.agent', 'knowledge');
|
|
51
|
+
const lessonsPath = path.join(knowledgePath, 'lessons-learned.json');
|
|
52
|
+
const autoRulesPath = path.join(knowledgePath, 'auto-rules.yaml');
|
|
53
|
+
const activeRulesPath = path.join(knowledgePath, 'active-rules.json');
|
|
54
|
+
const errorsPath = path.join(knowledgePath, 'detected-errors.json');
|
|
55
|
+
const successesPath = path.join(knowledgePath, 'successes.json');
|
|
56
|
+
|
|
57
|
+
// Load lessons
|
|
58
|
+
function loadLessons() {
|
|
59
|
+
try {
|
|
60
|
+
if (fs.existsSync(lessonsPath)) {
|
|
61
|
+
const data = JSON.parse(fs.readFileSync(lessonsPath, 'utf8'));
|
|
62
|
+
return data.lessons || [];
|
|
63
|
+
}
|
|
64
|
+
} catch { }
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Load errors for pattern analysis
|
|
69
|
+
function loadErrors() {
|
|
70
|
+
try {
|
|
71
|
+
if (fs.existsSync(errorsPath)) {
|
|
72
|
+
const data = JSON.parse(fs.readFileSync(errorsPath, 'utf8'));
|
|
73
|
+
return data.errors || [];
|
|
74
|
+
}
|
|
75
|
+
} catch { }
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Load successes for positive patterns
|
|
80
|
+
function loadSuccesses() {
|
|
81
|
+
try {
|
|
82
|
+
if (fs.existsSync(successesPath)) {
|
|
83
|
+
const data = JSON.parse(fs.readFileSync(successesPath, 'utf8'));
|
|
84
|
+
return data.successes || [];
|
|
85
|
+
}
|
|
86
|
+
} catch { }
|
|
87
|
+
return [];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Load auto-rules (parse YAML)
|
|
91
|
+
function loadAutoRules() {
|
|
92
|
+
try {
|
|
93
|
+
if (fs.existsSync(autoRulesPath)) {
|
|
94
|
+
const content = fs.readFileSync(autoRulesPath, 'utf8');
|
|
95
|
+
// Simple YAML parsing for rules
|
|
96
|
+
const rules = [];
|
|
97
|
+
const ruleBlocks = content.split(/\n\s*-\s+id:/);
|
|
98
|
+
|
|
99
|
+
for (let i = 1; i < ruleBlocks.length; i++) {
|
|
100
|
+
const block = '- id:' + ruleBlocks[i];
|
|
101
|
+
const rule = {};
|
|
102
|
+
|
|
103
|
+
const idMatch = block.match(/id:\s*(\S+)/);
|
|
104
|
+
const patternMatch = block.match(/pattern:\s*"([^"]+)"/);
|
|
105
|
+
const preventionMatch = block.match(/prevention:\s*"([^"]+)"/);
|
|
106
|
+
const statusMatch = block.match(/status:\s*(\S+)/);
|
|
107
|
+
const severityMatch = block.match(/severity:\s*(\S+)/);
|
|
108
|
+
|
|
109
|
+
if (idMatch) rule.id = idMatch[1];
|
|
110
|
+
if (patternMatch) rule.pattern = patternMatch[1];
|
|
111
|
+
if (preventionMatch) rule.prevention = preventionMatch[1];
|
|
112
|
+
if (statusMatch) rule.status = statusMatch[1];
|
|
113
|
+
if (severityMatch) rule.severity = severityMatch[1];
|
|
114
|
+
|
|
115
|
+
if (rule.id) rules.push(rule);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return rules;
|
|
119
|
+
}
|
|
120
|
+
} catch { }
|
|
121
|
+
return [];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Load active rules
|
|
125
|
+
function loadActiveRules() {
|
|
126
|
+
try {
|
|
127
|
+
if (fs.existsSync(activeRulesPath)) {
|
|
128
|
+
const data = JSON.parse(fs.readFileSync(activeRulesPath, 'utf8'));
|
|
129
|
+
return data.rules || [];
|
|
130
|
+
}
|
|
131
|
+
} catch { }
|
|
132
|
+
return [];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Save active rules
|
|
136
|
+
function saveActiveRules(rules) {
|
|
137
|
+
const data = {
|
|
138
|
+
_comment: "Active prevention rules",
|
|
139
|
+
updatedAt: new Date().toISOString(),
|
|
140
|
+
rules
|
|
141
|
+
};
|
|
142
|
+
fs.writeFileSync(activeRulesPath, JSON.stringify(data, null, 2));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ==================== INTENT DETECTION ====================
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Advanced intent detection from code/description
|
|
149
|
+
*/
|
|
150
|
+
function detectIntent(input) {
|
|
151
|
+
const intents = [];
|
|
152
|
+
const inputLower = input.toLowerCase();
|
|
153
|
+
|
|
154
|
+
// File operations
|
|
155
|
+
if (/\b(rename|mv|move)\b/i.test(input)) {
|
|
156
|
+
intents.push({ action: 'rename', target: 'file', risk: 'HIGH' });
|
|
157
|
+
}
|
|
158
|
+
if (/\b(delete|remove|unlink|rm)\b/i.test(input)) {
|
|
159
|
+
intents.push({ action: 'delete', target: 'file', risk: 'CRITICAL' });
|
|
160
|
+
}
|
|
161
|
+
if (/\b(create|new|add|write)\b.*\b(file|component|module)\b/i.test(input)) {
|
|
162
|
+
intents.push({ action: 'create', target: 'file', risk: 'LOW' });
|
|
163
|
+
}
|
|
164
|
+
if (/\b(modify|update|change|edit)\b/i.test(input)) {
|
|
165
|
+
intents.push({ action: 'modify', target: 'file', risk: 'MEDIUM' });
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Code patterns
|
|
169
|
+
if (/\b(async|await|promise|fetch)\b/i.test(input)) {
|
|
170
|
+
intents.push({ action: 'async', target: 'code', risk: 'MEDIUM' });
|
|
171
|
+
}
|
|
172
|
+
if (/\b(import|require|from)\b/i.test(input)) {
|
|
173
|
+
intents.push({ action: 'import', target: 'module', risk: 'MEDIUM' });
|
|
174
|
+
}
|
|
175
|
+
if (/\b(function|method|handler)\b/i.test(input)) {
|
|
176
|
+
intents.push({ action: 'function', target: 'code', risk: 'LOW' });
|
|
177
|
+
}
|
|
178
|
+
if (/\b(api|endpoint|request|response)\b/i.test(input)) {
|
|
179
|
+
intents.push({ action: 'api', target: 'network', risk: 'MEDIUM' });
|
|
180
|
+
}
|
|
181
|
+
if (/\b(database|db|query|sql|prisma)\b/i.test(input)) {
|
|
182
|
+
intents.push({ action: 'database', target: 'data', risk: 'HIGH' });
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Completion/notification
|
|
186
|
+
if (/\b(complete|finish|done|notify|submit)\b/i.test(input)) {
|
|
187
|
+
intents.push({ action: 'complete', target: 'task', risk: 'CRITICAL' });
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return intents;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Get high-frequency error patterns for matching
|
|
195
|
+
*/
|
|
196
|
+
function getHighFrequencyPatterns() {
|
|
197
|
+
const errors = loadErrors();
|
|
198
|
+
const patterns = {};
|
|
199
|
+
|
|
200
|
+
for (const err of errors) {
|
|
201
|
+
const key = err.pattern || err.type;
|
|
202
|
+
patterns[key] = (patterns[key] || 0) + 1;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Return patterns that occurred 2+ times
|
|
206
|
+
return Object.entries(patterns)
|
|
207
|
+
.filter(([, count]) => count >= 2)
|
|
208
|
+
.map(([pattern, count]) => ({ pattern, count, type: 'error' }));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Get success patterns for positive reinforcement
|
|
213
|
+
*/
|
|
214
|
+
function getSuccessPatterns() {
|
|
215
|
+
const successes = loadSuccesses();
|
|
216
|
+
const patterns = {};
|
|
217
|
+
|
|
218
|
+
for (const s of successes) {
|
|
219
|
+
patterns[s.pattern] = (patterns[s.pattern] || 0) + 1;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return Object.entries(patterns)
|
|
223
|
+
.map(([pattern, count]) => ({ pattern, count, type: 'success' }));
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// ==================== RULE MATCHING ====================
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Built-in prevention rules
|
|
230
|
+
*/
|
|
231
|
+
const BUILTIN_RULES = [
|
|
232
|
+
{
|
|
233
|
+
id: 'BUILTIN-001',
|
|
234
|
+
name: 'TypeScript type safety',
|
|
235
|
+
keywords: ['function', 'param', 'return', 'type'],
|
|
236
|
+
check: (intent) => intent.toLowerCase().includes('function'),
|
|
237
|
+
prevention: 'Add explicit TypeScript types to all function parameters and return types',
|
|
238
|
+
severity: 'HIGH'
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
id: 'BUILTIN-002',
|
|
242
|
+
name: 'Async/await usage',
|
|
243
|
+
keywords: ['async', 'await', 'promise', 'fetch', 'api'],
|
|
244
|
+
check: (intent) => /async|await|promise|fetch|api/i.test(intent),
|
|
245
|
+
prevention: 'Always use async/await pattern. Never mix callbacks and promises.',
|
|
246
|
+
severity: 'HIGH'
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
id: 'BUILTIN-003',
|
|
250
|
+
name: 'Error handling',
|
|
251
|
+
keywords: ['try', 'catch', 'error', 'exception'],
|
|
252
|
+
check: (intent) => /async|fetch|api|database|file/i.test(intent),
|
|
253
|
+
prevention: 'Wrap async operations in try/catch. Never use empty catch blocks.',
|
|
254
|
+
severity: 'HIGH'
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
id: 'BUILTIN-004',
|
|
258
|
+
name: 'Import paths',
|
|
259
|
+
keywords: ['import', 'require', 'from'],
|
|
260
|
+
check: (intent) => /import|require|module/i.test(intent),
|
|
261
|
+
prevention: 'Verify import paths exist. Use relative imports from project root.',
|
|
262
|
+
severity: 'MEDIUM'
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
id: 'BUILTIN-005',
|
|
266
|
+
name: 'Null safety',
|
|
267
|
+
keywords: ['null', 'undefined', 'optional'],
|
|
268
|
+
check: (intent) => /optional|null|undefined|maybe|might/i.test(intent),
|
|
269
|
+
prevention: 'Use optional chaining (?.) and nullish coalescing (??). Check for null/undefined.',
|
|
270
|
+
severity: 'HIGH'
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
id: 'BUILTIN-006',
|
|
274
|
+
name: 'React component types',
|
|
275
|
+
keywords: ['react', 'component', 'jsx', 'tsx'],
|
|
276
|
+
check: (intent) => /react|component|jsx|tsx/i.test(intent),
|
|
277
|
+
prevention: 'Use React.FC for components. Use ReactNode instead of JSX.Element.',
|
|
278
|
+
severity: 'MEDIUM'
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
id: 'BUILTIN-007',
|
|
282
|
+
name: 'Test before completion',
|
|
283
|
+
keywords: ['complete', 'finish', 'done', 'notify'],
|
|
284
|
+
check: (intent) => /complete|finish|done|notify/i.test(intent),
|
|
285
|
+
prevention: 'Run tests before marking task complete. Verify no TypeScript errors.',
|
|
286
|
+
severity: 'CRITICAL'
|
|
287
|
+
}
|
|
288
|
+
];
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Check intent against all rules (ENHANCED)
|
|
292
|
+
*/
|
|
293
|
+
function checkIntent(intent) {
|
|
294
|
+
const violations = [];
|
|
295
|
+
const warnings = [];
|
|
296
|
+
const recommendations = [];
|
|
297
|
+
|
|
298
|
+
// PHASE 1: Intent Detection
|
|
299
|
+
const detectedIntents = detectIntent(intent);
|
|
300
|
+
|
|
301
|
+
// Add risk warnings from detected intents
|
|
302
|
+
for (const di of detectedIntents) {
|
|
303
|
+
if (di.risk === 'CRITICAL') {
|
|
304
|
+
violations.push({
|
|
305
|
+
id: `INTENT-${di.action.toUpperCase()}`,
|
|
306
|
+
pattern: `${di.action} ${di.target}`,
|
|
307
|
+
prevention: `CRITICAL: ${di.action} operation detected. Verify safety before proceeding.`,
|
|
308
|
+
severity: 'CRITICAL',
|
|
309
|
+
source: 'intent-detection'
|
|
310
|
+
});
|
|
311
|
+
} else if (di.risk === 'HIGH') {
|
|
312
|
+
warnings.push({
|
|
313
|
+
id: `INTENT-${di.action.toUpperCase()}`,
|
|
314
|
+
name: `High-risk: ${di.action}`,
|
|
315
|
+
prevention: `${di.action} on ${di.target} - use extra caution`,
|
|
316
|
+
severity: 'HIGH',
|
|
317
|
+
source: 'intent-detection'
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Check builtin rules
|
|
323
|
+
for (const rule of BUILTIN_RULES) {
|
|
324
|
+
if (rule.check(intent)) {
|
|
325
|
+
warnings.push({
|
|
326
|
+
id: rule.id,
|
|
327
|
+
name: rule.name,
|
|
328
|
+
prevention: rule.prevention,
|
|
329
|
+
severity: rule.severity,
|
|
330
|
+
source: 'builtin'
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Check lessons
|
|
336
|
+
const lessons = loadLessons();
|
|
337
|
+
for (const lesson of lessons) {
|
|
338
|
+
if (lesson.pattern && intent.toLowerCase().includes(lesson.pattern.toLowerCase().split(' ')[0])) {
|
|
339
|
+
violations.push({
|
|
340
|
+
id: lesson.id,
|
|
341
|
+
pattern: lesson.pattern,
|
|
342
|
+
prevention: lesson.message,
|
|
343
|
+
severity: lesson.severity,
|
|
344
|
+
source: 'lesson'
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// PHASE 2: High-Frequency Error Pattern Matching
|
|
350
|
+
const errorPatterns = getHighFrequencyPatterns();
|
|
351
|
+
for (const ep of errorPatterns) {
|
|
352
|
+
if (ep.pattern && intent.toLowerCase().includes(ep.pattern.toLowerCase())) {
|
|
353
|
+
violations.push({
|
|
354
|
+
id: `FREQ-${ep.pattern.toUpperCase().replace(/\s+/g, '-').slice(0, 10)}`,
|
|
355
|
+
pattern: ep.pattern,
|
|
356
|
+
prevention: `This pattern caused ${ep.count} errors before. Apply extra care.`,
|
|
357
|
+
severity: ep.count >= 5 ? 'HIGH' : 'MEDIUM',
|
|
358
|
+
source: 'error-frequency'
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// PHASE 3: Success Pattern Recommendations
|
|
364
|
+
const successPatterns = getSuccessPatterns();
|
|
365
|
+
for (const sp of successPatterns) {
|
|
366
|
+
// If intent matches a success pattern, recommend it
|
|
367
|
+
const matchWords = sp.pattern.split('-').map(w => w.toLowerCase());
|
|
368
|
+
if (matchWords.some(w => intent.toLowerCase().includes(w))) {
|
|
369
|
+
recommendations.push({
|
|
370
|
+
id: `SUCCESS-${sp.pattern}`,
|
|
371
|
+
pattern: sp.pattern,
|
|
372
|
+
message: `Good pattern! "${sp.pattern}" has ${sp.count} successes.`,
|
|
373
|
+
type: 'positive'
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Check approved auto-rules
|
|
379
|
+
const autoRules = loadAutoRules().filter(r => r.status === 'approved');
|
|
380
|
+
for (const rule of autoRules) {
|
|
381
|
+
if (rule.pattern && intent.toLowerCase().includes(rule.pattern.toLowerCase())) {
|
|
382
|
+
violations.push({
|
|
383
|
+
id: rule.id,
|
|
384
|
+
pattern: rule.pattern,
|
|
385
|
+
prevention: rule.prevention,
|
|
386
|
+
severity: rule.severity,
|
|
387
|
+
source: 'auto-rule'
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Check active rules
|
|
393
|
+
const activeRules = loadActiveRules();
|
|
394
|
+
for (const rule of activeRules) {
|
|
395
|
+
if (rule.keywords?.some(kw => intent.toLowerCase().includes(kw))) {
|
|
396
|
+
warnings.push({
|
|
397
|
+
id: rule.id,
|
|
398
|
+
name: rule.name,
|
|
399
|
+
prevention: rule.prevention,
|
|
400
|
+
severity: rule.severity,
|
|
401
|
+
source: 'active'
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
return { violations, warnings, recommendations, detectedIntents };
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Generate prevention advice
|
|
411
|
+
*/
|
|
412
|
+
function generateAdvice(violations, warnings) {
|
|
413
|
+
const advice = [];
|
|
414
|
+
|
|
415
|
+
// Critical violations first
|
|
416
|
+
const critical = [...violations, ...warnings].filter(v => v.severity === 'CRITICAL');
|
|
417
|
+
if (critical.length > 0) {
|
|
418
|
+
advice.push({
|
|
419
|
+
level: 'STOP',
|
|
420
|
+
message: 'Critical rules triggered. Address these before proceeding:',
|
|
421
|
+
items: critical.map(v => `[${v.id}] ${v.prevention}`)
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// High severity
|
|
426
|
+
const high = [...violations, ...warnings].filter(v => v.severity === 'HIGH');
|
|
427
|
+
if (high.length > 0) {
|
|
428
|
+
advice.push({
|
|
429
|
+
level: 'CAUTION',
|
|
430
|
+
message: 'High-priority checks to apply:',
|
|
431
|
+
items: high.map(v => `[${v.id}] ${v.prevention}`)
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// Medium/Low as tips
|
|
436
|
+
const other = [...violations, ...warnings].filter(v => v.severity === 'MEDIUM' || v.severity === 'LOW');
|
|
437
|
+
if (other.length > 0) {
|
|
438
|
+
advice.push({
|
|
439
|
+
level: 'TIP',
|
|
440
|
+
message: 'Best practices to consider:',
|
|
441
|
+
items: other.map(v => `[${v.id}] ${v.prevention}`)
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
return advice;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// ==================== MAIN ====================
|
|
449
|
+
|
|
450
|
+
function runCheck(intent) {
|
|
451
|
+
console.log(`${c.cyan}🛡️ Pre-Execution Check${c.reset}\n`);
|
|
452
|
+
console.log(`${c.gray}Intent: "${intent}"${c.reset}\n`);
|
|
453
|
+
|
|
454
|
+
const { violations, warnings } = checkIntent(intent);
|
|
455
|
+
const advice = generateAdvice(violations, warnings);
|
|
456
|
+
|
|
457
|
+
if (advice.length === 0) {
|
|
458
|
+
console.log(`${c.green}✓ No known issues for this intent${c.reset}`);
|
|
459
|
+
console.log(`${c.gray}Proceed with standard best practices${c.reset}`);
|
|
460
|
+
return { proceed: true, violations: [], warnings: [] };
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
for (const a of advice) {
|
|
464
|
+
const color = {
|
|
465
|
+
'STOP': c.red,
|
|
466
|
+
'CAUTION': c.yellow,
|
|
467
|
+
'TIP': c.blue
|
|
468
|
+
}[a.level] || c.gray;
|
|
469
|
+
|
|
470
|
+
console.log(`${color}${c.bold}${a.level}${c.reset} ${a.message}`);
|
|
471
|
+
for (const item of a.items) {
|
|
472
|
+
console.log(` ${color}●${c.reset} ${item}`);
|
|
473
|
+
}
|
|
474
|
+
console.log('');
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// Determine if should proceed
|
|
478
|
+
const hasCritical = violations.some(v => v.severity === 'CRITICAL') ||
|
|
479
|
+
warnings.some(v => v.severity === 'CRITICAL');
|
|
480
|
+
|
|
481
|
+
if (hasCritical) {
|
|
482
|
+
console.log(`${c.red}${c.bold}⛔ BLOCKED${c.reset} - Critical rules violated`);
|
|
483
|
+
console.log(`${c.gray}Address critical issues before proceeding${c.reset}`);
|
|
484
|
+
return { proceed: false, violations, warnings };
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
console.log(`${c.yellow}⚠️ PROCEED WITH CAUTION${c.reset}`);
|
|
488
|
+
console.log(`${c.gray}Apply the recommendations above${c.reset}`);
|
|
489
|
+
return { proceed: true, violations, warnings };
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
function listRules() {
|
|
493
|
+
console.log(`${c.cyan}📋 Active Prevention Rules${c.reset}\n`);
|
|
494
|
+
|
|
495
|
+
console.log(`${c.bold}Built-in Rules:${c.reset}`);
|
|
496
|
+
for (const rule of BUILTIN_RULES) {
|
|
497
|
+
const sevColor = { CRITICAL: c.red, HIGH: c.yellow, MEDIUM: c.blue }[rule.severity] || c.gray;
|
|
498
|
+
console.log(` ${c.cyan}${rule.id}${c.reset} ${sevColor}[${rule.severity}]${c.reset}`);
|
|
499
|
+
console.log(` ${rule.name}`);
|
|
500
|
+
console.log(` ${c.gray}${rule.prevention}${c.reset}\n`);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
const lessons = loadLessons();
|
|
504
|
+
if (lessons.length > 0) {
|
|
505
|
+
console.log(`${c.bold}Lessons (${lessons.length}):${c.reset}`);
|
|
506
|
+
for (const lesson of lessons.slice(0, 5)) {
|
|
507
|
+
console.log(` ${c.cyan}${lesson.id}${c.reset}: ${lesson.pattern}`);
|
|
508
|
+
}
|
|
509
|
+
if (lessons.length > 5) {
|
|
510
|
+
console.log(` ${c.gray}... and ${lessons.length - 5} more${c.reset}`);
|
|
511
|
+
}
|
|
512
|
+
console.log('');
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
const autoRules = loadAutoRules();
|
|
516
|
+
const approved = autoRules.filter(r => r.status === 'approved');
|
|
517
|
+
const pending = autoRules.filter(r => r.status === 'pending');
|
|
518
|
+
|
|
519
|
+
if (approved.length > 0) {
|
|
520
|
+
console.log(`${c.bold}Approved Auto-Rules (${approved.length}):${c.reset}`);
|
|
521
|
+
for (const rule of approved) {
|
|
522
|
+
console.log(` ${c.green}${rule.id}${c.reset}: ${rule.pattern}`);
|
|
523
|
+
}
|
|
524
|
+
console.log('');
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
if (pending.length > 0) {
|
|
528
|
+
console.log(`${c.bold}${c.yellow}Pending Auto-Rules (${pending.length}):${c.reset}`);
|
|
529
|
+
for (const rule of pending) {
|
|
530
|
+
console.log(` ${c.yellow}${rule.id}${c.reset}: ${rule.pattern}`);
|
|
531
|
+
}
|
|
532
|
+
console.log(`\n${c.gray}Approve pending rules with: --approve RULE-ID${c.reset}`);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
function approveRule(ruleId) {
|
|
537
|
+
const content = fs.readFileSync(autoRulesPath, 'utf8');
|
|
538
|
+
const updated = content.replace(
|
|
539
|
+
new RegExp(`(id:\\s*${ruleId}[\\s\\S]*?status:\\s*)pending`, 'm'),
|
|
540
|
+
'$1approved'
|
|
541
|
+
);
|
|
542
|
+
|
|
543
|
+
if (updated === content) {
|
|
544
|
+
console.log(`${c.red}Rule ${ruleId} not found or already approved${c.reset}`);
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
fs.writeFileSync(autoRulesPath, updated);
|
|
549
|
+
console.log(`${c.green}✓ Approved rule: ${ruleId}${c.reset}`);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
function rejectRule(ruleId) {
|
|
553
|
+
const content = fs.readFileSync(autoRulesPath, 'utf8');
|
|
554
|
+
const updated = content.replace(
|
|
555
|
+
new RegExp(`(id:\\s*${ruleId}[\\s\\S]*?status:\\s*)pending`, 'm'),
|
|
556
|
+
'$1rejected'
|
|
557
|
+
);
|
|
558
|
+
|
|
559
|
+
if (updated === content) {
|
|
560
|
+
console.log(`${c.red}Rule ${ruleId} not found or already processed${c.reset}`);
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
fs.writeFileSync(autoRulesPath, updated);
|
|
565
|
+
console.log(`${c.yellow}✓ Rejected rule: ${ruleId}${c.reset}`);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// Parse CLI args
|
|
569
|
+
const args = process.argv.slice(2);
|
|
570
|
+
|
|
571
|
+
if (args.includes('--check') || args.includes('-c')) {
|
|
572
|
+
const idx = args.findIndex(a => a === '--check' || a === '-c');
|
|
573
|
+
const intent = args.slice(idx + 1).join(' ');
|
|
574
|
+
if (intent) {
|
|
575
|
+
runCheck(intent);
|
|
576
|
+
} else {
|
|
577
|
+
console.log(`${c.red}Error: --check requires an intent description${c.reset}`);
|
|
578
|
+
}
|
|
579
|
+
} else if (args.includes('--list') || args.includes('-l')) {
|
|
580
|
+
listRules();
|
|
581
|
+
} else if (args.includes('--approve')) {
|
|
582
|
+
const idx = args.findIndex(a => a === '--approve');
|
|
583
|
+
const ruleId = args[idx + 1];
|
|
584
|
+
if (ruleId) {
|
|
585
|
+
approveRule(ruleId);
|
|
586
|
+
} else {
|
|
587
|
+
console.log(`${c.red}Error: --approve requires a rule ID${c.reset}`);
|
|
588
|
+
}
|
|
589
|
+
} else if (args.includes('--reject')) {
|
|
590
|
+
const idx = args.findIndex(a => a === '--reject');
|
|
591
|
+
const ruleId = args[idx + 1];
|
|
592
|
+
if (ruleId) {
|
|
593
|
+
rejectRule(ruleId);
|
|
594
|
+
} else {
|
|
595
|
+
console.log(`${c.red}Error: --reject requires a rule ID${c.reset}`);
|
|
596
|
+
}
|
|
597
|
+
} else {
|
|
598
|
+
console.log(`${c.cyan}pre_execution_check - Prevent known errors before they happen${c.reset}
|
|
599
|
+
|
|
600
|
+
${c.bold}Usage:${c.reset}
|
|
601
|
+
node pre_execution_check.js --check "intent" Check intent against rules
|
|
602
|
+
node pre_execution_check.js --list List all active rules
|
|
603
|
+
node pre_execution_check.js --approve ID Approve an auto-rule
|
|
604
|
+
node pre_execution_check.js --reject ID Reject an auto-rule
|
|
605
|
+
|
|
606
|
+
${c.bold}Examples:${c.reset}
|
|
607
|
+
node pre_execution_check.js --check "create async function to fetch API"
|
|
608
|
+
node pre_execution_check.js --check "complete task and notify user"
|
|
609
|
+
node pre_execution_check.js --approve AUTO-IMPORT
|
|
610
|
+
|
|
611
|
+
${c.bold}Rule sources:${c.reset}
|
|
612
|
+
• Built-in rules (7 core patterns)
|
|
613
|
+
• Lessons from lessons-learned.json
|
|
614
|
+
• Approved auto-rules from auto-rules.yaml
|
|
615
|
+
|
|
616
|
+
${c.bold}Output levels:${c.reset}
|
|
617
|
+
STOP - Critical violation, must address
|
|
618
|
+
CAUTION - High priority, should address
|
|
619
|
+
TIP - Best practice recommendation
|
|
620
|
+
`);
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
export { runCheck, checkIntent, generateAdvice, loadActiveRules };
|