add-skill-kit 3.2.2 → 3.2.4

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.
Files changed (72) hide show
  1. package/bin/lib/commands/install.js +67 -45
  2. package/lib/agent-cli/README.md +21 -0
  3. package/lib/agent-cli/bin/ag-smart.js +158 -0
  4. package/lib/agent-cli/lib/audit.js +154 -0
  5. package/lib/agent-cli/lib/audit.test.js +100 -0
  6. package/lib/agent-cli/lib/auto-learn.js +319 -0
  7. package/lib/agent-cli/lib/auto_preview.py +148 -0
  8. package/lib/agent-cli/lib/backup.js +138 -0
  9. package/lib/agent-cli/lib/backup.test.js +78 -0
  10. package/lib/agent-cli/lib/checklist.py +222 -0
  11. package/lib/agent-cli/lib/cognitive-lesson.js +476 -0
  12. package/lib/agent-cli/lib/completion.js +149 -0
  13. package/lib/agent-cli/lib/config.js +35 -0
  14. package/lib/agent-cli/lib/eslint-fix.js +238 -0
  15. package/lib/agent-cli/lib/evolution-signal.js +215 -0
  16. package/lib/agent-cli/lib/export.js +86 -0
  17. package/lib/agent-cli/lib/export.test.js +65 -0
  18. package/lib/agent-cli/lib/fix.js +337 -0
  19. package/lib/agent-cli/lib/fix.test.js +80 -0
  20. package/lib/agent-cli/lib/gemini-export.js +83 -0
  21. package/lib/agent-cli/lib/generate-registry.js +42 -0
  22. package/lib/agent-cli/lib/hooks/install-hooks.js +152 -0
  23. package/lib/agent-cli/lib/hooks/lint-learn.js +172 -0
  24. package/lib/agent-cli/lib/ignore.js +116 -0
  25. package/lib/agent-cli/lib/ignore.test.js +58 -0
  26. package/lib/agent-cli/lib/init.js +124 -0
  27. package/lib/agent-cli/lib/learn.js +255 -0
  28. package/lib/agent-cli/lib/learn.test.js +70 -0
  29. package/lib/agent-cli/lib/migrate-to-v4.js +322 -0
  30. package/lib/agent-cli/lib/proposals.js +199 -0
  31. package/lib/agent-cli/lib/proposals.test.js +56 -0
  32. package/lib/agent-cli/lib/recall.js +820 -0
  33. package/lib/agent-cli/lib/recall.test.js +107 -0
  34. package/lib/agent-cli/lib/selfevolution-bridge.js +167 -0
  35. package/lib/agent-cli/lib/session_manager.py +120 -0
  36. package/lib/agent-cli/lib/settings.js +203 -0
  37. package/lib/agent-cli/lib/skill-learn.js +296 -0
  38. package/lib/agent-cli/lib/stats.js +132 -0
  39. package/lib/agent-cli/lib/stats.test.js +94 -0
  40. package/lib/agent-cli/lib/types.js +33 -0
  41. package/lib/agent-cli/lib/ui/audit-ui.js +146 -0
  42. package/lib/agent-cli/lib/ui/backup-ui.js +107 -0
  43. package/lib/agent-cli/lib/ui/clack-helpers.js +317 -0
  44. package/lib/agent-cli/lib/ui/common.js +83 -0
  45. package/lib/agent-cli/lib/ui/completion-ui.js +126 -0
  46. package/lib/agent-cli/lib/ui/custom-select.js +69 -0
  47. package/lib/agent-cli/lib/ui/dashboard-ui.js +123 -0
  48. package/lib/agent-cli/lib/ui/evolution-signals-ui.js +107 -0
  49. package/lib/agent-cli/lib/ui/export-ui.js +94 -0
  50. package/lib/agent-cli/lib/ui/fix-all-ui.js +191 -0
  51. package/lib/agent-cli/lib/ui/help-ui.js +49 -0
  52. package/lib/agent-cli/lib/ui/index.js +169 -0
  53. package/lib/agent-cli/lib/ui/init-ui.js +56 -0
  54. package/lib/agent-cli/lib/ui/knowledge-ui.js +55 -0
  55. package/lib/agent-cli/lib/ui/learn-ui.js +706 -0
  56. package/lib/agent-cli/lib/ui/lessons-ui.js +148 -0
  57. package/lib/agent-cli/lib/ui/pretty.js +145 -0
  58. package/lib/agent-cli/lib/ui/proposals-ui.js +99 -0
  59. package/lib/agent-cli/lib/ui/recall-ui.js +342 -0
  60. package/lib/agent-cli/lib/ui/routing-demo.js +79 -0
  61. package/lib/agent-cli/lib/ui/routing-ui.js +325 -0
  62. package/lib/agent-cli/lib/ui/settings-ui.js +381 -0
  63. package/lib/agent-cli/lib/ui/stats-ui.js +123 -0
  64. package/lib/agent-cli/lib/ui/watch-ui.js +236 -0
  65. package/lib/agent-cli/lib/verify_all.py +327 -0
  66. package/lib/agent-cli/lib/watcher.js +181 -0
  67. package/lib/agent-cli/lib/watcher.test.js +85 -0
  68. package/lib/agent-cli/package.json +51 -0
  69. package/lib/agentskillskit-cli/README.md +21 -0
  70. package/lib/agentskillskit-cli/ag-smart.js +158 -0
  71. package/lib/agentskillskit-cli/package.json +51 -0
  72. package/package.json +11 -6
@@ -0,0 +1,255 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Smart Learning Script - ESM Version (Production-Ready)
4
+ *
5
+ * The "Teacher" script. Adds new lessons to the system memory.
6
+ *
7
+ * Features:
8
+ * - Manual lesson addition
9
+ * - Category tagging
10
+ * - Source tracking (manual, eslint, test-failure)
11
+ *
12
+ * Usage:
13
+ * ag-smart learn --add --pattern "regex" --message "why bad"
14
+ * ag-smart learn --list
15
+ * ag-smart learn --remove <id>
16
+ */
17
+
18
+ import fs from "fs";
19
+ import path from "path";
20
+ import yaml from "js-yaml";
21
+ import { KNOWLEDGE_DIR, LESSONS_PATH, DEBUG, VERSION } from "./config.js";
22
+
23
+ // ============================================================================
24
+ // CORE FUNCTIONS
25
+ // ============================================================================
26
+
27
+ /**
28
+ * Load knowledge base from YAML file
29
+ * @returns {{ lessons: Array, version?: number }}
30
+ */
31
+ function loadKnowledge() {
32
+ try {
33
+ if (!fs.existsSync(LESSONS_PATH)) {
34
+ const initial = { lessons: [], version: 1 };
35
+ fs.mkdirSync(KNOWLEDGE_DIR, { recursive: true });
36
+ fs.writeFileSync(LESSONS_PATH, yaml.dump(initial), "utf8");
37
+ return initial;
38
+ }
39
+ const content = fs.readFileSync(LESSONS_PATH, "utf8");
40
+ return yaml.load(content) || { lessons: [], version: 1 };
41
+ } catch (error) {
42
+ console.error("❌ Failed to load knowledge base:", error.message);
43
+ if (DEBUG) console.error(error.stack);
44
+ process.exit(1);
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Save knowledge base to YAML file
50
+ * @param {{ lessons: Array, version?: number }} data
51
+ */
52
+ function saveKnowledge(data) {
53
+ try {
54
+ fs.mkdirSync(KNOWLEDGE_DIR, { recursive: true });
55
+ const str = yaml.dump(data, { lineWidth: -1, quotingType: '"' });
56
+ fs.writeFileSync(LESSONS_PATH, str, "utf8");
57
+ console.log("✅ Knowledge base updated successfully.");
58
+ } catch (error) {
59
+ console.error("❌ Failed to save knowledge base:", error.message);
60
+ if (DEBUG) console.error(error.stack);
61
+ process.exit(1);
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Add a new lesson to the knowledge base
67
+ * @param {string} pattern - Regex pattern
68
+ * @param {string} message - Explanation message
69
+ * @param {string} severity - WARNING or ERROR
70
+ * @param {string} category - Category tag
71
+ */
72
+ function addLesson(pattern, message, severity = "WARNING", category = "general") {
73
+ const db = loadKnowledge();
74
+
75
+ // Validate Regex
76
+ try {
77
+ new RegExp(pattern);
78
+ } catch (e) {
79
+ console.error("❌ Invalid Regex pattern:", e.message);
80
+ process.exit(1);
81
+ }
82
+
83
+ // Validate severity
84
+ if (!["WARNING", "ERROR"].includes(severity.toUpperCase())) {
85
+ console.error("❌ Invalid severity. Must be WARNING or ERROR");
86
+ process.exit(1);
87
+ }
88
+
89
+ // Check for duplicates
90
+ const exists = db.lessons.some(l => l.pattern === pattern);
91
+ if (exists) {
92
+ console.log("⚠️ Pattern already exists in knowledge base.");
93
+ process.exit(0);
94
+ }
95
+
96
+ const id = `LEARN-${String(db.lessons.length + 1).padStart(3, "0")}`;
97
+
98
+ const lesson = {
99
+ id,
100
+ pattern,
101
+ message,
102
+ severity: severity.toUpperCase(),
103
+ category,
104
+ source: "manual",
105
+ hitCount: 0,
106
+ lastHit: null,
107
+ autoEscalated: false,
108
+ addedAt: new Date().toISOString()
109
+ };
110
+
111
+ db.lessons.push(lesson);
112
+ saveKnowledge(db);
113
+
114
+ console.log(`\n🎓 Lesson Learned: [${id}]`);
115
+ console.log(` Pattern: /${pattern}/`);
116
+ console.log(` Message: ${message}`);
117
+ console.log(` Severity: ${severity.toUpperCase()}`);
118
+ console.log(` Category: ${category}\n`);
119
+ }
120
+
121
+ /**
122
+ * Remove a lesson by ID
123
+ * @param {string} lessonId
124
+ */
125
+ function removeLesson(lessonId) {
126
+ const db = loadKnowledge();
127
+ const idx = db.lessons.findIndex(l => l.id === lessonId.toUpperCase());
128
+
129
+ if (idx === -1) {
130
+ console.log(`❌ Lesson not found: ${lessonId}`);
131
+ process.exit(1);
132
+ }
133
+
134
+ const removed = db.lessons.splice(idx, 1)[0];
135
+ saveKnowledge(db);
136
+
137
+ console.log(`\n🗑️ Removed lesson: [${removed.id}]`);
138
+ console.log(` Pattern: /${removed.pattern}/\n`);
139
+ }
140
+
141
+ /**
142
+ * List all learned lessons
143
+ * @param {string} category - Filter by category
144
+ */
145
+ function listLessons(category = null) {
146
+ const db = loadKnowledge();
147
+
148
+ if (!db.lessons || db.lessons.length === 0) {
149
+ console.log("\nℹ️ No lessons learned yet.");
150
+ console.log(" Use: ag-smart learn --add --pattern \"pat\" --message \"msg\"\n");
151
+ return;
152
+ }
153
+
154
+ let lessons = db.lessons;
155
+ if (category) {
156
+ lessons = lessons.filter(l => l.category === category);
157
+ }
158
+
159
+ console.log(`\n🧠 Smart Agent Knowledge Base (${lessons.length} lesson(s))\n`);
160
+ console.log("─".repeat(60));
161
+
162
+ lessons.forEach(l => {
163
+ const icon = l.severity === "ERROR" ? "❌" : "⚠️";
164
+ const hits = l.hitCount ? ` (${l.hitCount} hits)` : "";
165
+ const escalated = l.autoEscalated ? " ⚡" : "";
166
+
167
+ console.log(`${icon} [${l.id}] ${l.message}${hits}${escalated}`);
168
+ console.log(` Pattern: /${l.pattern}/`);
169
+ console.log(` Category: ${l.category || "general"} | Source: ${l.source || "manual"}`);
170
+ console.log("");
171
+ });
172
+ }
173
+
174
+ // ============================================================================
175
+ // CLI
176
+ // ============================================================================
177
+
178
+ function printHelp() {
179
+ console.log(`
180
+ 🎓 Smart Learning Tool v${VERSION}
181
+
182
+ USAGE:
183
+ ag-smart learn --add --pattern "..." --message "..."
184
+ ag-smart learn --list [--category <cat>]
185
+ ag-smart learn --remove <ID>
186
+
187
+ OPTIONS:
188
+ --add Add a new lesson
189
+ --pattern Regex pattern to flag
190
+ --message Explanation message
191
+ --severity WARNING (default) or ERROR
192
+ --category Category tag (default: general)
193
+ --list List all lessons
194
+ --remove Remove lesson by ID
195
+ --help Show this help
196
+
197
+ EXAMPLES:
198
+ ag-smart learn --add --pattern "console\\.log" --message "No console.log in production" --severity ERROR
199
+ ag-smart learn --list
200
+ ag-smart learn --remove LEARN-001
201
+ `);
202
+ }
203
+
204
+ function main() {
205
+ const args = process.argv.slice(2);
206
+
207
+ if (args.includes("--help") || args.length === 0) {
208
+ printHelp();
209
+ process.exit(0);
210
+ }
211
+
212
+ if (args.includes("--list")) {
213
+ const catIdx = args.indexOf("--category");
214
+ const category = catIdx !== -1 ? args[catIdx + 1] : null;
215
+ listLessons(category);
216
+ process.exit(0);
217
+ }
218
+
219
+ if (args.includes("--remove")) {
220
+ const removeIdx = args.indexOf("--remove");
221
+ const lessonId = args[removeIdx + 1];
222
+ if (!lessonId) {
223
+ console.error("❌ Missing lesson ID for --remove");
224
+ process.exit(1);
225
+ }
226
+ removeLesson(lessonId);
227
+ process.exit(0);
228
+ }
229
+
230
+ if (args.includes("--add")) {
231
+ const pIdx = args.indexOf("--pattern");
232
+ const mIdx = args.indexOf("--message");
233
+ const sIdx = args.indexOf("--severity");
234
+ const cIdx = args.indexOf("--category");
235
+
236
+ if (pIdx === -1 || mIdx === -1) {
237
+ console.error("❌ --pattern and --message are required for --add");
238
+ process.exit(1);
239
+ }
240
+
241
+ const pattern = args[pIdx + 1];
242
+ const message = args[mIdx + 1];
243
+ const severity = sIdx !== -1 ? args[sIdx + 1] : "WARNING";
244
+ const category = cIdx !== -1 ? args[cIdx + 1] : "general";
245
+
246
+ if (!pattern || !message) {
247
+ console.error("❌ Missing values for pattern/message");
248
+ process.exit(1);
249
+ }
250
+
251
+ addLesson(pattern, message, severity, category);
252
+ }
253
+ }
254
+
255
+ main();
@@ -0,0 +1,70 @@
1
+ /**
2
+ * @fileoverview Tests for learn.js functionality
3
+ */
4
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
5
+ import fs from "fs";
6
+ import path from "path";
7
+ import os from "os";
8
+
9
+ // Mock config để test
10
+ const TEST_DIR = path.join(os.tmpdir(), "agent-skill-kit-test");
11
+ const KNOWLEDGE_DIR = path.join(TEST_DIR, ".agent", "knowledge");
12
+ const LESSONS_PATH = path.join(KNOWLEDGE_DIR, "lessons-learned.yaml");
13
+
14
+ describe("Knowledge Base Operations", () => {
15
+ beforeEach(() => {
16
+ fs.mkdirSync(KNOWLEDGE_DIR, { recursive: true });
17
+ });
18
+
19
+ afterEach(() => {
20
+ fs.rmSync(TEST_DIR, { recursive: true, force: true });
21
+ });
22
+
23
+ it("creates initial knowledge file if missing", () => {
24
+ // Simulate missing file scenario
25
+ expect(fs.existsSync(LESSONS_PATH)).toBe(false);
26
+
27
+ // Create initial file
28
+ const initial = { lessons: [] };
29
+ fs.writeFileSync(LESSONS_PATH, JSON.stringify(initial), "utf8");
30
+
31
+ expect(fs.existsSync(LESSONS_PATH)).toBe(true);
32
+ });
33
+
34
+ it("can write and read lessons", () => {
35
+ const lesson = {
36
+ id: "LEARN-001",
37
+ pattern: "console\\.log",
38
+ message: "No console.log in production",
39
+ severity: "WARNING",
40
+ addedAt: new Date().toISOString()
41
+ };
42
+
43
+ const data = { lessons: [lesson] };
44
+ fs.writeFileSync(LESSONS_PATH, JSON.stringify(data), "utf8");
45
+
46
+ const content = fs.readFileSync(LESSONS_PATH, "utf8");
47
+ const parsed = JSON.parse(content);
48
+
49
+ expect(parsed.lessons).toHaveLength(1);
50
+ expect(parsed.lessons[0].id).toBe("LEARN-001");
51
+ expect(parsed.lessons[0].pattern).toBe("console\\.log");
52
+ });
53
+
54
+ it("validates regex patterns", () => {
55
+ const validPattern = "console\\.log";
56
+ const invalidPattern = "[invalid(";
57
+
58
+ expect(() => new RegExp(validPattern)).not.toThrow();
59
+ expect(() => new RegExp(invalidPattern)).toThrow();
60
+ });
61
+
62
+ it("validates severity values", () => {
63
+ const validSeverities = ["WARNING", "ERROR"];
64
+ const invalidSeverity = "INFO";
65
+
66
+ expect(validSeverities.includes("WARNING")).toBe(true);
67
+ expect(validSeverities.includes("ERROR")).toBe(true);
68
+ expect(validSeverities.includes(invalidSeverity)).toBe(false);
69
+ });
70
+ });
@@ -0,0 +1,322 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Migration Script: v3.x → v4.x Cognitive Lesson Engine
4
+ *
5
+ * This script:
6
+ * 1. Backs up current lessons-learned.yaml
7
+ * 2. Classifies lessons into mistakes vs improvements
8
+ * 3. Generates mistakes.yaml and improvements.yaml
9
+ * 4. Preserves all existing data
10
+ */
11
+
12
+ import fs from 'fs';
13
+ import path from 'path';
14
+ import yaml from 'js-yaml';
15
+ import { fileURLToPath } from 'url';
16
+
17
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
18
+ const PROJECT_ROOT = path.join(__dirname, '../../..');
19
+ const KNOWLEDGE_DIR = path.join(PROJECT_ROOT, '.agent/knowledge');
20
+ const LESSONS_PATH = path.join(KNOWLEDGE_DIR, 'lessons-learned.yaml');
21
+ const BACKUP_DIR = path.join(KNOWLEDGE_DIR, '_migration_backup');
22
+ const MISTAKES_PATH = path.join(KNOWLEDGE_DIR, 'mistakes.yaml');
23
+ const IMPROVEMENTS_PATH = path.join(KNOWLEDGE_DIR, 'improvements.yaml');
24
+
25
+ // ============================================================================
26
+ // STEP 1: Backup Current Data
27
+ // ============================================================================
28
+
29
+ function backupCurrentLessons() {
30
+ console.log('📦 Step 1: Backing up current lessons...');
31
+
32
+ if (!fs.existsSync(LESSONS_PATH)) {
33
+ console.log('⚠️ No lessons-learned.yaml found, skipping backup');
34
+ return null;
35
+ }
36
+
37
+ // Create backup directory
38
+ fs.mkdirSync(BACKUP_DIR, { recursive: true });
39
+
40
+ // Backup with timestamp
41
+ const timestamp = new Date().toISOString().replace(/:/g, '-');
42
+ const backupPath = path.join(BACKUP_DIR, `lessons-learned_${timestamp}.yaml`);
43
+
44
+ fs.copyFileSync(LESSONS_PATH, backupPath);
45
+ console.log(`✅ Backup created: ${backupPath}`);
46
+
47
+ // Load and return data
48
+ const content = fs.readFileSync(LESSONS_PATH, 'utf8');
49
+ return yaml.load(content);
50
+ }
51
+
52
+ // ============================================================================
53
+ // STEP 2: Classification Logic
54
+ // ============================================================================
55
+
56
+ /**
57
+ * Auto-classify lesson as mistake or improvement
58
+ * Conservative: default to mistake (safer assumption)
59
+ */
60
+ function classifyLesson(lesson) {
61
+ const message = lesson.message.toLowerCase();
62
+
63
+ // Keywords that indicate improvement/best practice
64
+ const improvementKeywords = [
65
+ 'use ', 'always use', 'prefer ', 'should use',
66
+ 'best practice', 'recommended', 'instead use',
67
+ 'better to', 'proper way', 'correct approach'
68
+ ];
69
+
70
+ // Keywords that indicate mistake/anti-pattern
71
+ const mistakeKeywords = [
72
+ 'never', 'avoid', 'don\'t', 'do not', 'incorrect',
73
+ 'wrong', 'bad', 'conflicts', 'causes', 'breaks'
74
+ ];
75
+
76
+ const hasMistakeKeyword = mistakeKeywords.some(kw => message.includes(kw));
77
+ const hasImprovementKeyword = improvementKeywords.some(kw => message.includes(kw));
78
+
79
+ // Both keywords present - need manual review
80
+ if (hasMistakeKeyword && hasImprovementKeyword) {
81
+ return 'mixed';
82
+ }
83
+
84
+ // Clear improvement
85
+ if (hasImprovementKeyword && !hasMistakeKeyword) {
86
+ return 'improvement';
87
+ }
88
+
89
+ // Default: mistake (conservative)
90
+ return 'mistake';
91
+ }
92
+
93
+ /**
94
+ * Extract tags from lesson data
95
+ * Tags used for grouping into Cognitive Lessons
96
+ */
97
+ function extractTags(lesson) {
98
+ const tags = new Set();
99
+
100
+ // Add category as tag
101
+ if (lesson.category) {
102
+ tags.add(lesson.category);
103
+ }
104
+
105
+ // Extract from pattern
106
+ const pattern = lesson.pattern.toLowerCase();
107
+ if (pattern.includes('select')) tags.add('cli-navigation');
108
+ if (pattern.includes('menu')) tags.add('ux');
109
+ if (pattern.includes('rename') || pattern.includes('move') || pattern.includes('rebrand')) {
110
+ tags.add('file-safety');
111
+ tags.add('rebranding');
112
+ }
113
+ if (pattern.includes('import')) tags.add('imports');
114
+ if (pattern.includes('recursive')) tags.add('architecture');
115
+
116
+ // Extract from message
117
+ const message = lesson.message.toLowerCase();
118
+ if (message.includes('esc')) tags.add('cli-navigation');
119
+ if (message.includes('clack')) tags.add('clack-framework');
120
+ if (message.includes('menu')) tags.add('ux');
121
+ if (message.includes('security')) tags.add('security');
122
+ if (message.includes('performance')) tags.add('performance');
123
+
124
+ return Array.from(tags);
125
+ }
126
+
127
+ /**
128
+ * Split mixed lessons into mistake + improvement
129
+ */
130
+ function splitMixedLesson(lesson) {
131
+ const message = lesson.message;
132
+
133
+ // Try to extract both parts
134
+ // Pattern: "NEVER X. Use Y instead"
135
+ const neverMatch = message.match(/(NEVER|Don't|Avoid)\s+([^.]+)\./i);
136
+ const useMatch = message.match(/(Use|Always use|Instead use)\s+([^.]+)/i);
137
+
138
+ const mistake = {
139
+ ...lesson,
140
+ id: lesson.id.replace('LEARN', 'MISTAKE'),
141
+ title: neverMatch ? neverMatch[0] : message.split('.')[0],
142
+ message: neverMatch ? neverMatch[0] : message.split('.')[0],
143
+ };
144
+
145
+ let improvement = null;
146
+ if (useMatch) {
147
+ improvement = {
148
+ id: lesson.id.replace('LEARN', 'IMPROVE'),
149
+ title: useMatch[0],
150
+ message: useMatch[0],
151
+ pattern: lesson.pattern,
152
+ priority: lesson.severity === 'ERROR' ? 'HIGH' : 'MEDIUM',
153
+ tags: extractTags(lesson),
154
+ added: lesson.addedAt,
155
+ appliedCount: 0,
156
+ };
157
+ }
158
+
159
+ return { mistake, improvement };
160
+ }
161
+
162
+ // ============================================================================
163
+ // STEP 3: Migration Logic
164
+ // ============================================================================
165
+
166
+ function migrateToV4(oldData) {
167
+ console.log('\n🔄 Step 2: Classifying lessons...');
168
+
169
+ const mistakes = [];
170
+ const improvements = [];
171
+ const needsReview = [];
172
+
173
+ oldData.lessons.forEach((lesson, index) => {
174
+ const classification = classifyLesson(lesson);
175
+ const tags = extractTags(lesson);
176
+
177
+ console.log(` ${lesson.id}: ${classification} (tags: ${tags.join(', ')})`);
178
+
179
+ if (classification === 'mistake') {
180
+ mistakes.push({
181
+ id: lesson.id.replace('LEARN', 'MISTAKE'),
182
+ title: lesson.message.split('.')[0], // First sentence as title
183
+ pattern: lesson.pattern,
184
+ message: lesson.message,
185
+ severity: lesson.severity,
186
+ tags,
187
+ context: lesson.category,
188
+ hitCount: lesson.hitCount || 0,
189
+ lastHit: lesson.lastHit,
190
+ added: lesson.addedAt,
191
+ source: lesson.source,
192
+ excludePaths: lesson.excludePaths || [],
193
+ });
194
+ } else if (classification === 'improvement') {
195
+ improvements.push({
196
+ id: lesson.id.replace('LEARN', 'IMPROVE'),
197
+ title: lesson.message.split('.')[0],
198
+ pattern: lesson.pattern,
199
+ message: lesson.message,
200
+ priority: lesson.severity === 'ERROR' ? 'HIGH' : 'MEDIUM',
201
+ tags,
202
+ added: lesson.addedAt,
203
+ appliedCount: lesson.hitCount || 0,
204
+ lastApplied: lesson.lastHit,
205
+ source: lesson.source,
206
+ });
207
+ } else {
208
+ // Mixed - split into both
209
+ const { mistake, improvement } = splitMixedLesson(lesson);
210
+ mistakes.push({
211
+ ...mistake,
212
+ severity: lesson.severity,
213
+ tags,
214
+ hitCount: lesson.hitCount || 0,
215
+ lastHit: lesson.lastHit,
216
+ added: lesson.addedAt,
217
+ source: lesson.source,
218
+ excludePaths: lesson.excludePaths || [],
219
+ });
220
+
221
+ if (improvement) {
222
+ improvements.push({
223
+ ...improvement,
224
+ source: lesson.source,
225
+ });
226
+ }
227
+
228
+ needsReview.push({
229
+ ...lesson,
230
+ reason: 'Mixed mistake + improvement keywords, auto-split but needs verification',
231
+ });
232
+ }
233
+ });
234
+
235
+ console.log(`\n✅ Classification complete:`);
236
+ console.log(` ${mistakes.length} mistakes`);
237
+ console.log(` ${improvements.length} improvements`);
238
+ console.log(` ${needsReview.length} need manual review`);
239
+
240
+ return { mistakes, improvements, needsReview };
241
+ }
242
+
243
+ // ============================================================================
244
+ // STEP 4: Save New Files
245
+ // ============================================================================
246
+
247
+ function saveYAML(filename, data) {
248
+ const filepath = path.join(KNOWLEDGE_DIR, filename);
249
+ const yamlStr = yaml.dump(data, {
250
+ lineWidth: -1,
251
+ noRefs: true,
252
+ sortKeys: false,
253
+ });
254
+ fs.writeFileSync(filepath, yamlStr, 'utf8');
255
+ console.log(`✅ Created: ${filename}`);
256
+ }
257
+
258
+ function saveNewStructure(result) {
259
+ console.log('\n📝 Step 3: Creating new data files...');
260
+
261
+ // Save mistakes
262
+ saveYAML('mistakes.yaml', {
263
+ version: 4.0,
264
+ mistakes: result.mistakes,
265
+ });
266
+
267
+ // Save improvements
268
+ saveYAML('improvements.yaml', {
269
+ version: 4.0,
270
+ improvements: result.improvements,
271
+ });
272
+
273
+ // Save review queue if needed
274
+ if (result.needsReview.length > 0) {
275
+ saveYAML('_needs_review.yaml', {
276
+ note: 'These lessons contained both mistake and improvement keywords and were auto-split. Please review.',
277
+ items: result.needsReview,
278
+ });
279
+ console.log(`⚠️ ${result.needsReview.length} items saved to _needs_review.yaml`);
280
+ }
281
+ }
282
+
283
+ // ============================================================================
284
+ // MAIN MIGRATION
285
+ // ============================================================================
286
+
287
+ async function main() {
288
+ console.log('🧠 Cognitive Lesson Engine v4.x Migration\n');
289
+ console.log('This script will transform your lessons into the new architecture.');
290
+ console.log('All existing data will be preserved in backups.\n');
291
+
292
+ try {
293
+ // Step 1: Backup
294
+ const oldData = backupCurrentLessons();
295
+
296
+ if (!oldData || !oldData.lessons || oldData.lessons.length === 0) {
297
+ console.log('❌ No lessons found to migrate.');
298
+ return;
299
+ }
300
+
301
+ // Step 2: Classify
302
+ const result = migrateToV4(oldData);
303
+
304
+ // Step 3: Save
305
+ saveNewStructure(result);
306
+
307
+ // Step 4: Summary
308
+ console.log('\n🎉 Migration complete!');
309
+ console.log('\nNext steps:');
310
+ console.log(' 1. Review _needs_review.yaml (if exists)');
311
+ console.log(' 2. Test with: node packages/cli/lib/ui/index.js');
312
+ console.log(' 3. Original file preserved in _migration_backup/');
313
+ console.log('\n✅ You can now use the Cognitive Lesson Engine!');
314
+
315
+ } catch (error) {
316
+ console.error('\n❌ Migration failed:', error.message);
317
+ console.error(error.stack);
318
+ process.exit(1);
319
+ }
320
+ }
321
+
322
+ main();