feat: v0.8.3 工作空间切换链路根治 · 思考强度扩档 — 启动TDZ连锁/继承丢数/回显滞后三修复 · xhigh+true档位单源 · 安全防线ready后注册 · 2217 用例全量回归 + 生产模式E2E
CI / 类型检查 + Lint + 单元测试 (push) Failing after 9m37s
CI / 全量测试 (Electron ABI) (push) Failing after 6m1s
CI / 产物编译验证 (push) Successful in 10m54s

This commit is contained in:
2026-09-08 21:14:59 +08:00
parent 4cd6e997b5
commit 9329df68af
18 changed files with 250 additions and 114 deletions
+54
View File
@@ -0,0 +1,54 @@
/**
* 工作空间路径独立持久化 — userData/workspace-config.json
*
* 为什么独立于数据库:agent.db 存放在工作空间目录内,而"工作空间在哪"必须先于
* 数据库初始化得知(鸡生蛋问题),因此路径单独落一份 JSON。
*
* 为什么独立成模块:此前 read/writeWorkspacePathToFile 定义在 main.ts 并由
* ipc/shared.ts 动态 import('../main') 取用 —— main ↔ shared 循环依赖。一旦主
* 入口模块求值中途崩溃(如 v0.8.2 前的顶层 session 访问),bundle 末尾的模块
* 命名空间永不初始化,该动态 import 抛 TDZ "Cannot access 'main' before
* initialization",工作空间切换保存随之失败。抽出后为单向依赖,与入口模块
* 生命周期解耦。
*
* 注意:文件路径必须在使用时实时计算(app.getPath('userData')),不能在模块
* 顶层缓存 —— E2E 通过 METONA_USER_DATA_DIR 在 main.ts 模块体内重定向 userData
* 而 ESM import 会提升到模块体之前执行,顶层缓存会锁死重定向前的路径。
*/
import { app } from 'electron';
import { join } from 'path';
import { existsSync, readFileSync, writeFileSync } from 'fs';
import log from 'electron-log';
function getWorkspaceConfigFile(): string {
return join(app.getPath('userData'), 'workspace-config.json');
}
export function readWorkspacePathFromFile(): string | null {
try {
const file = getWorkspaceConfigFile();
if (existsSync(file)) {
const data = JSON.parse(readFileSync(file, 'utf-8'));
return data.workspacePath ?? null;
}
} catch {
// 忽略读取错误
}
return null;
}
/**
* 写入失败向上抛出(调用方决定是否告知用户):
* - 启动路径回写(main.ts):非致命,仅记日志;
* - 切换工作空间保存(ipc/shared.ts):必须 toast 告知,否则用户以为切换成功,
* 下次启动仍回到旧空间(v0.3.10 契约 —— 此前函数内部吞错,错误上报路径为死代码)。
*/
export function writeWorkspacePathToFile(workspacePath: string): void {
try {
writeFileSync(getWorkspaceConfigFile(), JSON.stringify({ workspacePath }, null, 2), 'utf-8');
} catch (err) {
log.error('Failed to write workspace config file:', err);
throw err;
}
}