Commit graph

7 commits

Author SHA1 Message Date
Pascal André
e76e4484ab
fix(opencode): ground compatibility retirement in native contracts
Replace the arbitrary 2.0.11 floor with the 2.0.7 native step-timestamp boundary, keeping 2.0.11 as the separately recommended qualification target. Unlisted, prerelease and custom runtimes negotiate authenticated API requirements; preserve complete CLI labels so unknown builds neither fail solely by name nor enable unintended automatic upgrades.

Finish retiring pre-2.0.4 location/worktree/credential/Form serialization and obsolete catalog events while preserving internal identity, import/cursor authorization, pruning claims and connection fences. Remove the unused global package-manager installer and clean generated server output before packaging so deleted modules cannot survive incremental builds.

Distinguish missing setup, technical incompatibility and optional updates in the shared UI, including minimum rationale and optional restart wording. Retain a usable daemon through older discovery CLIs, check reload capability independently, and suppress installation when bundled npm is unavailable.

Validated 622 server tests, 7 browser scenarios, real reducers and fixture guards, production native suites on 2.0.7 and 2.0.10, and synthetic 2.0.3-to-2.0.7 history migration. Independent gatekeeper re-review closed the production version-parser finding. CI now qualifies the source-defined minimum and latest; rebuilt desktop acceptance is recorded separately.
2026-09-20 23:46:54 +02:00
Pascal André
7869e609b3
feat(opencode): enforce stable runtime support and add managed setup
Require stable OpenCode >=2.0.11 <3.0.0 from authenticated daemon metadata before functional clients and plugin provisioning. Keep bounded contract recognition, connection-generation fencing and native ownership checks while retiring old request, response and event conversions.

Unify missing and outdated runtime recovery with Preferences. Install exact stable releases through bundled Node/npm into a verified versioned user prefix, preserve custom and WSL selections, and separate installation from explicit shared-service restart through the native-parent starter. Fence stale setup responses, retain pending folder opening and never replay prompts.

Certify isolated 2.0.3-to-2.0.11 history migration with executable hashes, untouched seed storage, paginated messages, forks, compaction checkpoints, location moves and pending inbox data. Add minimum/latest cross-platform migration and installation gates, packaged npm closure checks, real Solid recovery regressions and supported-contract authority tests.

Validated server/UI types, focused unit and reducer suites, browser captures, actual packaging-prepared Node 24.20.0 installation without system Node, and native location, automation and pruning fixtures. Document packaged-desktop, WSL, broader historical-state and remote-CI evidence as remaining release gates.
2026-09-20 16:09:36 +02:00
Pascal André
ca94224b74
fix(opencode): align current contracts and fence native message settlement (#728)
Align the server/UI OpenCode client and bundled plugin at 2.0.11. Route canonical server.info through authenticated discovery, preserve legacy step timing, and honor hidden Forms protocol fields without rendering their inputs or dropping defaults.

Reconcile terminal tools into the bounded visible transcript and fence native reducer history reads against intervening events. Discard stale pages and coalesce trailing reads so a late settlement snapshot cannot remove a newer streaming assistant. Preserve lifecycle, generation, disposal, location and historical-data safeguards.

Qualify the latest stable runtime in CI and record the resolved version. Each CodeNomad release fixes its minimum supported OpenCode version to the latest stable available when that CodeNomad release ships. Keep one shared compatibility reference and detailed evidence in PR/CI history rather than per-version reports.

Validation includes isolated native runtime/proxy/pruning, automation, environment and fork acceptance; hidden Forms browser coverage; deferred settlement/new-execution regressions; 112 final targeted UI tests, typechecks and production builds. Gatekeeper findings were fixed and independently re-reviewed before merging.
2026-09-20 13:48:53 +02:00
Pascal André
aa51cbb9ff
fix(opencode): support earlier and modern V2 runtime contracts (#695)
Closes #694

## Status

This PR contains the stable 2.0.4 client migration, authenticated V2
discovery fallback and shared cross-runtime compatibility
implementation. The validation results below are local execution
evidence; the newly added CI matrix must also run on the updated PR
head.

## Published changes

- Pin UI/server to official `@opencode/client@2.0.4` and the bundled
pruning plugin to `@opencode/plugin@2.0.4`, with the corresponding
lockfile migration.
- Probe authenticated `/api/status` first. Fall back to earlier V2
`/api/health` **only on HTTP 404**, retaining the endpoint, credentials,
64 KiB response bound and absolute deadline. Authentication, transport,
server and malformed-status failures do not trigger fallback.
- Migrate the canonical UI/server contract to stable Forms, permission
decisions, command names, interrupts, renaming, forks, message lookup
and inbox delivery.
- Update the guarded proxy for stable methods/paths, native
active-session envelopes, native `cursor.next`, global Form directory
headers and current resource/plugin events.
- Follow the renamed upstream platform binary `bin/opencode(.exe)` while
retaining public CLI aliases.

Discovery success alone does not establish compatibility with an earlier
runtime's conversation APIs.

## Shared cross-runtime compatibility

### Shared cross-runtime integration

- Introduce one connection-scoped adapter under
`packages/server/src/opencode/compatibility/`, used by both the guarded
UI proxy and direct server callers, including Yolo.
- Select the contract using authenticated daemon identity rather than
the CLI executable's version. Recognize unknown publications through
authenticated, bounded OpenAPI negotiation instead of an exact
runtime-version gate.
- Bind authorization, client, transport and profile to one connection
generation. Fence actual mutation dispatch after asynchronous body
preparation; prevent late old streams from publishing or invalidating
their replacement.
- Translate earlier V2 routes, methods and payloads before sending.
Never retry a mutation speculatively after 400, 404, authentication or
transport failures.
- Normalize legacy HTTP inbox timestamps, including compaction
admission, before the pinned Solid reducer. Preserve the distinct native
SSE inbox schema and durable event metadata.
- Restore legacy catalog/content invalidation and permission-event
convergence. Preserve meaningful method/path/status/profile diagnostics
and native 401 error envelopes.

### Location authority and pruning

- Preserve legacy workspace identity internally through request
serialization, catalog/cache keys, Forms, imports, cursors, events and
exact move rollback. Modern public APIs continue to reject obsolete
workspace selectors.
- Authorize complete locations before translating directories or
synthesizing upstream Form/location headers. Keep native cursor tokens
unchanged.
- Preserve session/path ownership, worktree mutation fences and the
restricted proxy allowlist. Generic RPC, plugin management and
destructive revert commit remain blocked.
- Carry verified legacy identity through pruning membership checks,
preview and the existing transactional storage/claim fence; do not relax
deletion checks.
- Treat native idle records as control records, retaining
identity/outcome without fabricated assistant text.
- Add a common multi-runtime CI matrix and the audit/evidence register
in `dev-docs/OPENCODE_V2_COMPATIBILITY.md`, including preserved
historical architecture findings.

## Local validation

All native tests use isolated synthetic daemons, configuration and
databases, never the shared daemon or user storage.

| Check | Result |
| --- | --- |
| Same native suite on beta-19271, 2.0.3, 2.0.4 and 2.0.5 with pinned
client/plugin 2.0.4 | Passed |
| Full native pruning suite with non-null legacy workspace identity on
beta-19271 and 2.0.3 | Passed |
| Rendered UI on modern 2.0.5 and beta-19271 with non-null identity |
Passed |
| Native 2.0.5 suite inside Ubuntu/WSL, using a temporary Linux
filesystem root | Passed |
| Server tests (after CI follow-up) | 500 passed, 2 skipped |
| UI store tests | 441 passed |
| Electron native tests | 194 passed, 4 skipped |
| UI/server/Electron typechecks | Passed |
| UI/server and Electron production builds | Passed |
| Windows Tauri release executable (`--no-bundle`) | Passed |
| Electron/Tauri packaged-resource smoke checks | Passed |
| Desktop packaging invariants | 4 passed |
| `git diff --check` | Passed |

The native matrix exercises the actual shared connection, generated
client, UI fetch adapter and guarded proxy: voice-off/on instructions,
prompts, commands, session Shell, background Shell output
cursors/removal, UI/Yolo permission acceptance and rejection, busy inbox
delivery/cancellation, interrupt/wait, staged revert clearing,
session/global/worktree Forms, native pagination, export/import,
same-directory legacy identities, scoped events, foreign authority
refusal and exact rollback.

Pruning coverage includes actual storage identity and execution claims,
busy refusal, idempotency, competing admission, next-model payload, fork
isolation, pre-compaction history, restart, backend presence
disposal/reopening and crash expiry. Rendered tests cover
individual/group/response/session cleanup, confirmation counts,
persistence and reload.

## Autonomous gatekeeper review

Review/fix/retest loops concluded with no remaining actionable findings
in the reviewed transport/lifecycle/proxy,
identity/UI/events/pruning/rollback, scripts/CI and rendered-fixture
scopes.

Corrections included dispatch-generation races, compaction admission
normalization, independent negotiation cancellation, first-request
profile resolution, preservation of streamed 401 envelopes and direct
Shell/PTY identity propagation. A final rendered failure was traced to
the fixture awaiting only the first RPC of a cross-message deletion; the
fixture and regression now await every affected message. Production
deletion guards were not relaxed.

This scoped approval does not close the separately preserved historical
architecture findings.

## Validation boundaries

### CI follow-up

The first run on `a0c1c943`
([35142559235](https://github.com/NeuralNomadsAI/CodeNomad/actions/runs/35142559235))
failed in five native jobs. The local bundle tests had missed the
standalone npm archive's missing sibling import, and Windows legacy jobs
exposed a short-path versus canonical-path project comparison. The
dependent artifact-comment job reported that same build failure.

The follow-up makes the plugin's identity primitives self-contained,
adds an isolated npm-file-list regression for all exported entrypoints,
and corrects project identity selection with alias and nested-repository
regressions. The packed-plugin failure was reproduced before correction;
the corrected installed package passes the native suite on Windows 2.0.4
and Linux/WSL 2.0.4/2.0.5. The corrected 2.0.4 shipped bundle also
passes rendered/native pruning. Fresh full beta-19271 and 2.0.3
`--legacy-pruning` suites pass under a reproducing Windows short-path
TEMP root after the final exact-directory fix. Independent final reviews
approve packaging/documentation and worktree identity with zero
actionable findings. Remote checks on the new head remain the CI
authority; these are local follow-up results.

- Full interaction with the installed desktop application through
Developer Mode was not verified because Developer Mode is inactive. The
release executable and packaged-resource checks above are build/smoke
evidence, not a fresh-install interactive certification.
- Remote run
[35146390688](https://github.com/NeuralNomadsAI/CodeNomad/actions/runs/35146390688)
at `486e856d` passes all runtime-contract jobs, Windows/Linux native
pruning, service compatibility, general tests and both Tauri checks.
macOS passes packed-plugin loading/pruning, then times out on late
bundle discovery. The fixture now canonicalizes its root before daemon
startup to align `/var` configuration paths with `/private/var` FSEvents
paths. Late installation remains mandatory and asserts the plugin was
initially absent; failures now upload isolated diagnostic
logs/inventory/captures. Actual macOS confirmation remains pending on
the new head.
- Interactive native TUI validation was not performed.
- The passing WSL result is Linux-native execution inside WSL, not a
complete Windows-host/WSL desktop traversal. With the fixture's
configuration directory under `/mnt/c`, conversation/proxy checks passed
but late plugin discovery timed out; the otherwise equivalent
Linux-filesystem run passed. Mounted-configuration late discovery
remains a documented environment limitation.
- Other audited publications are declaration-reviewed, not individually
native-certified. The four-runtime matrix does not imply universal V2
compatibility.
- Earlier PR artifacts do not contain the completed cross-runtime
implementation; use artifacts built from the updated head. Local passing
results do not imply that the updated remote CI has completed.
2026-09-16 23:48:08 +02:00
Pascal André
1fbd043ae2
V2(ui): progressively harmonize the CodeNomad interface (#667)
## Summary

- Harmonizes tabs, session hierarchy, messages, tools, timeline and
panels with shared compact styling and scrollbars. Chrome stays square;
switches and badges use the requested rounded shapes.
- Adds 17 built-in palettes (10 dark, 7 light), calibrated to the saved
colors. Auto follows the system, with a remembered palette per
appearance and editable presets.
- Compacts General preferences: language first, palette menu and actions
beside two rows of half-height swatches. Composer selectors share one
responsive footer.
- Preserves Chat ordering, keyboard/touch/RTL behavior, localization and
native OpenCode V2 integration.

## Validation

Latest UI pass: typecheck/build, 60 palette/theme tests, two appearance
browser tests covering all 17 palettes, five tab tests including
Electron, and 24 locale/width/appearance combinations. Final
implementation gatekeeper: no findings.
[Details](24b269a7af/dev-docs/SAVED_PALETTE_CALIBRATION_2026-09-11.md).

<!-- ui-harmonization-demo:start -->
## Palettes

Captured **12 September 2026** · native Tauri · English interface · five
projects open. Click a thumbnail for the **1584 × 1031** original.
[Gallery](24b269a7af/dev-docs/ui-harmonization-demo).

### Dark

| | | |
| --- | --- | --- |
| **Classic**<br>[<img
src="https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/01-classic.png"
alt="Classic dark"
width="240">](https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/01-classic.png)
| **Mist**<br>[<img
src="https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/02-mist.png"
alt="Mist dark"
width="240">](https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/02-mist.png)
| **Slate**<br>[<img
src="https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/03-slate.png"
alt="Slate dark"
width="240">](https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/03-slate.png)
|
| **Clay**<br>[<img
src="https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/04-clay.png"
alt="Clay dark"
width="240">](https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/04-clay.png)
| **Sage**<br>[<img
src="https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/05-sage.png"
alt="Sage dark"
width="240">](https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/05-sage.png)
| **Basalt**<br>[<img
src="https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/06-basalt.png"
alt="Basalt"
width="240">](https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/06-basalt.png)
|
| **Fjord**<br>[<img
src="https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/07-fjord.png"
alt="Fjord"
width="240">](https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/07-fjord.png)
| **Lichen**<br>[<img
src="https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/08-lichen.png"
alt="Lichen"
width="240">](https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/08-lichen.png)
| **Velvet**<br>[<img
src="https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/09-velvet.png"
alt="Velvet"
width="240">](https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/09-velvet.png)
|
| **Ember**<br>[<img
src="https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/10-ember.png"
alt="Ember"
width="240">](https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/10-ember.png)
| | |

### Light

| | | |
| --- | --- | --- |
| **Classic**<br>[<img
src="https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/11-light.png"
alt="Classic light"
width="240">](https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/11-light.png)
| **Mist**<br>[<img
src="https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/12-porcelain.png"
alt="Mist light"
width="240">](https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/12-porcelain.png)
| **Slate**<br>[<img
src="https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/13-dawn.png"
alt="Slate light"
width="240">](https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/13-dawn.png)
|
| **Clay**<br>[<img
src="https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/14-parchment.png"
alt="Clay light"
width="240">](https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/14-parchment.png)
| **Linen**<br>[<img
src="https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/15-linen.png"
alt="Linen"
width="240">](https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/15-linen.png)
| **Iris**<br>[<img
src="https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/16-iris.png"
alt="Iris"
width="240">](https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/16-iris.png)
|
| **Sage**<br>[<img
src="https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/17-sage-light.png"
alt="Sage light"
width="240">](https://raw.githubusercontent.com/NeuralNomadsAI/CodeNomad/24b269a7af2f182bb2b8415c099aa0a20d7e3584/dev-docs/ui-harmonization-demo/17-sage-light.png)
| | |
<!-- ui-harmonization-demo:end -->

**Awaiting final visual approval; do not merge.**
2026-09-15 14:17:30 +01:00
Pascal André
ea37f97bea
feat(pruning): restore opt-in selective deletion through native plugin RPC (#686)
## Summary

Restore selective deletion of completed assistant tool/reasoning content
after OpenCode removed `session.messageUpdate`, without forking OpenCode
or opening a generic RPC proxy.

The original draft's unconditional `maintenance_required` stub is
replaced by a working **experimental, explicit opt-in** plugin path for
the audited `0.0.0-beta-19419` runtime. The default remains read-only.
Unknown runtimes/storage and active native execution fail closed.
Nothing is installed or enabled on app startup.

## Implementation

- Keep individual/message/group/session cleanup entry points. Send
selected technical indices and a canonical SHA-256 revision, never
arbitrary replacement content, SQL, database filenames or
caller-selected locations.
- Use an ownership-checked CodeNomad broker with a fixed RPC
ID/method/location and worktree-deletion fence. Keep the removed PATCH
and generic RPC routes blocked.
- Bind the plugin's explicitly configured database connection to the
actual daemon DB with a fresh `ctx.storage` challenge. Inside a
synchronous SQLite write transaction, recheck
directory/project/workspace ownership, native durable execution claim,
staged revert/compaction state, event ownership and retained payloads.
- Rely on the audited native **write-ahead execution claim before runner
history reads**, not an `idle` check, plugin mutex or `BEGIN IMMEDIATE`
alone. Never set or release the native claim ourselves.
- CAS only the completed assistant's content array. Preserve IDs,
ordering, text, snapshots, usage and metadata. Commit a content-free
idempotency receipt atomically with the change; identical retries cannot
delete a second shifted block.
- Emit the custom invalidation after commit. Re-read via the native API,
invalidate the SDK transcript and pending rotations, and fence late
reads against newer invalidations. Add a public-API TUI cache companion
and reconnect handling.
- Correct native Windows path encoding; support more than 4,096 selected
parts within explicit request/message budgets.
- Provide an independently packable plugin with main and `./tui`
entrypoints, deployment/safety docs, and a Windows/Linux/macOS native
package CI matrix. Plugin installation remains manual and separately
approved.

## Validation performed locally

| Check | Result |
|---|---|
| Server/plugin/SQLite/broker/proxy tests | 72 passed |
| UI actions, events, SDK projection and stale-read tests | 60 passed |
| Plugin/SQLite/TUI-companion tests under Node 22 | 30 passed |
| Server and UI TypeScript checks | Passed |
| Production UI build | Passed; existing large-chunk warnings |
| Official Windows x64 beta-19419 executable | Passed on a private
daemon and generated DB |
| Independently packed and installed plugin | Same native test passed,
outside the checkout |

The native integration test uses the real beta-19271 network client
against the official beta-19419 runtime, with a local synthetic provider
and no credentials. It verifies actual preview/prune RPC, refusal while
a primary generation holds the native claim, both prompt/transaction
orderings, idempotent retry, two event subscribers, native re-reading,
the subsequent primary model payload, fork isolation, pre-compaction
history without summary changes, and persistence after server restart.

The new three-OS native CI matrix must pass on this head before merge.
No CI result is inferred from the local Windows run.

## Boundaries and remaining validation

- This is a reviewable opt-in implementation, **not general availability
across OpenCode versions/providers/platforms**. Exact runtime gating is
intentional; don't widen it without re-auditing/testing.
- Interactive official TUI, two native CodeNomad windows/scroll
behavior, WSL, provider-specific continuation state and budget/token
estimates are not claimed as validated. TUI companion tests use its
cache contract, not an interactive terminal. Two HTTP subscribers are
not two GUI windows.
- Existing bulk cleanup is per-message and reports failure counts;
dedicated installation/capability and bulk progress/cancel UI are not
added here.
- Existing summaries/native checkpoints, fork copies and already
assembled/sent requests are not retroactively scrubbed. Historical usage
remains historical usage; mock token values are not a token-savings
measurement.
- This changes persisted V2 content, not only visibility. It frees
reusable SQLite pages but does **not** promise a smaller physical file.
No VACUUM, V1 cleanup, durable-event rewriting, automatic backup
restoration or universal repair is included.
- No active user DB was changed, no shared-daemon plugin installed, no
shared OpenCode service stopped/upgraded, and no native desktop
executable/profile rebuilt or replaced. Tests use isolated synthetic
data only.

## Documentation

- [Request flow and validation](dev-docs/SESSION_PRUNING_RPC.md)
- [Audited safety boundary](dev-docs/SESSION_PRUNING_SAFETY.md)
- [Explicit deployment and
recovery](dev-docs/SESSION_PRUNING_DEPLOYMENT.md)

References: anomalyco/opencode#44984, anomalyco/opencode#48043,
anomalyco/opencode#48090 and the maintainer's plugin/RPC direction. No
upstream API or distribution fork is introduced.
2026-09-10 13:31:40 +02:00
Pascal André
52f0e62935
feat(opencode): migrate CodeNomad to native V2 (#647)
# OpenCode V2 Migration and Desktop Restructuring

## Summary

This branch replaces CodeNomad's OpenCode V1 SDK, custom plugin, and
per-workspace runtime architecture with the native OpenCode V2 client
and one shared OpenCode service. It intentionally ships no V1 runtime
fallback.

The scope includes native location ownership, Forms and Shell resources,
project-wide cursor pagination, bounded resident message windows,
streaming reconciliation, duplicate-folder instances, multi-window
Electron/Tauri behavior, content-addressed restore, worktree mutation
fencing, and reproducible desktop packaging.

The reviewed implementation head is `dea20996`. UI and server resolve
`@opencode-ai/client@beta` to `beta-18999`; the runtime CLI is managed
independently. The official comparison baseline remains `upstream/beta`
at `eb1ac54d73`.

Full details: [`MIGRATION_V2.md`](./MIGRATION_V2.md),
[`DESKTOP_V2_COMPARISON.md`](./DESKTOP_V2_COMPARISON.md), and
[`dev-docs/DEV_V2_CODE_REDUCTION.md`](./dev-docs/DEV_V2_CODE_REDUCTION.md).

## Stabilization Fixes

- Preserve manual scroll escape across pagination, remote updates,
capped-window shifts, tab changes, and desktop restore; only a local
prompt submission forces the bottom.
- Keep the timeline resident window capped at 200 messages. Ordered
window slides use Virtua shift, while reorder, pagination, and
non-aligned replacement remount with a fresh measurement epoch.
- Finalize the temporary `200 -> 201 -> 200` transition in a
generation-guarded microtask before paint and compensate followed
content growth from a `ResizeObserver` attached to the mounted Virtua
root.
- Keep all pending inbox prompts after delivered transcript messages in
native inbox admission order.
- Add a persisted `steer`/`queue` follow-up preference; the alternate
shortcut uses the inverse while idle sends remain `steer`.
- Edit a pending prompt only after authoritative inbox cancellation
succeeds, then restore its text, structured payload, files, and agent
references to the composer.
- Expose native `session.background` through the ownership-checked
proxy, a prompt action, and `Ctrl/Cmd+B`.
- Remove the duplicate model-selector "show all" action and make the
favorites toggle label reflect its current action.
- Restore permission/Form synchronization plus skill, reference,
MCP-resource, and websearch-provider reads in the reviewed proxy
allowlist.
- Validate and preserve native location workspace identities for
root/worktree requests, session moves/imports, cursors, and global
Forms.

## Capability Decisions

| Capability | Native V2 availability | CodeNomad `DEV-v2` decision |
Revisit or complete when |
| --- | --- | --- | --- |
| Assistant content mutation | `session.messageUpdate` authoritatively
replaces the text, reasoning, and tool content of a completed assistant
message. There is still no generic deletion of a complete delivered
message or mutation of user messages. | Restores individual
tool/reasoning deletion through the native update route. Arbitrary
whole-message deletion remains absent rather than locally simulated. |
Add broader deletion only if V2 exposes an authoritative operation for
the required message type. |
| Bulk tool and reasoning cleanup | No native bulk operation, but
`session.messageUpdate` can safely compose cleanup one assistant message
at a time. | Restores selected-group and full-session technical-part
cleanup through authoritative per-message updates. | A native bulk
operation is only needed if per-message updates become a measured
performance problem. |
| Delete-to-boundary / undo | `session.revert.stage` and
`session.revert.clear` use V2 staged-revert semantics instead of
arbitrary deletion. | Command-palette Undo uses `revert.stage`; Redo
clears the staged revert through `revert.clear`. | Revisit only if V2
adds broader authoritative transcript deletion. |
| Compaction | Native checkpoint compaction summarizes the older head
and retains a server-selected recent tail controlled by
`compaction.keep.tokens`. | Uses `session.compact`; there is no
message-level selective compaction. CodeNomad displays the partial
summary through the same reactive streaming path as text and reasoning,
then replaces it with the terminal summary. | Add scoped controls only
if V2 defines scoped compaction semantics. |
| Transcript pagination authority | Message pages expose only opaque
previous/next cursors. They provide no transcript revision, total,
absolute range, position, or random seek target. | Uses bounded cursor
traversal and a 200-message resident window, with defensive
reconciliation after destructive events. It cannot prove that pages
loaded across compaction or revert belong to one snapshot. | V2 adds
snapshot revision authority
([#43766](https://github.com/anomalyco/opencode/issues/43766)) and
navigable position metadata
([#44660](https://github.com/anomalyco/opencode/issues/44660)). |
| Full-session search | `session.list(search)` filters session titles
only. There is no server transcript-search endpoint returning message
identity, excerpt, navigable position, and transcript revision. |
Retained through exhaustive message-cursor traversal while keeping only
the 200-message resident window and collected matches. Large searches
still fetch every page. | V2 exposes transcript search
([#45801](https://github.com/anomalyco/opencode/issues/45801)) with a
target that composes with transcript revision and seek metadata. |
| Queued prompt management | Native inbox list, cancel, steer, and queue
operations cover authoritative follow-up delivery. The TUI's edit action
cancels a queued prompt before restoring it to the composer; it is not
an atomic inbox update. | Implements persisted primary `steer`/`queue`
delivery, inverse alternate shortcut, delivery switching, cancellation,
cancel-first composer restoration with structured payload retention, and
native-order timeline projection. | Revisit atomic editing or reordering
only if V2 adds an authoritative operation and a concrete product need
is established. |
| Background execution | Native `session.background` moves blocking
tools out of the foreground; Shell resources separately support listing,
bounded output, and removal. | Exposes `session.background` through the
proxy and UI with `Ctrl/Cmd+B`, and replaces the custom process manager
with native Shells. Unsupported controls such as rename remain removed.
| Add controls only when the native session or Shell APIs support them.
|
| Service lifecycle | V2 uses one shared externally owned service rather
than one runtime per workspace. | CodeNomad discovers or starts the
service. Stop Workspace evicts the native location after its final
logical owner is removed; application shutdown never stops the daemon. |
No parity work planned unless V2 changes service ownership semantics. |

## Validation

Migration gate (`878550ca`):

- UI and server TypeScript typechecks.
- 86 focused UI tests covering follow, pagination, queue ordering,
bottom pinning, shortcuts, delivery resolution, and model visibility.
- 64 focused server tests covering proxy ownership/location enforcement
and shared-service workspace identity.
- Production UI/server build.
- Tauri `cargo check` and all 121 Rust tests.
- `git diff --check`.

Timeline stabilization (`dea20996`):

- UI TypeScript typecheck and all 68 focused timeline, pagination,
request-authority, and restore tests.
- Tauri release build against the `beta-18999` lock.
- Native Developer Mode validation: no remount or empty frame during
capped shifts, same-cycle growth compensation, preserved manual escape,
and inactive-tab anchor restore within 0.3125 px.

## Remaining Gaps

- Active-session-location authority for MCP/plugin status.
- Optional interactive PTY, session export, and reference/MCP-resource
attachment UI.
- Desktop release signing/notarization hardening.
2026-09-04 11:36:11 +01:00