Skip to content

fix(opencode): probe XDG path on Windows for session storage#1026

Open
pedramamini wants to merge 1 commit into
mainfrom
fix/1025-opencode-windows-xdg-path
Open

fix(opencode): probe XDG path on Windows for session storage#1026
pedramamini wants to merge 1 commit into
mainfrom
fix/1025-opencode-windows-xdg-path

Conversation

@pedramamini
Copy link
Copy Markdown
Collaborator

@pedramamini pedramamini commented May 19, 2026

Summary

  • OpenCode v1.2+ on Windows actually stores its SQLite database and JSON session files under %USERPROFILE%\.local\share\opencode (XDG-style), not %APPDATA%\opencode. As a result, Maestro's OpenCode session history was empty on Windows even when opencode session list returned sessions.
  • getOpenCodeDataDir() now resolves through a candidate list (XDG_DATA_HOME~/.local/share/opencode%APPDATA%\opencode on Windows) and picks the first that exists, so both current and legacy installs are discovered.
  • getOpenCodeDbPath() performs the same probe so the SQLite reader hits the correct file regardless of which candidate dir holds it.

Closes #1025

Test plan

  • On Windows with OpenCode v1.15.5 installed, open an OpenCode-backed agent in Maestro and confirm Session History lists the same sessions as opencode session list.
  • On Windows where only the legacy %APPDATA%\opencode\storage JSON layout exists, confirm sessions still appear (fallback path).
  • On macOS/Linux, confirm existing OpenCode session history continues to load (no regression).
  • maestro-cli list sessions <opencode-agent-id> --json returns the expected totalCount on each platform above.

Summary by CodeRabbit

  • Chores
    • Improved data directory detection and storage management with enhanced cross-platform compatibility across Windows, Linux, and macOS.
    • Refined database initialization with more robust fallback logic for automatic data location discovery.

Review Change Stack

OpenCode v1.2+ on Windows actually stores its SQLite database and JSON
files under %USERPROFILE%\.local\share\opencode (XDG-style), not
%APPDATA%\opencode. Maestro's hard-coded %APPDATA% probe meant Windows
users saw empty Session History even when `opencode session list` worked.

Resolve the data dir by checking each candidate (XDG_DATA_HOME ->
~/.local/share/opencode -> %APPDATA%\opencode on Windows) and picking
the first that exists, so both current and legacy installs are found.

Closes #1025
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ad210a47-ccca-48e0-a30c-7d43054c2d10

📥 Commits

Reviewing files that changed from the base of the PR and between 1006e3b and 40eccf1.

📒 Files selected for processing (1)
  • src/main/storage/opencode-session-storage.ts

📝 Walkthrough

Walkthrough

This PR updates OpenCode storage path discovery to search across XDG, Linux home, and Windows APPDATA directories. Instead of checking a single hardcoded location, it now builds an ordered list of candidates and returns the first existing directory, with a deterministic fallback for new installations or database initialization.

Changes

Multi-platform OpenCode storage discovery

Layer / File(s) Summary
Data directory candidates and resolution
src/main/storage/opencode-session-storage.ts
getOpenCodeDataDirCandidates() builds a platform-aware list prioritizing XDG_DATA_HOME/opencode, then ~/.local/share/opencode, and on Windows adds %APPDATA%/opencode with Roaming fallback. getOpenCodeDataDir() returns the first candidate that exists, otherwise the preferred candidate for deterministic defaults.
Database path discovery with fallback
src/main/storage/opencode-session-storage.ts
getOpenCodeDbPath() searches across all candidate data directories for an existing opencode.db and returns the first match; when no database is found, it falls back to a deterministic path under the preferred candidate.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • RunMaestro/Maestro#569: Modifies the same storage file to add SQLite-backed session reading with fallback to JSON storage, complementing this PR's path discovery logic.

Poem

🐰 Across all platforms, the data now roams,
XDG and AppData find OpenCode's home,
Candidates checked, and fallbacks so wise,
Windows and Linux both synchronized,
Session history no longer hides! 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: updating OpenCode session storage probing to handle Windows XDG paths for correct data directory discovery.
Linked Issues check ✅ Passed The changes implement the core requirements from issue #1025: probe multiple Windows storage locations (XDG, legacy), support SQLite DB discovery, and retain fallback logic.
Out of Scope Changes check ✅ Passed All changes are directly related to the stated objectives: replacing the single-path data dir logic with candidate-based probing for Windows and implementing matching SQLite DB path resolution.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/1025-opencode-windows-xdg-path

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 19, 2026

Greptile Summary

This PR fixes OpenCode session discovery on Windows by replacing the hard-coded single path with a candidate-list probe that respects XDG_DATA_HOME, then tries ~/.local/share/opencode (the actual v1.2+ location on all platforms), and finally falls back to %APPDATA%\opencode for legacy installs.

  • getOpenCodeDataDirCandidates() builds the ordered list; getOpenCodeDataDir() walks it checking directory existence; getOpenCodeDbPath() walks it checking for the concrete opencode.db file — these two probes use different criteria, which can produce mismatched results in mixed-install environments.
  • Both OPENCODE_STORAGE_DIR and OPENCODE_DB_PATH remain module-level constants evaluated once at startup; path resolution is correct for all three single-install scenarios covered by the test plan.

Confidence Score: 3/5

Safe to merge for the primary use case, but the JSON-storage fallback path can silently miss legacy sessions in mixed-install environments where both an XDG directory and an APPDATA directory coexist.

The fix correctly resolves the reported Windows XDG path issue for the primary SQLite flow. However, the JSON fallback uses a weaker probe (directory existence vs. file existence), meaning legacy pre-v1.2 sessions stored in APPDATA could be invisible when both directories exist.

src/main/storage/opencode-session-storage.ts — specifically the getOpenCodeStorageDir/getOpenCodeDataDir interaction and the fallback return path in getOpenCodeDbPath.

Important Files Changed

Filename Overview
src/main/storage/opencode-session-storage.ts Introduces candidate-list path probing for XDG-style directories on Windows; getOpenCodeDbPath() calls getOpenCodeDataDirCandidates() twice, and getOpenCodeStorageDir() uses a weaker directory-existence probe vs. the stronger file-existence probe in getOpenCodeDbPath(), which can mismatch in mixed-install scenarios.

Comments Outside Diff (1)

  1. src/main/storage/opencode-session-storage.ts, line 86-88 (link)

    P1 JSON storage dir probe is weaker than the DB probe in mixed-install scenarios

    getOpenCodeStorageDir() calls getOpenCodeDataDir(), which picks the first parent directory that exists — it does not verify that a storage/ subdirectory is actually present there. getOpenCodeDbPath(), by contrast, checks each candidate for the concrete file opencode.db.

    On Windows where a user has upgraded from pre-v1.2 (JSON at %APPDATA%\opencode\storage\) to v1.2+ (SQLite at ~/.local/share/opencode\opencode.db), both parent directories exist. getOpenCodeDataDir() returns ~/.local/share/opencode (first match), so OPENCODE_STORAGE_DIR becomes ~/.local/share/opencode\storage — which doesn't contain the legacy JSON files. Pre-v1.2 sessions that were never migrated to SQLite would be silently invisible in the merge step of listSessions.

Reviews (1): Last reviewed commit: "fix(opencode): probe XDG path on Windows..." | Re-trigger Greptile

Comment on lines 97 to 105
function getOpenCodeDbPath(): string {
return path.join(getOpenCodeDataDir(), 'opencode.db');
for (const candidate of getOpenCodeDataDirCandidates()) {
const dbPath = path.join(candidate, 'opencode.db');
if (fsSync.existsSync(dbPath)) {
return dbPath;
}
}
return path.join(getOpenCodeDataDirCandidates()[0], 'opencode.db');
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 getOpenCodeDbPath() calls getOpenCodeDataDirCandidates() twice: once for the loop and once again in the fallback return. The second call is redundant — the candidates are already known from the first iteration. Cache the result to avoid the duplicate work.

Suggested change
function getOpenCodeDbPath(): string {
return path.join(getOpenCodeDataDir(), 'opencode.db');
for (const candidate of getOpenCodeDataDirCandidates()) {
const dbPath = path.join(candidate, 'opencode.db');
if (fsSync.existsSync(dbPath)) {
return dbPath;
}
}
return path.join(getOpenCodeDataDirCandidates()[0], 'opencode.db');
}
function getOpenCodeDbPath(): string {
const candidates = getOpenCodeDataDirCandidates();
for (const candidate of candidates) {
const dbPath = path.join(candidate, 'opencode.db');
if (fsSync.existsSync(dbPath)) {
return dbPath;
}
}
return path.join(candidates[0], 'opencode.db');
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OpenCode-backed agents show empty session history with current OpenCode storage on Windows

1 participant