Commit Graph
5 Commits
Author SHA1 Message Date
pastilhasandClaude Opus 5 8b409e8af8 finish phase 1: correct the stale comments, and put the ndjson mapping under test
Path names: the serve's cwd is DATA_PATH/opencode_server, not opencode-sidecar. Two comments said
otherwise and would send the next reader to a directory that does not exist.

Version pin: the comment claimed "verified live against 1.17.9" as though that were a property of the
code. It is a property of whichever binary is installed, and this project already runs two — 1.17.9 here,
1.18.11 on the other machine. Says so now, and points at the test as the thing that actually enforces it.

Tests, the first on the OpenCode path. `runner.ts`'s NDJSON → ChatEvent mapping was described as pure and
untested; it was untested but not pure — it lived inside `handleLine` as a closure over `emit`, the
accumulated cost and a reported-session flag, so it could not be called without spawning a binary.

Extracted as `mapRunLine`, genuinely pure: line in, {sessionId, events, costDelta} out. The two concerns
that span lines stay with the caller, because they are not properties of a line — emitting the session id
exactly once, and accumulating cost across steps. Behaviour is unchanged.

11 tests over what the mapping forwards, what it drops and what it must not turn into NaN. The last one
matters: a missing `cost` on a step_finish would otherwise propagate NaN into the turn total.

Phase 1 is complete: dead code deleted (previous commit), comments corrected, tests added.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 02:58:11 +00:00
pastilhasandClaude Opus 5 cfbf58cdba delete the AGENTS.md injection; --dir was always the real anchor
The sidecar seeded an AGENTS.md into the serve's project root telling the agent to read its working
directory from the "Working directory for this session" line in its system prompt. The run path sends no
system prompt, so there was no such line and the instruction had been inert since turns moved off the
serve to `opencode run --dir`.

What it was standing in for, `--dir` does properly — tested rather than assumed
(docs/opencode-phase0-review.md): `--dir` anchors the agent's own file operations, not just the process
cwd, and the anchor survives a multi-step turn with a write in the middle. Nothing replaces it.

The generated file is removed from disk too, not only from the code that wrote it; leaving it would have
kept feeding standing instructions to every session while looking, in the source, as though it were gone.

Also corrects the claim that all OpenCode sessions live in one server's project. True when turns
inherited the serve's directory, false now: one serve lists 7 sessions across several directories, which
is why the cwd filter has to read `directory` rather than assume a single one.

docs/opencode-phase0-review.md, item 2 — Phase 1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 02:51:20 +00:00
pastilhasandClaude Opus 4.8 71e39b7639 move opencode's turn output into its own sidecar
The second copy of the same problem. The opencode sidecar reported raw
ChatEvents and officer translated them, buffered the assistant text and wrote
every durable message to chat_session_events — so an officer restart mid-turn
lost whatever the model had produced since the last write, and `connect.ts`
dropped the events that arrived while it was down without a word.

Both harnesses speak ChatEvents, so the sidecar reuses the agent's session log
verbatim: translate, commit, then deliver the finished message with its cursor
id as `opencode:message`. Officer folds it into the in-memory transcript and
relays it, exactly as it now does for claude — `createEventHandler` (166 lines,
a duplicate of turn-stream.ts) and `emitToSession` are gone, and nothing in
officer writes to chat_session_events any more.

`opencode:event` stops being a wire event; it is the runner's internal report to
the sidecar it runs in, typed as such so it cannot leak back onto the socket.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-30 05:18:09 +00:00
pastilhasandClaude Opus 4.8 5d077a4a54 route OpenCode chat through the officer-opencode sidecar
Turns now run in the sidecar via `opencode run --dir <cwd> --format json
--dangerously-skip-permissions [-s <ses_>]` instead of the serve's
`POST /session/{id}/message` path. That path was unreliable at reporting
tool completion — tools finished but the turn stayed status=running,
wedging the UI at "Working…". `run` re-anchors tools to the chat cwd via
--dir, reports completion faithfully, and exits when done.

- runner.ts (new): spawn `run`, map its JSON events (text/tool_use/
  step_finish) to ChatEvent, report the `ses_` id for resume, accumulate
  cost; inactivity (120s) + hard-cap (10min) watchdogs kill a hung turn
  and emit a clean error instead of hanging forever.
- protocol.ts: opencode:run-streaming/kill commands; opencode:spawned/
  event/session events; OpenCodeRunParams.
- sidecar index.ts: wire run/kill; sweepStaleServes() on startup kills
  only an `opencode serve` whose resolved /proc/<pid>/cwd == SERVE_CWD,
  so an unclean prior exit can't leave two.
- sidecar-registry.ts: spawnOpenCodeStreaming/killOpenCode/onOpenCodeEvent/
  onOpenCodeSession helpers.
- send-opencode.ts: rewritten to mirror send-claude-code (subscribe →
  resolve resume id → spawn → kill handle).
- sidecar-server.ts: persist reported ses_ id into state for resume.
- list-models/server-manager: route to the sidecar's reported serve URL.

The serve stays up only for read-only calls that never hung (model
listing, session history).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 14:54:52 +00:00
pastilhasandClaude Opus 4.8 203a8b0708 opencode: add the OpenCode sidecar (step 1 — serve lifecycle + port report)
New officer-opencode sidecar (same philosophy as officer-claude): a singleton that owns
an `opencode serve` running from DATA_PATH/opencode-sidecar (created if missing) on a
random port, registers with the API as capability 'opencode', and reports its port via a
new `opencode:server` protocol event. The API stores it (sidecar-server.ts, wired in
server.tsx via getOpenCodeServerUrl). ecosystem.config.cjs runs the sidecar instead of a
bare pm2 serve. Turn-running + API rewiring come in later steps.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 13:43:57 +00:00