55 lines
2.3 KiB
TypeScript
55 lines
2.3 KiB
TypeScript
/**
|
||
* 工作空间路径独立持久化 — 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;
|
||
}
|
||
}
|