fix(cli): write OpenCode config to ~/.config on all platforms incl. Windows (#3330) (#3343)

resolveOpencodeConfigDir used %APPDATA% on Windows, but OpenCode reads its
config from XDG ~/.config/opencode/ on every platform (on Windows:
%USERPROFILE%\.config\opencode\, NOT %APPDATA%). So a Windows user who
configured OpenCode via the dashboard had the file written where OpenCode never
looks — it silently had no effect.

Use the XDG path (XDG_CONFIG_HOME || ~/.config) unconditionally. Update the UI
note + route JSDoc, and flip the three tests that encoded the old %APPDATA%
behavior (t40 per-platform + card-note, cli-runtime-extended getCliConfigPaths).

Co-authored-by: abdulkadirozyurt <abdulkadirozyurt@users.noreply.github.com>
This commit is contained in:
Diego Rodrigues de Sa e Souza
2026-06-06 22:52:05 -03:00
committed by GitHub
parent bb55a804e9
commit 23d7bd1589
6 changed files with 29 additions and 17 deletions

View File

@@ -14,6 +14,7 @@ _Development cycle in progress — entries are added as work merges into `releas
### 🔧 Bug Fixes
- **fix(cli):** write the OpenCode config to `~/.config/opencode/opencode.json` on **all** platforms — on Windows OmniRoute wrote to `%APPDATA%\opencode\` but OpenCode reads from `%USERPROFILE%\.config\opencode\` (XDG), so dashboard-saved config silently had no effect. (#3330 — thanks @abdulkadirozyurt)
- **fix(catalog):** remove `minimaxai/minimax-m3` from the **NVIDIA NIM** tier — NVIDIA does not host it yet, so every request 404'd (`404 page not found`), while sibling `minimax-m2.7` on the same provider works. MiniMax M3 stays available on the tiers that actually serve it. (#3329 — thanks @mikmaneggahommie)
- **fix(electron):** ship `loginManager.js` in the packaged app — #3292 added it (and a `require("./loginManager")` in `main.js`) without adding it to electron-builder's `build.files`, so the packaged app crashed at startup with "Cannot find module" on the Linux/macOS smoke tests. Plus a regression test asserting every local `require("./x")` in the Electron entry points is shipped. ([#3334](https://github.com/diegosouzapw/OmniRoute/pull/3334) — thanks @diegosouzapw)
- **fix(startup):** correct the #3292 auto-refresh daemon import (`@/open-sse/...``@omniroute/open-sse/services/autoRefreshDaemon`); the `@/` alias maps to `src/`, so the daemon silently never ran in the built standalone (non-fatal "Cannot find module", caught at runtime). Adds a regression test banning `@/open-sse/*` imports in `src/`. ([#3335](https://github.com/diegosouzapw/OmniRoute/pull/3335) — thanks @diegosouzapw)

View File

@@ -159,9 +159,9 @@ async function saveContinueConfig({ baseUrl, apiKey, model }) {
}
/**
* Save OpenCode config to:
* - Linux/macOS: ~/.config/opencode/opencode.json (XDG_CONFIG_HOME aware)
* - Windows: %APPDATA%/opencode/opencode.json
* Save OpenCode config to ~/.config/opencode/opencode.json on ALL platforms
* (XDG_CONFIG_HOME aware). OpenCode uses XDG `~/.config` even on Windows
* (%USERPROFILE%\.config), NOT %APPDATA% (#3330).
*
* (#524) OpenCode was silently failing because this handler was missing.
*/

View File

@@ -273,7 +273,7 @@ export const CLI_TOOLS: Record<string, CliCatalogEntry> = {
notes: [
{
type: "warning",
text: "Config path: Linux/macOS ~/.config/opencode/opencode.json Windows %APPDATA%\\\\opencode\\\\opencode.json",
text: "Config path: ~/.config/opencode/opencode.json on all platforms (Windows: %USERPROFILE%\\\\.config\\\\opencode\\\\opencode.json)",
},
{
type: "warning",

View File

@@ -932,16 +932,15 @@ export const getCliConfigHome = () => {
};
export const resolveOpencodeConfigDir = (
platform = process.platform,
_platform = process.platform,
env: NodeJS.ProcessEnv = process.env,
homeDir = os.homedir()
) => {
const isWin = platform === "win32";
if (isWin) {
const appData = String(env.APPDATA || "").trim();
return appData || path.join(homeDir, "AppData", "Roaming");
}
// #3330: OpenCode reads its config from XDG `~/.config/opencode/` on ALL
// platforms — including Windows, where it uses `%USERPROFILE%\.config`, NOT
// `%APPDATA%`. Writing to %APPDATA% on Windows put the file where OpenCode
// never looks, so dashboard-saved config silently had no effect. `_platform`
// is kept in the signature for call-site/test compatibility.
const xdgConfigHome = String(env.XDG_CONFIG_HOME || "").trim();
return xdgConfigHome || path.join(homeDir, ".config");
};

View File

@@ -85,10 +85,9 @@ test("CLI config helpers enforce safe config homes and expose per-tool config pa
assert.equal(cliRuntime.getCliConfigPaths("unknown"), null);
process.env.XDG_CONFIG_HOME = path.join(homeDir, ".config-test");
const expectedOpencodeRoot =
process.platform === "win32"
? process.env.APPDATA || path.join(homeDir, "AppData", "Roaming")
: process.env.XDG_CONFIG_HOME;
// #3330: OpenCode uses XDG (`~/.config` / $XDG_CONFIG_HOME) on every platform,
// including Windows — no %APPDATA% special-case.
const expectedOpencodeRoot = process.env.XDG_CONFIG_HOME;
assert.deepEqual(cliRuntime.getCliConfigPaths("opencode"), {
config: path.join(expectedOpencodeRoot, "opencode", "opencode.json"),
});

View File

@@ -21,7 +21,10 @@ test("T40: OpenCode card documents config paths and --variant usage", () => {
.toLowerCase();
assert.match(notesText, /\.config\/opencode\/opencode\.json/);
assert.match(notesText, /%appdata%/);
// #3330: OpenCode uses ~/.config on all platforms (incl. Windows) — the note
// must no longer point Windows users at %APPDATA%.
assert.doesNotMatch(notesText, /%appdata%/);
assert.match(notesText, /%userprofile%/);
assert.match(notesText, /--variant/);
});
@@ -36,6 +39,8 @@ test("T40: OpenCode config path resolves per-platform", () => {
const linuxDefault = resolveOpencodeConfigPath("linux", {}, "/home/dev");
assert.equal(linuxDefault, path.join("/home/dev", ".config", "opencode", "opencode.json"));
// #3330: OpenCode uses XDG `~/.config/opencode/` on ALL platforms including
// Windows (NOT %APPDATA%) — OmniRoute must write where OpenCode reads.
const windowsPath = resolveOpencodeConfigPath(
"win32",
{ APPDATA: "C:\\Users\\dev\\AppData\\Roaming" },
@@ -43,8 +48,16 @@ test("T40: OpenCode config path resolves per-platform", () => {
);
assert.equal(
windowsPath,
path.join("C:\\Users\\dev\\AppData\\Roaming", "opencode", "opencode.json")
path.join("C:\\Users\\dev", ".config", "opencode", "opencode.json")
);
// Windows still honors XDG_CONFIG_HOME when set.
const windowsXdg = resolveOpencodeConfigPath(
"win32",
{ XDG_CONFIG_HOME: "D:\\xdg" },
"C:\\Users\\dev"
);
assert.equal(windowsXdg, path.join("D:\\xdg", "opencode", "opencode.json"));
});
test("T40: OpenCode config generator includes endpoint and selected API key", () => {