Problem
Four call sites across the extension hardcode ~/.config/opencode/ and ~/.local/share/opencode/ as literal path.join(os.homedir(), ".config", "opencode", ...) / path.join(os.homedir(), ".local", "share", "opencode", ...) strings. They break under non-standard XDG_CONFIG_HOME / XDG_DATA_HOME and bypass configurable settings.
This slice extracts the shared resolution logic into a single module that all consumers import.
Scope
Create packages/extension/src/opencode_xdg.ts exporting two functions:
opencodeConfigDir(): string — returns $XDG_CONFIG_HOME/opencode (or ~/.config/opencode when unset)
opencodeDataDir(): string — returns $XDG_DATA_HOME/opencode (or ~/.local/share/opencode when unset)
Pure utility — no VS Code API dependencies, no side effects.
Acceptance Criteria
Testing Decisions
Create packages/extension/test/opencode_xdg.test.ts:
- Mock
process.env.XDG_CONFIG_HOME / XDG_DATA_HOME and os.homedir().
- Three cases per function: unset → default, set → custom, empty string → default.
Key Decisions
| Decision |
Rationale |
| No VS Code API dependency |
Keeps the module testable without vscode mock; consumers layer settings on top |
| Empty-string env treated as unset |
XDG spec: unset or empty means default |
path.join (not template literals) |
Cross-platform safety (though macOS is the primary target) |
Constraints & Invariants
- This module MUST NOT read VS Code settings (
amicode.configDir, amicode.sessionDatabase) — those are consumer-side overrides, not base resolution.
- No filesystem side effects (no
mkdirp, no writes).
- Consumers that need the VS Code setting override apply it themselves on top of these helpers.
Source
Part of #556
Problem
Four call sites across the extension hardcode
~/.config/opencode/and~/.local/share/opencode/as literalpath.join(os.homedir(), ".config", "opencode", ...)/path.join(os.homedir(), ".local", "share", "opencode", ...)strings. They break under non-standardXDG_CONFIG_HOME/XDG_DATA_HOMEand bypass configurable settings.This slice extracts the shared resolution logic into a single module that all consumers import.
Scope
Create
packages/extension/src/opencode_xdg.tsexporting two functions:opencodeConfigDir(): string— returns$XDG_CONFIG_HOME/opencode(or~/.config/opencodewhen unset)opencodeDataDir(): string— returns$XDG_DATA_HOME/opencode(or~/.local/share/opencodewhen unset)Pure utility — no VS Code API dependencies, no side effects.
Acceptance Criteria
opencodeConfigDir()returnspath.join(process.env.XDG_CONFIG_HOME, "opencode")whenXDG_CONFIG_HOMEis set; otherwisepath.join(os.homedir(), ".config", "opencode").opencodeDataDir()returnspath.join(process.env.XDG_DATA_HOME, "opencode")whenXDG_DATA_HOMEis set; otherwisepath.join(os.homedir(), ".local", "share", "opencode").Testing Decisions
Create
packages/extension/test/opencode_xdg.test.ts:process.env.XDG_CONFIG_HOME/XDG_DATA_HOMEandos.homedir().Key Decisions
vscodemock; consumers layer settings on toppath.join(not template literals)Constraints & Invariants
amicode.configDir,amicode.sessionDatabase) — those are consumer-side overrides, not base resolution.mkdirp, no writes).Source
Part of #556