diff --git a/AI_DISCLOSURE.md b/AI_DISCLOSURE.md index 02b666b..db04999 100644 --- a/AI_DISCLOSURE.md +++ b/AI_DISCLOSURE.md @@ -6,6 +6,7 @@ models-used: - claude-opus-5-5 - claude-sonnet-4-6 - claude-sonnet-5 + - claude-sonnet-5-5 - gpt-5.6-sol providers: - Anthropic @@ -18,7 +19,7 @@ scope: Shell wrapper scripts (bin/, lib/), the `azoidcapp` Python helper, documentation (docs/), and CI/lint configuration — all with human review and validation. -last-updated: 2026-10-23 +last-updated: 2026-10-24 --- # AI Disclosure diff --git a/bin/bwopencode2 b/bin/bwopencode2 index 82dd1ec..af42e87 100755 --- a/bin/bwopencode2 +++ b/bin/bwopencode2 @@ -38,8 +38,11 @@ # (database incl. saved sign-in, logs, ...) # - OpenCode 2 cache (host ~/.cache/opencode2/opencode, mounted at # ~/.cache/opencode): read-write -# - OpenCode 2 state (~/.local/state/opencode): ephemeral -# (last-used model and prompt history are not remembered) +# - OpenCode 2 state (~/.local/state/opencode): ephemeral, except the TUI +# plugin storage (host ~/.local/state/opencode2/opencode/latest/tui, +# mounted at ~/.local/state/opencode/latest/tui): read-write, so +# dismissed onboarding boxes and tab layout persist (locks and service +# files, and last-used model and prompt history, are not remembered) # - Managed config: /etc/opencode/opencode.json{,c} and # /etc/opencode/{agents,commands,plugins,skills}, read-only # - Project .opencode/: persistent copy kept outside the repository @@ -385,6 +388,7 @@ resolve_opencode2_paths() { OC2_CONFIG_SRC="${_HOME}/.config/opencode2/opencode" OC2_DATA_SRC="${_HOME}/.local/share/opencode2/opencode" OC2_CACHE_SRC="${_HOME}/.cache/opencode2/opencode" + OC2_TUI_STATE_SRC="${_HOME}/.local/state/opencode2/opencode/latest/tui" # Sandbox side: always the standard locations, which is where OpenCode 2 # looks by default, so no XDG_* override is needed. The XDG_* values are @@ -394,6 +398,7 @@ resolve_opencode2_paths() { OC2_DATA_DIR="${XDG_DATA_HOME}/opencode" OC2_CACHE_DIR="${XDG_CACHE_HOME}/opencode" OC2_STATE_DIR="${_HOME}/.local/state/opencode" + OC2_TUI_STATE_DIR="${OC2_STATE_DIR}/latest/tui" # The opencode2 config directory holds service.json, which is never # mounted: refuse a working directory / --ro-path / --rw-path that would @@ -405,13 +410,14 @@ resolve_opencode2_paths() { # the checks mirror bwopencode and also catch symlinked directories. _check_dir_safe "${OC2_DATA_SRC}" "opencode2 data dir" _check_dir_safe "${OC2_CACHE_SRC}" "opencode2 cache dir" + _check_dir_safe "${OC2_TUI_STATE_SRC}" "opencode2 TUI state dir" } # Ensure writable directories exist on host. The data dir is bound whole # because the OpenCode 2 layout is not documented (database + -shm/-wal, log, # repos, shell, ...), so no file list could be kept in sync. ensure_host_dirs() { - mkdir -p "${OC2_DATA_SRC}" "${OC2_CACHE_SRC}" + mkdir -p "${OC2_DATA_SRC}" "${OC2_CACHE_SRC}" "${OC2_TUI_STATE_SRC}" } # Resolve opencode2 config symlinks. @@ -583,13 +589,22 @@ build_opencode2_cache_mount() { ) } -# ── OpenCode 2 state (ephemeral) ───────────────────────────────── +# ── OpenCode 2 state (ephemeral, TUI plugin storage persists) ──── # $HOME is a tmpfs, so state is discarded on exit; this avoids lock -# clashes on NFS homes. Create the directory chain so OpenCode 2 can -# write into it without having to create parents. +# clashes on NFS homes (locks/) and sharing service files with a host +# opencode2. Create the directory chain so OpenCode 2 can write into it +# without having to create parents. +# +# Only the TUI plugin storage directory is persisted: it holds the +# dismissed "Getting started" box and the tab layout, and is never locked. +# A directory is bound (not single files) because OpenCode writes a temp +# file and renames it over the target, which fails on a bind-mounted file. +# "latest" is the release channel directory name used by OpenCode 2; a +# different channel would use another name and not be persisted. build_opencode2_state_dir() { BWRAP_ARGS+=( --dir "${OC2_STATE_DIR}" + --bind "${OC2_TUI_STATE_SRC}" "${OC2_TUI_STATE_DIR}" ) } diff --git a/docs/bw-wrappers.md b/docs/bw-wrappers.md index a7471bd..1835054 100644 --- a/docs/bw-wrappers.md +++ b/docs/bw-wrappers.md @@ -347,7 +347,8 @@ binary path there too, not `opencode2`. | `~/.config/opencode2/opencode` | `~/.config/opencode` | read-only, symlinks resolved | | `~/.local/share/opencode2/opencode` | `~/.local/share/opencode` | read-write, the whole directory persists | | `~/.cache/opencode2/opencode` | `~/.cache/opencode` | read-write (provider npm packages install here) | -| (none) | `~/.local/state/opencode` | not persisted (ephemeral) | +| (none) | `~/.local/state/opencode` | not persisted (ephemeral), except the next row | +| `~/.local/state/opencode2/opencode/latest/tui` | `~/.local/state/opencode/latest/tui` | read-write (TUI plugin storage: dismissed onboarding boxes, tab layout) | | `/.opencode` | `/.opencode` | persistent copy under the host data dir `project-dotfiles/`, so repository content cannot inject config or plugins | | `/etc/opencode/opencode.json{,c}`, `skills`, `agents`, `commands`, `plugins` | same | read-only, when present | @@ -355,8 +356,12 @@ The whole data directory is bound because the OpenCode 2 layout (database with `-shm`/`-wal`, `log`, `repos`, `shell`, ...) is not documented. Credentials are stored in the `credential` table of its database, so `opencode2 auth login` persists across sessions without anything like `--init-auth` (OpenCode 2's -legacy `auth.json` is only an import source). State is not persisted, so the -last-used model and prompt history are not remembered between sessions. +legacy `auth.json` is only an import source). State is not persisted, except +the TUI plugin storage directory (`latest/tui`), so a dismissed "Getting +started" box and the tab layout survive restarts. Locks and background-service +files stay ephemeral (avoids lock clashes on NFS homes and sharing service +files with a host `opencode2`), so the last-used model and prompt history are +not remembered between sessions. ### Config and authoring directories