Files
Dragan Spiridonov a5a0af3ca3 fix: prevent SQLite corruption — centralized safe-db opener with WAL + busy_timeout (#290)
* fix: resolve issues #284-#288 — HNSW dimension mismatch, real security scanning, hooks directory

- Fix HNSW 128→768 dimension mismatch across 13 source files and 5 test files
  that caused native SIGABRT crashes in ruvector-gnn (#284, #285)
- Add dimension guard in unified-memory-hnsw.ts to skip mismatched vectors
- Rewrite security scan to perform real SAST file analysis instead of
  returning hardcoded fake findings (#287)
- Add Cobertura XML parser, fix secret detection regex, broaden CORS
  detection patterns (#286)
- Replace fake MCP handlers with real implementations (#286)
- Create .claude/hooks/ directory and install hook assets in init
  phase 07-hooks.ts (#288)
- Remove dangerous uncaughtException handler from protocol-server.ts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore(release): bump version to v3.6.12

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: prevent SQLite corruption from concurrent writers — centralized safe-db opener

Root cause: 40+ places opened memory.db with `new Database()` without WAL mode
or busy_timeout. When 10 Claude Code hooks spawn separate processes that
concurrently write to the DB, rollback journal mode causes page-level corruption.

Fix: Created v3/src/shared/safe-db.ts with openDatabase() that enforces
WAL + busy_timeout=5000 on every open. Replaced all 28 direct new Database()
calls across v3/src (22 files), hooks (1 file), helpers (2 files), and
scripts (2 files). Only remaining direct call is the UnifiedMemoryManager
singleton which already sets WAL + busy_timeout itself.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 11:46:59 +01:00

101 lines
2.8 KiB
JavaScript

#!/usr/bin/env node
/**
* Sync Claude Flow memories to AQE V3 database
*/
const fs = require('fs');
const path = require('path');
const projectRoot = process.cwd();
const claudeFlowPath = path.join(projectRoot, '.claude-flow', 'memory', 'store.json');
const aqeDbPath = path.join(projectRoot, 'v3', '.agentic-qe', 'memory.db');
console.log('Claude Flow:', claudeFlowPath);
console.log('AQE DB:', aqeDbPath);
if (!fs.existsSync(claudeFlowPath)) {
console.error('Claude Flow store not found');
process.exit(1);
}
if (!fs.existsSync(aqeDbPath)) {
console.error('AQE DB not found');
process.exit(1);
}
const store = JSON.parse(fs.readFileSync(claudeFlowPath, 'utf-8'));
const entries = store.entries || store;
const keys = Object.keys(entries).filter(k => !k.startsWith('_') && k !== 'version');
console.log('Entries to sync:', keys.length);
const Database = require('better-sqlite3');
const db = new Database(aqeDbPath);
db.pragma('busy_timeout = 5000');
db.pragma('journal_mode = WAL');
const insert = db.prepare(`
INSERT OR REPLACE INTO kv_store (key, namespace, value, created_at)
VALUES (?, ?, ?, ?)
`);
let count = 0;
let learning = 0;
// Also insert into sona_patterns for learning-related entries
const insertSona = db.prepare(`
INSERT OR REPLACE INTO sona_patterns
(id, type, domain, action_type, outcome_reward, outcome_success, metadata, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, datetime('now'))
`);
for (const key of keys) {
const value = entries[key];
// Always store in kv_store
insert.run(
'cf:' + key,
'claude-flow',
JSON.stringify(value),
Date.now()
);
count++;
// Store learning-relevant entries in sona_patterns too
const keyLower = key.toLowerCase();
if (keyLower.includes('pattern') || keyLower.includes('analysis') ||
keyLower.includes('learning') || keyLower.includes('agent') ||
keyLower.includes('outcome') || keyLower.includes('quality')) {
// Determine domain
let domain = 'general';
const domains = ['test-generation', 'coverage-analysis', 'security-compliance',
'quality-assessment', 'code-intelligence'];
for (const d of domains) {
if (keyLower.includes(d.replace('-', ''))) {
domain = d;
break;
}
}
const id = 'cf-' + key.replace(/[^a-zA-Z0-9-]/g, '-').slice(0, 60);
try {
insertSona.run(
id,
'claude-flow-import',
domain,
'learn-from-session',
0.7, // Assume successful since it was stored
1,
JSON.stringify({ sourceKey: key, importedAt: new Date().toISOString() })
);
learning++;
} catch (e) {
// Ignore duplicate errors
}
}
}
db.close();
console.log('Synced to kv_store:', count, 'entries');
console.log('Synced to sona_patterns:', learning, 'learning entries');