Skip to content

Releases: jkrandom-sudo/opencode-plugin-peers

0.2.2 — same-directory instance name disambiguation

Choose a tag to compare

@jkrandom-sudo jkrandom-sudo released this 11 Aug 09:28
ebf109d

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 explicit name config option or /peers-name replaces 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 pass
  • npm run typecheck: clean
  • Existing real-opencode E2E: pass

Full Changelog: v0.2.1...v0.2.2

v0.2.1 — clean /peers list

Choose a tag to compare

@jkrandom-sudo jkrandom-sudo released this 10 Aug 04:05
7bb5b9c

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. /peers and list_agents now collapse multiple session endpoints of the same process into one row (the most recently active). Routing (send_message by 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: /peers went 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

Choose a tag to compare

@jkrandom-sudo jkrandom-sudo released this 10 Aug 02:04
3b94f28

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 promptAsync per message, deterministic msg_* IDs, structured metadata.peerMessage provenance — no more waiting for idle
  • Durable per-endpoint spool: queued/held/inflight/done state 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_status tool and /peers-outbox command
  • 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 allow mode, 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-outbox are injected via the plugin config hook — fresh installs get them without any manual config (opencode does not scan plugin packages for commands/*.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 hung promptAsync no longer wedges delivery and dispose() 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: /peers and /peers-outbox execute on a single Enter from the home route

Docs

  • README rewritten: v2 architecture, migration behavior, security model (incl. honest limits of the allow guardrail), Claude Code comparison, new options (heldExpiryMs, maxMessageAgeMs, inboundPolicy: "auto", injectTimeoutMs)

Full Changelog: v0.1.7...v0.2.0

v0.1.7

Choose a tag to compare

@jkrandom-sudo jkrandom-sudo released this 09 Aug 08:41
7b4d236

Fixes

  • Single-Enter slash commands now also work on the start (home) screen — previously the first Enter on /peers & friends only inserted /peers there 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.create failure 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

Choose a tag to compare

@jkrandom-sudo jkrandom-sudo released this 09 Aug 08:13
b15e021

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 test 70/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

Choose a tag to compare

@jkrandom-sudo jkrandom-sudo released this 09 Aug 07:35
53896fd

Features

  • Single-Enter slash commands: /peers, /list-agents, /peers-name, /peers-inbox now 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 from opencode.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 test 64/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

Choose a tag to compare

@jkrandom-sudo jkrandom-sudo released this 09 Aug 03:35
fdf5fa4

Features

  • Peer-triggered turns run unattended by default — new peerPermissions option ("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 new busy/queuedCount registry fields (optional, backward compatible with 0.1.3 entries). The agent-facing list_agents tool output is unchanged.

Fixes

  • All toast popups removed — command results were already inline via consumeCommand; held-message notices now use delivery.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.ask hook; auto-approval instead listens for permission.asked / permission.v2.asked bus events, attributes the request to a turn by walking tool.messageID up parentID to the originating user message, and replies once/reject when 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 --noEmit clean.

Verification

Live E2E with two isolated opencode serve 1.18.15 instances (bash/edit set to ask):

  • /peers rendered the new format inline on both instances; no toasts.
  • A → B peer task (touch via bash) executed with zero local confirmation (auto-allow permission in peer-triggered turn logged 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 常量与包版本对齐

Choose a tag to compare

@jkrandom-sudo jkrandom-sudo released this 08 Aug 11:28
9ec987a

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 无法启动

Choose a tag to compare

@jkrandom-sudo jkrandom-sudo released this 08 Aug 11:26
5030e2f

Fixes

  • showToast 不再可能挂死插件初始化:无 TUI 附加时(headless opencode run,或 bootstrap 期间 TUI 尚未连接),/tui showToast 端点永不响应;此前 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/wangshuai bootstrap 卡死(25s 无任何输出),修复后完整启动(peers started name=wangshuai-2,TUI 正常渲染,opencode run 完整跑通)。

Full Changelog: v0.1.1...v0.1.2

v0.1.1 — /list-agents alias

Choose a tag to compare

@jkrandom-sudo jkrandom-sudo released this 08 Aug 10:04
e9b4c8e

Features

  • /list-agents command 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 serve instances): /list-agents listed the online peer with directory, active session and inbound policy; stale entries separated correctly

Full Changelog: v0.1.0...v0.1.1