Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 15 additions & 27 deletions .github/workflows/pr-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ jobs:
New-Item -ItemType Directory -Force $sandbox | Out-Null
$package = npm pack ./packages/server/src/opencode/session-pruning --pack-destination $sandbox --json | ConvertFrom-Json
if ($LASTEXITCODE) { exit $LASTEXITCODE }
npm install --prefix $sandbox (Join-Path $sandbox $package.filename) '@opencode/cli@2.0.4' --ignore-scripts --no-audit --no-fund
npm install --prefix $sandbox (Join-Path $sandbox $package.filename) '@opencode/cli@latest' --ignore-scripts --no-audit --no-fund
if ($LASTEXITCODE) { exit $LASTEXITCODE }
"PRUNING_NATIVE_INSTALL=$sandbox" >> $env:GITHUB_ENV
- name: Test the installed plugin with an isolated official runtime
Expand All @@ -101,6 +101,8 @@ jobs:
$arch = node -p "process.arch"
$extension = node -p "process.platform === 'win32' ? '.exe' : ''"
$cli = Join-Path $env:PRUNING_NATIVE_INSTALL "node_modules/@opencode/cli-$platform-$arch/bin/opencode$extension"
& $cli --version
if ($LASTEXITCODE) { exit $LASTEXITCODE }
$plugin = Join-Path $env:PRUNING_NATIVE_INSTALL 'node_modules/@neuralnomads/codenomad-session-pruning'
$fixtures = node -p "require('node:path').join(require('node:fs').realpathSync(require('node:os').tmpdir()), 'opencode')"
"PRUNING_NATIVE_FIXTURES=$fixtures" >> $env:GITHUB_ENV
Expand Down Expand Up @@ -137,22 +139,6 @@ jobs:
if: ${{ needs.authorize.outputs.allowed == 'true' && !github.event.pull_request.draft }}
runs-on: windows-latest
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
include:
- version: 0.0.0-beta-19271
scope: '@opencode-ai'
binary: opencode2
- version: 2.0.3
scope: '@opencode'
binary: opencode
- version: 2.0.5
scope: '@opencode'
binary: opencode
- version: 2.0.7
scope: '@opencode'
binary: opencode
steps:
- uses: actions/checkout@v4
with:
Expand All @@ -164,24 +150,23 @@ jobs:
- run: npm ci --ignore-scripts
- run: npm run build:pruning --workspace @neuralnomads/codenomad
- run: npm run build:automation --workspace @neuralnomads/codenomad
- name: Cross the pinned client with an isolated runtime
- name: Qualify the pinned client against the latest stable runtime
shell: pwsh
env:
RUNTIME_VERSION: ${{ matrix.version }}
RUNTIME_SCOPE: ${{ matrix.scope }}
RUNTIME_BINARY: ${{ matrix.binary }}
run: |
$sandbox = Join-Path $env:RUNNER_TEMP 'opencode-contract-runtime'
npm install --prefix $sandbox "$env:RUNTIME_SCOPE/cli@$env:RUNTIME_VERSION" --ignore-scripts --no-audit --no-fund
npm install --prefix $sandbox '@opencode/cli@latest' --ignore-scripts --no-audit --no-fund
if ($LASTEXITCODE) { exit $LASTEXITCODE }
$cli = Join-Path $sandbox 'node_modules/@opencode/cli-windows-x64/bin/opencode.exe'
& $cli --version
if ($LASTEXITCODE) { exit $LASTEXITCODE }
$cli = Join-Path $sandbox "node_modules/$env:RUNTIME_SCOPE/cli-windows-x64/bin/$env:RUNTIME_BINARY.exe"
node scripts/test-automation-native.mjs $cli
if ($LASTEXITCODE) { exit $LASTEXITCODE }
node scripts/test-session-pruning-native.mjs $cli
if ($LASTEXITCODE) { exit $LASTEXITCODE }
if ($env:RUNTIME_VERSION -eq '0.0.0-beta-19271' -or $env:RUNTIME_VERSION -eq '2.0.3') {
node scripts/test-session-pruning-native.mjs $cli --legacy-pruning
}
node scripts/test-session-environment-native.mjs $cli
if ($LASTEXITCODE) { exit $LASTEXITCODE }
node scripts/test-session-fork-native.mjs $cli
if ($LASTEXITCODE) { exit $LASTEXITCODE }

tests:
needs: authorize
Expand Down Expand Up @@ -260,6 +245,7 @@ jobs:
packages/ui/src/lib/clipboard.test.ts
packages/ui/src/lib/message-selection-position.test.ts
packages/ui/src/lib/model-visibility.test.ts
packages/ui/src/lib/provider-auth.test.ts
packages/ui/src/lib/native/browser.test.ts
packages/ui/src/lib/runtime-env.test.ts
packages/ui/src/lib/server-meta.test.ts
Expand Down Expand Up @@ -308,6 +294,7 @@ jobs:
packages/ui/src/stores/forms.test.ts
packages/ui/src/stores/instances-restore-ownership.test.ts
packages/ui/src/stores/opencode-data.test.ts
packages/ui/src/stores/opencode-data-settlement.test.ts
packages/ui/src/stores/message-v2/empty-content.test.ts
packages/ui/src/stores/permission-lifecycle.test.ts
packages/ui/src/stores/shell-store-reactivity.test.ts
Expand All @@ -316,6 +303,7 @@ jobs:
packages/ui/src/stores/session-pruning-projection.test.ts
packages/ui/src/stores/session-pruning-pagination.test.ts
packages/ui/src/stores/session-native-events.test.ts
packages/ui/src/stores/runtime-contract.test.ts
packages/ui/src/stores/session-move-restore.test.ts
packages/ui/src/stores/session-request-authority.test.ts
packages/ui/src/stores/session-send-lifecycle.test.ts
Expand Down
2 changes: 1 addition & 1 deletion .opencode/skills/codenomad-architecture-guide/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ description: |

## Native OpenCode V2 Baseline

- Server and UI pin the official `@opencode/client@2.0.4` together; the pruning plugin pins `@opencode/plugin@2.0.4`. Review official V2 docs, installed declarations, generated wire paths and native integration tests when upgrading. The runtime CLI is managed independently and startup has no exact version gate.
- Server and UI pin the official `@opencode/client@2.0.11` together; the pruning plugin pins `@opencode/plugin@2.0.11`. Review official V2 docs, installed declarations, generated wire paths and native integration tests when upgrading. Qualify against the latest published stable runtime. Each CodeNomad release sets its minimum supported OpenCode version to the latest stable available at that CodeNomad release; the minimum stays fixed for that release. Record results in PR/CI logs and update `dev-docs/OPENCODE_V2_COMPATIBILITY.md` in place rather than adding per-version reports. The runtime CLI is managed independently and startup has no exact version gate.
- Do not use `@opencode-ai/sdk`, `@opencode-ai/sdk/v2/client`, or `createOpencodeClient()`; follow installed `@opencode/client` declarations.
- There is no legacy `packages/opencode-plugin/`. Do not restore the V1 compatibility runtime or add general plugin extension points. The narrow integrations are the bundled `codenomad.automation` plugin and bundled session-pruning RPC; see `dev-docs/DEVELOPER_MODE.md`, `dev-docs/BROWSER_AUTOMATION.md` and `dev-docs/SESSION_PRUNING_RPC.md`. All automation tools follow backend presence without a Developer Mode gate, sharing the authenticated native transport and execution-time session/window fences.
- The server uses the selected host or WSL CLI's official `service status`, `service start`, and `service get password` lifecycle to connect to one externally owned global OpenCode daemon. It owns no private port/database/registration/PID and never stops the daemon on backend shutdown. WSL requires Windows localhost forwarding and uses no cross-namespace PID operations.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Client-state V3 is a per-window envelope over the V2 content-addressed partition

| Owner | Responsibilities | Main paths |
|---|---|---|
| OpenCode V2 | Sessions, messages, permissions, Forms, files, session Shell/instructions, background Shells, interactive PTYs | pinned stable `@opencode/client@2.0.4` contract across server and UI |
| OpenCode V2 | Sessions, messages, permissions, Forms, files, session Shell/instructions, background Shells, interactive PTYs | pinned stable `@opencode/client@2.0.11` contract across server and UI |
| CodeNomad server | Shared service lifecycle, locations, proxy authorization, Git mutations, Yolo, auth, storage, speech, SSE multiplexing, Developer Mode bridge | `packages/server/src/` |
| CodeNomad UI | Generated Promise clients, state reconciliation, interaction and rendering | `packages/ui/src/` |
| Desktop hosts | Start CodeNomad and provide native OS integration | `packages/electron-app/`, `packages/tauri-app/` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Package

CodeNomad server and UI pin `@opencode/client@2.0.4`. The runtime CLI is managed independently; startup validates authenticated loopback `/api/status`, then `/api/health`, then `/api/info`, advancing only on HTTP 404 with the same endpoint, credentials and deadline. Each response has its own validated schema and a 64 KiB bound. The shared transport maps canonical `server.status()` to the discovered route. Discovery does not prove compatibility for other APIs. Review official V2 docs, installed declarations, generated routes and native regression tests together when upgrading.
CodeNomad server and UI pin `@opencode/client@2.0.11`. The runtime CLI is managed independently; startup validates authenticated loopback `/api/status`, then `/api/health`, then `/api/info`, advancing only on HTTP 404 with the same endpoint, credentials and deadline. Each response has its own validated schema and a 64 KiB bound. The shared transport maps canonical `server.info()` to the discovered route. Older services do not expose `paths.tmp`; consumers may use only the metadata actually provided. Discovery does not prove compatibility for other APIs. Review official V2 docs, installed declarations, generated routes and native regression tests together when upgrading.

Cross-runtime adaptation lives in `packages/server/src/opencode/compatibility/`. The shared connection binds authenticated runtime identity, the canonical client and forwarding transport. Known published contracts select their serializer directly; unknown versions require authenticated bounded OpenAPI recognition before calls. Never add operation-specific retry fallbacks in UI stores or Yolo. See `dev-docs/OPENCODE_V2_COMPATIBILITY.md` for the evidence matrix and maintained issue register.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Contract

- Server and UI pin `@opencode/client@2.0.4`. Manage the runtime CLI independently: startup checks authenticated loopback `/api/status`, then `/api/health`, then `/api/info`, advancing only on HTTP 404. All probes share the endpoint, credentials, 64 KiB response bound and absolute deadline; authentication, transport and malformed response failures do not trigger fallback. The shared transport maps canonical `server.status()` to the discovered route. Discovery alone does not prove client/API compatibility. Review documentation, installed declarations and proxy/API parity whenever the client contract changes.
- Server and UI pin `@opencode/client@2.0.11`. Manage the runtime CLI independently: startup checks authenticated loopback `/api/status`, then `/api/health`, then `/api/info`, advancing only on HTTP 404. All probes share the endpoint, credentials, 64 KiB response bound and absolute deadline; authentication, transport and malformed response failures do not trigger fallback. The shared transport maps canonical `server.info()` to the discovered route. Older services do not provide `paths.tmp`; never infer that path from the backend host. Discovery alone does not prove client/API compatibility. Review documentation, installed declarations and proxy/API parity whenever the client contract changes.
- The package root is the generated zero-Effect Promise client. Use installed declarations, not current public `@opencode-ai/sdk` examples.
- Native routes are `/api/*`; CodeNomad exposes them only through the authorized `/workspaces/:id/instance` proxy.
- That proxy is an explicit method/path allowlist. Future upstream APIs are not exposed automatically.
Expand Down
9 changes: 8 additions & 1 deletion MIGRATION_V2.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,21 @@ This branch replaces CodeNomad's OpenCode V1 SDK, custom plugin, and per-workspa

The work grew beyond an SDK swap. It also introduces location-based ownership, native Forms and Shell resources, project-wide session pagination, reconnect reconciliation, bounded virtualized timelines, multi-window desktop state, and a content-addressed restore format.

Server and UI pin the official `@opencode/client@2.0.4`; the bundled pruning plugin pins `@opencode/plugin@2.0.4`. Upgrade the client, plugin and lock together using official V2 documentation, installed declarations and generated wire paths. The runtime CLI is independently managed: production startup validates authenticated `/api/status` (`version`, `pid`, `urls`), falling back only on HTTP 404 to the earlier V2 `/api/health` contract (`healthy: true`, `version`, positive `pid`). Both probes share the endpoint, credentials, response-size bound and absolute deadline. There is no exact version gate. Discovery compatibility alone does not establish compatibility for the remaining client APIs. The older beta reviews below are historical.
Server and UI pin the official `@opencode/client@2.0.11`; the bundled pruning plugin pins `@opencode/plugin@2.0.11`. Upgrade the client, plugin and lock together using official V2 documentation, installed declarations and generated wire paths. The runtime CLI is independently managed: production startup validates authenticated `/api/status`, then `/api/health`, then `/api/info`, advancing only on HTTP 404. All probes share the endpoint, credentials, response-size bound and absolute deadline. Canonical `server.info()` follows the discovered route. There is no exact version gate. Discovery compatibility alone does not establish compatibility for the remaining client APIs. The older beta reviews below are historical.

The incremental comparison with official OpenCode Desktop V2, including closed findings and remaining gaps, is recorded in [`DESKTOP_V2_COMPARISON.md`](DESKTOP_V2_COMPARISON.md).

The current cross-version issue register, published API-change timeline and connection-scoped compatibility architecture are maintained in [`dev-docs/OPENCODE_V2_COMPATIBILITY.md`](dev-docs/OPENCODE_V2_COMPATIBILITY.md). The server integration module adapts earlier V2 requests/responses for both the guarded UI proxy and direct server callers; native regression runs cross the pinned client with beta-19271, 2.0.3, 2.0.4 and 2.0.5. Discovery success alone does not certify an older runtime's conversation, event or pruning contract.

## Native V2 Adoption

Qualification targets the latest published stable runtime. Maintain the
[shared compatibility reference](dev-docs/OPENCODE_V2_COMPATIBILITY.md) in place;
keep detailed acceptance results in PRs and CI logs.
Each CodeNomad release sets its minimum supported OpenCode version to the latest
stable available when that CodeNomad release is published. Record that minimum
in the release notes and keep it fixed for that release.

### Stable 2.0.4 contract (PR #695)

The former `@opencode-ai/client` beta contract cannot load normal sessions from a fresh 2.0.4 daemon. Fixing discovery alone is insufficient. This migration updates the server, UI, pruning plugin and guarded proxy together:
Expand Down
17 changes: 17 additions & 0 deletions dev-docs/OPENCODE_V2_COMPATIBILITY.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
# OpenCode V2 compatibility: audit and implementation roadmap

## Current qualification policy

Qualify against the latest published stable OpenCode runtime (`@opencode/cli@latest`).
For each CodeNomad release, the minimum supported OpenCode version is the latest
stable OpenCode version available at the time of that CodeNomad release. Record
the resolved version in the release notes; that minimum stays fixed for that
CodeNomad release and is reassessed at the next release.

CI records the resolved runtime version. Pin client/plugin dependencies together
to the release target and qualify them before publishing CodeNomad. Retained
compatibility code and historical-data handling do not imply support for older
runtimes. Keep detailed results in the change's PR and CI logs, not in per-version
reports. Update this reference in place.

The audit and implementation record below is historical context, not a runtime
qualification matrix to maintain.

**Audit date:** 2026-09-16. **CodeNomad baseline:** PR #695 at `bcfe4d24`.
**Status:** connection-scoped compatibility is implemented. Autonomous gatekeeper loops approved transport, identity, scripts/CI and rendered-fixture scopes with no remaining actionable findings. The original audit findings below remain as the change rationale; the implementation results section records their current disposition.

Expand Down
Loading
Loading