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
Maintainers
Readme
opencode-collaboration
English | 中文
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看看谁在线:
/peersOther 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 才需要手动复制。手动复制的文件来源(二选一):
- 仓库 checkout:从 gitee 仓库
commands/目录取;- 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或duplicateACK 会持久化重试到发送方,并存入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-runnpm 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
