@ai-setting/opencode-cli
v0.1.9
Published
Minimal CLI to talk to an opencode server (HTTP + SSE)
Readme
opencode-cli
Minimal CLI to talk to an opencode server over HTTP + SSE. Zero npm dependencies — pure TypeScript, runs with Bun.
Why
The official opencode server exposes its HTTP API directly. This CLI gives you a
one-shot prompt "1+1=?" from your shell, without spinning up the TUI or
writing a custom integration. Targets opencode 1.18.x (verified on
1.18.35).
Install
bun install
bun link # optional — exposes `opencode-cli` in PATH
# OR run directly:
bun src/cli.ts ...Requires Bun ≥ 1.3.
Usage
opencode-cli health [--port X] [--host H] [--base-url URL] [--json]
opencode-cli session new [--base-url URL] [--json]
opencode-cli session list [--base-url URL] [--json]
opencode-cli session show <id> [--base-url URL] [--json]
opencode-cli session messages <id> [--base-url URL] [--json]
opencode-cli prompt <text>... [--base-url URL] [--port X] [--session ID]
[--stream] [--json]Default base URL: http://localhost:4096. Override with --base-url,
--port + --host, or the env var OPENCODE_BASE_URL.
Examples
# Health
opencode-cli health
# → {"healthy":true,"version":"1.18.35"}
# Quick prompt (synchronous, v3 endpoint)
opencode-cli prompt "1+1=?"
# → 2
# Streamed output (best-effort SSE; falls back to sync if SSE unavailable)
opencode-cli prompt --stream "explain quicksort in one paragraph"
# Reuse a session
opencode-cli prompt --session ses_xxx "continue the previous answer"
# JSON output (for piping into jq)
opencode-cli session list --json | jq '.[].id'
# Talk to a remote server
opencode-cli --base-url http://box.local:4096 prompt "hello"Endpoints (opencode v3)
| Method | Path | Used by |
| ------ | -------------------------- | ------------------------------------ |
| GET | /global/health | health |
| POST | /session | session new, prompt auto-create |
| GET | /session | session list |
| GET | /session/{id} | session show |
| GET | /session/{id}/message | session messages |
| POST | /session/{id}/message | prompt (sync) |
| GET | /session/{id}/event | prompt --stream (best-effort SSE) |
The prompt command uses the synchronous /session/{id}/message endpoint by
default — returns the full assistant message with info.finish and parts[].
When --stream is set, the CLI also opens the SSE stream and incrementally
writes new text to stdout; if the server's SSE endpoint is unavailable (e.g.
returns the SPA fallback HTML), the CLI gracefully degrades to the sync result.
Tests
# Unit tests (default, no server needed)
bun test src/
# End-to-end (requires running opencode server on http://127.0.0.1:4096)
OPENCODE_E2E=1 bun test src/The e2e suite sends Reply with the single word: pong (sync) and
Reply with the single word: stream-ok (stream) and asserts a non-empty
response with finish === "stop" / "session.idle".
Error handling
- Non-2xx HTTP responses throw with status code + body preview
info.finish === "error"or non-nullinfo.errorthrows with the server message- Stream timeouts are not imposed by the CLI; it waits for the opencode server response (v2 poll + SSE 自然终止:assistant+idle / session.execution.succeeded) until completion — stop a stuck request with Ctrl+C
- Exit code is
0on success,1on prompt/stream failure,2on argument errors
Development
bun test src/ --parallel 4 # fast feedback
OPENCODE_E2E=1 bun test src/ # with real server
bun src/cli.ts --helpFiles:
src/client.ts— HTTP client (zero deps, fetch-injectable)src/sse.ts— SSE block / buffer / stream parsersrc/prompt.ts—sendPrompt(client, text, opts)orchestrationsrc/cli.ts— argv parser + dispatch + main entry (bun src/cli.ts)src/*.test.ts— TDD unit testssrc/e2e.test.ts— real-server e2e (skipped unlessOPENCODE_E2E=1)
License
MIT.
