Root cause: loadPluginConfig() unconditionally switched userConfigPath to the
canonical name after calling migrateLegacyConfigFile(), even when migration
failed (e.g. file lock on Windows, permission denied). This left the config
path pointing to a non-existent file, so the plugin config silently loaded
as empty defaults.
Additionally, several fallback/default paths were hardcoded to the legacy
'oh-my-opencode' basename instead of using CONFIG_BASENAME ('oh-my-openagent'),
causing CLI config commands (writeOmoConfig, detectCurrentConfig) to write to
the wrong filename.
Changes:
- plugin-config.ts: check migrateLegacyConfigFile() return value; only switch
to canonical path if migration succeeded OR the canonical file already exists
- opencode-config-dir.ts: use CONFIG_BASENAME for omoConfig path in
getOpenCodeConfigPaths()
- config-context.ts: getOmoConfigPath() now uses detectPluginConfigFile() to
find whichever name variant actually exists on disk
- plugin-config.ts: default fallback paths use CONFIG_BASENAME instead of
hardcoded legacy name
- Added test: loadPluginConfig still loads config when migration fails
(read-only directory simulation)
- model-fallback hook: mock selectFallbackProvider and add _resetForTesting()
to test-setup.ts to clear module-level state between files
- fallback-retry-handler: add afterAll(mock.restore) and use mockReturnValueOnce
to prevent connected-providers mock leaking to subsequent test files
- opencode-config-dir: use win32.join for Windows APPDATA path construction
so tests pass on macOS (path.join uses POSIX semantics regardless of
process.platform override)
- system-loaded-version: use resolveSymlink from file-utils instead of
realpathSync to handle macOS /var -> /private/var symlink consistently
All 4456 tests pass (0 failures) on full bun test suite.
Windows CLI tests were not deleting XDG_CONFIG_HOME, making them
fragile in environments where this variable is set. getCliConfigDir()
reads XDG_CONFIG_HOME on all platforms, not just Linux.
Multiple files were hardcoding ~/.config/opencode paths instead of using
getOpenCodeConfigDir() which respects the OPENCODE_CONFIG_DIR env var.
This broke profile isolation features like OCX ghost mode, where users
set OPENCODE_CONFIG_DIR to a custom path but oh-my-opencode.json and
other configs weren't being read from that location.
Changes:
- plugin-config.ts: Use getOpenCodeConfigDir() directly
- cli/doctor/checks: Use getOpenCodeConfigDir() for auth and config checks
- tools/lsp/config.ts: Use getOpenCodeConfigDir() for LSP config paths
- command loaders: Use getOpenCodeConfigDir() for global command dirs
- hooks: Use getOpenCodeConfigDir() for hook config paths
- config-path.ts: Mark getUserConfigDir() as deprecated
- tests: Ensure OPENCODE_CONFIG_DIR is properly isolated in tests
- Add env var check to getCliConfigDir() for config directory override
- Update detectExistingConfigDir() to include env var path in locations
- Add comprehensive tests (7 test cases)
- Document in README
Closes#627
The installer now dynamically detects and uses the appropriate config
directory based on whether opencode CLI or opencode-desktop (Tauri) is
being used:
- opencode CLI: ~/.config/opencode/ (all platforms)
- opencode-desktop on Linux: ~/.config/ai.opencode.desktop/
- opencode-desktop on macOS: ~/Library/Application Support/ai.opencode.desktop/
- opencode-desktop on Windows: %APPDATA%/ai.opencode.desktop/
Key changes:
- Add new opencode-config-dir.ts module with platform-specific path resolution
- Support dev builds with ai.opencode.desktop.dev identifier
- Backward compatibility: checks legacy ~/.config/opencode/ first
- Refactor config-manager.ts to use dynamic paths via config context
- Update doctor plugin check to use shared path utilities
Fixes#440
Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>