Files
AIclinicalresearch/backend/recover-code-from-cursor-db.js
HaHafeng decff0bb1f docs(deploy): Complete full system deployment to Aliyun SAE
Summary:
- Successfully deployed complete system to Aliyun SAE (2025-12-25)
- All services running: Python microservice + Node.js backend + Frontend Nginx + CLB
- Public access available at http://8.140.53.236/

Major Achievements:
1. Python microservice deployed (v1.0, internal IP: 172.17.173.66:8000)
2. Node.js backend deployed (v1.3, internal IP: 172.17.173.73:3001)
   - Fixed 4 critical issues: bash path, config directory, pino-pretty, ES Module
3. Frontend Nginx deployed (v1.0, internal IP: 172.17.173.72:80)
4. CLB load balancer configured (public IP: 8.140.53.236)

New Documentation (9 docs):
- 11-Node.js backend SAE deployment config checklist (21 env vars)
- 12-Node.js backend SAE deployment operation manual
- 13-Node.js backend image fix record (config directory)
- 14-Node.js backend pino-pretty fix
- 15-Node.js backend deployment success summary
- 16-Frontend Nginx deployment success summary
- 17-Complete deployment practical manual 2025 edition (1800 lines)
- 18-Deployment documentation usage guide
- 19-Daily update quick operation manual (670 lines)

Key Fixes:
- Environment variable name correction: EXTRACTION_SERVICE_URL (not PYTHON_SERVICE_URL)
- Dockerfile fix: added COPY config ./config
- Logger configuration: conditional pino-pretty for dev only
- Health check fix: ES Module compatibility (require -> import)

Updated Files:
- System status document updated with full deployment info
- Deployment progress overview updated with latest IPs
- All 3 Docker services' Dockerfiles and configs refined

Verification:
- All health checks passed
- Tool C 7 features working correctly
- Literature screening module functional
- Response time < 1 second

BREAKING CHANGE: Node.js backend internal IP changed from 172.17.173.71 to 172.17.173.73

Closes #deployment-milestone
2025-12-25 21:24:37 +08:00

210 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;
}