A5 (light): Level-2 wrapper now calls ctx.ask({permission: 'browser_execute'}).
The default agent ruleset has '"*": "allow"' so this auto-allows by default —
no user-visible change. But it makes opencode.json's existing controls work:
"tools": { "browser_execute": false } -> deny
"permission": { "browser_execute": "ask" } -> prompt each call
A7: Level 1 grew an optional onChunk hook on ExecuteContext that's invoked
with the accumulated output on every stream chunk. Level 2 supplies a hook
that calls ctx.metadata({metadata: {output: preview(...)}}), matching the
exact pattern bash.ts uses (preview tail-truncates to 30k chars). The TUI's
existing metadata subscription renders incremental output as it streams.
Implementation notes:
- Level 1 stays free of opencode types (Tool.Context, ctx.metadata) — the
hook is a generic Effect callback. Keeps the Level-1 surface portable.
- onChunk receives the full accumulated string, not just the delta. Simpler
for consumers that just want "set current output" semantics; matches how
bash drives ctx.metadata.
- Uses Stream.runForEach instead of Stream.mkString. Stream.all on
[drain, exitCode] keeps the same concurrency model.
Verified on this sprite:
- typecheck 5/5 pass
- streaming: 4 chunks delivered to onChunk during a run; final output and
exitCode unchanged
- uv-missing path still returns exit 127 with hint, 0 chunks (short-circuits
before stream)
- happy path: full output captured, real exit code returned
What
Two small additions to browser_execute:
A5 (light) — adds ctx.ask({ permission: "browser_execute", patterns: ["*"], always: ["*"], metadata: {} }) to the Level-2 wrapper. The default agent ruleset has "*": "allow" (agent.ts:88) so this auto-allows by default — no user-visible change. But it makes opencode.json's existing controls work:
{ "tools": { "browser_execute": false } // deny "permission": { "browser_execute": "ask" } // prompt every call }A7 — streaming output to TUI. Adds an optional onChunk hook on Level-1 ExecuteContext invoked with the accumulated output on every stream chunk. Level 2 supplies a hook that calls ctx.metadata({ metadata: { output: preview(...) }}), mirroring bash.ts exactly (preview tail-truncates to 30k chars). The TUI's existing metadata subscription renders incremental output live.
Why this shape
Tests on the sprite
Roadmap