Skip to content

fix: support OpenCode 2.x web app and API (#74) - #75

Open
romor001 wants to merge 1 commit into
mtymek:mainfrom
romor001:fix/opencode-v2-compat
Open

romor001 wants to merge 1 commit into
mtymek:mainfrom
romor001:fix/opencode-v2-compat

Conversation

@romor001

@romor001 romor001 commented Nov 4, 2026

Copy link
Copy Markdown

Problem

Since OpenCode 2.0 the panel never comes up. Opening it shows:

TypeError: Cannot read properties of undefined (reading 'type')
    at Object.current (/_assets/current-*.js:6:44234)
    at Object.fn (/_assets/solid-*.js:1:40792)
    ...

Fixes #74.

Root cause

Three independent 2.x changes, all confirmed against opencode 2.2.5:

  1. Route scheme. The web app's router (_assets/current-*.js) only accepts
    /, /settings, /connect, /components, /new-session and
    /server/<serverKey>/session/<id>. Everything else throws
    Unrecognised route!, which a Solid memo swallows into undefined - and the
    next line does e.type, which is the reported TypeError. The plugin still
    built http://host:port/<base64(vault path)>, the 1.x scheme.
    <serverKey> is the base64url encoding of the server URL.

  2. Authentication. serve now prints a password and every /api/* request
    needs HTTP Basic (opencode:<password>). The old health check
    /global/health does not exist anymore - it falls through to the SPA and
    answers 200 text/html, so "server is running" was a false positive.

  3. Embedding. The web app keeps its server list (url + password) in
    localStorage; without it the panel only shows "Connect to a server". That
    storage is not reachable from an iframe (cross-origin to app://obsidian.md),
    and the pairing-link cookie is SameSite=Lax, so it is never sent from an
    embedded frame either - pairing does not help.

Additionally, fetch from the renderer is CORS-blocked against the server: the
preflight is answered for loopback HTTP origins but carries no
access-control-allow-origin for app://obsidian.md.

Changes

  • src/lib/serverUrl.ts - base64url server key, session URL, Basic auth header.
  • src/lib/http.ts - node:http client, so plugin API calls are not subject to
    the renderer's CORS restrictions.
  • src/ui/embed.ts - webview detection + script that seeds the server
    credential into the web app's localStorage (one reload, no loop).
  • OpenCodeView - embeds the app in an Electron <webview> (Obsidian's main
    window has webviewTag: true), seeds the credential on dom-ready, falls back
    to the old <iframe> with an explanatory note if the webview does not become
    ready.
  • ServerManager - OPENCODE_SERVER_PASSWORD handed to the server, health via
    GET /api/info with auth, URL without the project path segment. A server left
    over from a previous session keeps working because the password is derived from
    host + port.
  • OpenCodeClient - /api/location, POST /api/session with
    location.directory, POST /api/session/<id>/synthetic for context injection
    (v1's hidden-message-part update no longer exists).
  • README note about the 2.x specifics.

Testing

  • bun run build (tsc + esbuild) clean, bun test: 25 pass, 3 skipped
    (Windows-only), 0 fail. tests/serverUrl.test.ts is new; the
    ServerManager tests now start a real 2.2.5 server and authenticate against
    /api/info.
  • Manual: Obsidian 1.15.0 on macOS, opencode 2.2.5. Panel opens, the session for
    the vault renders, @-mention completion only lists files of that vault, and a
    message round-trips to the model. Before/after screenshots available on
    request.

Compatibility

No behaviour change for existing users: the plugin still starts its own
opencode serve per vault on the configured port. It just speaks the 2.x
protocol now. A follow-up PR will propose attaching to the shared service that
2.x is designed around; that one changes defaults and is out of scope here.

OpenCode 2 replaced the per-project URL scheme and added authentication,
which made the panel fail with "Cannot read properties of undefined
(reading 'type')" (mtymek#74).

- Server: pass OPENCODE_SERVER_PASSWORD and authenticate /api/* with HTTP
  Basic; probe /api/info instead of the removed /global/health.
- URLs: open sessions at <server>/server/<base64url(server)>/session/<id>
  instead of <server>/<base64-directory>, which is no longer a route.
- Embed: use an Electron <webview> and seed the server credential into the
  web app's localStorage (server pairings are client-side; the pairing-link
  cookie is SameSite=Lax and never sent from an iframe).
- API: talk to the server through node:http; renderer fetch is CORS-blocked
  because OpenCode sends no allow-origin header for app://obsidian.md.
- Client: /api/location, /api/session with location.directory and
  /api/session/<id>/synthetic for context injection.

Closes mtymek#74
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

It seems the Obsidian OpenCode plugin is incompatible with OpenCode 2.0 and above.

1 participant