Skip to content

v1.6.24

Choose a tag to compare

@marmutapp marmutapp released this 21 May 09:11
· 14 commits to main since this release

fix(opencode): capture per-message effort level (variant)

Closes operator-reported "Only the CLI session was captured but without
effort level." OpenCode CLI stores per-(provider, model) effort selection
in ~/.local/state/opencode/model.json under variant.<provider>/<model>,
and the CLI stamps the chosen level ("low" / "medium" / "high") onto every
assistant message's data.variant JSON field. Pre-fix the adapter's
messageData struct had no Variant field, so JSON unmarshalling
silently dropped the key — every CLI assistant row had Metadata.EffortLevel
NULL.

Fix (internal/adapter/opencode/adapter.go): add
Variant string json:"variant"`` to messageData. Stamp
`Metadata = effortMetadata(msg.Variant)` on every assistant-side ToolEvent
emit site (completion, tool, assistant_text, subtask, reasoning, step_finish).
User prompts intentionally stay nil (variant is on the assistant response,
not the user message). Mirrors codex's `withEffort` pattern.

Empirical asymmetry — the Windows Desktop variant does NOT emit variant
today (verified 2026-05-21 against a live Desktop session). Only the CLI
does. F1's wiring picks Desktop effort up automatically if a future
Desktop release starts stamping the field.

fix(opencode): cross-mount mirror unblocks Windows Desktop sessions

Closes operator-reported "the desktop one was completely missed." When the
adapter opened a /mnt/c-mounted opencode.db (WSL2 reading the Windows-side
OpenCode Desktop store) while Windows was actively writing the WAL,
modernc.org/sqlite returned disk I/O error (SQLITE_IOERR_SHORT_READ 4618) on every read — every Windows Desktop session never landed. Verified
by reproducing the failure mode with the adapter's exact DSN against the
live Windows-side path.

Fix (internal/adapter/opencode/adapter.go): new stageMirrorIfForeign
helper. When the source path lives under a crossmount.AllHomes()-detected
non-native home, copy the SQLite trio (.db + -wal + -shm) into a
per-source mirror dir under os.UserCacheDir()/superbased-observer/ opencode-mirror/<sha8>/, open the mirror, return the mirrored path.
Refresh skips the copy when every source sibling is older than (and matches
size with) the mirror sibling — WAL is checked separately because its mtime
ticks every flush.

openReadOnlyDB calls into the helper so both latestWatermark and the
load functions benefit. The mirror is fully transparent: SourceFile on
emitted events still references the original /mnt/c/... path so the
watcher's (source_file, source_event_id) UNIQUE constraint is preserved
across native + foreign hosts.

Cost: ~2.3 MB I/O per refresh per foreign source under steady-state load.
Negligible compared to the data the fix unblocks (11 messages + 60 parts
in a single 30-second Desktop turn during the audit).

fix(opencode): translate foreign cwd before git.Resolve

OpenCode Desktop on Windows records path.cwd as a Windows-style path
("C:\programsx\superbased-observer"). Per
[[feedback-foreign-path-git-resolve]], calling git.Resolve on a
Windows-style path from a Linux host causes filepath.Abs to treat the
string as relative, prepend the observer's CWD, and git.Resolve walks
UP that bogus path — landing on observer's own .git in the worst case.

Fix: wrap cwd through crossmount.TranslateForeignPath before
git.Resolve in resolveProjectRoot. Mirrors the existing wiring in
claudecode/adapter.go:1055 and codex/adapter.go:2494. Only relevant
once the v1.6.24 cross-mount mirror unblocks Windows Desktop ingestion
in the first place — pre-fix there were no foreign-cwd rows to misroute.

feat(opencode): capture reasoning + step-finish parts

OpenCode's part table contains two part types the adapter dropped pre-
v1.6.24: reasoning (the model's visible chain-of-thought body — 11
per Desktop session in the audit corpus) and step-finish (per-step
token + cost slice — 10 per Desktop session). The reasoning COUNT
survived via TokenEvent.ReasoningTokens, but the actual reasoning TEXT
and the per-step granularity were both lost.

Fix:

  • loadReasoningEvents mirrors loadAssistantTextEvents: each non-empty
    reasoning part emits one ActionTaskComplete row with
    RawToolName="opencode.reasoning", body in ToolOutput (scrubbed,
    capped 4000 chars), DurationMs derived from time.{start,end}.
  • loadStepFinishEvents emits one ActionUnknown ToolEvent per
    step-finish with RawToolName="opencode.step_finish",
    Target=finish_reason, full step-finish JSON in RawToolInput.

Critical design contract — no TokenEvent emit from step-finish. The
message-level data.tokens bundle is the SUM across that message's
step-finish parts; emitting TokenEvents from step-finish would double-
count against loadTokenEvents. step-finish surfaces as observability
metadata only, NOT as a token-attribution source. Documented inline so
a future audit doesn't accidentally "fix" this into a double-count.

docs

docs/opencode-audit-2026-05-21.md documents the full audit: live
ground-truth tables, per-finding evidence, cross-platform inventory of
OpenCode storage locations, deferred carry-forward (X1 backfill on next
daemon restart; X2 snapshot-vs-append note; X3 session.title/version
not lifted; X4 Windows Desktop variant emit policy).


Downloads

Pre-built binaries for each supported platform are attached below. Linux variants bundle antigravity-bridge.exe next to the observer binary for WSL2 users of the Antigravity adapter.

Platform Asset
Linux x86_64 observer-v1.6.24-linux-x64.tar.gz
Linux arm64 observer-v1.6.24-linux-arm64.tar.gz
macOS x86_64 (Intel) observer-v1.6.24-darwin-x64.tar.gz
macOS arm64 (Apple Silicon) observer-v1.6.24-darwin-arm64.tar.gz
Windows x86_64 observer-v1.6.24-win32-x64.zip

Verify with sha256sum -c SHA256SUMS (or shasum -a 256 -c SHA256SUMS on macOS) from the directory containing the downloads.

Also available via npm: npm install -g @superbased/observer@1.6.24