Skip to content

Commit 0c665fc

Browse files
committed
Make app data portable - store next to EXE instead of AppData
1 parent c4defbd commit 0c665fc

3 files changed

Lines changed: 37 additions & 9 deletions

File tree

packages/desktop/src/main/index.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { existsSync, mkdirSync, rmSync } from "node:fs"
44
import * as http from "node:http"
55
import { createServer } from "node:net"
66
import { homedir, tmpdir } from "node:os"
7-
import { join } from "node:path"
7+
import { dirname, join } from "node:path"
88
import { getCACertificates, setDefaultCACertificates } from "node:tls"
99
import type { Event } from "electron"
1010
import { app, BrowserWindow } from "electron"
@@ -164,7 +164,13 @@ const main = Effect.gen(function* () {
164164
return
165165
}
166166

167-
preferAppEnv(app.getPath("userData"))
167+
const dataPath = app.isPackaged
168+
? join(dirname(app.getPath("exe")), "data")
169+
: app.getPath("userData")
170+
if (app.isPackaged && !existsSync(dataPath)) {
171+
mkdirSync(dataPath, { recursive: true })
172+
}
173+
preferAppEnv(dataPath)
168174

169175
app.on("second-instance", (_event: Event, argv: string[]) => {
170176
const urls = argv.filter((arg: string) => arg.startsWith("opencode://"))
@@ -303,7 +309,7 @@ const main = Effect.gen(function* () {
303309
},
304310
{
305311
needsMigration,
306-
userDataPath: app.getPath("userData"),
312+
userDataPath: dataPath,
307313
onSqliteProgress: (progress) => initEmitter.emit("sqlite", progress),
308314
onStdout: (message) => logger.log("sidecar stdout", { message }),
309315
onStderr: (message) => logger.warn("sidecar stderr", { message }),

packages/desktop/src/main/logging.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { MainLogger } from "electron-log"
22
import log from "electron-log/main.js"
3-
import { readFileSync, readdirSync, statSync, unlinkSync } from "node:fs"
3+
import { app } from "electron"
4+
import { mkdirSync, readFileSync, readdirSync, statSync, unlinkSync, existsSync } from "node:fs"
45
import { dirname, join } from "node:path"
56

67
const MAX_LOG_AGE_DAYS = 7
@@ -9,7 +10,22 @@ const TAIL_LINES = 1000
910
let logger: MainLogger
1011
export const getLogger = () => logger
1112

13+
function getPortableLogPath(): string {
14+
if (app.isPackaged) {
15+
const exePath = app.getPath("exe")
16+
const exeDir = dirname(exePath)
17+
const logDir = join(exeDir, "data", "logs")
18+
if (!existsSync(logDir)) {
19+
mkdirSync(logDir, { recursive: true })
20+
}
21+
return logDir
22+
}
23+
return log.transports.file.getFile().path.replace(/[^\\\/]+$/, "")
24+
}
25+
1226
export function initLogging() {
27+
const logDir = getPortableLogPath()
28+
log.transports.file.resolvePathFn = () => join(logDir, "opencode.log")
1329
log.transports.file.maxSize = 5 * 1024 * 1024
1430
initConsoleTransport()
1531
cleanup()

packages/desktop/src/main/store.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,26 @@
11
import Store from "electron-store"
22
import { app } from "electron"
3+
import { dirname, join } from "node:path"
34

45
import { SETTINGS_STORE } from "./constants"
56

67
const cache = new Map<string, Store>()
78

8-
// We cannot instantiate the electron-store at module load time because
9-
// module import hoisting causes this to run before app.setPath("userData", ...)
10-
// in index.ts has executed, which would result in files being written to the default directory
11-
// (e.g. bad: %APPDATA%\@opencode-ai\desktop\opencode.settings vs good: %APPDATA%\ai.opencode.desktop.dev\opencode.settings).
9+
function getPortableDataPath(): string {
10+
if (app.isPackaged) {
11+
const exePath = app.getPath("exe")
12+
const exeDir = dirname(exePath)
13+
return join(exeDir, "data")
14+
}
15+
return app.getPath("userData")
16+
}
17+
1218
export function getStore(name = SETTINGS_STORE) {
1319
const cached = cache.get(name)
1420
if (cached) return cached
1521
const next = new Store({
1622
name,
17-
cwd: app.getPath("userData"),
23+
cwd: getPortableDataPath(),
1824
fileExtension: "",
1925
accessPropertiesByDotNotation: false,
2026
})

0 commit comments

Comments
 (0)