| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091 |
- import { app } from "electron"
- import log from "electron-log/main.js"
- import { existsSync, readdirSync, readFileSync } from "node:fs"
- import { homedir } from "node:os"
- import { join } from "node:path"
- import { CHANNEL } from "./constants"
- import { getStore, store } from "./store"
- const TAURI_MIGRATED_KEY = "tauriMigrated"
- // Resolve the directory where Tauri stored its .dat files for the given app identifier.
- // Mirrors Tauri's AppLocalData / AppData resolution per OS.
- function tauriDir(id: string) {
- switch (process.platform) {
- case "darwin":
- return join(homedir(), "Library", "Application Support", id)
- case "win32":
- return join(process.env.APPDATA ?? join(homedir(), "AppData", "Roaming"), id)
- default:
- return join(process.env.XDG_DATA_HOME ?? join(homedir(), ".local", "share"), id)
- }
- }
- // The Tauri app identifier changes between dev/beta/prod builds.
- const TAURI_APP_IDS: Record<string, string> = {
- dev: "ai.opencode.desktop.dev",
- beta: "ai.opencode.desktop.beta",
- prod: "ai.opencode.desktop",
- }
- function tauriAppId() {
- return app.isPackaged ? TAURI_APP_IDS[CHANNEL] : "ai.opencode.desktop.dev"
- }
- // Migrate a single Tauri .dat file into the corresponding electron-store.
- // `opencode.settings.dat` is special: it maps to the `opencode.settings` store
- // (the electron-store name without the `.dat` extension). All other .dat files
- // keep their full filename as the electron-store name so they match what the
- // renderer already passes via IPC (e.g. `"default.dat"`, `"opencode.global.dat"`).
- function migrateFile(datPath: string, filename: string) {
- let data: Record<string, unknown>
- try {
- data = JSON.parse(readFileSync(datPath, "utf-8"))
- } catch (err) {
- log.warn("tauri migration: failed to parse", filename, err)
- return
- }
- // opencode.settings.dat → the electron settings store ("opencode.settings").
- // All other .dat files keep their full filename as the store name so they match
- // what the renderer passes via IPC (e.g. "default.dat", "opencode.global.dat").
- const storeName = filename === "opencode.settings.dat" ? "opencode.settings" : filename
- const target = getStore(storeName)
- const migrated: string[] = []
- const skipped: string[] = []
- for (const [key, value] of Object.entries(data)) {
- // Don't overwrite values the user has already set in the Electron app.
- if (target.has(key)) {
- skipped.push(key)
- continue
- }
- target.set(key, value)
- migrated.push(key)
- }
- log.log("tauri migration: migrated", filename, "→", storeName, { migrated, skipped })
- }
- export function migrate() {
- if (store.get(TAURI_MIGRATED_KEY)) {
- log.log("tauri migration: already done, skipping")
- return
- }
- const dir = tauriDir(tauriAppId())
- log.log("tauri migration: starting", { dir })
- if (!existsSync(dir)) {
- log.log("tauri migration: no tauri data directory found, nothing to migrate")
- store.set(TAURI_MIGRATED_KEY, true)
- return
- }
- for (const filename of readdirSync(dir)) {
- if (!filename.endsWith(".dat")) continue
- migrateFile(join(dir, filename), filename)
- }
- log.log("tauri migration: complete")
- store.set(TAURI_MIGRATED_KEY, true)
- }
|