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,500 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Success Sensor - Detect successful patterns and best practices
|
|
4
|
+
*
|
|
5
|
+
* Part of FAANG-Grade Auto-Learn System
|
|
6
|
+
*
|
|
7
|
+
* Scans for:
|
|
8
|
+
* - Test successes (all tests pass)
|
|
9
|
+
* - Lint successes (no errors)
|
|
10
|
+
* - Build successes (compiled OK)
|
|
11
|
+
* - Code pattern successes (good practices)
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* node success_sensor.js --scan all
|
|
15
|
+
* node success_sensor.js --scan test
|
|
16
|
+
* node success_sensor.js --stats
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import fs from 'fs';
|
|
20
|
+
import path from 'path';
|
|
21
|
+
import { execSync } from 'child_process';
|
|
22
|
+
import { fileURLToPath } from 'url';
|
|
23
|
+
|
|
24
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
25
|
+
const __dirname = path.dirname(__filename);
|
|
26
|
+
|
|
27
|
+
// Colors
|
|
28
|
+
const c = {
|
|
29
|
+
reset: '\x1b[0m',
|
|
30
|
+
red: '\x1b[31m',
|
|
31
|
+
green: '\x1b[32m',
|
|
32
|
+
yellow: '\x1b[33m',
|
|
33
|
+
blue: '\x1b[34m',
|
|
34
|
+
cyan: '\x1b[36m',
|
|
35
|
+
gray: '\x1b[90m',
|
|
36
|
+
bold: '\x1b[1m'
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// Find project root
|
|
40
|
+
function findProjectRoot() {
|
|
41
|
+
let current = process.cwd();
|
|
42
|
+
while (current !== path.dirname(current)) {
|
|
43
|
+
if (fs.existsSync(path.join(current, '.agent'))) {
|
|
44
|
+
return current;
|
|
45
|
+
}
|
|
46
|
+
current = path.dirname(current);
|
|
47
|
+
}
|
|
48
|
+
return process.cwd();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const projectRoot = findProjectRoot();
|
|
52
|
+
const knowledgePath = path.join(projectRoot, '.agent', 'knowledge');
|
|
53
|
+
const successesPath = path.join(knowledgePath, 'successes.json');
|
|
54
|
+
|
|
55
|
+
// Ensure knowledge directory exists
|
|
56
|
+
if (!fs.existsSync(knowledgePath)) {
|
|
57
|
+
fs.mkdirSync(knowledgePath, { recursive: true });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Load existing successes
|
|
61
|
+
function loadSuccesses() {
|
|
62
|
+
try {
|
|
63
|
+
if (fs.existsSync(successesPath)) {
|
|
64
|
+
return JSON.parse(fs.readFileSync(successesPath, 'utf8'));
|
|
65
|
+
}
|
|
66
|
+
} catch { }
|
|
67
|
+
return { successes: [], totalSuccesses: 0, lastScan: null };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Save successes
|
|
71
|
+
function saveSuccesses(data) {
|
|
72
|
+
data.lastScan = new Date().toISOString();
|
|
73
|
+
fs.writeFileSync(successesPath, JSON.stringify(data, null, 2));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Generate success ID
|
|
77
|
+
function generateSuccessId(type) {
|
|
78
|
+
const data = loadSuccesses();
|
|
79
|
+
const count = data.successes.filter(s => s.type === type).length + 1;
|
|
80
|
+
return `SUCCESS-${type.toUpperCase()}-${String(count).padStart(3, '0')}`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ==================== CONTEXT DETECTION ====================
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Detect project context
|
|
87
|
+
*/
|
|
88
|
+
function detectProjectContext() {
|
|
89
|
+
const context = {
|
|
90
|
+
projectType: 'unknown',
|
|
91
|
+
framework: null,
|
|
92
|
+
language: 'javascript'
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
const pkgPath = path.join(projectRoot, 'package.json');
|
|
97
|
+
if (fs.existsSync(pkgPath)) {
|
|
98
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
99
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
100
|
+
|
|
101
|
+
if (deps['next']) context.projectType = 'nextjs';
|
|
102
|
+
else if (deps['react-native'] || deps['expo']) context.projectType = 'react-native';
|
|
103
|
+
else if (deps['react']) context.projectType = 'react';
|
|
104
|
+
else if (deps['express']) context.projectType = 'backend';
|
|
105
|
+
|
|
106
|
+
if (deps['typescript']) context.language = 'typescript';
|
|
107
|
+
}
|
|
108
|
+
} catch { }
|
|
109
|
+
|
|
110
|
+
return context;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Detect file context
|
|
115
|
+
*/
|
|
116
|
+
function detectFileContext(filePath) {
|
|
117
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
118
|
+
const relativePath = path.relative(projectRoot, filePath);
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
fileType: ext,
|
|
122
|
+
isTypeScript: ext === '.ts' || ext === '.tsx',
|
|
123
|
+
directory: relativePath.split(path.sep)[0] || 'root',
|
|
124
|
+
fullPath: relativePath
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ==================== SUCCESS SENSORS ====================
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Scan for test successes
|
|
132
|
+
*/
|
|
133
|
+
function scanTestSuccesses() {
|
|
134
|
+
const successes = [];
|
|
135
|
+
|
|
136
|
+
try {
|
|
137
|
+
// Try running tests
|
|
138
|
+
const output = execSync('npm test 2>&1', {
|
|
139
|
+
encoding: 'utf8',
|
|
140
|
+
timeout: 60000,
|
|
141
|
+
cwd: projectRoot
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// Check for success indicators
|
|
145
|
+
const successPatterns = [
|
|
146
|
+
/(\d+) pass/i,
|
|
147
|
+
/all tests passed/i,
|
|
148
|
+
/tests?\s+passed/i,
|
|
149
|
+
/0 failed/i,
|
|
150
|
+
/✓.*(\d+) tests?/,
|
|
151
|
+
/PASS\s+/
|
|
152
|
+
];
|
|
153
|
+
|
|
154
|
+
for (const pattern of successPatterns) {
|
|
155
|
+
const match = output.match(pattern);
|
|
156
|
+
if (match) {
|
|
157
|
+
successes.push({
|
|
158
|
+
id: generateSuccessId('test'),
|
|
159
|
+
type: 'test',
|
|
160
|
+
pattern: 'test-pass',
|
|
161
|
+
message: `Tests passed: ${match[0]}`,
|
|
162
|
+
source: 'npm test',
|
|
163
|
+
severity: 'SUCCESS',
|
|
164
|
+
detectedAt: new Date().toISOString()
|
|
165
|
+
});
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
} catch (error) {
|
|
170
|
+
// Test failed or not configured - not a success
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return successes;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Scan for lint successes
|
|
178
|
+
*/
|
|
179
|
+
function scanLintSuccesses() {
|
|
180
|
+
const successes = [];
|
|
181
|
+
|
|
182
|
+
try {
|
|
183
|
+
// Try running lint
|
|
184
|
+
const output = execSync('npm run lint 2>&1', {
|
|
185
|
+
encoding: 'utf8',
|
|
186
|
+
timeout: 30000,
|
|
187
|
+
cwd: projectRoot
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// Check for success indicators
|
|
191
|
+
const successPatterns = [
|
|
192
|
+
/0 errors/i,
|
|
193
|
+
/no issues found/i,
|
|
194
|
+
/no problems/i,
|
|
195
|
+
/all files pass/i,
|
|
196
|
+
/✓ no issues/i
|
|
197
|
+
];
|
|
198
|
+
|
|
199
|
+
for (const pattern of successPatterns) {
|
|
200
|
+
if (pattern.test(output)) {
|
|
201
|
+
successes.push({
|
|
202
|
+
id: generateSuccessId('lint'),
|
|
203
|
+
type: 'lint',
|
|
204
|
+
pattern: 'lint-clean',
|
|
205
|
+
message: 'Lint passed with no errors',
|
|
206
|
+
source: 'npm run lint',
|
|
207
|
+
severity: 'SUCCESS',
|
|
208
|
+
detectedAt: new Date().toISOString()
|
|
209
|
+
});
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Also count as success if no output (many linters silent on success)
|
|
215
|
+
if (output.trim() === '' || !output.includes('error')) {
|
|
216
|
+
successes.push({
|
|
217
|
+
id: generateSuccessId('lint'),
|
|
218
|
+
type: 'lint',
|
|
219
|
+
pattern: 'lint-clean',
|
|
220
|
+
message: 'Lint passed (no output = clean)',
|
|
221
|
+
source: 'npm run lint',
|
|
222
|
+
severity: 'SUCCESS',
|
|
223
|
+
detectedAt: new Date().toISOString()
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
} catch (error) {
|
|
227
|
+
// Lint failed or not configured - not a success
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return successes;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Scan for code pattern successes
|
|
235
|
+
*/
|
|
236
|
+
function scanCodePatternSuccesses() {
|
|
237
|
+
const successes = [];
|
|
238
|
+
|
|
239
|
+
// Good patterns to detect
|
|
240
|
+
const goodPatterns = [
|
|
241
|
+
{
|
|
242
|
+
name: 'proper-error-handling',
|
|
243
|
+
pattern: /try\s*\{[\s\S]*?\}\s*catch\s*\([^)]+\)\s*\{[\s\S]*?console\.(error|log)|throw/,
|
|
244
|
+
message: 'Proper try-catch with error logging/re-throw',
|
|
245
|
+
fileTypes: ['.js', '.ts', '.jsx', '.tsx']
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
name: 'typescript-types',
|
|
249
|
+
pattern: /:\s*(string|number|boolean|object|\w+\[\]|Promise<|React\.FC|void)/,
|
|
250
|
+
message: 'TypeScript type annotations used',
|
|
251
|
+
fileTypes: ['.ts', '.tsx']
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
name: 'async-await',
|
|
255
|
+
pattern: /async\s+function|\basync\s+\(|await\s+/,
|
|
256
|
+
message: 'Modern async/await pattern used',
|
|
257
|
+
fileTypes: ['.js', '.ts', '.jsx', '.tsx']
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
name: 'destructuring',
|
|
261
|
+
pattern: /const\s+\{[^}]+\}\s*=|const\s+\[[^\]]+\]\s*=/,
|
|
262
|
+
message: 'Modern destructuring used',
|
|
263
|
+
fileTypes: ['.js', '.ts', '.jsx', '.tsx']
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
name: 'optional-chaining',
|
|
267
|
+
pattern: /\?\.\w+|\?\.\[/,
|
|
268
|
+
message: 'Optional chaining (?.) used for null safety',
|
|
269
|
+
fileTypes: ['.js', '.ts', '.jsx', '.tsx']
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
name: 'nullish-coalescing',
|
|
273
|
+
pattern: /\?\?/,
|
|
274
|
+
message: 'Nullish coalescing (??) used',
|
|
275
|
+
fileTypes: ['.js', '.ts', '.jsx', '.tsx']
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
name: 'es6-exports',
|
|
279
|
+
pattern: /^export\s+(default\s+)?(function|class|const|let|var|async)/m,
|
|
280
|
+
message: 'ES6 module exports used',
|
|
281
|
+
fileTypes: ['.js', '.ts', '.jsx', '.tsx']
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
name: 'jsdoc-comments',
|
|
285
|
+
pattern: /\/\*\*[\s\S]*?@(param|returns|type|description)/,
|
|
286
|
+
message: 'JSDoc documentation present',
|
|
287
|
+
fileTypes: ['.js', '.ts', '.jsx', '.tsx']
|
|
288
|
+
}
|
|
289
|
+
];
|
|
290
|
+
|
|
291
|
+
// Scan source files
|
|
292
|
+
const srcDirs = ['src', 'lib', 'bin', 'scripts'];
|
|
293
|
+
const scannedFiles = new Set();
|
|
294
|
+
|
|
295
|
+
for (const dir of srcDirs) {
|
|
296
|
+
const dirPath = path.join(projectRoot, dir);
|
|
297
|
+
if (!fs.existsSync(dirPath)) continue;
|
|
298
|
+
|
|
299
|
+
scanDirectory(dirPath, (filePath) => {
|
|
300
|
+
if (scannedFiles.has(filePath)) return;
|
|
301
|
+
scannedFiles.add(filePath);
|
|
302
|
+
|
|
303
|
+
const ext = path.extname(filePath);
|
|
304
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
305
|
+
|
|
306
|
+
for (const gp of goodPatterns) {
|
|
307
|
+
if (!gp.fileTypes.includes(ext)) continue;
|
|
308
|
+
|
|
309
|
+
const matches = content.match(new RegExp(gp.pattern, 'g'));
|
|
310
|
+
if (matches && matches.length > 0) {
|
|
311
|
+
// Only add if significant (at least 2 occurrences or important pattern)
|
|
312
|
+
if (matches.length >= 2 || ['typescript-types', 'jsdoc-comments'].includes(gp.name)) {
|
|
313
|
+
successes.push({
|
|
314
|
+
id: generateSuccessId('pattern'),
|
|
315
|
+
type: 'pattern',
|
|
316
|
+
pattern: gp.name,
|
|
317
|
+
message: `${gp.message} (${matches.length}x)`,
|
|
318
|
+
file: path.relative(projectRoot, filePath),
|
|
319
|
+
count: matches.length,
|
|
320
|
+
severity: 'SUCCESS',
|
|
321
|
+
detectedAt: new Date().toISOString()
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return successes;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Helper: Scan directory recursively
|
|
334
|
+
*/
|
|
335
|
+
function scanDirectory(dir, callback) {
|
|
336
|
+
const items = fs.readdirSync(dir);
|
|
337
|
+
|
|
338
|
+
for (const item of items) {
|
|
339
|
+
if (item.startsWith('.') || item === 'node_modules') continue;
|
|
340
|
+
|
|
341
|
+
const fullPath = path.join(dir, item);
|
|
342
|
+
const stat = fs.statSync(fullPath);
|
|
343
|
+
|
|
344
|
+
if (stat.isDirectory()) {
|
|
345
|
+
scanDirectory(fullPath, callback);
|
|
346
|
+
} else if (stat.isFile()) {
|
|
347
|
+
callback(fullPath);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// ==================== DEDUPLICATION ====================
|
|
353
|
+
|
|
354
|
+
function deduplicateSuccesses(newSuccesses, existingSuccesses) {
|
|
355
|
+
const added = [];
|
|
356
|
+
|
|
357
|
+
for (const newS of newSuccesses) {
|
|
358
|
+
// Check if similar success exists
|
|
359
|
+
const exists = existingSuccesses.some(existing =>
|
|
360
|
+
existing.type === newS.type &&
|
|
361
|
+
existing.pattern === newS.pattern &&
|
|
362
|
+
existing.file === newS.file
|
|
363
|
+
);
|
|
364
|
+
|
|
365
|
+
if (!exists) {
|
|
366
|
+
added.push(newS);
|
|
367
|
+
} else {
|
|
368
|
+
// Update hit count for existing
|
|
369
|
+
const existing = existingSuccesses.find(e =>
|
|
370
|
+
e.type === newS.type && e.pattern === newS.pattern && e.file === newS.file
|
|
371
|
+
);
|
|
372
|
+
if (existing) {
|
|
373
|
+
existing.hitCount = (existing.hitCount || 1) + 1;
|
|
374
|
+
existing.lastHit = new Date().toISOString();
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
return added;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// ==================== MAIN ====================
|
|
383
|
+
|
|
384
|
+
function runScan(type) {
|
|
385
|
+
console.log(`${c.green}🎯 Success Sensor - Scanning ${type}...${c.reset}\n`);
|
|
386
|
+
|
|
387
|
+
let newSuccesses = [];
|
|
388
|
+
|
|
389
|
+
if (type === 'all' || type === 'test') {
|
|
390
|
+
console.log(` ${c.cyan}Scanning test results...${c.reset}`);
|
|
391
|
+
const testSuccesses = scanTestSuccesses();
|
|
392
|
+
console.log(` Found ${testSuccesses.length} test successes`);
|
|
393
|
+
newSuccesses = newSuccesses.concat(testSuccesses);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
if (type === 'all' || type === 'lint') {
|
|
397
|
+
console.log(` ${c.cyan}Scanning lint results...${c.reset}`);
|
|
398
|
+
const lintSuccesses = scanLintSuccesses();
|
|
399
|
+
console.log(` Found ${lintSuccesses.length} lint successes`);
|
|
400
|
+
newSuccesses = newSuccesses.concat(lintSuccesses);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
if (type === 'all' || type === 'pattern') {
|
|
404
|
+
console.log(` ${c.cyan}Scanning code patterns...${c.reset}`);
|
|
405
|
+
const patternSuccesses = scanCodePatternSuccesses();
|
|
406
|
+
console.log(` Found ${patternSuccesses.length} pattern successes`);
|
|
407
|
+
newSuccesses = newSuccesses.concat(patternSuccesses);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Load existing and merge
|
|
411
|
+
const data = loadSuccesses();
|
|
412
|
+
const added = deduplicateSuccesses(newSuccesses, data.successes);
|
|
413
|
+
data.successes = [...data.successes, ...added];
|
|
414
|
+
data.totalSuccesses = data.successes.length;
|
|
415
|
+
|
|
416
|
+
// Save
|
|
417
|
+
saveSuccesses(data);
|
|
418
|
+
|
|
419
|
+
console.log(`\n${c.green}════════════════════════════════════════${c.reset}`);
|
|
420
|
+
console.log(`${c.bold}Scan Complete${c.reset}`);
|
|
421
|
+
console.log(` Total detected: ${newSuccesses.length}`);
|
|
422
|
+
console.log(` New successes: ${added.length}`);
|
|
423
|
+
console.log(`${c.gray}Saved to: ${successesPath}${c.reset}`);
|
|
424
|
+
console.log(`${c.green}════════════════════════════════════════${c.reset}`);
|
|
425
|
+
|
|
426
|
+
return { detected: newSuccesses.length, added: added.length };
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
function showStats() {
|
|
430
|
+
const data = loadSuccesses();
|
|
431
|
+
|
|
432
|
+
console.log(`${c.cyan}╔════════════════════════════════════════╗${c.reset}`);
|
|
433
|
+
console.log(`${c.cyan}║${c.reset} ${c.green}🎯 Success Sensor Statistics${c.reset} ${c.cyan}║${c.reset}`);
|
|
434
|
+
console.log(`${c.cyan}╚════════════════════════════════════════╝${c.reset}\n`);
|
|
435
|
+
|
|
436
|
+
if (data.successes.length === 0) {
|
|
437
|
+
console.log(`${c.gray}No successes tracked yet.${c.reset}`);
|
|
438
|
+
console.log(`${c.gray}Run: node success_sensor.js --scan all${c.reset}`);
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// Group by type
|
|
443
|
+
const byType = {};
|
|
444
|
+
for (const s of data.successes) {
|
|
445
|
+
byType[s.type] = (byType[s.type] || 0) + 1;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// Group by pattern
|
|
449
|
+
const byPattern = {};
|
|
450
|
+
for (const s of data.successes) {
|
|
451
|
+
byPattern[s.pattern] = (byPattern[s.pattern] || 0) + 1;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
console.log(`${c.bold}By Type:${c.reset}`);
|
|
455
|
+
for (const [type, count] of Object.entries(byType)) {
|
|
456
|
+
console.log(` ${c.green}${type}${c.reset}: ${count}`);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
console.log(`\n${c.bold}By Pattern:${c.reset}`);
|
|
460
|
+
for (const [pattern, count] of Object.entries(byPattern)) {
|
|
461
|
+
console.log(` ${c.blue}${pattern}${c.reset}: ${count}`);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
console.log(`\n${c.bold}Total successes tracked:${c.reset} ${c.green}${data.totalSuccesses}${c.reset}`);
|
|
465
|
+
if (data.lastScan) {
|
|
466
|
+
console.log(`${c.gray}Last scan: ${data.lastScan}${c.reset}`);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// Parse CLI args
|
|
471
|
+
const args = process.argv.slice(2);
|
|
472
|
+
|
|
473
|
+
if (args.includes('--scan') || args.includes('-s')) {
|
|
474
|
+
const idx = args.findIndex(a => a === '--scan' || a === '-s');
|
|
475
|
+
const type = args[idx + 1] || 'all';
|
|
476
|
+
runScan(type);
|
|
477
|
+
} else if (args.includes('--stats') || args.includes('-t')) {
|
|
478
|
+
showStats();
|
|
479
|
+
} else {
|
|
480
|
+
console.log(`${c.green}success_sensor - Detect successful patterns${c.reset}
|
|
481
|
+
|
|
482
|
+
${c.bold}Usage:${c.reset}
|
|
483
|
+
node success_sensor.js --scan all Scan all sources
|
|
484
|
+
node success_sensor.js --scan test Scan test results only
|
|
485
|
+
node success_sensor.js --scan lint Scan lint results only
|
|
486
|
+
node success_sensor.js --scan pattern Scan code patterns only
|
|
487
|
+
node success_sensor.js --stats Show statistics
|
|
488
|
+
|
|
489
|
+
${c.bold}Success Types:${c.reset}
|
|
490
|
+
test - Tests passing
|
|
491
|
+
lint - Lint clean
|
|
492
|
+
pattern - Good code patterns (async/await, types, etc.)
|
|
493
|
+
|
|
494
|
+
${c.bold}Example:${c.reset}
|
|
495
|
+
node success_sensor.js --scan all
|
|
496
|
+
node success_sensor.js --stats
|
|
497
|
+
`);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
export { runScan, showStats, scanTestSuccesses, scanLintSuccesses, scanCodePatternSuccesses };
|