Repository navigation
fix(agent): restore /acp status command under OpenCode V2 (#809) - #850
Conversation
The /acp status command was implemented only against the legacy .server()
plugin API and orphaned by the V2 migration — OpenCode 2.x loads `{id, setup}`
and never calls `.server()`, so /acp never registered (native mode looked
"inactive").
Register /acp in the shared createOpencodeV2Setup factory so BOTH launcher and
native modes surface it. API verified against @opencode/cli v2.0.3 source:
- ctx.command.transform(editor.add({name, description, execute})) — commands
carry an execute(input) handler (input.sessionID is provided).
- ctx.session.synthetic({sessionID, text}) — inserts a synthetic message that
does NOT trigger a model turn (the V2 replacement for the legacy ignored
no-reply prompt).
/acp fetches <proxy>/__bili/plugin/status?conversationId=<sid>&fallback=latest
and renders the panel (or idle/error notice) via synthetic. Inert-safe on
surfaces without ctx.command; TUI-only (`run` dispatches no slash commands).
- src/agent/opencode-v2.ts: add command seam to V2PluginContext + V2CommandEditor
types; register /acp after tool registration.
- tests/opencode-v2.test.ts: fake ctx gains command.transform + session.synthetic;
fake proxy serves /status; 2 new tests (panel render, no-proxy notice).
typecheck clean; full suite 1654 pass / 0 fail / 2 skip (win32-only); build OK;
dist markers confirmed in both agent entries. Refs #809.
[bot] 🏷 Review of the What I did: pulled the branch ( Diff integrity — matches your description exactly: single commit on baseline Contract cross-check (all correct):
Verification gauntlet (re-ran, all green, matches your numbers):
Landing path (your actual question):
Recommendation: land I have not pushed or opened anything — confirm standalone vs. bundle and I'll cut the PR accordingly. 中文摘要:独立复核了 |
…t, inert-safe registration) F1: check empty-sessionID guard before the disabled branch so a missing id never reaches ctx.session.synthetic with an empty id. F2: read status via shared fetchStatus (5s STATUS_TIMEOUT_MS soft-fail) instead of a bare unbounded fetch. F3: surface status.error in the no-panel fall-through. F4: wrap command registration in its own try/catch so an unsupported editor.add degrades to no-/acp instead of rejecting setup. F5: console.warn on the no-sessionID path so a broken host contract surfaces instead of dead silence.
OpenCode V2's session.synthetic defaults to delivery="steer" and, unless resume:false, calls execution.wake(sessionID) — every /acp invocation started a model turn on behalf of a status query. Observed live in TUI: the model answered its own injected status panel with an unprompted assistant message. Pass resume:false so rendering stays inert.
The /acp panel was carried only in the synthetic message's text. OpenCode V2's TUI renders a synthetic message as a Notice row only when its display text fits the timeline cap (~1KB; message-timeline.tsx canRenderImmediately), so real panels were silently dropped: users saw nothing after /acp. The panel now goes to description (verbatim under 1024 chars, leading lines + [panel truncated] above) and the model-facing body is an inert one-line note (V2_SYNTHETIC_TEXT) so the model context never repeats panel content. Verified live in a v2.0.4 TUI: short panels render fully as the notice row, a >1.5KB panel renders its leading lines plus the marker; no model turn is triggered (pairs with the no-wake fix #879).
…o-wake fix(agent): /acp must not wake the model under OpenCode V2
…isible-panel fix(agent): make opencode v2 /acp status panel visible in the TUI
PR #878 was merged only into 2026-09-17_opencode-v2-acp-no-wake (tip 40c4970), so the #850 head was missing the panel-visibility fix. This fold makes 2026-09-15_opencode-native-plugin carry the complete /acp stack: register (11a82d7) + harden (f857ff1) + no-wake (d6d60f8, #875) + visible panel (304110a, #878).
… model request
Before the conversation's first model request the proxy knows no ACP session;
handlePluginStatus answers that with HTTP 404 {ok:false}. shared.fetchStatus()
soft-fails every non-2xx into undefined, so the v2 renderer fell through both
the panel and the ok===false branches and printed 'proxy returned no status
panel' instead of the friendly idle line.
Handle the undefined result explicitly: probe the manifest, and when it
answers render 'billion-context@<v> — proxy connected, no ACP session yet…';
when nothing answers, say the proxy is unreachable. Second-and-later calls were
already correct (panel or ok:false path). Same soft-fail contract as v1's
inline fetch, without changing the endpoint's wire semantics.
…dle-first fix(agent): first /acp under opencode v2 shows the idle notice, not 'no status panel'
|
继续 |
…ive plugin instead of standing down
The pseudo-attach hole: presetting BILLION_CONTEXT_PROXY and running bare
opencode disarmed the native bootstrap entirely (no spawn, no attach) while
tools still discovered the proxy through the env — model traffic silently
went direct, the proxy never saw the session, and every tool forward 404'd
("unknown plugin conversation"). planNativeOpencode now treats the preset
value as an external attach target (probe + rewrite + stamp, same semantics
as BILLION_CONTEXT_ATTACH; explicit ATTACH wins when both are set). Kill
switches (BILLION_CONTEXT_PLUGIN=0, BILI_NATIVE_OPENCODE=0) and /bili/
launches (BILI_PROVIDER_REWRITES) still stand down; a garbage preset falls
back to spawn.
Also: the opencode v2 plugin tool forward now returns guided text when the
proxy reports the conversation was never registered, instead of surfacing
the raw 404 that sent the model down a "refresh/restart" tangent.
Verified in-container end-to-end (real qwen upstream) across all four
postures: proxy (baseURL), launcher (bili opencode), native spawn (bare
opencode + plugin), and preset-env attach — session registration, live
conversation, acp_status real execution, /acp panel render.
…-modes fix(agent): opencode v2 preset-env attach — close the pseudo-attach 404 hole (three-mode delivery verified)
The history rewrite that dropped the tracked iso/build artifact also swallowed three unrelated dev-tool scripts (registry/codex-models snapshot refreshers, dump analyzer) into commit e59776b, whose message describes the tr_ keying fix. package.json still wires 'npm run registry:snapshot' / 'codex-models:snapshot' to them, so the deletion broke those scripts. Restore verbatim from the #850 base.
…rst) The forwarded kernel acp_status returns the legacy flat report while the /acp command shows the rich status panel — tool and command disagreed. acp_status is read-only, so the plugin now reads the panel from the proxy's status endpoint first and falls back to forwardTool when no panel is served (older proxy, unknown conversation). Fixes #911
…-first fix(agent): opencode v2 acp_status renders the status panel (panel-first)
The history rewrite that dropped the tracked iso/build artifact also swallowed three unrelated dev-tool scripts (registry/codex-models snapshot refreshers, dump analyzer) into commit 6f5ea52, whose message describes the tr_ keying fix. package.json still wires 'npm run registry:snapshot' / 'codex-models:snapshot' to them, so the deletion broke those scripts. Restore verbatim from the ranxianglei#850 base.
What & why
Restores the
/acpstatus command for OpenCode 2.x native mode.Root cause:
/acpwas implemented only against the legacy.server()plugin API (src/agent/opencode.ts). The V2 migration makes opencode load plugins as{id, setup}and never call.server(), so/acpwas orphaned — it never registered, and native mode looked "inactive".This registers
/acpin the sharedcreateOpencodeV2Setupfactory so BOTH the launcher entry and the native entry surface it.API contract (verified against @opencode/cli v2.0.3 source)
ctx.command.transform(editor.add({ name, description, execute }));execute(input)receivesinput.sessionID.ctx.session.synthetic({ sessionID, text })inserts a synthetic message that does NOT trigger a model turn (V2 replacement for the legacy ignored no-reply prompt)./acpfetches<proxy>/__bili/plugin/status?conversationID=<sid>&fallback=latestand renders the panel (idle/error notice when no proxy). Inert-safe on surfaces withoutctx.command; TUI-only.Scope check: the legacy
.server()registered ONLYcommand["acp"](src/agent/opencode.ts:98/:104) — no other local slash commands exist insrc/agent/, so/acpis the complete set of orphaned commands.Files
src/agent/opencode-v2.ts: addcommandseam to V2PluginContext + V2CommandEditor types; register/acpafter tool registration.tests/opencode-v2.test.ts: fake ctx gainscommand.transform+session.synthetic; fake proxy serves/status; 2 new tests (panel render, no-proxy notice).Verification
feat/pi-native-plugin(merge-base 1d4f38c, +133/-1, 2 files)Refs #809. (#809 intentionally left open per owner — baseline reference.)
Note: this is the /acp delta only. If you'd rather bundle it with the #842 coexistence gate (#840) before it lands on the umbrella, say so and I'll close this and re-cut from the updated branch.