agentic-qe 3.7.21 → 3.7.22

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 (52) hide show
  1. package/.claude/helpers/brain-checkpoint.cjs +4 -1
  2. package/.claude/helpers/statusline-v3.cjs +3 -1
  3. package/.claude/skills/skills-manifest.json +1 -1
  4. package/CHANGELOG.md +14 -0
  5. package/README.md +0 -12
  6. package/assets/helpers/statusline-v3.cjs +3 -1
  7. package/dist/cli/brain-commands.js +6 -10
  8. package/dist/cli/bundle.js +2049 -3380
  9. package/dist/cli/commands/hooks.js +29 -6
  10. package/dist/cli/commands/init.js +1 -73
  11. package/dist/cli/commands/learning.js +164 -12
  12. package/dist/cli/handlers/init-handler.d.ts +0 -1
  13. package/dist/cli/handlers/init-handler.js +0 -6
  14. package/dist/cli/index.js +0 -2
  15. package/dist/context/sources/defect-source.js +2 -2
  16. package/dist/context/sources/memory-source.js +2 -2
  17. package/dist/context/sources/requirements-source.js +2 -2
  18. package/dist/init/index.d.ts +0 -2
  19. package/dist/init/index.js +0 -1
  20. package/dist/init/init-wizard-steps.d.ts +10 -0
  21. package/dist/init/init-wizard-steps.js +87 -1
  22. package/dist/init/init-wizard.d.ts +1 -9
  23. package/dist/init/init-wizard.js +3 -69
  24. package/dist/init/orchestrator.js +0 -1
  25. package/dist/init/phases/01-detection.js +0 -27
  26. package/dist/init/phases/07-hooks.js +6 -4
  27. package/dist/init/phases/phase-interface.d.ts +0 -1
  28. package/dist/init/settings-merge.js +1 -1
  29. package/dist/kernel/unified-memory.js +5 -6
  30. package/dist/learning/experience-capture-middleware.js +20 -0
  31. package/dist/learning/index.d.ts +0 -2
  32. package/dist/learning/index.js +0 -4
  33. package/dist/learning/metrics-tracker.js +15 -13
  34. package/dist/learning/pattern-lifecycle.d.ts +1 -1
  35. package/dist/learning/pattern-lifecycle.js +18 -20
  36. package/dist/learning/qe-unified-memory.js +1 -28
  37. package/dist/mcp/bundle.js +180 -175
  38. package/package.json +1 -1
  39. package/dist/cli/commands/migrate.d.ts +0 -9
  40. package/dist/cli/commands/migrate.js +0 -566
  41. package/dist/init/init-wizard-migration.d.ts +0 -52
  42. package/dist/init/init-wizard-migration.js +0 -345
  43. package/dist/init/migration/config-migrator.d.ts +0 -31
  44. package/dist/init/migration/config-migrator.js +0 -149
  45. package/dist/init/migration/data-migrator.d.ts +0 -72
  46. package/dist/init/migration/data-migrator.js +0 -232
  47. package/dist/init/migration/detector.d.ts +0 -44
  48. package/dist/init/migration/detector.js +0 -105
  49. package/dist/init/migration/index.d.ts +0 -8
  50. package/dist/init/migration/index.js +0 -8
  51. package/dist/learning/v2-to-v3-migration.d.ts +0 -86
  52. package/dist/learning/v2-to-v3-migration.js +0 -529
@@ -358,7 +358,24 @@ async function consolidateExperiencesToPatterns() {
358
358
  await um.initialize();
359
359
  }
360
360
  const db = um.getDatabase();
361
- // Aggregate unprocessed experiences by domain+agent with quality thresholds
361
+ // Ensure consolidation columns exist (may be missing on older DBs)
362
+ const existingCols = new Set(db.prepare('PRAGMA table_info(captured_experiences)').all().map(c => c.name));
363
+ const migrations = [
364
+ ['consolidated_into', 'TEXT DEFAULT NULL'],
365
+ ['consolidation_count', 'INTEGER DEFAULT 1'],
366
+ ['quality_updated_at', 'TEXT DEFAULT NULL'],
367
+ ['reuse_success_count', 'INTEGER DEFAULT 0'],
368
+ ['reuse_failure_count', 'INTEGER DEFAULT 0'],
369
+ ];
370
+ for (const [col, def] of migrations) {
371
+ if (!existingCols.has(col)) {
372
+ db.exec(`ALTER TABLE captured_experiences ADD COLUMN ${col} ${def}`);
373
+ }
374
+ }
375
+ // Aggregate unprocessed experiences by domain+agent with quality thresholds.
376
+ // Exclude 'cli-hook' agent — these are low-quality hook telemetry events
377
+ // (quality ~0.40, success_rate ~0.24) that flood the pipeline and block
378
+ // real pattern creation. See issue #348.
362
379
  const aggregates = db.prepare(`
363
380
  SELECT
364
381
  domain,
@@ -371,6 +388,7 @@ async function consolidateExperiencesToPatterns() {
371
388
  GROUP_CONCAT(DISTINCT source) as sources
372
389
  FROM captured_experiences
373
390
  WHERE application_count = 0
391
+ AND agent != 'cli-hook'
374
392
  GROUP BY domain, agent
375
393
  HAVING cnt >= 3 AND avg_quality >= 0.5 AND success_rate >= 0.6
376
394
  ORDER BY avg_quality DESC
@@ -382,20 +400,25 @@ async function consolidateExperiencesToPatterns() {
382
400
  let created = 0;
383
401
  for (const agg of aggregates) {
384
402
  try {
385
- // Check for existing pattern with same domain+agent to avoid duplicates
403
+ // Use date-bucketed names so new patterns emerge as usage evolves,
404
+ // instead of silently reinforcing one static pattern forever.
405
+ const dateBucket = new Date().toISOString().slice(0, 7); // YYYY-MM
406
+ const patternName = `${agg.agent}-${agg.domain}-${dateBucket}`;
407
+ // Check for existing pattern with same name this month
386
408
  const existing = db.prepare(`
387
409
  SELECT id FROM qe_patterns
388
410
  WHERE qe_domain = ? AND name = ?
389
411
  LIMIT 1
390
- `).get(agg.domain, `${agg.agent}-session-pattern`);
412
+ `).get(agg.domain, patternName);
391
413
  if (existing) {
392
- // Reinforce existing pattern instead of creating duplicate
414
+ // Reinforce existing monthly pattern
393
415
  db.prepare(`
394
416
  UPDATE qe_patterns
395
417
  SET usage_count = usage_count + ?,
396
418
  successful_uses = successful_uses + ?,
397
419
  confidence = MIN(0.99, confidence + 0.01),
398
- quality_score = MIN(0.99, quality_score + 0.005)
420
+ quality_score = MIN(0.99, quality_score + 0.005),
421
+ updated_at = datetime('now')
399
422
  WHERE id = ?
400
423
  `).run(agg.cnt, agg.successes, existing.id);
401
424
  }
@@ -409,7 +432,7 @@ async function consolidateExperiencesToPatterns() {
409
432
  confidence, usage_count, success_rate, quality_score, tier,
410
433
  template_json, context_json, created_at, successful_uses
411
434
  ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'), ?)
412
- `).run(patternId, 'workflow', agg.domain, agg.domain, `${agg.agent}-session-pattern`, `Auto-consolidated from ${agg.cnt} experiences. Agent: ${agg.agent}, success rate: ${(agg.success_rate * 100).toFixed(0)}%`, confidence, agg.cnt, agg.success_rate, qualityScore, 'short-term', JSON.stringify({ type: 'workflow', content: `${agg.agent} pattern for ${agg.domain}`, variables: [] }), JSON.stringify({ tags: (agg.sources || '').split(','), sourceType: 'session-consolidation', extractedAt: new Date().toISOString() }), agg.successes);
435
+ `).run(patternId, 'workflow', agg.domain, agg.domain, patternName, `Auto-consolidated from ${agg.cnt} experiences. Agent: ${agg.agent}, success rate: ${(agg.success_rate * 100).toFixed(0)}%`, confidence, agg.cnt, agg.success_rate, qualityScore, 'short-term', JSON.stringify({ type: 'workflow', content: `${agg.agent} pattern for ${agg.domain}`, variables: [] }), JSON.stringify({ tags: (agg.sources || '').split(','), sourceType: 'session-consolidation', extractedAt: new Date().toISOString() }), agg.successes);
413
436
  created++;
414
437
  }
415
438
  // Mark experiences as processed
@@ -28,7 +28,6 @@ export function createInitCommand() {
28
28
  .description('Initialize Agentic QE v3 in your project')
29
29
  .option('-a, --auto', 'Auto-configure without prompts')
30
30
  .option('-u, --upgrade', 'Upgrade existing installation (overwrites skills, agents, validation)')
31
- .option('--auto-migrate', 'Automatically migrate from v2 if detected')
32
31
  .option('--minimal', 'Minimal installation (no skills, patterns, or workers)')
33
32
  .option('--skip-patterns', 'Skip pattern loading')
34
33
  .option('--with-n8n', 'Include n8n workflow testing platform')
@@ -57,14 +56,6 @@ export function createInitCommand() {
57
56
  .action(async () => {
58
57
  await checkStatus();
59
58
  });
60
- initCmd
61
- .command('migrate')
62
- .description('Migrate from v2 to v3')
63
- .option('--dry-run', 'Show what would be migrated without making changes')
64
- .option('--force', 'Force migration even if v3 already exists')
65
- .action(async (migrateOptions) => {
66
- await runMigration(migrateOptions);
67
- });
68
59
  initCmd
69
60
  .command('reset')
70
61
  .description('Reset AQE configuration (keeps data)')
@@ -87,11 +78,10 @@ async function runInit(options) {
87
78
  // Check if already initialized
88
79
  const aqeDir = path.join(projectRoot, '.agentic-qe');
89
80
  const isExisting = existsSync(aqeDir);
90
- if (isExisting && !options.auto && !options.autoMigrate && !options.upgrade) {
81
+ if (isExisting && !options.auto && !options.upgrade) {
91
82
  console.log(chalk.yellow(' ⚠ AQE directory already exists at:'), aqeDir);
92
83
  console.log(chalk.gray(' Use --auto to update configuration (keeps existing skills)'));
93
84
  console.log(chalk.gray(' Use --upgrade to update all skills, agents, and validation'));
94
- console.log(chalk.gray(' Use --auto-migrate to migrate from v2'));
95
85
  console.log('');
96
86
  }
97
87
  // Expand --with-all-platforms into individual flags
@@ -110,7 +100,6 @@ async function runInit(options) {
110
100
  projectRoot,
111
101
  autoMode: options.auto,
112
102
  upgrade: options.upgrade,
113
- autoMigrate: options.autoMigrate,
114
103
  minimal: options.minimal,
115
104
  skipPatterns: options.skipPatterns,
116
105
  withN8n: options.withN8n,
@@ -223,67 +212,6 @@ async function checkStatus() {
223
212
  }
224
213
  console.log('');
225
214
  }
226
- /**
227
- * Run v2 to v3 migration
228
- */
229
- async function runMigration(options) {
230
- const projectRoot = process.cwd();
231
- const aqeDir = path.join(projectRoot, '.agentic-qe');
232
- console.log('');
233
- console.log(chalk.bold.blue(' AQE v2 to v3 Migration'));
234
- console.log(chalk.gray(' ──────────────────────────'));
235
- console.log('');
236
- // Import migration modules
237
- const { createV2Detector, createV2DataMigrator, createV2ConfigMigrator } = await import('../../init/migration/index.js');
238
- // Detect v2
239
- const detector = createV2Detector(projectRoot);
240
- const v2Info = await detector.detect();
241
- if (!v2Info.detected) {
242
- console.log(chalk.yellow(' ⚠ No v2 installation detected'));
243
- console.log(chalk.gray(' Run "aqe init" to create a new installation'));
244
- console.log('');
245
- return;
246
- }
247
- console.log(chalk.green(' ✓ Found v2 installation'));
248
- console.log(chalk.gray(` Database: ${v2Info.paths.memoryDb || 'not found'}`));
249
- console.log(chalk.gray(` Config: ${v2Info.paths.configDir || 'not found'}`));
250
- console.log(chalk.gray(` Version: ${v2Info.version || 'unknown'}`));
251
- console.log('');
252
- if (options.dryRun) {
253
- console.log(chalk.yellow(' Dry run - no changes will be made'));
254
- console.log('');
255
- return;
256
- }
257
- // Run migration
258
- console.log(chalk.blue(' Migrating data...'));
259
- if (v2Info.paths.memoryDb) {
260
- const dataMigrator = createV2DataMigrator({
261
- v2DbPath: v2Info.paths.memoryDb,
262
- v3PatternsDbPath: path.join(aqeDir, 'patterns.db'),
263
- onProgress: (p) => console.log(chalk.gray(` ${p.message}`)),
264
- });
265
- const dataResult = await dataMigrator.migrate();
266
- if (dataResult.success) {
267
- console.log(chalk.green(` ✓ Migrated ${dataResult.counts.patterns || 0} patterns`));
268
- console.log(chalk.green(` ✓ Migrated ${dataResult.counts.experiences || 0} experiences`));
269
- }
270
- else {
271
- console.log(chalk.red(` ✗ Data migration failed: ${dataResult.errors.join(', ')}`));
272
- }
273
- }
274
- const configMigrator = createV2ConfigMigrator(projectRoot);
275
- const configResult = await configMigrator.migrate();
276
- if (configResult.success) {
277
- console.log(chalk.green(' ✓ Config migrated'));
278
- }
279
- else {
280
- console.log(chalk.yellow(' ⚠ Config migration skipped (no v2 config found)'));
281
- }
282
- console.log('');
283
- console.log(chalk.green(' Migration complete!'));
284
- console.log(chalk.gray(' Run "aqe init" to complete setup'));
285
- console.log('');
286
- }
287
215
  /**
288
216
  * Reset AQE configuration
289
217
  */
@@ -13,7 +13,7 @@ import { Command } from 'commander';
13
13
  import chalk from 'chalk';
14
14
  import path from 'node:path';
15
15
  import { findProjectRoot } from '../../kernel/unified-memory.js';
16
- import { existsSync, writeFileSync, readFileSync, mkdirSync, copyFileSync } from 'node:fs';
16
+ import { existsSync, writeFileSync, readFileSync, mkdirSync, copyFileSync, renameSync } from 'node:fs';
17
17
  import { safeJsonParse } from '../../shared/safe-json.js';
18
18
  import { stat, unlink } from 'node:fs/promises';
19
19
  import { QE_DOMAIN_LIST } from '../../learning/qe-patterns.js';
@@ -62,6 +62,7 @@ Examples:
62
62
  registerExportFullCommand(learning);
63
63
  registerImportMergeCommand(learning);
64
64
  registerDreamCommand(learning);
65
+ registerRepairCommand(learning);
65
66
  return learning;
66
67
  }
67
68
  // ============================================================================
@@ -372,15 +373,19 @@ function registerExtractCommand(learning) {
372
373
  console.log(` Min occurrences: ${minCount}\n`);
373
374
  const db = openDatabase(dbPath, { readonly: true });
374
375
  const experiences = db.prepare(`
375
- SELECT task_type, COUNT(*) as count, AVG(reward) as avg_reward, MAX(reward) as max_reward,
376
- MIN(reward) as min_reward, GROUP_CONCAT(DISTINCT action) as actions
377
- FROM learning_experiences WHERE reward >= ? GROUP BY task_type HAVING COUNT(*) >= ? ORDER BY avg_reward DESC
376
+ SELECT domain as task_type, COUNT(*) as count, AVG(quality) as avg_reward, MAX(quality) as max_reward,
377
+ MIN(quality) as min_reward, GROUP_CONCAT(DISTINCT agent) as actions
378
+ FROM captured_experiences WHERE quality >= ? AND agent != 'cli-hook' GROUP BY domain HAVING COUNT(*) >= ? ORDER BY avg_reward DESC
378
379
  `).all(minReward, minCount);
379
- const memoryPatterns = db.prepare(`
380
- SELECT substr(key, 1, 40) as key_prefix, COUNT(*) as count
381
- FROM memory_entries WHERE key LIKE 'phase2/learning/%'
382
- GROUP BY substr(key, 1, 40) HAVING COUNT(*) >= ? ORDER BY COUNT(*) DESC LIMIT 20
383
- `).all(minCount);
380
+ let memoryPatterns = [];
381
+ try {
382
+ memoryPatterns = db.prepare(`
383
+ SELECT substr(key, 1, 40) as key_prefix, COUNT(*) as count
384
+ FROM memory_entries WHERE key LIKE 'phase2/learning/%'
385
+ GROUP BY substr(key, 1, 40) HAVING COUNT(*) >= ? ORDER BY COUNT(*) DESC LIMIT 20
386
+ `).all(minCount);
387
+ }
388
+ catch { /* memory_entries table may not exist */ }
384
389
  db.close();
385
390
  const extractedPatterns = [];
386
391
  for (const exp of experiences) {
@@ -689,7 +694,7 @@ function registerVerifyCommand(learning) {
689
694
  let tableCounts = {};
690
695
  try {
691
696
  const db = openDatabase(dbPath, { readonly: true });
692
- for (const table of ['qe_patterns', 'qe_trajectories', 'learning_experiences', 'kv_store', 'vectors']) {
697
+ for (const table of ['qe_patterns', 'qe_trajectories', 'captured_experiences', 'kv_store', 'vectors']) {
693
698
  try {
694
699
  const r = db.prepare(`SELECT COUNT(*) as count FROM ${table}`).get();
695
700
  tableCounts[table] = r.count;
@@ -770,9 +775,9 @@ function registerExportFullCommand(learning) {
770
775
  if (options.includeExperiences) {
771
776
  try {
772
777
  const db = openDatabase(dbPath, { readonly: true });
773
- const experiences = db.prepare(`SELECT task_type, action, AVG(reward) as avg_reward, COUNT(*) as count FROM learning_experiences GROUP BY task_type, action ORDER BY count DESC LIMIT 500`).all();
778
+ const experiences = db.prepare(`SELECT domain as task_type, agent as action, AVG(quality) as avg_reward, COUNT(*) as count FROM captured_experiences WHERE agent != 'cli-hook' GROUP BY domain, agent ORDER BY count DESC LIMIT 500`).all();
774
779
  exportData.experiences = experiences.map(e => ({ taskType: e.task_type, action: e.action, reward: e.avg_reward, count: e.count }));
775
- const metaRow = db.prepare(`SELECT COUNT(*) as total, AVG(reward) as avg_reward FROM learning_experiences`).get();
780
+ const metaRow = db.prepare(`SELECT COUNT(*) as total, AVG(quality) as avg_reward FROM captured_experiences WHERE agent != 'cli-hook'`).get();
776
781
  exportData.metadata = { totalExperiences: metaRow.total, avgReward: metaRow.avg_reward };
777
782
  db.close();
778
783
  }
@@ -1136,6 +1141,153 @@ function registerDreamCommand(learning) {
1136
1141
  });
1137
1142
  }
1138
1143
  // ============================================================================
1144
+ // Subcommand: repair
1145
+ // ============================================================================
1146
+ function registerRepairCommand(learning) {
1147
+ learning
1148
+ .command('repair')
1149
+ .description('Repair a corrupted learning database (dump + reimport to rebuild indexes)')
1150
+ .option('-f, --file <path>', 'Database file to repair (defaults to current project)')
1151
+ .option('--dry-run', 'Show what would be done without modifying files')
1152
+ .option('--json', 'Output as JSON')
1153
+ .action(async (options) => {
1154
+ try {
1155
+ const dbPath = options.file ? path.resolve(options.file) : getDbPath();
1156
+ if (!existsSync(dbPath))
1157
+ throw new Error(`Database file not found: ${dbPath}`);
1158
+ // Step 1: Check integrity first
1159
+ const integrityResult = await verifyDatabaseIntegrity(dbPath);
1160
+ if (integrityResult.valid) {
1161
+ if (options.json) {
1162
+ printJson({ status: 'healthy', message: 'Database is already healthy, no repair needed', path: dbPath });
1163
+ }
1164
+ else {
1165
+ printSuccess('Database integrity check passed — no repair needed.');
1166
+ }
1167
+ process.exit(0);
1168
+ }
1169
+ printInfo(`Corruption detected: ${integrityResult.message}`);
1170
+ // Step 2: Count rows before repair
1171
+ let rowCountsBefore = {};
1172
+ try {
1173
+ const db = openDatabase(dbPath, { readonly: true });
1174
+ const tables = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'").all();
1175
+ for (const t of tables) {
1176
+ try {
1177
+ const r = db.prepare(`SELECT COUNT(*) as count FROM "${t.name}"`).get();
1178
+ rowCountsBefore[t.name] = r.count;
1179
+ }
1180
+ catch { /* corrupted table, count what we can */ }
1181
+ }
1182
+ db.close();
1183
+ }
1184
+ catch { /* ignore count failures */ }
1185
+ const totalBefore = Object.values(rowCountsBefore).reduce((a, b) => a + b, 0);
1186
+ printInfo(`Found ${Object.keys(rowCountsBefore).length} tables, ~${totalBefore} total rows`);
1187
+ if (options.dryRun) {
1188
+ if (options.json) {
1189
+ printJson({ status: 'dry-run', corruptionDetected: true, message: integrityResult.message, tables: rowCountsBefore, totalRows: totalBefore });
1190
+ }
1191
+ else {
1192
+ console.log(chalk.bold('\nDry run — would perform these steps:'));
1193
+ console.log(' 1. Backup corrupted DB');
1194
+ console.log(' 2. Dump all data via .dump');
1195
+ console.log(' 3. Reimport into fresh DB (rebuilds all indexes)');
1196
+ console.log(' 4. Verify integrity of repaired DB');
1197
+ console.log(' 5. Verify row counts match');
1198
+ console.log(' 6. Swap repaired DB into place');
1199
+ console.log('');
1200
+ }
1201
+ process.exit(0);
1202
+ }
1203
+ // Step 3: Backup
1204
+ const backupPath = `${dbPath}.bak-${Date.now()}`;
1205
+ copyFileSync(dbPath, backupPath);
1206
+ printInfo(`Backup created: ${backupPath}`);
1207
+ // Step 4: Remove stale WAL/SHM
1208
+ for (const suffix of ['-wal', '-shm']) {
1209
+ const walFile = dbPath + suffix;
1210
+ if (existsSync(walFile)) {
1211
+ await unlink(walFile);
1212
+ }
1213
+ }
1214
+ // Step 5: Dump and reimport using sqlite3 CLI
1215
+ const { execSync } = await import('node:child_process');
1216
+ const repairedPath = `${dbPath}.repaired`;
1217
+ const dumpPath = `${dbPath}.dump.sql`;
1218
+ try {
1219
+ // Dump all data
1220
+ execSync(`sqlite3 "${dbPath}" ".dump" > "${dumpPath}"`, { stdio: 'pipe', timeout: 120000 });
1221
+ // Reimport into fresh DB
1222
+ execSync(`sqlite3 "${repairedPath}" < "${dumpPath}"`, { stdio: 'pipe', timeout: 120000 });
1223
+ // Enable WAL on repaired DB
1224
+ execSync(`sqlite3 "${repairedPath}" "PRAGMA journal_mode=WAL;"`, { stdio: 'pipe' });
1225
+ }
1226
+ catch (dumpError) {
1227
+ // Clean up partial files
1228
+ if (existsSync(repairedPath))
1229
+ await unlink(repairedPath);
1230
+ if (existsSync(dumpPath))
1231
+ await unlink(dumpPath);
1232
+ throw new Error(`sqlite3 dump/reimport failed: ${dumpError instanceof Error ? dumpError.message : 'unknown'}. Is sqlite3 installed?`);
1233
+ }
1234
+ // Step 6: Verify repaired DB
1235
+ const repairedIntegrity = await verifyDatabaseIntegrity(repairedPath);
1236
+ if (!repairedIntegrity.valid) {
1237
+ if (existsSync(dumpPath))
1238
+ await unlink(dumpPath);
1239
+ throw new Error(`Repaired DB still has integrity issues: ${repairedIntegrity.message}. Backup preserved at ${backupPath}`);
1240
+ }
1241
+ // Step 7: Verify row counts
1242
+ let rowCountsAfter = {};
1243
+ const repairedDb = openDatabase(repairedPath, { readonly: true });
1244
+ const repairedTables = repairedDb.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'").all();
1245
+ for (const t of repairedTables) {
1246
+ try {
1247
+ const r = repairedDb.prepare(`SELECT COUNT(*) as count FROM "${t.name}"`).get();
1248
+ rowCountsAfter[t.name] = r.count;
1249
+ }
1250
+ catch { /* skip */ }
1251
+ }
1252
+ repairedDb.close();
1253
+ const totalAfter = Object.values(rowCountsAfter).reduce((a, b) => a + b, 0);
1254
+ // Step 8: Swap
1255
+ renameSync(dbPath, `${dbPath}.pre-repair`);
1256
+ renameSync(repairedPath, dbPath);
1257
+ // Clean up dump file
1258
+ if (existsSync(dumpPath))
1259
+ await unlink(dumpPath);
1260
+ if (options.json) {
1261
+ printJson({
1262
+ status: 'repaired',
1263
+ backupPath,
1264
+ rowsBefore: totalBefore,
1265
+ rowsAfter: totalAfter,
1266
+ tablesRepaired: Object.keys(rowCountsAfter).length,
1267
+ rowCounts: rowCountsAfter,
1268
+ });
1269
+ }
1270
+ else {
1271
+ printSuccess('Database repaired successfully!');
1272
+ console.log(` Backup: ${backupPath}`);
1273
+ console.log(` Rows before: ${totalBefore}`);
1274
+ console.log(` Rows after: ${totalAfter}`);
1275
+ if (totalAfter < totalBefore) {
1276
+ console.log(chalk.yellow(` Warning: ${totalBefore - totalAfter} rows may have been lost due to data page corruption`));
1277
+ }
1278
+ console.log(` Tables: ${Object.keys(rowCountsAfter).length}`);
1279
+ console.log(` Integrity: ${chalk.green('OK')}`);
1280
+ console.log('');
1281
+ }
1282
+ process.exit(0);
1283
+ }
1284
+ catch (error) {
1285
+ printError(`repair failed: ${error instanceof Error ? error.message : 'unknown'}`);
1286
+ process.exit(1);
1287
+ }
1288
+ });
1289
+ }
1290
+ // ============================================================================
1139
1291
  // Exports
1140
1292
  // ============================================================================
1141
1293
  export { initializeLearningSystem } from './learning-helpers.js';
@@ -40,7 +40,6 @@ interface InitOptions {
40
40
  withWindsurf?: boolean;
41
41
  withContinuedev?: boolean;
42
42
  withAllPlatforms?: boolean;
43
- autoMigrate?: boolean;
44
43
  withClaudeFlow?: boolean;
45
44
  skipClaudeFlow?: boolean;
46
45
  noGovernance?: boolean;
@@ -72,10 +72,6 @@ export class InitHandler {
72
72
  options.withWindsurf = true;
73
73
  options.withContinuedev = true;
74
74
  }
75
- // --auto-migrate implies --auto (must use orchestrator for migration)
76
- if (options.autoMigrate && !options.auto && !options.wizard) {
77
- options.auto = true;
78
- }
79
75
  // --upgrade implies --auto (must use modular orchestrator to overwrite files)
80
76
  if (options.upgrade && !options.auto && !options.wizard) {
81
77
  options.auto = true;
@@ -118,7 +114,6 @@ export class InitHandler {
118
114
  withCodex: options.withCodex,
119
115
  withWindsurf: options.withWindsurf,
120
116
  withContinueDev: options.withContinuedev,
121
- autoMigrate: options.autoMigrate,
122
117
  noGovernance: options.noGovernance,
123
118
  });
124
119
  console.log(chalk.white(' Analyzing project...\n'));
@@ -192,7 +187,6 @@ export class InitHandler {
192
187
  minimal: options.minimal,
193
188
  skipPatterns: options.skipPatterns,
194
189
  withN8n: options.withN8n,
195
- autoMigrate: options.autoMigrate,
196
190
  };
197
191
  const orchestrator = new InitOrchestrator(orchestratorOptions);
198
192
  if (options.wizard) {
package/dist/cli/index.js CHANGED
@@ -790,7 +790,6 @@ import { createCoverageCommand } from './commands/coverage.js';
790
790
  import { createQualityCommand } from './commands/quality.js';
791
791
  import { createSecurityCommand } from './commands/security.js';
792
792
  import { createCodeCommand } from './commands/code.js';
793
- import { createMigrateCommand } from './commands/migrate.js';
794
793
  import { createCompletionsCommand } from './commands/completions.js';
795
794
  import { createFleetCommand } from './commands/fleet.js';
796
795
  import { createValidateSwarmCommand } from './commands/validate-swarm.js';
@@ -803,7 +802,6 @@ program.addCommand(createCoverageCommand(context, cleanupAndExit, ensureInitiali
803
802
  program.addCommand(createQualityCommand(context, cleanupAndExit, ensureInitialized));
804
803
  program.addCommand(createSecurityCommand(context, cleanupAndExit, ensureInitialized));
805
804
  program.addCommand(createCodeCommand(context, cleanupAndExit, ensureInitialized));
806
- program.addCommand(createMigrateCommand(context, cleanupAndExit, ensureInitialized));
807
805
  program.addCommand(createCompletionsCommand(cleanupAndExit));
808
806
  program.addCommand(createFleetCommand(context, cleanupAndExit, ensureInitialized, registerDomainWorkflowActions));
809
807
  program.addCommand(createValidateSwarmCommand(context, cleanupAndExit, ensureInitialized));
@@ -19,8 +19,8 @@ export class DefectContextSource {
19
19
  if (!existsSync(dbPath)) {
20
20
  return [];
21
21
  }
22
- const Database = (await import('better-sqlite3')).default;
23
- const db = new Database(dbPath, { readonly: true });
22
+ const { openDatabase } = await import('../../shared/safe-db.js');
23
+ const db = openDatabase(dbPath, { readonly: true });
24
24
  try {
25
25
  // Check if patterns table exists
26
26
  const tableCheck = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='qe_patterns'").get();
@@ -20,8 +20,8 @@ export class MemoryContextSource {
20
20
  return this.fallbackGather(request);
21
21
  }
22
22
  // Dynamic import to avoid hard dependency
23
- const Database = (await import('better-sqlite3')).default;
24
- const db = new Database(dbPath, { readonly: true });
23
+ const { openDatabase } = await import('../../shared/safe-db.js');
24
+ const db = openDatabase(dbPath, { readonly: true });
25
25
  try {
26
26
  // Query patterns relevant to the task domain
27
27
  const domainKeywords = this.extractDomainKeywords(request.taskDescription);
@@ -18,8 +18,8 @@ export class RequirementsContextSource {
18
18
  if (!existsSync(dbPath)) {
19
19
  return this.fallbackGather(request);
20
20
  }
21
- const Database = (await import('better-sqlite3')).default;
22
- const db = new Database(dbPath, { readonly: true });
21
+ const { openDatabase } = await import('../../shared/safe-db.js');
22
+ const db = openDatabase(dbPath, { readonly: true });
23
23
  try {
24
24
  // Check if requirements table exists
25
25
  const tableCheck = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='qe_patterns'").get();
@@ -41,6 +41,4 @@ export type { WindsurfInstallerOptions, WindsurfInstallResult } from './windsurf
41
41
  export { WindsurfInstaller, createWindsurfInstaller } from './windsurf-installer.js';
42
42
  export type { ContinueDevInstallerOptions, ContinueDevInstallResult } from './continuedev-installer.js';
43
43
  export { ContinueDevInstaller, createContinueDevInstaller } from './continuedev-installer.js';
44
- export type { V2DetectionInfo, MigrationResult, } from './migration/index.js';
45
- export { V2Detector, createV2Detector, V2DataMigrator, createV2DataMigrator, V2ConfigMigrator, createV2ConfigMigrator, } from './migration/index.js';
46
44
  //# sourceMappingURL=index.d.ts.map
@@ -24,5 +24,4 @@ export { RooCodeInstaller, createRooCodeInstaller } from './roocode-installer.js
24
24
  export { CodexInstaller, createCodexInstaller } from './codex-installer.js';
25
25
  export { WindsurfInstaller, createWindsurfInstaller } from './windsurf-installer.js';
26
26
  export { ContinueDevInstaller, createContinueDevInstaller } from './continuedev-installer.js';
27
- export { V2Detector, createV2Detector, V2DataMigrator, createV2DataMigrator, V2ConfigMigrator, createV2ConfigMigrator, } from './migration/index.js';
28
27
  //# sourceMappingURL=index.js.map
@@ -6,6 +6,16 @@
6
6
  * Extracted from init-wizard.ts.
7
7
  */
8
8
  import type { AQEInitConfig, PretrainedLibrary } from './types.js';
9
+ /**
10
+ * Read AQE version directly from memory.db without full initialization.
11
+ * Returns undefined if no version is stored.
12
+ */
13
+ export declare function readVersionFromDb(dbPath: string): string | undefined;
14
+ /**
15
+ * Write AQE version to memory.db in _system namespace.
16
+ * Used by init wizard to mark installation version.
17
+ */
18
+ export declare function writeVersionToDb(projectRoot: string, version: string): Promise<boolean>;
9
19
  /**
10
20
  * Initialize the persistence database (REQUIRED).
11
21
  * Creates the SQLite database file with proper schema.
@@ -6,12 +6,98 @@
6
6
  * Extracted from init-wizard.ts.
7
7
  */
8
8
  import { existsSync, mkdirSync, writeFileSync } from 'fs';
9
- import { join } from 'path';
9
+ import { join, dirname } from 'path';
10
10
  import { createSkillsInstaller } from './skills-installer.js';
11
11
  import { createAgentsInstaller } from './agents-installer.js';
12
12
  import { createN8nInstaller } from './n8n-installer.js';
13
13
  import { toErrorMessage } from '../shared/error-utils.js';
14
14
  import { openDatabase } from '../shared/safe-db.js';
15
+ import { safeJsonParse } from '../shared/safe-json.js';
16
+ // ============================================================================
17
+ // Version Management
18
+ // ============================================================================
19
+ /**
20
+ * Read AQE version directly from memory.db without full initialization.
21
+ * Returns undefined if no version is stored.
22
+ */
23
+ export function readVersionFromDb(dbPath) {
24
+ try {
25
+ const db = openDatabase(dbPath, { readonly: true, fileMustExist: true });
26
+ try {
27
+ const tableExists = db.prepare(`
28
+ SELECT name FROM sqlite_master
29
+ WHERE type='table' AND name='kv_store'
30
+ `).get();
31
+ if (!tableExists) {
32
+ db.close();
33
+ return undefined;
34
+ }
35
+ const row = db.prepare(`
36
+ SELECT value FROM kv_store
37
+ WHERE key = 'aqe_version' AND namespace = '_system'
38
+ `).get();
39
+ db.close();
40
+ if (row) {
41
+ return safeJsonParse(row.value);
42
+ }
43
+ return undefined;
44
+ }
45
+ catch {
46
+ db.close();
47
+ return undefined;
48
+ }
49
+ }
50
+ catch {
51
+ return undefined;
52
+ }
53
+ }
54
+ /**
55
+ * Write AQE version to memory.db in _system namespace.
56
+ * Used by init wizard to mark installation version.
57
+ */
58
+ export async function writeVersionToDb(projectRoot, version) {
59
+ const memoryDbPath = join(projectRoot, '.agentic-qe', 'memory.db');
60
+ try {
61
+ const dir = dirname(memoryDbPath);
62
+ if (!existsSync(dir)) {
63
+ mkdirSync(dir, { recursive: true });
64
+ }
65
+ const db = openDatabase(memoryDbPath);
66
+ try {
67
+ db.exec(`
68
+ CREATE TABLE IF NOT EXISTS kv_store (
69
+ key TEXT NOT NULL,
70
+ namespace TEXT NOT NULL,
71
+ value TEXT NOT NULL,
72
+ expires_at INTEGER,
73
+ created_at INTEGER DEFAULT (strftime('%s', 'now') * 1000),
74
+ PRIMARY KEY (namespace, key)
75
+ );
76
+ `);
77
+ const now = Date.now();
78
+ db.prepare(`
79
+ INSERT OR REPLACE INTO kv_store (key, namespace, value, created_at)
80
+ VALUES (?, '_system', ?, ?)
81
+ `).run('aqe_version', JSON.stringify(version), now);
82
+ db.prepare(`
83
+ INSERT OR REPLACE INTO kv_store (key, namespace, value, created_at)
84
+ VALUES (?, '_system', ?, ?)
85
+ `).run('init_timestamp', JSON.stringify(new Date().toISOString()), now);
86
+ db.close();
87
+ console.log(` ✓ Version ${version} written to memory.db`);
88
+ return true;
89
+ }
90
+ catch (err) {
91
+ db.close();
92
+ console.warn(` ⚠ Could not write version: ${toErrorMessage(err)}`);
93
+ return false;
94
+ }
95
+ }
96
+ catch (err) {
97
+ console.warn(` ⚠ Could not open memory.db: ${toErrorMessage(err)}`);
98
+ return false;
99
+ }
100
+ }
15
101
  // ============================================================================
16
102
  // Persistence Database
17
103
  // ============================================================================