diff --git a/bun.lock b/bun.lock index 0d032ee3e7..2d30b2d37f 100644 --- a/bun.lock +++ b/bun.lock @@ -1038,7 +1038,6 @@ "minimatch": "10.2.5", "npm-package-arg": "13.0.2", "resolve.exports": "catalog:", - "xdg-basedir": "5.1.0", }, "devDependencies": { "@tsconfig/bun": "catalog:", @@ -1104,7 +1103,6 @@ "unenv": "2.0.0-rc.24", "vitest": "3.2.7", "wrangler": "4.28.0", - "xdg-basedir": "5.1.0", }, }, "packages/www": { @@ -5999,8 +5997,6 @@ "xdg-app-paths": ["xdg-app-paths@5.5.1", "", { "dependencies": { "os-paths": "^4.0.1", "xdg-portable": "^7.2.0" } }, "sha512-hI3flOB4PLZIy5prbtTpirobtPE2ZtZ52szO+2mM9Efp6ErM398La+C1lIpNWDfNoQk+6Lsi6nMcCwVB7pxeMQ=="], - "xdg-basedir": ["xdg-basedir@5.1.0", "", {}, "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ=="], - "xdg-portable": ["xdg-portable@7.3.0", "", { "dependencies": { "os-paths": "^4.0.1" } }, "sha512-sqMMuL1rc0FmMBOzCpd0yuy9trqF2yTTVe+E9ogwCSWQCdDEtQUwrZPT6AxqtsFGRNxycgncbP/xmOOSPw5ZUw=="], "xml-naming": ["xml-naming@0.3.0", "", {}, "sha512-ghig2TBE/H11aOVgmahA3MhimvkBr6JIYknH/Dhdk10nXwdbIqBJsbfMxpvFPG8bAw77gN29aQWvKpmVoPlvPQ=="], diff --git a/packages/util/package.json b/packages/util/package.json index 340905a5e2..993c23d401 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -52,8 +52,7 @@ "mime-types": "3.0.2", "minimatch": "10.2.5", "npm-package-arg": "13.0.2", - "resolve.exports": "catalog:", - "xdg-basedir": "5.1.0" + "resolve.exports": "catalog:" }, "devDependencies": { "@tsconfig/bun": "catalog:", diff --git a/packages/util/src/global-roots.ts b/packages/util/src/global-roots.ts index d1d2957a54..a9324e4987 100644 --- a/packages/util/src/global-roots.ts +++ b/packages/util/src/global-roots.ts @@ -1,14 +1,19 @@ import os from "os" import path from "path" -import { xdgCache, xdgConfig, xdgData, xdgState } from "xdg-basedir" + +const home = os.homedir() +const data = process.env.XDG_DATA_HOME || (home ? path.join(home, ".local", "share") : undefined) +const cache = process.env.XDG_CACHE_HOME || (home ? path.join(home, ".cache") : undefined) +const config = process.env.XDG_CONFIG_HOME || (home ? path.join(home, ".config") : undefined) +const state = process.env.XDG_STATE_HOME || (home ? path.join(home, ".local", "state") : undefined) /** The XDG base directories that root opencode's global paths. */ export function roots(app: string) { return { - data: path.join(xdgData!, app), - cache: path.join(xdgCache!, app), - config: path.join(xdgConfig!, app), - state: path.join(xdgState!, app), + data: path.join(data!, app), + cache: path.join(cache!, app), + config: path.join(config!, app), + state: path.join(state!, app), tmp: path.join(os.tmpdir(), app), } } diff --git a/packages/util/test/global-roots.test.ts b/packages/util/test/global-roots.test.ts new file mode 100644 index 0000000000..a5ce4032bb --- /dev/null +++ b/packages/util/test/global-roots.test.ts @@ -0,0 +1,62 @@ +import { describe, expect, test } from "bun:test" +import os from "os" +import path from "path" +import { pathToFileURL } from "url" + +const module = pathToFileURL(path.join(import.meta.dir, "../src/global-roots.ts")).href + +describe("global roots", () => { + test("uses XDG overrides", () => { + const root = path.join(os.tmpdir(), "opencode-xdg-overrides") + const env = { + XDG_DATA_HOME: path.join(root, "data"), + XDG_CACHE_HOME: path.join(root, "cache"), + XDG_CONFIG_HOME: path.join(root, "config"), + XDG_STATE_HOME: path.join(root, "state"), + } + + expect(run(env)).toEqual({ + data: path.join(env.XDG_DATA_HOME, "opencode"), + cache: path.join(env.XDG_CACHE_HOME, "opencode"), + config: path.join(env.XDG_CONFIG_HOME, "opencode"), + state: path.join(env.XDG_STATE_HOME, "opencode"), + tmp: path.join(os.tmpdir(), "opencode"), + }) + }) + + test("empty XDG overrides use home directory defaults", () => { + const home = path.join(os.tmpdir(), "opencode-xdg-home") + + expect( + run({ + XDG_DATA_HOME: "", + XDG_CACHE_HOME: "", + XDG_CONFIG_HOME: "", + XDG_STATE_HOME: "", + ...(process.platform === "win32" ? { USERPROFILE: home } : { HOME: home }), + }), + ).toEqual({ + data: path.join(home, ".local", "share", "opencode"), + cache: path.join(home, ".cache", "opencode"), + config: path.join(home, ".config", "opencode"), + state: path.join(home, ".local", "state", "opencode"), + tmp: path.join(os.tmpdir(), "opencode"), + }) + }) +}) + +function run(env: Record) { + const result = Bun.spawnSync({ + cmd: [ + process.execPath, + "-e", + `const { roots } = await import(${JSON.stringify(module)}); console.log(JSON.stringify(roots("opencode")))`, + ], + env: { ...process.env, ...env }, + stdout: "pipe", + stderr: "pipe", + }) + + expect(result.exitCode, result.stderr.toString()).toBe(0) + return JSON.parse(result.stdout.toString()) +} diff --git a/packages/workerd-spike/package.json b/packages/workerd-spike/package.json index 982e224dcd..4dc505d008 100644 --- a/packages/workerd-spike/package.json +++ b/packages/workerd-spike/package.json @@ -24,7 +24,6 @@ "@cloudflare/workers-types": "^4.20250808.0", "vitest": "3.2.7", "wrangler": "4.28.0", - "xdg-basedir": "5.1.0", "unenv": "2.0.0-rc.24", "@effect/platform-node": "catalog:" }