Skip to content

feat: integration (OpenAPI 3.1, guide), web link in the TUI, launch docs - #13

Merged
malhashemi merged 11 commits into
mainfrom
release-prep-0.3
Sep 26, 2026
Merged

malhashemi merged 11 commits into
mainfrom
release-prep-0.3

Conversation

@malhashemi

Copy link
Copy Markdown
Owner

For integrators

  • The Gateway's HTTP + SSE API as an OpenAPI 3.1 document, generated from the protocol's zod schemas, served at GET /v1/openapi.json and committed at packages/plugin/docs/protocol/openapi.json (checked by the schema drift test; Redocly lint: valid, no warnings).
  • docs/integrating.md: plugin RPC vs the Gateway, auth, being attached so questions and approvals reach your users, a Run from start to finish. Every example was run against a real server.
  • README: a Build on it section and a protocol badge.

TUI

  • The /workflows header links to the web app page for what is on screen; b opens it.

Tests

  • Live-test servers no longer read the machine's plugins (a globally installed copy of this plugin loaded beside the one under test). 26/26 live checks pass on Opus 5.5.

Docs

  • TUI screenshots, install with opencode plugin add, the new keys.

The TUI knew the Gateway's address (from info) but never showed it, so the web
app was only discoverable through tool output. The /workflows header now links
to the web app page for what is on screen (the library, or the Run), and b
opens it in the system browser. The pairing key reads "pair a device".
The live servers read the machine's global config, so a copy of this plugin
installed there (npm, with its own options such as inline: "allow") loaded
beside the one under test and answered some calls: 7 of 26 live checks failed.
Each server now gets a config directory with the global config minus its
plugins. The development guide explains why a checkout and the installed
package must not load in one place.
- the Gateway's HTTP + SSE API as an OpenAPI 3.1 document, built from the
  protocol's zod schemas, served at GET /v1/openapi.json and written to
  docs/protocol/openapi.json (the schema drift test checks it)
- protocol: GatewayInfoOutput, PairInput, PairOutput (additions)
- docs/integrating.md: the two ways in, auth, being attached so questions and
  approvals reach your users, a Run from start to finish over RPC and HTTP
- screenshots of the TUI: a Run, the library, a Unit, the approval panel
- install with opencode plugin add; per-project options override the global
- the new keys (b, approval) and the web app link in the TUI header
- a Build on it section with the protocol, the OpenAPI spec and the guide
Comment thread packages/plugin/src/protocol/openapi.ts Resolved
Comment thread docs/integrating.md Resolved
Comment thread packages/plugin/src/tui/app.tsx Resolved
Comment thread docs/integrating.md Resolved
Comment thread packages/plugin/src/tui/app.tsx Resolved
Comment thread packages/plugin/src/protocol/openapi.ts Resolved
Comment thread packages/plugin/src/tui/views.tsx Resolved
…the browser key

- OpenAPI: reads document a bearer requirement (the loopback exception is in the
  descriptions, which OpenAPI cannot express in security), and the served
  document names the Gateway's real address
- guide: the event is interaction.pending; listen before starting a Run and
  answer interactions that were already pending; library.changed; read tokens
- TUI: the browser opener is detached and a failed open says so; b works in
  the Unit view too
Comment thread packages/plugin/src/tui/views.tsx Resolved
Comment thread docs/integrating.md Resolved
…eraction once

- info reports gateway.web (an addition); the TUI hides its web link and b, and
  tool results drop the Run link, when gateway.web is false
- the guide's example tracks answered interaction ids, so the event and the
  read after startRun never answer the same one twice
Comment thread docs/integrating.md Resolved
Comment thread packages/plugin/src/host/plugin.ts Resolved
…per window

- the Gateway is shared by every location and keeps the settings of the one
  that started it: info.gateway.web and tool-result links follow the running
  Gateway (GatewayHandle.web), not each location's config
- the guide's example attaches with a surface id unique to the window
Comment thread docs/integrating.md Resolved
Comment thread docs/integrating.md Resolved
…loses a Run's end

The example takes the answer from the app's UI (askPerson) instead of a fixed
label, holds events that arrive before startRun returns, and reconciles with
the Run afterwards, so a Run that ends at once is still finished exactly once.
Type-checked against the package and run against a real server: a Workflow
that asks (answered with the chosen label) and one that ends at once.
Comment thread docs/integrating.md Resolved
The heartbeat also re-reads the Run (the same reconcile as after startRun), so
a dropped interaction.pending or run.ended is caught within 20 seconds; exact
recovery with seq/epoch and eventsSince is pointed to. Run against a real server
with the event listener removed entirely: the question was answered and the
Run finished from the re-reads alone.
Comment thread docs/integrating.md Resolved
Comment thread docs/integrating.md Resolved
Comment thread docs/integrating.md Resolved
…ateway

The Gateway kept its tokens in memory, so a token deleted from
gateway-tokens.json kept working until a restart, although the docs said
deleting revokes it. The store now re-reads the file when its modification
time or size changes (one stat per check); a missing or unreadable file grants
nothing. Two tests cover it; both fail on the previous code.

Also: the guide's example retries an answer or the finish that failed, instead
of marking it done before it succeeded.
Comment thread packages/plugin/src/gateway/auth.ts Resolved
Comment thread docs/integrating.md Resolved
Comment thread packages/plugin/src/gateway/auth.ts Resolved
Comment thread docs/integrating.md Resolved
…vokes too

- issue and revoke read, change and replace the token file synchronously, with
  nothing awaited in between, so an edit made meanwhile (a revocation) is never
  overwritten with a stale list
- the change stamp includes ctime and mode, so making the file unreadable
  (chmod 000) revokes its tokens at once; a test covers it and fails on the
  previous code
- guide: native OpenCode forms are answered with OpenCode's form API, not
  replyInteraction; a long-lived app stops its heartbeat and detaches when its
  view closes
@malhashemi
malhashemi merged commit 1da9229 into main Sep 26, 2026
5 checks passed
@malhashemi
malhashemi deleted the release-prep-0.3 branch September 26, 2026 08:16
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.

1 participant