chore: bump to 1.5.15, publish full package + hot update
- 版本号 1.5.14 → 1.5.15 - 新增 scripts/publish-full.js:一键上传完整包到 latest 与 v<version> release - 清理未引用的 session_sync_enhanced.js 与临时 test-sync.js Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,187 +0,0 @@
|
||||
// session_sync_enhanced.js —— 增强版会话同步:确保本地所有会话一个不剩地同步到新 Codex 账号。
|
||||
// 在 provider_sync.js 的基础上增强,确保:
|
||||
// 1. 扫描所有 sessions/ 和 archived_sessions/ 下的会话
|
||||
// 2. 强制插入到当前账号的数据库(UPSERT 逻辑)
|
||||
// 3. 重建 session_index.jsonl
|
||||
// 4. 更新全局项目索引
|
||||
// 5. 提供详细的同步报告
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const os = require("os");
|
||||
const providerSync = require("./provider_sync");
|
||||
|
||||
const CODEX_HOME = path.join(os.homedir(), ".codex");
|
||||
const SESSION_INDEX = path.join(CODEX_HOME, "session_index.jsonl");
|
||||
|
||||
// 完整同步方案:确保所有本地会话都进入新账号
|
||||
async function syncAllSessionsToNewAccount(opts = {}) {
|
||||
const log = opts.log || (() => {});
|
||||
const onProgress = opts.onProgress || (() => {});
|
||||
|
||||
log("=== 开始全量会话同步 ===");
|
||||
log("目标:将本地所有会话同步到当前 Codex 账号");
|
||||
|
||||
// 1. 检查 Codex 是否在运行
|
||||
if (providerSync.codexRunning()) {
|
||||
throw new Error("检测到 Codex 正在运行,请先完全退出 Codex 再同步。");
|
||||
}
|
||||
|
||||
// 2. 获取当前 provider(从 config.toml)
|
||||
const targetProvider = providerSync.targetProvider();
|
||||
log(`当前账号 provider:${targetProvider}`);
|
||||
|
||||
// 3. 执行核心同步(provider_sync 已经做了 UPSERT)
|
||||
log("开始同步本地会话到数据库...");
|
||||
const result = await providerSync.syncProviderToCurrent(log, onProgress);
|
||||
|
||||
// 4. 重建 session_index.jsonl(确保索引完整)
|
||||
log("重建会话索引...");
|
||||
const indexResult = rebuildSessionIndex(log);
|
||||
|
||||
// 5. 生成同步报告
|
||||
const report = {
|
||||
success: true,
|
||||
provider: result.target,
|
||||
totalSessions: result.totalConversations,
|
||||
syncedToDatabase: result.insertedRows,
|
||||
updatedProvider: result.provRows,
|
||||
updatedUserEvent: result.ueRows,
|
||||
indexRebuilt: indexResult.total,
|
||||
projects: result.projectRows,
|
||||
backup: result.backup,
|
||||
details: {
|
||||
changedFiles: result.changedFiles,
|
||||
userEventSessions: result.userEvents,
|
||||
archivedSessions: indexResult.archived,
|
||||
activeSessions: indexResult.active,
|
||||
}
|
||||
};
|
||||
|
||||
log("\n=== 同步完成 ===");
|
||||
log(`✅ 总会话数:${report.totalSessions}`);
|
||||
log(`✅ 新增到数据库:${report.syncedToDatabase} 条`);
|
||||
log(`✅ 更新 provider:${report.updatedProvider} 条`);
|
||||
log(`✅ 重建索引:${report.indexRebuilt} 条`);
|
||||
log(`✅ 项目分组:${report.projects} 个`);
|
||||
log(`✅ 备份位置:${report.backup}`);
|
||||
log("\n现在可以启动 Codex,所有会话应该都能看到了。");
|
||||
|
||||
return report;
|
||||
}
|
||||
|
||||
// 重建 session_index.jsonl:扫描所有会话文件,生成完整索引
|
||||
function rebuildSessionIndex(log = () => {}) {
|
||||
const sessions = require("./sessions");
|
||||
|
||||
// 列出所有会话(包括 archived)
|
||||
const allConversations = sessions.listConversations({
|
||||
includeSubagent: true,
|
||||
includeArchived: true,
|
||||
});
|
||||
|
||||
log(`扫描到 ${allConversations.length} 个会话文件`);
|
||||
|
||||
// 备份旧索引
|
||||
if (fs.existsSync(SESSION_INDEX)) {
|
||||
const backup = SESSION_INDEX + ".bak-" + Date.now();
|
||||
fs.copyFileSync(SESSION_INDEX, backup);
|
||||
log(`已备份旧索引:${path.basename(backup)}`);
|
||||
}
|
||||
|
||||
// 重建索引:每个会话一行 JSON
|
||||
const lines = [];
|
||||
let active = 0;
|
||||
let archived = 0;
|
||||
|
||||
for (const conv of allConversations) {
|
||||
if (!conv.id) continue;
|
||||
|
||||
const indexEntry = {
|
||||
id: conv.id,
|
||||
thread_name: conv.title || "(无标题对话)",
|
||||
project_path: conv.cwd || null,
|
||||
created_at: conv.ts || new Date().toISOString(),
|
||||
source: conv.source || "vscode",
|
||||
archived: conv.archived || false,
|
||||
};
|
||||
|
||||
lines.push(JSON.stringify(indexEntry));
|
||||
|
||||
if (conv.archived) archived++;
|
||||
else active++;
|
||||
}
|
||||
|
||||
// 写入新索引
|
||||
fs.writeFileSync(SESSION_INDEX, lines.join("\n") + "\n", "utf-8");
|
||||
log(`已重建索引:活跃 ${active} 条,归档 ${archived} 条`);
|
||||
|
||||
return { total: lines.length, active, archived };
|
||||
}
|
||||
|
||||
// 诊断:检查会话同步状态
|
||||
function diagnoseSessionSync(log = () => {}) {
|
||||
const sessions = require("./sessions");
|
||||
|
||||
log("=== 会话同步诊断 ===");
|
||||
|
||||
// 1. 统计本地会话文件
|
||||
const allConversations = sessions.listConversations({
|
||||
includeSubagent: true,
|
||||
includeArchived: true,
|
||||
});
|
||||
const activeSessions = allConversations.filter(c => !c.archived);
|
||||
const archivedSessions = allConversations.filter(c => c.archived);
|
||||
|
||||
log(`本地会话文件:${allConversations.length} 个`);
|
||||
log(` - 活跃:${activeSessions.length} 个`);
|
||||
log(` - 归档:${archivedSessions.length} 个`);
|
||||
|
||||
// 2. 检查数据库
|
||||
const dbFiles = fs.readdirSync(CODEX_HOME).filter(f => /^state_.*\.sqlite$/.test(f));
|
||||
log(`数据库文件:${dbFiles.length} 个`);
|
||||
for (const db of dbFiles) {
|
||||
log(` - ${db}`);
|
||||
}
|
||||
|
||||
// 3. 检查索引文件
|
||||
const indexExists = fs.existsSync(SESSION_INDEX);
|
||||
log(`session_index.jsonl:${indexExists ? "存在" : "不存在"}`);
|
||||
|
||||
if (indexExists) {
|
||||
const indexContent = fs.readFileSync(SESSION_INDEX, "utf-8");
|
||||
const indexLines = indexContent.split("\n").filter(l => l.trim());
|
||||
log(` - 索引条目:${indexLines.length} 条`);
|
||||
}
|
||||
|
||||
// 4. 检查 provider
|
||||
const currentProvider = providerSync.targetProvider();
|
||||
log(`当前 provider:${currentProvider}`);
|
||||
|
||||
// 5. 检查会话文件中的 provider 分布
|
||||
const providerStats = {};
|
||||
for (const conv of allConversations) {
|
||||
const p = conv.provider || "(未设置)";
|
||||
providerStats[p] = (providerStats[p] || 0) + 1;
|
||||
}
|
||||
log("会话文件 provider 分布:");
|
||||
for (const [p, count] of Object.entries(providerStats)) {
|
||||
log(` - ${p}: ${count} 个`);
|
||||
}
|
||||
|
||||
return {
|
||||
totalSessions: allConversations.length,
|
||||
activeSessions: activeSessions.length,
|
||||
archivedSessions: archivedSessions.length,
|
||||
databases: dbFiles.length,
|
||||
indexExists,
|
||||
currentProvider,
|
||||
providerStats,
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
syncAllSessionsToNewAccount,
|
||||
rebuildSessionIndex,
|
||||
diagnoseSessionSync,
|
||||
};
|
||||
Reference in New Issue
Block a user