add-skill-kit 3.2.4 → 3.2.6
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 +179 -119
- package/bin/lib/commands/help.js +0 -4
- package/bin/lib/commands/install.js +129 -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 +12 -6
- package/lib/agent-cli/lib/auto_preview.py +0 -148
- package/lib/agent-cli/lib/checklist.py +0 -222
- package/lib/agent-cli/lib/session_manager.py +0 -120
- package/lib/agent-cli/lib/verify_all.py +0 -327
- /package/bin/{cli.js → kit.js} +0 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ThresholdChecker - Core Business Logic
|
|
3
|
+
*
|
|
4
|
+
* Determines if a lesson is ready for evolution based on:
|
|
5
|
+
* - Hit count threshold
|
|
6
|
+
* - Cognitive confidence
|
|
7
|
+
* - Pattern stability
|
|
8
|
+
*
|
|
9
|
+
* Pure function with NO side effects.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export class ThresholdChecker {
|
|
13
|
+
/**
|
|
14
|
+
* Check if a lesson is ready for evolution
|
|
15
|
+
* @param {object} lesson - Cognitive lesson with hitCount, confidence, etc.
|
|
16
|
+
* @param {number} threshold - Hit count threshold from settings
|
|
17
|
+
* @returns {{ ready: boolean, reason?: string, confidence?: number }}
|
|
18
|
+
*/
|
|
19
|
+
static check(lesson, threshold = 10) {
|
|
20
|
+
const hitCount = lesson.hitCount || 0;
|
|
21
|
+
const cognitiveConfidence = lesson.cognitive?.confidence || 0.3;
|
|
22
|
+
|
|
23
|
+
// Rule 1: Hit count threshold reached
|
|
24
|
+
if (hitCount >= threshold) {
|
|
25
|
+
return {
|
|
26
|
+
ready: true,
|
|
27
|
+
reason: 'hitCountThreshold',
|
|
28
|
+
confidence: Math.min(0.9, 0.7 + (hitCount - threshold) * 0.02)
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Rule 2: High cognitive confidence even with lower hits
|
|
33
|
+
if (cognitiveConfidence >= 0.85 && hitCount >= threshold * 0.5) {
|
|
34
|
+
return {
|
|
35
|
+
ready: true,
|
|
36
|
+
reason: 'highConfidence',
|
|
37
|
+
confidence: cognitiveConfidence
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Rule 3: Pattern stability (if we have violation history)
|
|
42
|
+
if (lesson.metadata?.stabilityScore && lesson.metadata.stabilityScore > 0.9) {
|
|
43
|
+
return {
|
|
44
|
+
ready: true,
|
|
45
|
+
reason: 'patternStable',
|
|
46
|
+
confidence: lesson.metadata.stabilityScore
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Not ready for evolution
|
|
51
|
+
return { ready: false };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Calculate pattern stability from violation history
|
|
56
|
+
* @param {Array} violationHistory - Array of { timestamp, file, line }
|
|
57
|
+
* @returns {number} - Stability score 0.0 to 1.0
|
|
58
|
+
*/
|
|
59
|
+
static calculateStability(violationHistory = []) {
|
|
60
|
+
if (violationHistory.length < 3) return 0.0;
|
|
61
|
+
|
|
62
|
+
// Check if violations are consistent (same files, similar patterns)
|
|
63
|
+
const uniqueFiles = new Set(violationHistory.map(v => v.file)).size;
|
|
64
|
+
const totalViolations = violationHistory.length;
|
|
65
|
+
|
|
66
|
+
// High stability = violations come from same files (not random)
|
|
67
|
+
const fileConsistency = 1 - (uniqueFiles / totalViolations);
|
|
68
|
+
|
|
69
|
+
// Time-based stability: violations spread over time (not one-off)
|
|
70
|
+
const timestamps = violationHistory.map(v => v.timestamp).sort();
|
|
71
|
+
const timeSpan = timestamps[timestamps.length - 1] - timestamps[0];
|
|
72
|
+
const daySpan = timeSpan / (1000 * 60 * 60 * 24);
|
|
73
|
+
|
|
74
|
+
const timeStability = daySpan > 1 ? Math.min(1.0, daySpan / 7) : 0.2;
|
|
75
|
+
|
|
76
|
+
// Combined stability
|
|
77
|
+
return (fileConsistency * 0.6 + timeStability * 0.4);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core - Domain Layer
|
|
3
|
+
*
|
|
4
|
+
* Pure business logic with ZERO external dependencies.
|
|
5
|
+
* This layer defines the business rules and domain models.
|
|
6
|
+
*
|
|
7
|
+
* Exported modules:
|
|
8
|
+
* - learning: Lesson management, cognitive enhancements, lesson merging
|
|
9
|
+
* - evolution: Signal detection, threshold checking, review gate
|
|
10
|
+
* - scanning: File scanning, pattern matching, violation tracking
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export * from './learning/index.js';
|
|
14
|
+
export * from './evolution/index.js';
|
|
15
|
+
export * from './scanning/index.js';
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CognitiveEnhancer - Core Business Logic
|
|
3
|
+
*
|
|
4
|
+
* Transforms raw lessons into cognitive lessons with intelligence layers:
|
|
5
|
+
* 1. Intent Inference - detect purpose
|
|
6
|
+
* 2. Pattern Classification - categorize by type
|
|
7
|
+
* 3. Maturity Calculation - confidence & state
|
|
8
|
+
* 4. Evolution Analysis - gap detection
|
|
9
|
+
*
|
|
10
|
+
* Pure business logic with NO external dependencies.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// INTENT INFERENCE
|
|
15
|
+
// ============================================================================
|
|
16
|
+
|
|
17
|
+
const INTENT_PATTERNS = {
|
|
18
|
+
'safe-rebranding': {
|
|
19
|
+
keywords: ['rebrand', 'rename', 'file-safety'],
|
|
20
|
+
goal: 'Rename files/entities without data loss or breaking changes',
|
|
21
|
+
category: 'file-operations',
|
|
22
|
+
},
|
|
23
|
+
'cli-ux-consistency': {
|
|
24
|
+
keywords: ['cli', 'ux', 'menu', 'navigation', 'clack'],
|
|
25
|
+
goal: 'Provide consistent, intuitive CLI user experience',
|
|
26
|
+
category: 'user-experience',
|
|
27
|
+
},
|
|
28
|
+
'error-prevention': {
|
|
29
|
+
keywords: ['validation', 'error', 'check', 'verify'],
|
|
30
|
+
goal: 'Prevent runtime errors through proactive validation',
|
|
31
|
+
category: 'reliability',
|
|
32
|
+
},
|
|
33
|
+
'code-quality': {
|
|
34
|
+
keywords: ['import', 'architecture', 'quality'],
|
|
35
|
+
goal: 'Maintain clean, maintainable code structure',
|
|
36
|
+
category: 'maintainability',
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export class CognitiveEnhancer {
|
|
41
|
+
/**
|
|
42
|
+
* Infer lesson intent from tags
|
|
43
|
+
* @param {Array<string>} tags
|
|
44
|
+
* @returns {{id: string, goal: string, strength: number, category: string}}
|
|
45
|
+
*/
|
|
46
|
+
static inferIntent(tags) {
|
|
47
|
+
if (!tags || tags.length === 0) {
|
|
48
|
+
return {
|
|
49
|
+
id: 'unknown',
|
|
50
|
+
goal: 'General code quality improvement',
|
|
51
|
+
strength: 0.3,
|
|
52
|
+
category: 'general',
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
let bestMatch = null;
|
|
57
|
+
let bestScore = 0;
|
|
58
|
+
|
|
59
|
+
for (const [intentId, pattern] of Object.entries(INTENT_PATTERNS)) {
|
|
60
|
+
const matchCount = tags.filter(tag =>
|
|
61
|
+
pattern.keywords.some(kw => tag.toLowerCase().includes(kw.toLowerCase()))
|
|
62
|
+
).length;
|
|
63
|
+
|
|
64
|
+
const score = matchCount / tags.length; // 0-1 confidence
|
|
65
|
+
|
|
66
|
+
if (score > bestScore) {
|
|
67
|
+
bestScore = score;
|
|
68
|
+
bestMatch = {
|
|
69
|
+
id: intentId,
|
|
70
|
+
goal: pattern.goal,
|
|
71
|
+
strength: score,
|
|
72
|
+
category: pattern.category,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return bestMatch || {
|
|
78
|
+
id: 'unknown',
|
|
79
|
+
goal: 'General code quality improvement',
|
|
80
|
+
strength: 0.3,
|
|
81
|
+
category: 'general',
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Calculate lesson maturity metrics
|
|
87
|
+
* @param {Array} mistakes
|
|
88
|
+
* @param {Array} improvements
|
|
89
|
+
* @returns {{state: string, confidence: number, indicators: object, coverage: string, recommendation: string}}
|
|
90
|
+
*/
|
|
91
|
+
static calculateMaturity(mistakes, improvements) {
|
|
92
|
+
const m = mistakes.length;
|
|
93
|
+
const i = improvements.length;
|
|
94
|
+
|
|
95
|
+
// State determination
|
|
96
|
+
let state;
|
|
97
|
+
if (i === 0 && m > 0) state = 'RAW'; // 🟥 Only mistakes
|
|
98
|
+
else if (i > 0 && m === 0) state = 'IDEAL'; // 🟦 Only improvements (rare)
|
|
99
|
+
else if (i >= m) state = 'MATURE'; // 🟩 Balanced or improvement-heavy
|
|
100
|
+
else state = 'LEARNING'; // 🟨 More mistakes than solutions
|
|
101
|
+
|
|
102
|
+
// Multi-factor confidence
|
|
103
|
+
const balanceScore = i / (m + i) || 0;
|
|
104
|
+
const evidenceScore = this.calculateEvidenceScore(mistakes, improvements);
|
|
105
|
+
const recencyScore = this.calculateRecencyScore(mistakes, improvements);
|
|
106
|
+
|
|
107
|
+
const confidence = (
|
|
108
|
+
balanceScore * 0.5 + // Balance is most important
|
|
109
|
+
evidenceScore * 0.3 + // Evidence validates
|
|
110
|
+
recencyScore * 0.2 // Fresh is better
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
state,
|
|
115
|
+
confidence: Math.round(confidence * 100) / 100,
|
|
116
|
+
indicators: {
|
|
117
|
+
balance: Math.round(balanceScore * 100) / 100,
|
|
118
|
+
evidence: Math.round(evidenceScore * 100) / 100,
|
|
119
|
+
recency: Math.round(recencyScore * 100) / 100,
|
|
120
|
+
},
|
|
121
|
+
coverage: `${m} mistakes / ${i} improvements`,
|
|
122
|
+
recommendation: this.getRecommendation(state, confidence),
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Calculate evidence score based on hit counts
|
|
128
|
+
*/
|
|
129
|
+
static calculateEvidenceScore(mistakes, improvements) {
|
|
130
|
+
const totalMistakeHits = mistakes.reduce((sum, m) => sum + (m.hitCount || 0), 0);
|
|
131
|
+
const totalImprovementHits = improvements.reduce((sum, i) => sum + (i.appliedCount || 0), 0);
|
|
132
|
+
const totalHits = totalMistakeHits + totalImprovementHits;
|
|
133
|
+
|
|
134
|
+
if (totalHits === 0) return 0.1; // No evidence
|
|
135
|
+
if (totalHits < 5) return 0.3; // Weak
|
|
136
|
+
if (totalHits < 20) return 0.6; // Moderate
|
|
137
|
+
return 0.9; // Strong
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Calculate recency score
|
|
142
|
+
*/
|
|
143
|
+
static calculateRecencyScore(mistakes, improvements) {
|
|
144
|
+
const now = Date.now();
|
|
145
|
+
|
|
146
|
+
const allDates = [
|
|
147
|
+
...mistakes.map(m => new Date(m.lastHit || m.added).getTime()),
|
|
148
|
+
...improvements.map(i => new Date(i.lastApplied || i.added).getTime()),
|
|
149
|
+
];
|
|
150
|
+
|
|
151
|
+
if (allDates.length === 0) return 0.5;
|
|
152
|
+
|
|
153
|
+
const lastUpdate = Math.max(...allDates);
|
|
154
|
+
const daysSinceUpdate = (now - lastUpdate) / (1000 * 60 * 60 * 24);
|
|
155
|
+
|
|
156
|
+
if (daysSinceUpdate < 7) return 1.0; // This week
|
|
157
|
+
if (daysSinceUpdate < 30) return 0.8; // This month
|
|
158
|
+
if (daysSinceUpdate < 90) return 0.5; // This quarter
|
|
159
|
+
return 0.3; // Stale
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Get recommendation based on state and confidence
|
|
164
|
+
*/
|
|
165
|
+
static getRecommendation(state, confidence) {
|
|
166
|
+
if (state === 'RAW') {
|
|
167
|
+
return 'URGENT: Discover best practices for this area';
|
|
168
|
+
}
|
|
169
|
+
if (state === 'LEARNING' && confidence < 0.5) {
|
|
170
|
+
return 'Needs more improvements to balance anti-patterns';
|
|
171
|
+
}
|
|
172
|
+
if (state === 'MATURE' && confidence > 0.8) {
|
|
173
|
+
return 'Stable - can be trusted for skill injection';
|
|
174
|
+
}
|
|
175
|
+
if (state === 'IDEAL') {
|
|
176
|
+
return 'Perfect - all best practices, no anti-patterns';
|
|
177
|
+
}
|
|
178
|
+
return 'Continue learning';
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Analyze evolution needs and gaps
|
|
183
|
+
* @param {Array} mistakes
|
|
184
|
+
* @param {Array} improvements
|
|
185
|
+
* @param {object} intent
|
|
186
|
+
* @returns {{signals: Array, missingAreas: Array, nextAction: string}}
|
|
187
|
+
*/
|
|
188
|
+
static analyzeEvolution(mistakes, improvements, intent) {
|
|
189
|
+
const signals = [];
|
|
190
|
+
const missingAreas = [];
|
|
191
|
+
|
|
192
|
+
// Signal 1: Many mistakes, few solutions
|
|
193
|
+
if (mistakes.length > improvements.length * 2) {
|
|
194
|
+
signals.push({
|
|
195
|
+
type: 'SUGGEST_IMPROVEMENT_DISCOVERY',
|
|
196
|
+
priority: 'HIGH',
|
|
197
|
+
reason: `${mistakes.length} anti-patterns but only ${improvements.length} solution(s)`,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Signal 2: Uncovered tags
|
|
202
|
+
const mistakeTags = new Set(mistakes.flatMap(m => m.tags || []));
|
|
203
|
+
const improvementTags = new Set(improvements.flatMap(i => i.tags || []));
|
|
204
|
+
const uncoveredTags = [...mistakeTags].filter(tag => !improvementTags.has(tag));
|
|
205
|
+
|
|
206
|
+
uncoveredTags.forEach(tag => {
|
|
207
|
+
missingAreas.push({
|
|
208
|
+
area: tag,
|
|
209
|
+
reason: 'Anti-patterns detected but no best practice documented',
|
|
210
|
+
mistakeCount: mistakes.filter(m => m.tags && m.tags.includes(tag)).length,
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
// Signal 3: High-hit mistakes without solution
|
|
215
|
+
mistakes.forEach(m => {
|
|
216
|
+
if ((m.hitCount || 0) > 10 && !this.hasRelatedImprovement(m, improvements)) {
|
|
217
|
+
signals.push({
|
|
218
|
+
type: 'HOT_MISTAKE_NEEDS_SOLUTION',
|
|
219
|
+
priority: 'CRITICAL',
|
|
220
|
+
mistake: m.id,
|
|
221
|
+
reason: `${m.title} hit ${m.hitCount} times but no solution documented`,
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
missingAreas.push({
|
|
225
|
+
area: `solution-for-${m.id}`,
|
|
226
|
+
reason: 'Frequently violated anti-pattern needs best practice',
|
|
227
|
+
hitCount: m.hitCount,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
// Signal 4: Intent under-served
|
|
233
|
+
if (intent && intent.strength > 0.7) {
|
|
234
|
+
const coverageScore = improvements.length / (mistakes.length + improvements.length);
|
|
235
|
+
if (coverageScore < 0.5) {
|
|
236
|
+
signals.push({
|
|
237
|
+
type: 'INTENT_UNDER_SERVED',
|
|
238
|
+
priority: 'MEDIUM',
|
|
239
|
+
reason: `Intent "${intent.goal}" is clear but solutions are scarce`,
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return {
|
|
245
|
+
signals,
|
|
246
|
+
missingAreas,
|
|
247
|
+
nextAction: this.determineNextAction(signals),
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Check if mistake has related improvement
|
|
253
|
+
*/
|
|
254
|
+
static hasRelatedImprovement(mistake, improvements) {
|
|
255
|
+
return improvements.some(i =>
|
|
256
|
+
i.tags && mistake.tags && i.tags.some(tag => mistake.tags.includes(tag))
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Determine next action from signals
|
|
262
|
+
*/
|
|
263
|
+
static determineNextAction(signals) {
|
|
264
|
+
if (signals.some(s => s.priority === 'CRITICAL')) {
|
|
265
|
+
return 'Document solution for high-frequency violations immediately';
|
|
266
|
+
}
|
|
267
|
+
if (signals.some(s => s.type === 'SUGGEST_IMPROVEMENT_DISCOVERY')) {
|
|
268
|
+
return 'Research and document best practices in underserved areas';
|
|
269
|
+
}
|
|
270
|
+
return 'Continue normal learning';
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Format tag as title
|
|
275
|
+
*/
|
|
276
|
+
static formatTagAsTitle(tag) {
|
|
277
|
+
return tag
|
|
278
|
+
.split('-')
|
|
279
|
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
280
|
+
.join(' ');
|
|
281
|
+
}
|
|
282
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Learning Module - Core Domain
|
|
3
|
+
*
|
|
4
|
+
* Business logic for lesson management and cognitive enhancements.
|
|
5
|
+
*
|
|
6
|
+
* Exported:
|
|
7
|
+
* - CognitiveEnhancer: Transform raw lessons to cognitive lessons
|
|
8
|
+
* - LessonSynthesizer: Group and synthesize lessons
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export { CognitiveEnhancer } from './cognitive-enhancer.js';
|
|
12
|
+
export { LessonSynthesizer } from './lesson-synthesizer.js';
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LessonSynthesizer - Core Business Logic
|
|
3
|
+
*
|
|
4
|
+
* Synthesizes cognitive lessons from raw mistakes and improvements.
|
|
5
|
+
* Groups by tag, applies cognitive enhancements, and sorts by maturity.
|
|
6
|
+
*
|
|
7
|
+
* Pure function - no side effects.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { CognitiveEnhancer } from './cognitive-enhancer.js';
|
|
11
|
+
|
|
12
|
+
export class LessonSynthesizer {
|
|
13
|
+
/**
|
|
14
|
+
* Synthesize cognitive lessons from mistakes and improvements
|
|
15
|
+
* @param {Array} mistakes - Raw mistake data
|
|
16
|
+
* @param {Array} improvements - Raw improvement data
|
|
17
|
+
* @returns {Array} Cognitive lesson units
|
|
18
|
+
*/
|
|
19
|
+
static synthesize(mistakes, improvements) {
|
|
20
|
+
// Group by tag
|
|
21
|
+
const groups = new Map();
|
|
22
|
+
|
|
23
|
+
// Add mistakes to groups
|
|
24
|
+
mistakes.forEach(m => {
|
|
25
|
+
const tags = m.tags || ['uncategorized'];
|
|
26
|
+
tags.forEach(tag => {
|
|
27
|
+
if (!groups.has(tag)) {
|
|
28
|
+
groups.set(tag, { mistakes: [], improvements: [] });
|
|
29
|
+
}
|
|
30
|
+
groups.get(tag).mistakes.push(m);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Add improvements to groups
|
|
35
|
+
improvements.forEach(i => {
|
|
36
|
+
const tags = i.tags || ['uncategorized'];
|
|
37
|
+
tags.forEach(tag => {
|
|
38
|
+
if (!groups.has(tag)) {
|
|
39
|
+
groups.set(tag, { mistakes: [], improvements: [] });
|
|
40
|
+
}
|
|
41
|
+
groups.get(tag).improvements.push(i);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Build Cognitive Lessons
|
|
46
|
+
const lessons = [];
|
|
47
|
+
let lessonId = 1;
|
|
48
|
+
|
|
49
|
+
groups.forEach((group, tag) => {
|
|
50
|
+
const allTags = [tag, ...group.mistakes.flatMap(m => m.tags || [])];
|
|
51
|
+
const intent = CognitiveEnhancer.inferIntent(allTags);
|
|
52
|
+
const maturity = CognitiveEnhancer.calculateMaturity(group.mistakes, group.improvements);
|
|
53
|
+
const evolution = CognitiveEnhancer.analyzeEvolution(group.mistakes, group.improvements, intent);
|
|
54
|
+
|
|
55
|
+
lessons.push({
|
|
56
|
+
id: `LESSON-${String(lessonId++).padStart(3, '0')}`,
|
|
57
|
+
title: CognitiveEnhancer.formatTagAsTitle(tag),
|
|
58
|
+
tag,
|
|
59
|
+
intent,
|
|
60
|
+
mistakes: group.mistakes,
|
|
61
|
+
improvements: group.improvements,
|
|
62
|
+
maturity,
|
|
63
|
+
evolution,
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Sort by maturity (MATURE first, RAW last)
|
|
68
|
+
return this.sortByMaturity(lessons);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Sort lessons by maturity state and confidence
|
|
73
|
+
*/
|
|
74
|
+
static sortByMaturity(lessons) {
|
|
75
|
+
const stateOrder = { 'IDEAL': 0, 'MATURE': 1, 'LEARNING': 2, 'RAW': 3 };
|
|
76
|
+
|
|
77
|
+
return lessons.sort((a, b) => {
|
|
78
|
+
const stateCompare = stateOrder[a.maturity.state] - stateOrder[b.maturity.state];
|
|
79
|
+
if (stateCompare !== 0) return stateCompare;
|
|
80
|
+
return b.maturity.confidence - a.maturity.confidence; // Higher confidence first
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scanning Module - Core Domain
|
|
3
|
+
*
|
|
4
|
+
* Business logic for code scanning and violation detection.
|
|
5
|
+
*
|
|
6
|
+
* Exported:
|
|
7
|
+
* - FileScanner: Scan files for pattern violations
|
|
8
|
+
* - PatternMatcher: Match patterns against code
|
|
9
|
+
* - ViolationTracker: Track violation statistics
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export { FileScanner } from './file-scanner.js';
|
|
13
|
+
export { PatternMatcher } from './pattern-matcher.js';
|
|
14
|
+
export { ViolationTracker } from './violation-tracker.js';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Data Layer
|
|
3
|
+
*
|
|
4
|
+
* Data access layer with repositories and storage adapters.
|
|
5
|
+
* Implements persistence interfaces defined in core.
|
|
6
|
+
*
|
|
7
|
+
* Exported:
|
|
8
|
+
* - Repositories: LessonRepository, SignalRepository, SettingsRepository
|
|
9
|
+
* - Storage: FileStorage, YamlStorage, JsonStorage
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export * from './repositories/index.js';
|
|
13
|
+
export * from './storage/index.js';
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LessonRepository - Data Access Layer
|
|
3
|
+
*
|
|
4
|
+
* Manages persistence of mistakes and improvements.
|
|
5
|
+
* Provides CRUD operations with YAML storage.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export class LessonRepository {
|
|
9
|
+
constructor(storage) {
|
|
10
|
+
this.storage = storage;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Load mistakes from storage
|
|
15
|
+
* @returns {Promise<{version: number, mistakes: Array}>}
|
|
16
|
+
*/
|
|
17
|
+
async loadMistakes() {
|
|
18
|
+
try {
|
|
19
|
+
const data = await this.storage.read('mistakes');
|
|
20
|
+
return data || { version: 4.0, mistakes: [] };
|
|
21
|
+
} catch (error) {
|
|
22
|
+
console.error('Error loading mistakes:', error.message);
|
|
23
|
+
return { version: 4.0, mistakes: [] };
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Load improvements from storage
|
|
29
|
+
* @returns {Promise<{version: number, improvements: Array}>}
|
|
30
|
+
*/
|
|
31
|
+
async loadImprovements() {
|
|
32
|
+
try {
|
|
33
|
+
const data = await this.storage.read('improvements');
|
|
34
|
+
return data || { version: 4.0, improvements: [] };
|
|
35
|
+
} catch (error) {
|
|
36
|
+
console.error('Error loading improvements:', error.message);
|
|
37
|
+
return { version: 4.0, improvements: [] };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Save mistakes to storage
|
|
43
|
+
* @param {object} data - {version, mistakes}
|
|
44
|
+
*/
|
|
45
|
+
async saveMistakes(data) {
|
|
46
|
+
await this.storage.write('mistakes', data);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Save improvements to storage
|
|
51
|
+
* @param {object} data - {version, improvements}
|
|
52
|
+
*/
|
|
53
|
+
async saveImprovements(data) {
|
|
54
|
+
await this.storage.write('improvements', data);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Load legacy lessons.yaml (v1-v3 format)
|
|
59
|
+
* @returns {Promise<{version: number, lessons: Array}>}
|
|
60
|
+
*/
|
|
61
|
+
async loadLegacyLessons() {
|
|
62
|
+
try {
|
|
63
|
+
const data = await this.storage.read('lessons');
|
|
64
|
+
if (!data) {
|
|
65
|
+
// Initialize if doesn't exist
|
|
66
|
+
const initial = { lessons: [], version: 1 };
|
|
67
|
+
await this.storage.write('lessons', initial);
|
|
68
|
+
return initial;
|
|
69
|
+
}
|
|
70
|
+
return data;
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.error('Error loading legacy lessons:', error.message);
|
|
73
|
+
return { lessons: [], version: 1 };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Save legacy lessons.yaml
|
|
79
|
+
* @param {object} data - {version, lessons}
|
|
80
|
+
*/
|
|
81
|
+
async saveLegacyLessons(data) {
|
|
82
|
+
await this.storage.write('lessons', data);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Add a lesson to legacy format
|
|
87
|
+
* @param {object} lesson - Lesson object
|
|
88
|
+
*/
|
|
89
|
+
async addLegacyLesson(lesson) {
|
|
90
|
+
const db = await this.loadLegacyLessons();
|
|
91
|
+
db.lessons.push(lesson);
|
|
92
|
+
await this.saveLegacyLessons(db);
|
|
93
|
+
return lesson;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Remove a lesson from legacy format
|
|
98
|
+
* @param {string} lessonId
|
|
99
|
+
*/
|
|
100
|
+
async removeLegacyLesson(lessonId) {
|
|
101
|
+
const db = await this.loadLegacyLessons();
|
|
102
|
+
const idx = db.lessons.findIndex(l => l.id === lessonId.toUpperCase());
|
|
103
|
+
|
|
104
|
+
if (idx === -1) {
|
|
105
|
+
throw new Error(`Lesson not found: ${lessonId}`);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const removed = db.lessons.splice(idx, 1)[0];
|
|
109
|
+
await this.saveLegacyLessons(db);
|
|
110
|
+
return removed;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Find lesson by ID in legacy format
|
|
115
|
+
* @param {string} lessonId
|
|
116
|
+
*/
|
|
117
|
+
async findLegacyLessonById(lessonId) {
|
|
118
|
+
const db = await this.loadLegacyLessons();
|
|
119
|
+
return db.lessons.find(l => l.id === lessonId.toUpperCase());
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Find lessons by category in legacy format
|
|
124
|
+
* @param {string} category
|
|
125
|
+
*/
|
|
126
|
+
async findLegacyLessonsByCategory(category) {
|
|
127
|
+
const db = await this.loadLegacyLessons();
|
|
128
|
+
return db.lessons.filter(l => l.category === category);
|
|
129
|
+
}
|
|
130
|
+
}
|