fix(opencode): tests drop XDG_DATA_HOME, status reads the adapter's db, the version probe runs in a home of its own (Issue #60, review 2)

- Review 8a485fa0 B1 / c9d06e85 / c4e96018 (blocking): the adapter now
  follows the caller's XDG_DATA_HOME for its own home, but the tests did not
  drop it: a sandbox that sets HOME resolved the runner's real data dir.
  XDG_DATA_HOME joins _agent_home_guard.DROPPED_VARS (dropped per test), and
  the session guard watches <XDG_DATA_HOME>/opencode when it is set.
  Checked with XDG_DATA_HOME set to a separate dir: the opencode modules
  pass and nothing is written there.
- status.sh asks the adapter for the db (`debug paths`, XDG-aware) instead
  of a fixed ~/.local/share/opencode (8a485fa0 N1).
- The opt-in test's `opencode --version` probe ran with the real HOME at
  import and appended to the real opencode log; it runs in a temporary home
  now (8a485fa0 N2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff
This commit is contained in:
GodopuandClaude Opus 5.5 committed 2026-10-18 16:36:12 +09:00
1 parent cb5f439cce
commit 0e05b1b677
3 files changed
+17 -31

No files matched your search

@@ -105,20 +105,10 @@ def resume_on_disk(s):
if agent == 'opencode': if agent == 'opencode':
u = s.get('opencode_session_id_own') u = s.get('opencode_session_id_own')
if u: if u:
base_dir = f"{home}/.local/share/opencode" # the adapter's db: `opencode debug paths`, which follows XDG_DATA_HOME (Issue #60)
odb = None from lib_py.agents.registry import get_adapter
for cand in [f"{base_dir}/opencode.db", f"{base_dir}/storage.db"]: from lib_py.agents.base import DiscoveryContext
if os.path.exists(cand): odb = get_adapter('opencode')._resolve_db(DiscoveryContext(workspace=cwd, agent_name='opencode', home_dir=home))
odb = cand
break
if not odb and os.path.isdir(f"{base_dir}/project"):
for root, _, files in os.walk(f"{base_dir}/project"):
for f in files:
if f.endswith(".db"):
odb = os.path.join(root, f)
break
if odb:
break
if not odb or not os.path.exists(odb): if not odb or not os.path.exists(odb):
return 'MISSING' return 'MISSING'
try: try:
@@ -315,20 +305,10 @@ def resume_on_disk(s):
if agent == 'opencode': if agent == 'opencode':
u = s.get('opencode_session_id_own') u = s.get('opencode_session_id_own')
if u: if u:
base_dir = f"{home}/.local/share/opencode" # the adapter's db: `opencode debug paths`, which follows XDG_DATA_HOME (Issue #60)
odb = None from lib_py.agents.registry import get_adapter
for cand in [f"{base_dir}/opencode.db", f"{base_dir}/storage.db"]: from lib_py.agents.base import DiscoveryContext
if os.path.exists(cand): odb = get_adapter('opencode')._resolve_db(DiscoveryContext(workspace=cwd, agent_name='opencode', home_dir=home))
odb = cand
break
if not odb and os.path.isdir(f"{base_dir}/project"):
for root, _, files in os.walk(f"{base_dir}/project"):
for f in files:
if f.endswith(".db"):
odb = os.path.join(root, f)
break
if odb:
break
if not odb or not os.path.exists(odb): if not odb or not os.path.exists(odb):
return 'MISSING' return 'MISSING'
try: try:
+3 -2
View File
@@ -18,7 +18,7 @@ import tempfile
# The pane-inherited variables conftest._isolate_agent_homes drops for every # The pane-inherited variables conftest._isolate_agent_homes drops for every
# test, so HOME (which the tests set) governs, as it does in a plain shell. # test, so HOME (which the tests set) governs, as it does in a plain shell.
DROPPED_VARS = ("HOME_DIR", "CLAUDE_PROJECT_DIR", "CLAUDE_CONFIG_DIR", "CODEX_HOME", "LOCAL_BIN") DROPPED_VARS = ("HOME_DIR", "CLAUDE_PROJECT_DIR", "CLAUDE_CONFIG_DIR", "CODEX_HOME", "XDG_DATA_HOME", "LOCAL_BIN")
# Read by the code under test but left alone, on purpose: HOME is where the # Read by the code under test but left alone, on purpose: HOME is where the
# real herdr tests and the shim bootstrap find the server socket, and it is # real herdr tests and the shim bootstrap find the server socket, and it is
# what the suite's own tests set for an isolated home; XDG_CONFIG_HOME and # what the suite's own tests set for an isolated home; XDG_CONFIG_HOME and
@@ -45,7 +45,8 @@ def watch_dirs(ambient):
for d in ("conversations", "cache", "brain", "annotations", "presence")] for d in ("conversations", "cache", "brain", "annotations", "presence")]
dirs += [("codex", os.path.join(codex, "sessions")), dirs += [("codex", os.path.join(codex, "sessions")),
("grok", os.path.join(home, ".grok", "sessions")), ("grok", os.path.join(home, ".grok", "sessions")),
("opencode", os.path.join(home, ".local", "share", "opencode")), ("opencode", os.path.join(ambient.get("XDG_DATA_HOME") or os.path.join(home, ".local", "share"),
"opencode")),
("hermes", os.path.join(home, ".hermes"))] ("hermes", os.path.join(home, ".hermes"))]
return dirs return dirs
+6 -1
View File
@@ -291,8 +291,13 @@ def _real_opencode():
path = shutil.which("opencode") or os.path.expanduser("~/.opencode/bin/opencode") path = shutil.which("opencode") or os.path.expanduser("~/.opencode/bin/opencode")
if not os.path.isfile(path): if not os.path.isfile(path):
return None return None
import tempfile
try: try:
out = subprocess.run([path, "--version"], capture_output=True, text=True, timeout=20).stdout # Even --version writes opencode's log under its data dir: give it a
# home of its own (review 8a485fa0 N2).
with tempfile.TemporaryDirectory() as tmp:
env = {"PATH": os.environ.get("PATH", ""), "HOME": tmp, "TMPDIR": tmp}
out = subprocess.run([path, "--version"], capture_output=True, text=True, timeout=20, env=env).stdout
except Exception: except Exception:
return None return None
m = re.search(r"(\d+)\.\d+\.\d+", out) m = re.search(r"(\d+)\.\d+\.\d+", out)