From 10cb6fb3871829088c4207eac591f801db1fd266 Mon Sep 17 00:00:00 2001 From: Rohith Pariki Date: Sat, 15 Aug 2026 22:38:31 +0530 Subject: [PATCH] fix(sleep): add Windows AppData support for default OpenCode database discovery (#56) --- docs/reference/cli.md | 4 ++-- plugins/README.md | 2 +- skillopt_sleep/harvest_opencode.py | 4 ++++ tests/test_harvest_opencode.py | 14 ++++++++++++++ 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/docs/reference/cli.md b/docs/reference/cli.md index 0ec5e82b..9fdcb91c 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -223,8 +223,8 @@ login, or contact a model provider. Source selection remains explicit: `--source auto` keeps Codex-then-Claude precedence and does not select OpenCode. The database path is selected from `--opencode-db` or the `opencode_db` config -key, then `OPENCODE_DB`, then -`${XDG_DATA_HOME:-~/.local/share}/opencode/opencode.db`. A relative +key, then `OPENCODE_DB`, then `%LOCALAPPDATA%\opencode\opencode.db` or `%APPDATA%\opencode\opencode.db` on Windows or +`${XDG_DATA_HOME:-~/.local/share}/opencode/opencode.db` on POSIX. A relative `OPENCODE_DB` value is resolved below OpenCode's data directory; `OPENCODE_DB=:memory:` has no persistent history to harvest. diff --git a/plugins/README.md b/plugins/README.md index 0a999c8c..7bfc1ff2 100644 --- a/plugins/README.md +++ b/plugins/README.md @@ -145,7 +145,7 @@ Common implemented flags include: | `--pi-home PATH` | `~/.pi` | select the parent directory containing `agent/sessions` | | `--pi-path PATH` | auto-detect `pi` | select the Pi coding-agent CLI executable | | `--opencode-path PATH` | `SKILLOPT_SLEEP_OPENCODE_PATH`, then `opencode` on `PATH`/`PATHEXT` | select the OpenCode CLI executable | -| `--opencode-db PATH` | `OPENCODE_DB`, then `${XDG_DATA_HOME:-~/.local/share}/opencode/opencode.db` | select the OpenCode SQLite history database | +| `--opencode-db PATH` | `OPENCODE_DB`, `%LOCALAPPDATA%`/`%APPDATA%` (Windows), or `${XDG_DATA_HOME:-~/.local/share}/opencode/opencode.db` | select the OpenCode SQLite history database | | `--project PATH` | current directory | select the project and invoked harvest scope | | `--scope invoked\|all` | `invoked` | limit transcript harvesting | | `--target-skill-path PATH` | managed skill | select a specific `SKILL.md` to stage/adopt | diff --git a/skillopt_sleep/harvest_opencode.py b/skillopt_sleep/harvest_opencode.py index e2919811..0fb7e565 100644 --- a/skillopt_sleep/harvest_opencode.py +++ b/skillopt_sleep/harvest_opencode.py @@ -13,6 +13,7 @@ import os import re import sqlite3 +import sys from datetime import datetime, timezone from typing import Any, Iterable, List, Optional from urllib.request import pathname2url @@ -48,6 +49,9 @@ def default_opencode_db() -> str: data_home = os.environ.get("XDG_DATA_HOME", "") if data_home: data_dir = os.path.abspath(os.path.expanduser(data_home)) + elif sys.platform == "win32" and (os.environ.get("LOCALAPPDATA") or os.environ.get("APPDATA")): + win_appdata = os.environ.get("LOCALAPPDATA") or os.environ.get("APPDATA") or "" + data_dir = os.path.abspath(os.path.expanduser(win_appdata)) else: data_dir = os.path.join(os.path.expanduser("~"), ".local", "share") opencode_data = os.path.join(data_dir, "opencode") diff --git a/tests/test_harvest_opencode.py b/tests/test_harvest_opencode.py index 5b66703b..acaf6a27 100644 --- a/tests/test_harvest_opencode.py +++ b/tests/test_harvest_opencode.py @@ -6,6 +6,7 @@ import json import os import sqlite3 +import sys from collections.abc import Iterable from datetime import datetime, timezone from pathlib import Path @@ -913,10 +914,23 @@ def test_default_database_honors_xdg_and_opencode_db(monkeypatch, tmp_path: Path assert default_opencode_db() == "" +def test_default_database_honors_windows_appdata(monkeypatch, tmp_path: Path) -> None: + local_app_data = tmp_path / "LocalAppData" + monkeypatch.delenv("XDG_DATA_HOME", raising=False) + monkeypatch.delenv("OPENCODE_DB", raising=False) + monkeypatch.setattr(sys, "platform", "win32") + monkeypatch.setenv("LOCALAPPDATA", str(local_app_data)) + monkeypatch.delenv("APPDATA", raising=False) + + assert default_opencode_db() == os.path.abspath(local_app_data / "opencode" / "opencode.db") + + def test_default_database_falls_back_to_home_local_share(monkeypatch, tmp_path: Path) -> None: home = tmp_path / "home" monkeypatch.delenv("XDG_DATA_HOME", raising=False) monkeypatch.delenv("OPENCODE_DB", raising=False) + monkeypatch.delenv("LOCALAPPDATA", raising=False) + monkeypatch.delenv("APPDATA", raising=False) monkeypatch.setenv("HOME", str(home)) monkeypatch.setenv("USERPROFILE", str(home))