npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

opencode-collaboration

v0.12.4

Published

Cross-session messaging for opencode — let independent sessions discover and text each other, modeled after Claude Code's cross-session messaging

Readme

opencode-collaboration

English | 中文

npm version npm downloads License: MIT

opencode 的跨会话消息插件 —— 让同一台机器上彼此独立的 opencode 实例互相发现、互发纯文本消息。设计参考了 Claude Code 的跨会话消息。

并行运行多个 opencode 终端(不同的仓库、worktree 或任务),让它们直接互相传递结论,而不是在窗口之间手动复制粘贴上下文:

前端会话:"API 契约变了,字段现在是 user_id" 后端会话:"迁移已完成,可以安全 rebase 到 main 了"

功能特性

  • list_agents / send_message 工具 —— Agent 可以发现对端并给它们发消息
  • /peers(别名 /list-agents)、/peers-name、/peers-online、/peers-inbox、/peers-outbox 命令 —— 面向用户的控制入口
  • 入站消息的 accept / auto / hold / refuse 四种门禁策略;auto 接受同目录对端,跨目录消息进入待审
  • 每个 OpenCode 会话(包括子会话)都有一个可独立寻址的端点;出现重名时可用精确的端点 ID 区分
  • 持久化机制完善:按会话的队列、待审消息、投递结果和发送方发件箱都能在进程重启后存活
  • 被接受的消息会立即注入 —— 每条消息一次 promptAsync 调用,目标会话忙时同样立即注入
  • 消息仅限纯文本 —— 不能传文件,也不能共享对话历史
  • 由对端消息触发的回合默认无人值守运行:处理注入的对端消息期间产生的权限请求会被自动批准(peerPermissions,参考了 Claude Code 的权限模式)。你自己输入的回合不受影响
  • 命令结果和通知内联显示在会话中 —— 没有 toast 弹窗
  • 明确的 TUI 控制:面板操作使用宿主对话框进行选择确认;斜杠命令封装仍可用于自动化和兼容性场景
  • 纯本地运行:一切都在你的机器上(macOS/Linux 使用 Unix 域套接字,Windows 使用回环 TCP,另有一个兼容 v1 对端的回环监听器)
  • 本进程的 peer 名字会追加到根会话标题后面,一眼就能看出每个 opencode 窗口是谁
  • peer 触发的回合会沿用接收方会话当前选中的 agent/模式(如自定义的 teacher),而不是 opencode 默认的 build,因此该 agent 的模型、工具与权限规则都会生效。模式取自服务端记录的 agent(会话创建时写入,并随消息/命令的 prompt 更新);若尚无所知则使用默认 agent。若记录的 agent 之后被删除,下一条 peer 消息会回退到默认 agent

安装

opencode plugin -g opencode-collaboration

或者加入你的 opencode.json:

{
  "plugin": ["opencode-collaboration"]
}

要求 opencode >= 1.18.0。

单回车执行命令(可选但推荐)。 本包附带一个 TUI 入口,让插件的斜杠命令按一次回车即可执行。opencode 的 TUI 从 ~/.config/opencode/tui.json 加载插件(这是与 opencode.json 相互独立的另一个列表),所以请把插件也加进去:

{
  "plugin": ["opencode-collaboration"]
}

不加这个入口一切也照常工作 —— 只是命令会保持 opencode 默认的行为:第一次回车插入 /name ,第二次回车才提交。说明:

  • 自动补全仍然为每条命令显示单独一行 /peers*(服务器定义的那个)。立即执行来自 TUI 入口中的一个高优先级回车绑定:当输入框内容恰好是一条插件命令 —— 或能唯一识别某条命令的前缀(如 /peers-nam)—— 回车立即执行;其他内容全部原样落回 opencode 的原生绑定。无论在会话内还是开始(主页)界面都有效 —— 主页界面会先创建一个会话,和普通提交完全一样。
  • 携带参数输入的命令(如 /peers-name frontend)不受影响 —— 回车按正常方式提交,参数会被保留。
  • 旧版 opencode 完全忽略 TUI 入口,保持两次回车的行为。

本地从源码目录开发时,把构建产物软链接到全局插件目录:

npm install && npm run build
ln -sf "$PWD/dist/index.js" ~/.config/opencode/plugins/opencode-collaboration.js

(~/.config/opencode/plugins/*.js 会在启动时自动加载。)

使用方法

给实例命名,让对端可以寻址你:

/peers-name frontend

看看谁在线:

/peers
Other Opencode sessions (2):
  [waiting]  ·  frontend  ·  /Users/you/app/frontend  ·  started 9m ago
  [idle]  ·  backend  ·  /Users/you/app/backend  ·  started 29m ago

[waiting] = 该处有一个回合正在运行,但对端消息仍会立即注入;[idle] = 没有回合在运行。出现排队消息只表示某次立即注入尝试需要重试,不代表投递会等待空闲;发送方在此期间会持有一个待确认的最终 ACK。

重启后如何重新上线(0.12.0 —— 升级前务必读):

peer 的名字是持久的,但在线不是。进程重启后,会话在你把它重新上线之前都是离线的,方式二选一:

/peers-online

或在该会话里输入任意一行(一句 1 即可,或任意斜杠命令)。两者走同一条恢复路径;名字保存在会话标题和本地"已验证锚点账本"里,会原样恢复。会话一旦上线,闲置多久都保持在线 —— 空闲永远不会把 peer 下线(硬规则)。

为什么改:在你首次输入之前,插件无法从宿主得知你打开的是哪个会话,因此旧的启动自动召回本质上是一次可能复活幽灵身份的猜测。0.12.0 删掉了这次猜测。它放弃的便利很小 —— 你重开的会话几乎总会立刻被你碰一下。(成本提示:opencode 把斜杠命令当作一次 prompt,所以 /peers-online 会消耗一次宿主模型回合;输入 1 同样是一次普通回合。)

让 Agent 来对话:

Use send_message to tell "backend" that the login form now posts to /v2/login.

接收方会话会立即收到这条文本,以一条用户可见的消息出现,并带发送方前缀([来自 "名字" @ 目录]),其中包含发送方精确的端点 ID 以及回复方式。接收方被要求只在确实需要回应时才通过 send_message 回复,并明确禁止仅确认/致谢类消息——避免两个 agent 无限礼貌往返。send_message 返回一个追踪 ID;用 peer_message_status 或 /peers-outbox 来区分"传输层已收到"和"最终已投递"。

默认情况下,只有与本会话工作目录完全相同的对端才可见、可寻址(peerScope: "directory");跨目录的对端在 list_agents//peers 和 send_message 中不可见。设置 peerScope: "all" 即可跨目录协作。入站消息永远不受 scope 限制。

注入的 peer 回合会以该会话最后一条人类输入(消息/命令)的 agent/mode 运行——例如接收方最后在 plan 模式下发过消息,那么 peer 回合就以 plan 模式到达、无法编辑。opencode 只有在某个 mode 下发过消息才会持久化它,因此"仅切换 UI mode"插件还无法感知。若希望 peer 以指定 mode 找到你,请先在该 mode 下发送一条消息。

审阅待审消息(当 inboundPolicy 为 "hold" 时):

/peers-inbox                 # 列出待审消息
/peers-inbox accept 2        # 投递第 2 条消息
/peers-inbox drop all        # 全部丢弃
/peers-outbox                # 回执与最终 ACK 结果

角色命令(/peers-jiagoushi / /peers-yanfa)

/peers-jiagoushi(架构师)与 /peers-yanfa(研发工程师)是两个角色规范命令,把「1 架构师 + n 研发」的协作分工、工作流与行为准则固化成交互规范。

0.12.3 起自动注册:插件启动时自动注入这两条命令(配置 roleCommands: false 可关闭)。插件版本 ≤0.12.2 才需要手动复制。手动复制的文件来源(二选一):

  1. 仓库 checkout:从 gitee 仓库 commands/ 目录取;
  2. npm 安装后的包目录:~/.cache/opencode/packages/opencode-collaboration@<版本>/commands/。
# 手动复制 —— 仅插件版本 ≤0.12.2 需要(Windows 示例)
copy commands\peers-jiagoushi.md %USERPROFILE%\.config\opencode\command\
copy commands\peers-yanfa.md  %USERPROFILE%\.config\opencode\command\

用法:

  • /peers-jiagoushi <研发peer名,多个用英文逗号隔开> —— 架构师角色,参数为你的研发搭档(peer 名)
  • /peers-yanfa <架构师peer名> —— 研发工程师角色,参数为你的架构师搭档

前置条件:

  • 所有角色会话同一工作目录,或在 opencode.json 配置 peerScope: "all"(跨目录时出站消息会被 scope 挡住)
  • 每个角色会话需先 /peers-name 起名,对方才能寻址到你

UX 说明:这两个命令走 opencode 原生补全(选中只插入命令名,需再按一次 Enter 提交参数),与 /deliberate 同款;插件的"单 Enter 直跑"只覆盖插件自家命令,属预期。插件 TUI 面板/palette 不列出这两个命令(它们不是插件命令),从原生补全菜单选用。

说明:commands/*.md 随包发布,既是自动注册的读源(0.12.3+,经插件 config hook 注入 —— opencode 本身从不扫描插件包),也是旧版本的手动分发源。

长内容纪律(0.12.4+)

两个角色规范都内嵌了让 peer 消息保持短小、可持久的双向规则:

  • 发送侧:内容含代码块/diff/表格/多级清单,或预计超过约 2000 字时,先写项目内 docs/ 下带日期命名的 md 文档;send_message 只发不超过 10 行的结论 + 文档相对路径。禁止把整篇方案塞进一条消息——单条消息上限 8192 UTF-8 字节(约 2700 个中文字),超限在发送时即被拒。
  • 读取侧:消息指向文档路径时,先用 read 工具读取文档全文再回复,不要只凭消息摘要表态。

peerScope: "all"(跨目录协作)时,项目内相对路径对方读不到——请给出对方实际可访问的路径。

注入 agent 与 prefill 说明

  • peer 消息注入使用会话最后一次真实 chat.message 记录的 agent。TUI 里切换 Build↔Plan 本身不更新任何记录;切换后先发一条普通消息,注入才会跟随新 agent(例如想让注入保持 plan 只读语义,请先在 Plan 下发一条消息再收 peer 消息)。
  • 使用不支持 prefill 的模型(如 volcengine-plan/glm-5.3-flash)时,peer 注入撞上宿主自动续跑可能偶发 The last message cannot be from the assistant for a model that does not support prefill 报错。属宿主行为,低概率、下一条消息即自愈。

配置

可以通过 opencode.json 中的元组形式传入选项:

{
  "plugin": [
    ["opencode-collaboration", { "inboundPolicy": "hold", "name": "frontend" }]
  ]
}

| 选项 | 默认值 | 说明 | |---|---|---| | inboundPolicy | "accept" | accept 立即投递;auto 仅当发送方与接收方目录相同时接受,否则进入待审;hold 暂存消息供人工审阅;refuse 直接拒绝 | | peerPermissions | "allow" | 对端来源的权限请求:allow 自动批准普通请求,ask 保持原生提示不变,deny 拒绝。即使在 allow 模式下,OpenCode/插件权限配置、AGENTS.md、凭据/密钥以及权限升级也永远不会被自动批准;已存在的 OpenCode 拒绝规则始终优先 | | peerScope | "directory" | directory(默认)将 list_agents//peers/send_message 限定为与本会话工作目录完全相同的对端;"all" 恢复跨目录可见性。入站消息不受 scope 限制 | | roleCommands | true | 启动时自动注册两个角色命令 /peers-jiagoushi + /peers-yanfa(0.12.3+)。设为 false 关闭注入 —— 例如你自己在 ~/.config/opencode/command/ 维护同名副本时(用户自定义同名命令始终优先) | | name | <dir>-<hex4> | 用于寻址的显示名。0.11.0 起名字属于「会话」而非进程:显式名(/peers-name、name 选项、或从标题恢复的名字)保存在该会话根标题的 (name) 后缀里,重新进入该会话并产生交互时恢复(聊天消息、任意斜杠命令 —— 含 /peers-online —— 或入站 peer 消息)。0.12.0:仅重启进程不再恢复名字 —— 启动自动召回与 30 分钟重进窗口均已删除(见《重启后如何重新上线》与《命名 ≠ 在线》)。从未被验证过的会话(如仅有旧标题的会话)永不恢复;等于进程默认名 config.name 的名字不会被采纳为会话名。0.11.0 起名字属于「会话」而非进程:改名只影响运行命令的那一个会话。名字需在同一工作目录内的在线对端之间唯一(跨目录可重名);/peers-name 撞名会被拒绝。name 选项(config.name)是本进程的默认名,供未自行命名的会话使用。隐式默认名永不写入标题 | | showNameInTitle | true | 把该会话的显式名字追加到它自己的根标题后(如 Fix login bug(张三))。0.11.0 起改名只影响命令所在的那一个会话,不再广播到进程内其它会话;后缀在退出后保留,便于按名定位 | | storageDir | $XDG_DATA_HOME/opencode-collaboration | 注册表与待审收件箱的存储目录 | | heartbeatMs | 10000 | 注册表心跳间隔 | | staleMs | 30000 | 心跳早于该时长则视为对端离线 | | maxQueue | 50 | 排队中(已接受、未投递)消息上限 | | maxHeld | 100 | 待审收件箱容量 | | heldExpiryMs | 300000 | 待审消息的批准时限;超时会产生一条最终 ACK | | maxMessageBytes | 8192 | 单条消息大小上限 | | sendRatePerMin | 10 | 每个对端的出站限流 | | recvRatePerMin | 20 | 每个发送方的入站限流 | | sweepMs | 15000 | 投递/ACK 可靠性兜底扫描间隔 | | toastOnMessage | true | 收到 peer 消息并实际注入会话后弹一条仅展示用的 TUI toast(来自 X: 摘要)。纯旁路可见性:投递语义与权限不变;仅在注入持久化成功后弹出(失败/重复不弹),批量投递合并为一条(来自 X (+N 条))。注意:该 toast 在 0.11.2~0.11.3 期间从未生效——请求缺少宿主必填的 variant 字段,被以 400 Payload 拒绝(且因 SDK 对非 2xx 不抛异常而被静默吞掉)。0.11.4 已发送正确形状。 | | stallTimeoutMin | 30 | 某个工具超过该分钟数无进展时自动中止(abort),并注入一条恢复提示。0 完全关闭本功能。环境变量兜底:OPENCODE_COLLAB_STALL_TIMEOUT_MIN(显式配置优先,env 为兜底) |

工作原理

OpenCode 进程 A                             OpenCode 进程 B
┌──────────────────────────────┐           ┌──────────────────────────────┐
│ 会话 A1 → 端点/spool          │           │ 会话 B1 → 端点/spool          │
│ 会话 A2 → 端点/spool          │           │ 会话 B2 → 端点/spool          │
│ 持久化发件箱 ◄── 最终 ACK      ├───────────┤ 本地 UDS/TCP 监听器           │
│ 注册表 v1 + v2 ─────────────┼──────────►│ promptAsync(精确会话)        │
└──────────────────────────────┘           └──────────────────────────────┘
  • 发现:协议 v2 为每个会话端点发布一条 0600 权限的注册表记录,并额外为最近活跃的根会话发布一条 v1 兼容记录。只有在本进程内有活跃迹象的会话才会被公布 —— 启动时的 busy/retry 状态、此后任何会话事件或消息活动,或有未投递 spool 记录等待恢复的会话。session.list() 返回的历史会话永远不会被公布,因此 /peers 只显示活跃会话(已关闭的进程在一个 stale 窗口内消失;已删除的会话在下一次心跳后消失)。读取方同时接受两个版本。默认对端名为 <dir>-<hex4>(如 my-app-a3f2),使同目录实例可以区分;每个具名会话作为独立对端、以它自己的名字发布,未命名会话在同一进程内折叠成 /peers 的一行、使用进程默认名(config.name 或 <dir>-<hex4>)。
  • 传输:v2 在 macOS/Linux 上使用带认证的 Unix 域套接字,Windows 上使用回环 TCP。另保留一个回环 HTTP 监听器供协议 v1 发送方使用。对端之间永远不会直接调用对方的 OpenCode 服务器。
  • 投递与恢复:每条消息是 spool/<endpoint>/{queued,held,inflight,done} 下一条 0600 权限的 JSON 记录。原子状态转移、进程锁、确定性的 OpenCode 消息 ID 和持久化去重使重试与重启都是安全的。旧版 inbox.json 会被归档但不投递,因为它没有可信的会话目标。
  • ACK 语义:HTTP 接受只代表"已收到"。最终的 delivered、refused、expired、dropped 或 duplicate ACK 会持久化重试到发送方,并存入 outbox/<sender-endpoint>。
  • 发送记账与有界重试(0.11.2):每次发送的终态结果都会落账——最终 ACK 到达后记 delivered(<ack>);不可重试的结果(401/403/404/429 及 v1"无可寻址会话")记 failed;重试预算耗尽记 dropped。可重试失败(5xx/网络)在心跳 tick 上以同一 message id 重试,预算为 60 秒内最多 3 次(接收侧幂等——已落地的重试是空操作)。终态记录保留 24 小时供查验后过期;仍可投递的记录永不自动删除。peer_message_status 无参调用列出本会话最近的出站消息(一行一条、只显示最新状态、最多 20 条)。
  • 环路保护:消息携带 via 跳数列表;超过 4 跳的链会被拒绝。
  • 读懂 /peers(0.11.3):每行显示的是会话最后活动时间(active X 分钟前),不是宿主进程的启动时间——重进窗口接管旧会话时不再显示"started just now"。v2 行会标注发布原因:带 接管会话 标签的是该对端进程接管的显式命名会话(用户命名或账本恢复,含用户当前未在驱动的会话)。另请注意关闭 TUI 窗口 ≠ 停止宿主进程:进程真正退出、注册表条目过期前,对端会一直广告并持有锚点;同目录重进的窗口可能与仍存活的旧进程短暂竞争名字。
  • 命名 ≠ 在线(0.12.0):peer 的名字是持久的——存在于会话标题和本地"已验证锚点账本"中,重启后仍在。但在线(被广告、可列出、可寻址)不是:会话只有出现活跃迹象才算在线,而"仅重启进程"已不再算活跃迹象。所有恢复现在都走同一条路径 tryRestore,它只在真实交互时触发——聊天消息、任意斜杠命令(含 /peers-online)或入站 peer 消息。因此重启后:零输入 ⇒ 离线(账本保住名字,不发布任何东西),输入一行或 /peers-online ⇒ 以同名上线。0.11.3 的行为——同目录新窗口在 30 分钟窗口内自动重新上线——已删除(决策 ①=A,2026-09-16):它是一次可能复活幽灵身份的启动期猜测,最多只省一次按键。会话一旦在线,只要进程存活,闲多久都在线——没有任何 recency/时间条件能把在线 peer 下线(硬规则;会话只会在其进程退出、心跳过期,或会话本身被删除时离开列表)。
  • 入站消息可见性(0.11.4):peer 消息以用户可见 part 注入——在 opencode TUI 中渲染为带发送方前缀的用户气泡([来自 X @ 目录]),收到消息不再"像什么都没发生"。已对真实宿主验证:synthetic 标志只影响 TUI 渲染,持久化与模型输入两种情况下完全一致;权限标记(metadata.peerMessage)原样随行,peer 权限作用域不受影响。notice() 通知保持不可见设计(synthetic),停滞恢复提示本来就是用户可见。此外消息实际注入成功后会弹一条仅展示用的 TUI toast(来自 X: 摘要,见 toastOnMessage,默认 true)。须如实说明:该 toast 在 0.11.2~0.11.3 期间从未生效——每次请求都因缺失宿主必填的 variant 字段被 400 Missing key ["variant"] 拒绝,且失败被静默吞掉(SDK 对非 2xx 结果不抛异常而是 resolve 错误对象);0.11.4 修复了请求形状并让首次失败以 warn 可见。

安全模型 —— 请务必阅读

  • 同机信任:任何以你的用户身份运行的进程都能读取注册表文件,从而向你实例的收件箱发消息。bearer token 只能防其他用户和误连,防不住拥有你 UID 的恶意进程。这与 Claude Code 本地 IPC 的信任级别一致。
  • 提示注入:对端消息对模型而言是不可信输入,和你手动粘贴的文本一样。纯文本无法传递文件、历史、授权或可执行的斜杠命令。在兼容默认的 peerPermissions: "allow" 下,普通工具请求可以无人值守执行;敏感项目请改用 ask、hold 或 refuse。
  • 受保护类别护栏是尽力而为的,不是安全边界:在 allow 模式下,插件对提及权限配置、AGENTS.md、凭据/密钥文件、shell 启动文件等敏感路径的请求会保留自己的自动批准 —— 但它匹配的只是请求文本,精心措辞的请求可以不出现这些路径(例如 npm config set x y 会写 ~/.npmrc 但全程不显示该路径)。请把 allow 视为完全信任机器上的每一个对端;当这种信任不成立时,请设置 ask(或 inboundPolicy: "hold"/"refuse")。
  • 自动批准如何保持作用域:插件监听权限请求事件,仅当发起请求的回合是由它注入的消息启动时(通过从工具调用的消息沿 parentID 向上追溯到原始用户消息并检查其 metadata 来判定)才会自动回复。你自己输入的回合产生的权限请求不会收到任何回复,原样落回 opencode 的正常提示流程。

宿主形态差异 —— 谁才算一个对端

一个 peer 就是一个会话端点,因此 /peers 能看到什么取决于 opencode 的宿主形态:

| 形态 | 每进程会话数 | 同目录兄弟会话互相可见 | |---|---|---| | opencode CLI(每终端一进程) | 1 | 不适用(每个窗口是独立进程) | | opencode serve | 多个(跨全部目录) | 是 —— 0.12.0 已修 | | opencode 官方桌面端(Electron) | 多个 | 是 —— 0.12.0 已修 | | openchamber(文档)(desktop/web/VS Code/mobile 共享同一 server;"Multi-run" 最多 5 个会话) | 多个,且自带并启动官方 serve | 是 —— 0.12.0 已修 |

以上四类均于 2026-09-16 现场实测。0.12.0 之前,寄居在同一个长驻进程里的两个具名会话互相看不见 —— 例如一个 opencode serve 托管的两个 worktree,或多会话桌面端/openchamber 服务端:/peers 与 list_agents 的每一行都被一个"这是不是我"的进程级判定过滤,把本进程的每个会话都当成了你自己。send_message 却与此不一致(已知兄弟名字的 agent 能给它发消息),于是各界面自相矛盾。0.12.0 按会话修正了列表界面:携带自己显式名字的同进程兄弟会被列出、可寻址,而你所处的会话仍然对自身隐藏。投递、命名与跨进程行为不变;同进程的未命名会话依旧折叠成一行,和以前一样。

0.12.0 之前没有可靠的用户侧绕法——这个不可见性出在列表计算里,不是配置项——请升级插件。

一个需要知道的宿主限制:toastOnMessage 弹窗需要有 TUI 客户端挂着。 裸的 opencode serve(以及桌面端/openchamber 的服务端)没有 TUI 消费者,因此即使消息本身已投递并注入,弹窗也不会显示。斜杠命令输出与注入的 peer 消息仍会在显示该会话的地方渲染。

局限性

  • 仅支持同一台机器(暂不支持跨主机转发)
  • OpenCode 的 command.execute.before 钩子目前不可取消。因此斜杠命令通过把提示文本替换为一个无害的已处理标记来"消费";TUI 面板操作提供了显式对话框,但服务器钩子本身无法阻止后续的命令处理。
  • 没有共享对话记录、Remote Control、Agent View、跨机器转发,也没有兼容 Claude Code 的团队/任务编排。

与 Claude Code 的对比

| 能力 | Claude Code | peers 0.2.0 | |---|---|---| | 跨进程与同进程会话寻址 | 原生支持 | 是,本地端点注册表 | | 重名时的精确目标 | 是 | 是,存在歧义时要求使用端点 ID | | 目标忙时发消息 | 是 | 是,立即注入一条消息的 promptAsync | | 持久化投递/重启恢复 | 产品层面托管 | 是,文件系统 spool 与持久化 ACK/发件箱 | | 权限边界 | 原生策略集成 | 基于事件的 allow/ask/deny,带受保护类别护栏 | | 用户批准交互 | 原生 | 显式的宿主 TUI 对话框加斜杠命令封装 | | 远程控制 / 共享任务 UI | Claude 生态可用 | 超出范围 |

本地纯文本交接在发现、精确寻址、忙时投递、重启恢复和最终结果追踪这些方面的效果基本等价。但它不是 Claude Code 产品级编排或远程 UI 的平替实现。

端到端验证

# 终端 1
cd /tmp/proj-a && opencode
/peers-name alpha

# 终端 2
cd /tmp/proj-b && opencode
/peers-name beta
/peers        # 应该能看到 alpha

# 在 beta 的会话中:
Use send_message to tell "alpha": the deploy keys rotated, pull again.

# alpha 会立即收到这条文本,即使它的会话正在忙;
# "传输层已收到"与"最终投递 ACK"始终是两个不同的概念。

开发中使用的无头(headless)变体:

cd /tmp/proj-a && opencode serve --port 14100 &
cd /tmp/proj-b && opencode serve --port 14101 &
# 然后通过 HTTP API 驱动两边(POST /session、/session/:id/prompt_async)

无凭据的真实进程测试会启动真实的 OpenCode 进程,并驱动已加载插件的事件与命令钩子。它会在真实 promptAsync 注入前验证 busy 注册表状态,通过真实存储的对端消息解析权限来源,验证默认 allow 与 ask 的差异,并检查受保护请求是否被留给原生策略处理。由于缺少模型提供商凭据,它无法产生真实的提供商权限请求,因此测试桩记录的是插件的回复调用,而不是声称完成了端到端原生权限提示;其余的原生拒绝和受保护类别判定由专项测试覆盖。

开发

npm install                # 不触发构建(无 prepare 脚本)
npm run build              # tsc → dist/(明文,本地快速迭代用)
npm run build:obfuscated   # clean + tsc + 混淆 → dist/(发布产物)
npm test                   # build:obfuscated + node --test tests/*.test.mjs
npm run typecheck
npm run dry-run            # npm publish --dry-run

npm test 跑的是发布产物 dist;tests/obfuscation.test.mjs 只在发布产物上通过。发布产物的 sourcemap 输出到 .obfuscate-maps/,不随包发布。

除 @opencode-ai/plugin(peer 依赖)和 zod(工具 schema)外,零运行时依赖。

发布说明

0.12.0 —— 同进程队友可见,以及一个显式上线入口

  • 修复(R5): 在 opencode serve、官方桌面端与 openchamber 下,同一长驻进程内的具名会话在 /peers 与 list_agents 中互相不可见。列表判定现按会话进行——具名兄弟会显示,调用者自身会话仍隐藏。2026-09-16 于 serve + 桌面端实测。
  • 变更(决策 ①=A): 仅重启进程不再自动恢复 peer 名字——启动自动召回与 30 分钟重进窗口均已删除。名字仍然持久;用 /peers-online 或在会话里输入任意一行即可上线。上线后闲置多久都在线。
  • 新增(R12): /peers-online —— 显式把当前会话置为在线。幂等;返回名字、目录与端点。与其他斜杠命令一样会消耗一次宿主模型回合。

0.11.0 —— peer 名字属于「会话」

  • 改名只影响运行 /peers-name 的那一个会话。 旧的广播写法(重写进程内每一个身份根标题)已改为只写单个会话;给会话 B 改名不会再改动会话 A,也不会使 A 已存的身份失效。
  • 具名会话本身就是一个对端。 /peers/list_agents 把每个具名会话列为独立一行,即使空闲也以它自己的名字发布;按该名字投递的消息会落到该会话。未命名会话仍按进程折叠成一行、用进程默认名。config.name 只是这个默认名,不再是"每个会话的名字"。
  • 名字在同一工作目录内的在线对端之间唯一。 若同名已被同目录内的其他在线对端占用,/peers-name 会被拒绝(对端退出后名字可复用);跨目录可重名。
  • 零交互恢复按会话进行。 启动时每条已验证锚点恢复到它自己的会话、用它自己的名字;旧的"歧义 → 一个临时名"层已移除,等于进程默认名的后缀永远不会被当作会话自己的名字。因此一个目录里若有多个具名会话,启动后会发布多个对端。(0.12.0 已移除 —— 启动不再恢复名字;见上方 0.12.0 说明。)
  • 互操作: 运行 ≤0.10.2 的对端仍按自己的"每进程折叠"解析名字,因此它按名发送的消息可能落到你最近活跃的会话而非具名会话。两端都是本插件,建议两端都升级以获得严格的按名投递。

许可证

MIT