| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990 |
- #!/usr/bin/env node
- 'use strict';
- const fs = require('fs');
- const path = require('path');
- const crypto = require('crypto');
- const { WORKSPACE_ROOT, outputsRoot } = require('../mcp/src/core/output-paths');
- const { readQiweiUid, readQiweiAccountMetadata, safeAccountKey } = require('../mcp/src/core/credentials');
- const execute = process.argv.includes('--execute');
- const force = process.argv.includes('--force');
- const legacyKey = safeAccountKey(readQiweiAccountMetadata().legacyAccountKey);
- const outputs = outputsRoot();
- const messages = process.env.QIWEI_MESSAGES_DIR
- ? path.resolve(process.env.QIWEI_MESSAGES_DIR)
- : path.join(WORKSPACE_ROOT, 'messages');
- const manifestPath = path.join(outputs, 'dashboard', legacyKey, 'legacy-migration.json');
- const uid = readQiweiUid();
- const oldWorkbenchKey = uid ? crypto.createHash('sha256').update(uid).digest('hex').slice(0, 16) : '';
- const actions = [];
- const DATE_DIR_RE = /^\d{4}-\d{2}-\d{2}$/;
- function addCopy(source, target) {
- if (fs.existsSync(source)) actions.push({ source, target });
- }
- function addDirectoryContents(source, target, include = () => true) {
- if (!fs.existsSync(source)) return;
- for (const entry of fs.readdirSync(source, { withFileTypes: true })) {
- if (entry.name === legacyKey || !include(entry)) continue;
- if (entry.isDirectory() && /^[a-f0-9]{16}$/i.test(entry.name)) continue;
- addCopy(path.join(source, entry.name), path.join(target, entry.name));
- }
- }
- const oldDb = oldWorkbenchKey
- ? path.join(outputs, 'messages', `agent-workbench-${oldWorkbenchKey}.db`)
- : path.join(outputs, 'messages', 'agent-workbench.db');
- const newDb = path.join(outputs, 'messages', `agent-workbench-${legacyKey}.db`);
- addCopy(oldDb, newDb);
- addCopy(`${oldDb}-wal`, `${newDb}-wal`);
- addCopy(`${oldDb}-shm`, `${newDb}-shm`);
- if (oldWorkbenchKey) {
- addCopy(
- path.join(outputs, 'messages', `claude-code-sessions-${oldWorkbenchKey}.json`),
- path.join(outputs, 'messages', `claude-code-sessions-${legacyKey}.json`)
- );
- }
- for (const category of ['customers', 'portraits', 'tags', 'groups']) {
- addDirectoryContents(
- path.join(outputs, category),
- path.join(outputs, category, legacyKey),
- entry => !DATE_DIR_RE.test(entry.name)
- && (category !== 'groups' || !/^agent-replies-.*\.json$/.test(entry.name))
- );
- }
- for (const category of ['chat', 'memory', 'group']) {
- addDirectoryContents(path.join(messages, category), path.join(messages, category, legacyKey));
- }
- addCopy(
- path.join(outputs, 'dashboard', 'dashboard-state.json'),
- path.join(outputs, 'dashboard', legacyKey, 'dashboard-state.json')
- );
- if (!execute) {
- console.log(JSON.stringify({ mode: 'dry-run', legacyKey, uid: uid || null, actions }, null, 2));
- console.log('No files changed. Re-run with --execute after reviewing the plan.');
- process.exit(0);
- }
- if (fs.existsSync(manifestPath) && !force) {
- console.error(`Migration already completed: ${manifestPath}. Use --force only after reviewing existing data.`);
- process.exit(2);
- }
- const results = actions.map(action => {
- if (fs.existsSync(action.target) && !force) return { ...action, result: 'skipped_target_exists' };
- fs.mkdirSync(path.dirname(action.target), { recursive: true });
- fs.cpSync(action.source, action.target, { recursive: true, force });
- return { ...action, result: 'copied' };
- });
- fs.mkdirSync(path.dirname(manifestPath), { recursive: true });
- fs.writeFileSync(manifestPath, JSON.stringify({
- version: 1,
- migratedAt: new Date().toISOString(),
- legacyKey,
- uid: uid || null,
- results,
- }, null, 2), 'utf8');
- console.log(JSON.stringify({ mode: 'execute', legacyKey, manifestPath, results }, null, 2));
|