Files
AIclinicalresearch/backend/recover-code-from-cursor-db.js
HaHafeng 5a17d096a7 feat(pkb): Complete PKB module frontend migration with V3 design
Summary:
- Implement PKB Dashboard and Workspace pages based on V3 prototype
- Add single-layer header with integrated Tab navigation
- Implement 3 work modes: Full Text, Deep Read, Batch Processing
- Integrate Ant Design X Chat component for AI conversations
- Create BatchModeComplete with template selection and document processing
- Add compact work mode selector with dropdown design

Backend:
- Migrate PKB controllers and services to /modules/pkb structure
- Register v2 API routes at /api/v2/pkb/knowledge
- Maintain dual API routes for backward compatibility

Technical details:
- Use Zustand for state management
- Handle SSE streaming responses for AI chat
- Support document selection for Deep Read mode
- Implement batch processing with progress tracking

Known issues:
- Batch processing API integration pending
- Knowledge assets page navigation needs optimization

Status: Frontend functional, pending refinement
2026-01-06 22:15:42 +08:00

226 lines
5.9 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 从Cursor的SQLite数据库中恢复代码历史
*
* 使用方法:
* 1. cd backend
* 2. npm install better-sqlite3
* 3. node recover-code-from-cursor-db.js
*/
const Database = require('better-sqlite3');
const fs = require('fs');
const path = require('path');
// Cursor SQLite数据库路径
const DB_PATH = path.join(
process.env.APPDATA || process.env.HOME,
'Cursor/User/workspaceStorage/d5e3431d02cbaa0109f69d72300733da/state.vscdb'
);
// 输出目录
const OUTPUT_DIR = path.join(__dirname, 'cursor-history-recovery');
console.log('🔍 正在读取Cursor历史数据库...');
console.log('📂 数据库路径:', DB_PATH);
if (!fs.existsSync(DB_PATH)) {
console.error('❌ 数据库文件不存在!');
process.exit(1);
}
// 创建输出目录
if (!fs.existsSync(OUTPUT_DIR)) {
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
}
try {
// 打开数据库(只读模式)
const db = new Database(DB_PATH, { readonly: true, fileMustExist: true });
console.log('✅ 数据库打开成功!');
// 1. 查看表结构
console.log('\n📊 数据库表列表:');
const tables = db.prepare("SELECT name FROM sqlite_master WHERE type='table'").all();
console.log(tables.map(t => ` - ${t.name}`).join('\n'));
// 2. 查询ItemTable表结构
if (tables.some(t => t.name === 'ItemTable')) {
console.log('\n📋 ItemTable 表结构:');
const columns = db.prepare("PRAGMA table_info(ItemTable)").all();
console.log(columns.map(c => ` - ${c.name} (${c.type})`).join('\n'));
// 3. 查询所有key了解有哪些类型的数据
console.log('\n🔑 ItemTable 中的所有key类型');
const keys = db.prepare("SELECT DISTINCT key FROM ItemTable").all();
console.log(keys.map(k => ` - ${k.key}`).join('\n'));
// 4. 查找聊天历史相关的key
console.log('\n💬 查找聊天/Composer历史记录...');
const chatKeys = [
'workbench.panel.chat',
'composer',
'chat',
'workbench.panel.aichat',
'aiPanel'
];
let foundCount = 0;
for (const keyPattern of chatKeys) {
const rows = db.prepare(
`SELECT key, value FROM ItemTable WHERE key LIKE ?`
).all(`%${keyPattern}%`);
if (rows.length > 0) {
console.log(`\n✅ 找到 ${rows.length} 条与 "${keyPattern}" 相关的记录`);
rows.forEach((row, index) => {
foundCount++;
const filename = `${keyPattern.replace(/[^a-z0-9]/gi, '_')}_${index + 1}.json`;
const filepath = path.join(OUTPUT_DIR, filename);
// 保存原始JSON
fs.writeFileSync(filepath, row.value);
console.log(` 📄 已保存: ${filename} (${(row.value.length / 1024).toFixed(2)} KB)`);
// 尝试解析JSON并提取代码
try {
const data = JSON.parse(row.value);
// 提取可能的代码片段
const codeBlocks = extractCodeBlocks(data);
if (codeBlocks.length > 0) {
const codeFilename = `${keyPattern.replace(/[^a-z0-9]/gi, '_')}_${index + 1}_code.txt`;
const codeFilepath = path.join(OUTPUT_DIR, codeFilename);
fs.writeFileSync(codeFilepath, codeBlocks.join('\n\n' + '='.repeat(80) + '\n\n'));
console.log(` 📝 提取了 ${codeBlocks.length} 个代码块: ${codeFilename}`);
}
} catch (err) {
console.log(` ⚠️ JSON解析失败: ${err.message}`);
}
});
}
}
if (foundCount === 0) {
console.log('\n⚠ 未找到聊天历史记录,尝试提取所有数据...');
// 导出所有ItemTable数据
const allRows = db.prepare("SELECT key, value FROM ItemTable").all();
console.log(`\n📦 共有 ${allRows.length} 条记录,正在导出...`);
const allDataFile = path.join(OUTPUT_DIR, 'all_itemtable_data.json');
fs.writeFileSync(allDataFile, JSON.stringify(allRows, null, 2));
console.log(`✅ 已导出所有数据到: all_itemtable_data.json (${(fs.statSync(allDataFile).size / 1024 / 1024).toFixed(2)} MB)`);
}
} else {
console.log('\n❌ ItemTable 表不存在!');
}
db.close();
console.log(`\n✅ 恢复完成!所有文件保存在: ${OUTPUT_DIR}`);
console.log('\n💡 下一步:');
console.log(' 1. 检查 cursor-history-recovery 文件夹');
console.log(' 2. 打开 .json 文件查找DC模块相关的代码');
console.log(' 3. 查找关键词DualModelExtractionService, HealthCheckService, ExtractionController');
} catch (error) {
console.error('❌ 错误:', error.message);
console.error(error.stack);
process.exit(1);
}
/**
* 从JSON数据中递归提取代码块
*/
function extractCodeBlocks(obj, blocks = []) {
if (typeof obj === 'string') {
// 查找代码块模式
const codePatterns = [
/```[\s\S]*?```/g, // Markdown代码块
/export\s+(const|function|class)\s+\w+/g, // TypeScript导出
/interface\s+\w+/g, // TypeScript接口
/async\s+function\s+\w+/g, // 异步函数
];
codePatterns.forEach(pattern => {
const matches = obj.match(pattern);
if (matches) {
blocks.push(...matches);
}
});
// 如果包含关键代码关键词,保存整段
const keywords = [
'DualModelExtractionService',
'HealthCheckService',
'TemplateService',
'ConflictDetectionService',
'ExtractionController',
'dc_extraction_tasks',
'dc_health_checks'
];
if (keywords.some(kw => obj.includes(kw))) {
blocks.push(obj);
}
} else if (Array.isArray(obj)) {
obj.forEach(item => extractCodeBlocks(item, blocks));
} else if (obj && typeof obj === 'object') {
Object.values(obj).forEach(value => extractCodeBlocks(value, blocks));
}
return blocks;
}