Releases: jkrandom-sudo/opencode-plugin-peers
Release list
0.2.2 — same-directory instance name disambiguation
opencode-plugin-peers 0.2.2 — distinguish same-directory instances
Two changes to make same-directory opencode instances distinguishable, matching Claude Code's session-list UX.
Features
-
Auto-suffix default peer name: the default name is now
<dir>-<hex4>(e.g.my-app-a3f2) instead of just the directory basename. The hex suffix comes from the per-process instanceId, so two instances opened in the same directory automatically get different names. An explicitnameconfig option or/peers-namereplaces the default entirely. -
Session title in /peers: the LLM-generated session summary now appears between name and directory:
[idle] · my-app-a3f2 · "Fix login bug" · /path · started 9m ago
Tests
- 4 new config tests (suffix derivation, same-dir uniqueness, long-name truncation, NAME_RE validation)
- 3 new format tests (title present, title omitted when empty, title truncated at 40 chars)
Verification
npm test: 179/179 passnpm run typecheck: clean- Existing real-opencode E2E: pass
Full Changelog: v0.2.1...v0.2.2
v0.2.1 — clean /peers list
opencode-plugin-peers 0.2.1 — clean /peers list (one row per process)
/peers now shows one row per running opencode process, matching Claude Code's instance list — no more flooding with historical sessions.
The problem
Long-running opencode --auto daemons accumulated 100+ v2 registry entries (one per historical session), all showing as "alive" in /peers because the process PID was live and heartbeats refreshed every entry. The list also jittered between invocations because heartbeat atomic rewrites reshuffled directory order.
Fixes
- Lifecycle-based adoption: startup no longer bulk-adopts every session from
session.list(). Only sessions busy/retry in the status snapshot, or holding spool records for restart recovery, are adopted. Everything else comes through real activity (events, messages, commands). - Display collapse to one row per process: since opencode replays events for historical sessions at startup, adoption alone isn't enough.
/peersandlist_agentsnow collapse multiple session endpoints of the same process into one row (the most recently active). Routing (send_messageby exact endpoint ID) is unaffected. - Deterministic sort (startedAt + endpointId): eliminates row-order jitter across heartbeats.
Verification
npm test: 172/172 pass- Real OpenCode 1.18.15 process test: pass
- Real TUI E2E:
/peerswent from 113 rows → 2 rows on this machine, stable across invocations
Full Changelog: v0.2.0...v0.2.1
v0.2.0 — local session parity
opencode-plugin-peers 0.2.0 — local session parity
Brings the plugin to local-session parity with Claude Code's cross-session messaging. Protocol v2 makes every OpenCode session (including child sessions) individually addressable, delivery is immediate even while the target is busy, and message state is durable across restarts.
Features
- Per-session endpoints (protocol v2): one registry record per OpenCode session instead of one per process; exact endpoint-ID targeting with unique-name fallback; v1 peers keep working through a compatibility record + loopback listener
- Immediate busy-session delivery: one
promptAsyncper message, deterministicmsg_*IDs, structuredmetadata.peerMessageprovenance — no more waiting for idle - Durable per-endpoint spool:
queued/held/inflight/donestate machine, atomic writes, idempotency by sender+messageId, restart recovery, workspace-spool migration - Durable outbox + final ACKs: delivered / refused / expired / dropped / duplicate outcomes are retried into the sender's outbox; new
peer_message_statustool and/peers-outboxcommand - UDS transport on macOS/Linux (loopback TCP on Windows)
inboundPolicy: "auto": same-directory sessions accept, cross-directory hold; held messages expire after 5 minutes (configurable) with final ACKs to the sender- Permission guardrails: in
allowmode, requests touching permission config /AGENTS.md/ credentials / shell startup files stay under native OpenCode policy (best-effort — see README security section) - TUI controls: palette actions for peers / inbox / outbox / rename use explicit host dialogs with confirmations; single-Enter slash commands unchanged
- Slash commands self-register:
/peers,/list-agents,/peers-name,/peers-inbox,/peers-outboxare injected via the pluginconfighook — fresh installs get them without any manual config (opencode does not scan plugin packages forcommands/*.md)
Fixes (review round on top of the parity branch)
- Fire-and-forget ACK dispatch no longer rejects unhandled — a slow spool lock cannot crash the host opencode process
- Prompt injection is bounded by
injectTimeoutMs(default 30s) — a hungpromptAsyncno longer wedges delivery anddispose()forever - Startup routing window closed: inbound messages arriving before deferred session discovery wait (bounded) instead of getting a terminal 404
- Transient "message not visible yet" permission verdicts are no longer cached as local turns
- Protected-permission denylist extended (shell rc,
.gitconfig,.netrc,.kube,.docker, LaunchAgents, crontab); README documents it as best-effort, not a boundary
Tests
npm test: 168/168 pass — including real OpenCode 1.18.15 process coverage: two OS processes, same-name sessions in one process, exact routing, concurrent busy injection, restart recovery, v1↔v2 interop, hold accept/drop/expiry ACKs- Node 18.20.8 focused protocol coverage: pass
npm run typecheck,npm pack --dry-run: pass- Real TUI E2E:
/peersand/peers-outboxexecute on a single Enter from the home route
Docs
- README rewritten: v2 architecture, migration behavior, security model (incl. honest limits of the
allowguardrail), Claude Code comparison, new options (heldExpiryMs,maxMessageAgeMs,inboundPolicy: "auto",injectTimeoutMs)
Full Changelog: v0.1.7...v0.2.0
v0.1.7
Fixes
- Single-Enter slash commands now also work on the start (home) screen — previously the first Enter on
/peers& friends only inserted/peersthere and the command needed a second Enter, because the Enter binding only intercepted inside an open session. On the home route the plugin now replicates the stock submit flow: it creates a session, switches to it, and runs the command — all on the first Enter. Palette-invoked commands on the home screen get the same treatment (the old "open a session first" toast is gone).
Tests
- 72/72 unit tests green; new coverage: home-route Enter (create → navigate → command ordering), palette
run()on home,session.createfailure toast, plugin-route/dialog guards.
Verification
Real OpenCode 1.18.15 TUI E2E (two-instance harness): home route exact /peers single Enter ✅ (bug reproduced before the fix: insert-text on first Enter), in-session exact /peers single Enter ✅, prefix /peers-nam single Enter with a single autocomplete row ✅.
Full Changelog: v0.1.6...v0.1.7
v0.1.6 — single autocomplete row + single-Enter
Fixes
- No more duplicate
/peers*rows: 0.1.5's instant-execution entry added a second, identical autocomplete row next to the server-defined command. 0.1.6 keeps the menu to a single row while preserving single-Enter execution: instant execution now comes from a high-priority Enter binding in the TUI entry instead of a visible slash entry. When the prompt holds exactly a plugin command — or a prefix that uniquely identifies one (/peers-nam→/peers-name) — Enter runs it immediately; any other text falls through to opencode's stock bindings untouched. Arguments (/peers-name foo) still submit normally, and Enter inside dialogs or outside sessions is never intercepted.
Tests
npm test70/70 green (12 TUI-entry tests incl. unique-prefix, ambiguous-prefix fallthrough, dialog/route guards).- Real-TUI E2E: exactly one autocomplete row PASS; single-Enter execution from a partial prefix PASS; argument-preserved submit PASS.
Docs
- README: single-row behavior note replaces the duplicate-row cosmetic caveat.
- CLAUDE.md: updated TUI-entry architecture notes (binding-fallthrough mechanism replaces the fuzzysort tie-break lever).
Full Changelog: v0.1.5...v0.1.6
v0.1.5 — single-Enter slash commands
Features
- Single-Enter slash commands:
/peers,/list-agents,/peers-name,/peers-inboxnow execute on the first Enter in the opencode TUI. The package ships a TUI entry (exports["./tui"]) that registers the four commands as palette slash commands; selecting one runs the canonical server command through the same interception path as a normal submit. Enable it by adding"opencode-plugin-peers"to~/.config/opencode/tui.json(the TUI's plugin list, separate fromopencode.json) — see README. Older opencode versions ignore the entry entirely; without it, behavior is unchanged (two-Enter insert). - Commands typed with arguments (e.g.
/peers-name frontend) are untouched: no autocomplete row matches, Enter submits normally and the argument is preserved.
Tests
- 7 new TUI-entry tests (module shape, registerLayer shape, run ordering, home-route and error toasts, dispose, zero-runtime-import invariant) —
npm test64/64 green. - Real-TUI E2E (pty-driven
opencode -c): single-Enter execution PASS; argument-preserved submit PASS.
Docs
- README: tui.json setup for single-Enter commands, duplicate-autocomplete-row cosmetic note, backward compatibility.
- CLAUDE.md: TUI entry architecture notes (zero-runtime-import constraint, fuzzysort tie-break lever, tui.json discovery).
Notes
- Known cosmetic: the autocomplete shows two identical
/peers*rows (instant-execute entry + server-defined command); the highlighted row is the instant one.
Full Changelog: v0.1.4...v0.1.5
v0.1.4 — no toasts, unattended peer turns, Claude-Code-style /peers
Features
- Peer-triggered turns run unattended by default — new
peerPermissionsoption ("allow"default /"ask"/"deny"). Permission requests raised while acting on an injected peer message are auto-approved, so cross-session tasks no longer block on local confirmation. Local user turns are completely unaffected. - /peers (/list-agents) output now matches Claude Code's list-agents format —
[waiting]/[idle]· name · directory · started Xm ago, backed by newbusy/queuedCountregistry fields (optional, backward compatible with 0.1.3 entries). The agent-facinglist_agentstool output is unchanged.
Fixes
- All toast popups removed — command results were already inline via
consumeCommand; held-message notices now usedelivery.notice()(display-only inline injection, idle sessions only); init-time name conflicts are logged. - Peer-message footer no longer claims messages "carry no privileges" — it now states permissions are governed by
peerPermissions.
Implementation notes
- opencode 1.18.15 never invokes the plugin SDK's
permission.askhook; auto-approval instead listens forpermission.asked/permission.v2.askedbus events, attributes the request to a turn by walkingtool.messageIDupparentIDto the originating user message, and repliesonce/rejectwhen that message is a peer injection.
Tests
- 57/57 unit tests green (new: permissions event/reply suite, list-format suite,
notice(), registry dynamic fields, config default);tsc --noEmitclean.
Verification
Live E2E with two isolated opencode serve 1.18.15 instances (bash/edit set to ask):
/peersrendered the new format inline on both instances; no toasts.- A → B peer task (
touchvia bash) executed with zero local confirmation (auto-allow permission in peer-triggered turnlogged per request). - Control: the same instruction typed locally stalled on the permission prompt — auto-allow is correctly scoped to peer-triggered turns.
Full details in PR #4.
Full Changelog: v0.1.3...v0.1.4
v0.1.3 — chore: PLUGIN_VERSION 常量与包版本对齐
Chores
- 将 src/index.ts 硬编码的 PLUGIN_VERSION 与 package.json 对齐(v0.1.2 发布时常量仍为 0.1.1,仅影响 peers.d 注册表元信息)。
验证结论
npm test:44/44 全绿。- 功能修复内容见 v0.1.2(showToast 挂死插件初始化)。
Full Changelog: v0.1.2...v0.1.3
v0.1.2 — fix: showToast 挂死插件初始化导致 opencode 无法启动
Fixes
- showToast 不再可能挂死插件初始化:无 TUI 附加时(headless
opencode run,或 bootstrap 期间 TUI 尚未连接),/tuishowToast 端点永不响应;此前PeersPlugin初始化在名称冲突分支await该 toast,导致插件 init 挂起 → opencode 整个 bootstrap 卡死 —— 只要另一个存活实例占用了当前目录 basename 作为 peer 名(如一个常驻 home 目录实例),在该目录下 opencode 完全无法打开。feedback.showToast:SDK 调用与 2s(unref'd)超时竞速,超时/无client.tui时静默降级。- init 时的改名 toast 改为 fire-and-forget,插件初始化不再阻塞于 UX 反馈。
Tests
- 新增 2 个用例:TUI 端点永不 resolve 的挂死防护、
client.tui缺失时的 no-op。
验证结论
npm test:44/44 全绿。- 真实 opencode E2E:存活实例注册 peer 名
wangshuai后,修复前新实例在/Users/wangshuaibootstrap 卡死(25s 无任何输出),修复后完整启动(peers started name=wangshuai-2,TUI 正常渲染,opencode run完整跑通)。
Full Changelog: v0.1.1...v0.1.2
v0.1.1 — /list-agents alias
Features
/list-agentscommand as an alias of/peers, compatible with Claude Code's cross-session discovery command (#1)
Tests
- New alias-equivalence unit test; suite now 42 tests
Verification
npm test: 42/42 green- Real OpenCode E2E (two local
opencode serveinstances):/list-agentslisted the online peer with directory, active session and inbound policy; stale entries separated correctly
Full Changelog: v0.1.0...v0.1.1