Skip to main content
Glama

Scratchpad MCP

by pc035860
checkpoint-database.cjs6.97 kB
#!/usr/bin/env node /** * 資料庫 WAL 檢查點工具 * * 功能: * 1. 將 WAL 檔案的變更合併回主資料庫 * 2. 清理 WAL 和 SHM 檔案 * 3. 可選擇切換到 DELETE 模式 * * 使用方法: * node scripts/checkpoint-database.cjs [--delete-mode] [--db-path=/path/to/db] */ const Database = require('better-sqlite3'); const path = require('path'); const fs = require('fs'); // 命令行參數解析 const args = process.argv.slice(2); const config = { dbPath: path.join(process.cwd(), 'scratchpad.db'), deleteMode: false }; args.forEach(arg => { if (arg === '--delete-mode') { config.deleteMode = true; } else if (arg.startsWith('--db-path=')) { config.dbPath = arg.substring(10); } }); console.log('🔄 資料庫 WAL 檢查點工具'); console.log(`📁 資料庫路徑: ${config.dbPath}`); // 檢查檔案存在 if (!fs.existsSync(config.dbPath)) { console.error(`❌ 資料庫檔案不存在:${config.dbPath}`); process.exit(1); } // 檢查相關檔案狀態 function checkDatabaseFiles(dbPath) { const files = { main: dbPath, wal: `${dbPath}-wal`, shm: `${dbPath}-shm` }; console.log('\n📊 檔案狀態檢查:'); Object.entries(files).forEach(([type, filePath]) => { if (fs.existsSync(filePath)) { const stats = fs.statSync(filePath); const sizeKB = (stats.size / 1024).toFixed(1); console.log(` ${type.toUpperCase()}: ${sizeKB}KB (${filePath})`); } else { console.log(` ${type.toUpperCase()}: 不存在`); } }); return files; } // 檢查資料庫是否被使用 function checkDatabaseInUse(dbPath) { try { const { execSync } = require('child_process'); const lsofResult = execSync( `lsof "${dbPath}" "${dbPath}-shm" "${dbPath}-wal" 2>/dev/null || true`, { encoding: 'utf8' } ); if (lsofResult.trim()) { console.error(`❌ 資料庫正在使用中!請先關閉 MCP 伺服器。`); console.error('使用中的進程:'); console.error(lsofResult); return true; } return false; } catch (error) { // lsof 可能不可用,繼續執行但發出警告 console.warn('⚠️ 無法檢查進程使用狀況,請確保 MCP 伺服器已關閉'); return false; } } // 執行 WAL 檢查點 function performCheckpoint(db) { console.log('\n🔄 執行 WAL 檢查點...'); try { // 檢查當前模式 const currentMode = db.prepare('PRAGMA journal_mode').get(); console.log(` 當前模式: ${currentMode.journal_mode}`); // 執行 WAL 檢查點 const checkpointResult = db.prepare('PRAGMA wal_checkpoint(FULL)').get(); console.log(` 檢查點結果: busy=${checkpointResult.busy}, log=${checkpointResult.log}, checkpointed=${checkpointResult.checkpointed}`); if (checkpointResult.busy > 0) { console.warn('⚠️ 檢查點執行時資料庫忙碌,可能有未完成的事務'); } if (checkpointResult.log > 0) { console.log(` ✅ 成功將 ${checkpointResult.log} 頁從 WAL 寫入主資料庫`); } else { console.log(' ✅ WAL 檔案已是最新狀態,無需檢查點'); } return checkpointResult; } catch (error) { console.error(` ❌ 檢查點執行失敗: ${error.message}`); throw error; } } // 切換到 DELETE 模式 function switchToDeleteMode(db) { console.log('\n🔄 切換到 DELETE 模式...'); try { const result = db.prepare('PRAGMA journal_mode=DELETE').get(); console.log(` ✅ 已切換到 ${result.journal_mode} 模式`); return result; } catch (error) { console.error(` ❌ 模式切換失敗: ${error.message}`); throw error; } } // 驗證資料完整性 function verifyIntegrity(db) { console.log('\n🔍 驗證資料完整性...'); try { // 檢查資料庫完整性 const integrityResult = db.prepare('PRAGMA integrity_check').get(); if (integrityResult.integrity_check === 'ok') { console.log(' ✅ 資料庫完整性檢查通過'); } else { console.warn(` ⚠️ 完整性檢查異常: ${integrityResult.integrity_check}`); } // 檢查資料統計 const workflowCount = db.prepare('SELECT COUNT(*) as count FROM workflows').get(); const scratchpadCount = db.prepare('SELECT COUNT(*) as count FROM scratchpads').get(); console.log(` 📊 資料統計: ${workflowCount.count} workflows, ${scratchpadCount.count} scratchpads`); // 如果有 FTS5,檢查索引 try { const ftsCount = db.prepare('SELECT COUNT(*) as count FROM scratchpads_fts').get(); console.log(` 🔍 FTS5 索引: ${ftsCount.count} 記錄`); } catch (error) { console.log(' 🔍 FTS5 索引: 不存在或不可用'); } return true; } catch (error) { console.error(` ❌ 完整性檢查失敗: ${error.message}`); return false; } } // 主程序 async function main() { const files = checkDatabaseFiles(config.dbPath); // 檢查是否有 WAL 檔案需要處理 const hasWal = fs.existsSync(files.wal); const hasShm = fs.existsSync(files.shm); if (!hasWal && !hasShm) { console.log('\n✅ 資料庫已經是乾淨狀態,無 WAL/SHM 檔案'); process.exit(0); } // 檢查資料庫使用狀況 if (checkDatabaseInUse(config.dbPath)) { process.exit(1); } console.log('\n🚀 開始處理 WAL 檔案...'); const db = new Database(config.dbPath); try { // 1. 執行檢查點 const checkpointResult = performCheckpoint(db); // 2. 如果需要,切換模式 if (config.deleteMode) { switchToDeleteMode(db); } // 3. 驗證完整性 const isValid = verifyIntegrity(db); if (!isValid) { console.error('❌ 資料完整性檢查失敗,請檢查資料庫狀態'); process.exit(1); } console.log('\n🎉 WAL 檢查點完成!'); } catch (error) { console.error('\n❌ 處理過程發生錯誤:'); console.error(error.message); console.error('\n🔧 建議操作:'); console.error('1. 確保沒有進程在使用資料庫'); console.error('2. 檢查資料庫檔案權限'); console.error('3. 考慮備份後重試'); process.exit(1); } finally { db.close(); } // 4. 檢查檔案清理結果 console.log('\n📊 處理後檔案狀態:'); checkDatabaseFiles(config.dbPath); // 如果切換到 DELETE 模式,WAL/SHM 檔案應該已被清理 if (config.deleteMode) { const walExists = fs.existsSync(files.wal); const shmExists = fs.existsSync(files.shm); if (walExists || shmExists) { console.warn('⚠️ WAL/SHM 檔案仍存在,可能需要手動清理'); } else { console.log('✅ WAL/SHM 檔案已成功清理'); } } console.log('\n✨ 現在可以安全地使用此資料庫進行合併操作!'); } main().catch(console.error);

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/pc035860/scratchpad-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server