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
5 changes: 0 additions & 5 deletions .changeset/abandoned-response-not-failure.md

This file was deleted.

5 changes: 0 additions & 5 deletions .changeset/bright-keys-float.md

This file was deleted.

9 changes: 0 additions & 9 deletions .changeset/chaos-network-proxy.md

This file was deleted.

20 changes: 0 additions & 20 deletions .changeset/current-v2.md

This file was deleted.

5 changes: 0 additions & 5 deletions .changeset/recording-annotations.md

This file was deleted.

5 changes: 0 additions & 5 deletions .changeset/tool-transport-hardening.md

This file was deleted.

5 changes: 0 additions & 5 deletions .changeset/wait-timeout-split.md

This file was deleted.

2 changes: 1 addition & 1 deletion apps/catalog/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"@types/bun": "^1.3.14",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"effect": "4.0.0-rc.111",
"effect": "4.0.0-rc.112",
"opencode-drive": "workspace:*",
"oxlint": "1.60.0",
"typescript": "^7.0.2",
Expand Down
30 changes: 15 additions & 15 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@
"@changesets/cli": "2.31.0"
},
"overrides": {
"@effect/platform-node-shared": "4.0.0-rc.111"
"@effect/platform-node-shared": "4.0.0-rc.112"
}
}
38 changes: 38 additions & 0 deletions packages/drive/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,43 @@
# opencode-drive

## 2.0.0

### Major Changes

- 04013ce: Update Drive to the current OpenCode V2 client (`0.0.0-dev-18535`) and its
matching Effect V4 stack (`4.0.0-rc.112`). Effect is now an exact peer dependency
so consumer programs and Drive share the same Effect types and runtime.
The client, protocol, schema, platform, and test packages use the same
coherent `rc.112` stack.

Migrate schema-backed errors and RPC JSON codecs, and preserve optional CLI
boolean flags with explicit false defaults. Static tool adapters now emit
native V2 progress metadata, result metadata, and `Tool.Error` failures.

Dynamic tool controls follow the current V2 protocol: change
`invocation.progress({ structured: { phase: "searching" } })` to
`invocation.progress({ phase: "searching" })`, and read the model call ID from
`invocation.context.id` instead of `invocation.context.callID`.
`finish({ structured, content })` and LLM queue/send/serve/title sequencing,
cancellation, reconnection, supervision, and settlement retain their contracts.

### Minor Changes

- 6e16c14: Add an opt-in KeyCastr-style overlay for semantic key presses in screenshots and recording exports.
- b02239e: Add a controllable chaos network proxy between launched TUIs and the OpenCode server, plus configurable simulated-LLM timeouts.

Enabling the new `network` option (on `defineScript`, driver options, and instance options) routes every launched TUI through a chaos TCP proxy: TUIs connect with an explicit `--server` pinned to the proxy and authenticate through the registered service password, so reconnects always cross the proxy, the TUI never elects a replacement server, and the drive control plane plus the driver's SDK client stay unaffected. Scripts and drivers control conditions through the new `network` capability: `set({ latencyMs, jitterMs, refuseNew, blackhole })` (replace-whole-state semantics), `clear()`, `killConnections()`, and `connections()`. The proxy resolves its upstream lazily from the service registration, so it follows server restarts that change ports.

The new `llm` option (`requestTimeout`, `settlementTimeout`) surfaces the existing LLM controller timeouts for scenarios that intentionally hold responses open longer than the 30s defaults.

- 56c42f5: Annotated recording exports. `tui.recording.mark(label)` labels the current instant during a recorded run; marks become a burned-in footer in the exported video (segment label bottom-left, elapsed timecode and "drive" branding bottom-right). `exportRecording` gains `footer`, `annotations`, and `clips` options — clips trim, re-speed (`speed`), and freeze (`holdMs`) segments of the raw timeline, concatenated in order. `SampledFrame` now carries `sourceAtMs` (raw timeline time before trim/rebase) alongside the exported `atMs`.
- b7ddb73: Split wait deadlines from control-plane timeouts. `ui.waitFor`, `ui.getElement`, and `ui.getNode` now fail with the new catchable `UiWaitTimeoutError` when their deadline passes, so scripts can branch on "did X appear in time?" (for example with `Effect.catchTag("UiWaitTimeoutError", ...)`). `UiTimeoutError` is reserved for unanswered UI RPCs — an unresponsive control plane — and remains fatal to script runs even when caught.

### Patch Changes

- 97d65df: A served or queued LLM response whose backend detaches mid-stream (for example `server.kill()` while a reply is streaming) is now abandoned instead of recorded as a controller failure. Previously the interrupt-only cause poisoned the run with a phantom `LlmControllerError: All fibers interrupted without error`, making restart scenarios impossible to script.
- c591d43: Fix two controlled-tool transport defects: `/execute` requests are exempt from Bun's idle timeout (a silent controlled tool no longer has its transport killed at the 255s ceiling), and plugin tool results no longer carry an `output` value, which opencode's tool runtime rejects for tools that declare no output schema.

## 1.4.5

### Patch Changes
Expand Down
6 changes: 3 additions & 3 deletions packages/drive/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ This project gives your agents control over OpenCode:

OpenCode Drive requires [Bun](https://bun.sh/) 1.3.14 or newer. MP4 recording export also requires `ffmpeg` on `PATH`.

Effect programs must use `effect@4.0.0-rc.111`, Drive's exact peer dependency.
Effect programs must use `effect@4.0.0-rc.112`, Drive's exact peer dependency.
The platform and test packages use the same release as the current V2 client,
`@opencode-ai/client@0.0.0-dev-18516`. Effect's `latest` tag still selects V3;
`rc.112` is newer but does not satisfy this client's exact Effect requirement.
`@opencode-ai/client@0.0.0-dev-18535` and its matching protocol and schema
packages. Effect's `latest` tag still selects V3; install the exact V4 peer.

Install dependencies with:

Expand Down
14 changes: 7 additions & 7 deletions packages/drive/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "opencode-drive",
"version": "1.4.5",
"version": "2.0.0",
"description": "Drive real and simulated OpenCode instances",
"license": "MIT",
"repository": {
Expand Down Expand Up @@ -58,23 +58,23 @@
"release:validate": "bun run check && bun run test && bun pm pack --dry-run"
},
"dependencies": {
"@effect/platform-node": "4.0.0-rc.111",
"@effect/platform-node-shared": "4.0.0-rc.111",
"@effect/platform-node": "4.0.0-rc.112",
"@effect/platform-node-shared": "4.0.0-rc.112",
"@napi-rs/canvas": "1.0.2",
"@opencode-ai/client": "0.0.0-dev-18516",
"@opencode-ai/client": "0.0.0-dev-18535",
"@opentui/core": "0.4.5",
"@types/bun": "1.3.13",
"@typescript/native-preview": "7.0.0-dev.20251207.1",
"@wterm/core": "0.3.0",
"@wterm/ghostty": "0.3.0"
},
"peerDependencies": {
"effect": "4.0.0-rc.111"
"effect": "4.0.0-rc.112"
},
"devDependencies": {
"@effect/vitest": "4.0.0-rc.111",
"@effect/vitest": "4.0.0-rc.112",
"@tsconfig/bun": "1.0.9",
"effect": "4.0.0-rc.111",
"effect": "4.0.0-rc.112",
"oxlint": "1.60.0",
"oxlint-tsgolint": "0.21.0",
"typescript": "5.8.2",
Expand Down
41 changes: 41 additions & 0 deletions packages/drive/test/manual/current-v2-relaunch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import assert from "node:assert/strict"
import { Effect } from "effect"
import { defineScript, Llm } from "opencode-drive"

// Check first, then `drive start --script ... --dev <isolated V2 checkout>`
// with OPENCODE_DRIVE_DB=release-relaunch.sqlite to retain the first session.
export default defineScript({
launch: "manual",
config: { autoupdate: false },
tui: { viewport: { cols: 100, rows: 35 } },
run: ({ server, tuis, llm }) =>
Effect.gen(function* () {
yield* llm.title(() => Effect.succeed("Drive relaunch"))
const first = yield* server.launch()
const tui = yield* tuis.launch("release-relaunch")
yield* llm.queue(Llm.text("BEFORE_RELAUNCH_OK", { delay: 0 }))
yield* tui.ui.submit("First generation fixture")
yield* tui.ui.waitFor("BEFORE_RELAUNCH_OK")
const sessionID = (yield* first.session.list({ limit: 1, order: "desc" })).data[0]?.id
assert(sessionID)
yield* first.session.wait({ sessionID })
yield* tui.close()
yield* server.kill()

const second = yield* server.launch()
assert.equal((yield* second.session.get({ sessionID })).id, sessionID)
const relaunched = yield* tuis.launch("release-relaunch")
yield* llm.queue(Llm.text("AFTER_RELAUNCH_OK", { delay: 0 }))
yield* relaunched.ui.submit("Second generation fixture")
yield* relaunched.ui.waitFor("AFTER_RELAUNCH_OK")
const secondID = (yield* second.session.list({ limit: 1, order: "desc" })).data[0]?.id
assert(secondID)
yield* second.session.wait({ sessionID: secondID })
assert.deepEqual(yield* second.session.inbox.list({ sessionID: secondID }), [])
assert.equal((yield* relaunched.ui.capture()).cols, 100)
console.log(yield* relaunched.ui.screenshot("release-relaunch"))
yield* relaunched.close()
yield* server.kill()
console.log("CHECKED_SCRIPT_RELAUNCH_OK")
}).pipe(Effect.timeout("90 seconds")),
})