opencode-collaboration 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +194 -0
- package/README.md +224 -0
- package/README.zh-CN.md +224 -0
- package/commands/list-agents.md +8 -0
- package/commands/peers-inbox.md +8 -0
- package/commands/peers-name.md +8 -0
- package/commands/peers-outbox.md +8 -0
- package/commands/peers.md +8 -0
- package/dist/commands.d.ts +29 -0
- package/dist/commands.js +95 -0
- package/dist/config.d.ts +31 -0
- package/dist/config.js +50 -0
- package/dist/delivery.d.ts +42 -0
- package/dist/delivery.js +177 -0
- package/dist/feedback.d.ts +8 -0
- package/dist/feedback.js +40 -0
- package/dist/format.d.ts +32 -0
- package/dist/format.js +107 -0
- package/dist/gating.d.ts +4 -0
- package/dist/gating.js +16 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.js +410 -0
- package/dist/listener.d.ts +37 -0
- package/dist/listener.js +335 -0
- package/dist/outbox.d.ts +12 -0
- package/dist/outbox.js +110 -0
- package/dist/permissions.d.ts +47 -0
- package/dist/permissions.js +194 -0
- package/dist/queue.d.ts +89 -0
- package/dist/queue.js +824 -0
- package/dist/registry.d.ts +70 -0
- package/dist/registry.js +308 -0
- package/dist/sender.d.ts +27 -0
- package/dist/sender.js +139 -0
- package/dist/session-runtime.d.ts +40 -0
- package/dist/session-runtime.js +355 -0
- package/dist/session-tracker.d.ts +16 -0
- package/dist/session-tracker.js +39 -0
- package/dist/tools/peers-tools.d.ts +26 -0
- package/dist/tools/peers-tools.js +173 -0
- package/dist/transport.d.ts +20 -0
- package/dist/transport.js +46 -0
- package/dist/tui.d.ts +3 -0
- package/dist/tui.js +228 -0
- package/dist/types.d.ts +162 -0
- package/dist/types.js +1 -0
- package/package.json +93 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
木兰宽松许可证,第2版
|
|
2
|
+
|
|
3
|
+
木兰宽松许可证,第2版
|
|
4
|
+
|
|
5
|
+
2020年1月 http://license.coscl.org.cn/MulanPSL2
|
|
6
|
+
|
|
7
|
+
您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第2版(“本许可证”)的如下条款的约束:
|
|
8
|
+
|
|
9
|
+
0. 定义
|
|
10
|
+
|
|
11
|
+
“软件” 是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。
|
|
12
|
+
|
|
13
|
+
“贡献” 是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。
|
|
14
|
+
|
|
15
|
+
“贡献者” 是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。
|
|
16
|
+
|
|
17
|
+
“法人实体” 是指提交贡献的机构及其“关联实体”。
|
|
18
|
+
|
|
19
|
+
“关联实体” 是指,对“本许可证”下的行为方而言,控制、受控制或与其共同受控制的机构,此处的控制是
|
|
20
|
+
指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。
|
|
21
|
+
|
|
22
|
+
1. 授予版权许可
|
|
23
|
+
|
|
24
|
+
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可
|
|
25
|
+
以复制、使用、修改、分发其“贡献”,不论修改与否。
|
|
26
|
+
|
|
27
|
+
2. 授予专利许可
|
|
28
|
+
|
|
29
|
+
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定
|
|
30
|
+
撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡
|
|
31
|
+
献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软
|
|
32
|
+
件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“
|
|
33
|
+
关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或
|
|
34
|
+
其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权
|
|
35
|
+
行动之日终止。
|
|
36
|
+
|
|
37
|
+
3. 无商标许可
|
|
38
|
+
|
|
39
|
+
“本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定
|
|
40
|
+
的声明义务而必须使用除外。
|
|
41
|
+
|
|
42
|
+
4. 分发限制
|
|
43
|
+
|
|
44
|
+
您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“
|
|
45
|
+
本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。
|
|
46
|
+
|
|
47
|
+
5. 免责声明与责任限制
|
|
48
|
+
|
|
49
|
+
“软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对
|
|
50
|
+
任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于
|
|
51
|
+
何种法律理论,即使其曾被建议有此种损失的可能性。
|
|
52
|
+
|
|
53
|
+
6. 语言
|
|
54
|
+
|
|
55
|
+
“本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文
|
|
56
|
+
版为准。
|
|
57
|
+
|
|
58
|
+
条款结束
|
|
59
|
+
|
|
60
|
+
如何将木兰宽松许可证,第2版,应用到您的软件
|
|
61
|
+
|
|
62
|
+
如果您希望将木兰宽松许可证,第2版,应用到您的新软件,为了方便接收者查阅,建议您完成如下三步:
|
|
63
|
+
|
|
64
|
+
1, 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字;
|
|
65
|
+
|
|
66
|
+
2, 请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中;
|
|
67
|
+
|
|
68
|
+
3, 请将如下声明文本放入每个源文件的头部注释中。
|
|
69
|
+
|
|
70
|
+
Copyright (c) [Year] [name of copyright holder]
|
|
71
|
+
[Software Name] is licensed under Mulan PSL v2.
|
|
72
|
+
You can use this software according to the terms and conditions of the Mulan
|
|
73
|
+
PSL v2.
|
|
74
|
+
You may obtain a copy of Mulan PSL v2 at:
|
|
75
|
+
http://license.coscl.org.cn/MulanPSL2
|
|
76
|
+
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
|
|
77
|
+
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
78
|
+
NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
79
|
+
See the Mulan PSL v2 for more details.
|
|
80
|
+
|
|
81
|
+
Mulan Permissive Software License,Version 2
|
|
82
|
+
|
|
83
|
+
Mulan Permissive Software License,Version 2 (Mulan PSL v2)
|
|
84
|
+
|
|
85
|
+
January 2020 http://license.coscl.org.cn/MulanPSL2
|
|
86
|
+
|
|
87
|
+
Your reproduction, use, modification and distribution of the Software shall
|
|
88
|
+
be subject to Mulan PSL v2 (this License) with the following terms and
|
|
89
|
+
conditions:
|
|
90
|
+
|
|
91
|
+
0. Definition
|
|
92
|
+
|
|
93
|
+
Software means the program and related documents which are licensed under
|
|
94
|
+
this License and comprise all Contribution(s).
|
|
95
|
+
|
|
96
|
+
Contribution means the copyrightable work licensed by a particular
|
|
97
|
+
Contributor under this License.
|
|
98
|
+
|
|
99
|
+
Contributor means the Individual or Legal Entity who licenses its
|
|
100
|
+
copyrightable work under this License.
|
|
101
|
+
|
|
102
|
+
Legal Entity means the entity making a Contribution and all its
|
|
103
|
+
Affiliates.
|
|
104
|
+
|
|
105
|
+
Affiliates means entities that control, are controlled by, or are under
|
|
106
|
+
common control with the acting entity under this License, ‘control’ means
|
|
107
|
+
direct or indirect ownership of at least fifty percent (50%) of the voting
|
|
108
|
+
power, capital or other securities of controlled or commonly controlled
|
|
109
|
+
entity.
|
|
110
|
+
|
|
111
|
+
1. Grant of Copyright License
|
|
112
|
+
|
|
113
|
+
Subject to the terms and conditions of this License, each Contributor hereby
|
|
114
|
+
grants to you a perpetual, worldwide, royalty-free, non-exclusive,
|
|
115
|
+
irrevocable copyright license to reproduce, use, modify, or distribute its
|
|
116
|
+
Contribution, with modification or not.
|
|
117
|
+
|
|
118
|
+
2. Grant of Patent License
|
|
119
|
+
|
|
120
|
+
Subject to the terms and conditions of this License, each Contributor hereby
|
|
121
|
+
grants to you a perpetual, worldwide, royalty-free, non-exclusive,
|
|
122
|
+
irrevocable (except for revocation under this Section) patent license to
|
|
123
|
+
make, have made, use, offer for sale, sell, import or otherwise transfer its
|
|
124
|
+
Contribution, where such patent license is only limited to the patent claims
|
|
125
|
+
owned or controlled by such Contributor now or in future which will be
|
|
126
|
+
necessarily infringed by its Contribution alone, or by combination of the
|
|
127
|
+
Contribution with the Software to which the Contribution was contributed.
|
|
128
|
+
The patent license shall not apply to any modification of the Contribution,
|
|
129
|
+
and any other combination which includes the Contribution. If you or your
|
|
130
|
+
Affiliates directly or indirectly institute patent litigation (including a
|
|
131
|
+
cross claim or counterclaim in a litigation) or other patent enforcement
|
|
132
|
+
activities against any individual or entity by alleging that the Software or
|
|
133
|
+
any Contribution in it infringes patents, then any patent license granted to
|
|
134
|
+
you under this License for the Software shall terminate as of the date such
|
|
135
|
+
litigation or activity is filed or taken.
|
|
136
|
+
|
|
137
|
+
3. No Trademark License
|
|
138
|
+
|
|
139
|
+
No trademark license is granted to use the trade names, trademarks, service
|
|
140
|
+
marks, or product names of Contributor, except as required to fulfill notice
|
|
141
|
+
requirements in section 4.
|
|
142
|
+
|
|
143
|
+
4. Distribution Restriction
|
|
144
|
+
|
|
145
|
+
You may distribute the Software in any medium with or without modification,
|
|
146
|
+
whether in source or executable forms, provided that you provide recipients
|
|
147
|
+
with a copy of this License and retain copyright, patent, trademark and
|
|
148
|
+
disclaimer statements in the Software.
|
|
149
|
+
|
|
150
|
+
5. Disclaimer of Warranty and Limitation of Liability
|
|
151
|
+
|
|
152
|
+
THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY
|
|
153
|
+
KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR
|
|
154
|
+
COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT
|
|
155
|
+
LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING
|
|
156
|
+
FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO
|
|
157
|
+
MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF
|
|
158
|
+
THE POSSIBILITY OF SUCH DAMAGES.
|
|
159
|
+
|
|
160
|
+
6. Language
|
|
161
|
+
|
|
162
|
+
THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION
|
|
163
|
+
AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF
|
|
164
|
+
DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION
|
|
165
|
+
SHALL PREVAIL.
|
|
166
|
+
|
|
167
|
+
END OF THE TERMS AND CONDITIONS
|
|
168
|
+
|
|
169
|
+
How to Apply the Mulan Permissive Software License,Version 2
|
|
170
|
+
(Mulan PSL v2) to Your Software
|
|
171
|
+
|
|
172
|
+
To apply the Mulan PSL v2 to your work, for easy identification by
|
|
173
|
+
recipients, you are suggested to complete following three steps:
|
|
174
|
+
|
|
175
|
+
i. Fill in the blanks in following statement, including insert your software
|
|
176
|
+
name, the year of the first publication of your software, and your name
|
|
177
|
+
identified as the copyright owner;
|
|
178
|
+
|
|
179
|
+
ii. Create a file named "LICENSE" which contains the whole context of this
|
|
180
|
+
License in the first directory of your software package;
|
|
181
|
+
|
|
182
|
+
iii. Attach the statement to the appropriate annotated syntax at the
|
|
183
|
+
beginning of each source file.
|
|
184
|
+
|
|
185
|
+
Copyright (c) [Year] [name of copyright holder]
|
|
186
|
+
[Software Name] is licensed under Mulan PSL v2.
|
|
187
|
+
You can use this software according to the terms and conditions of the Mulan
|
|
188
|
+
PSL v2.
|
|
189
|
+
You may obtain a copy of Mulan PSL v2 at:
|
|
190
|
+
http://license.coscl.org.cn/MulanPSL2
|
|
191
|
+
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
|
|
192
|
+
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
193
|
+
NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
194
|
+
See the Mulan PSL v2 for more details.
|
package/README.md
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# opencode-collaboration
|
|
2
|
+
|
|
3
|
+
**English** | [中文](./README.zh-CN.md)
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/opencode-collaboration)
|
|
6
|
+
[](https://www.npmjs.com/package/opencode-collaboration)
|
|
7
|
+
[](https://gitee.com/cqy0/opencode-collaboration/blob/master/LICENSE)
|
|
8
|
+
|
|
9
|
+
Cross-session messaging for [opencode](https://opencode.ai) — let independent opencode instances on the same machine discover each other and exchange plain-text messages. Modeled after [Claude Code's cross-session messaging](https://claudefa.st/blog/guide/mechanics/cross-session-messaging).
|
|
10
|
+
|
|
11
|
+
Run several opencode terminals in parallel (different repos, worktrees, or tasks) and let them hand each other conclusions instead of copy-pasting context between windows:
|
|
12
|
+
|
|
13
|
+
> frontend session: *"the API contract changed, field is now `user_id`"*
|
|
14
|
+
> backend session: *"migration is done, safe to rebase on main"*
|
|
15
|
+
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
- `list_agents` / `send_message` tools — the agent can discover peers and text them
|
|
19
|
+
- `/peers` (alias `/list-agents`), `/peers-name`, `/peers-inbox`, `/peers-outbox` commands — user-side control
|
|
20
|
+
- **accept / auto / hold / refuse** inbound gating; `auto` accepts same-directory peers and holds cross-directory messages
|
|
21
|
+
- One independently addressable endpoint per OpenCode session, including child sessions; exact endpoint IDs disambiguate duplicate names
|
|
22
|
+
- Durable per-session queues, held messages, delivery outcomes and sender outboxes survive process restarts
|
|
23
|
+
- Accepted messages are injected immediately with one `promptAsync` call per message, including while the target session is busy
|
|
24
|
+
- Messages are **plain text only** — no files, no shared conversation history
|
|
25
|
+
- **Peer-triggered turns run unattended by default**: permission requests raised while acting on an injected peer message are auto-approved (`peerPermissions`, modeled after Claude Code's permission modes). Your own turns are unaffected
|
|
26
|
+
- Command results and notifications are shown **inline in the session** — no toast popups
|
|
27
|
+
- **Explicit TUI controls**: palette actions use host dialogs for selection and confirmation; slash wrappers remain available for automation and compatibility
|
|
28
|
+
- Local only: everything stays on your machine (Unix-domain sockets on macOS/Linux, loopback TCP on Windows, plus a compatibility loopback listener for v1 peers)
|
|
29
|
+
|
|
30
|
+
## Install
|
|
31
|
+
|
|
32
|
+
This fork is **not published to npm** — it is maintained as a git repository and installed straight from Gitee. The repo ships prebuilt `dist/`, so no build step runs at install time (opencode's Bun installer does not run `prepare` for git dependencies).
|
|
33
|
+
|
|
34
|
+
Add to your `opencode.json`:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"plugin": ["opencode-collaboration@git+https://gitee.com/cqy0/opencode-collaboration.git"]
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Requires opencode >= 1.18.0.
|
|
43
|
+
|
|
44
|
+
> **Updating:** opencode caches git plugins under `~/.cache/opencode/packages/`. After a newer commit is pushed, delete the cached `opencode-collaboration@git+...` folder (or bump the repo ref) and restart opencode to pick it up — git plugins are not re-fetched on every launch.
|
|
45
|
+
|
|
46
|
+
**Single-Enter commands (optional but recommended).** The package ships a TUI entry that makes the plugin's slash commands execute on the first Enter. opencode's TUI loads plugins from `~/.config/opencode/tui.json` (a separate list from `opencode.json`), so add the plugin there too:
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
"plugin": ["opencode-collaboration"]
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Without this everything still works — the commands just keep opencode's default "first Enter inserts `/name `, second Enter submits" behavior. Notes:
|
|
55
|
+
|
|
56
|
+
- The autocomplete keeps showing a **single** `/peers*` row per command (the server-defined one). Instant execution comes from a high-priority Enter binding in the TUI entry: when the prompt holds exactly a plugin command — or a prefix that uniquely identifies it, like `/peers-nam` — Enter runs it immediately; anything else falls through to opencode's stock bindings untouched. This works both inside a session and on the start (home) screen — there a session is created first, exactly like a normal submit.
|
|
57
|
+
- Commands typed **with arguments** (e.g. `/peers-name frontend`) are untouched — Enter submits normally and the argument is preserved.
|
|
58
|
+
- Older opencode versions ignore the TUI entry entirely and keep the two-Enter behavior.
|
|
59
|
+
|
|
60
|
+
For local development from a checkout, symlink the built entry into the global plugins directory:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npm install && npm run build
|
|
64
|
+
ln -sf "$PWD/dist/index.js" ~/.config/opencode/plugins/opencode-collaboration.js
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
(`~/.config/opencode/plugins/*.js` is auto-loaded at startup.)
|
|
68
|
+
|
|
69
|
+
## Usage
|
|
70
|
+
|
|
71
|
+
**Name your instances** so peers can address you:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
/peers-name frontend
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**See who is online:**
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
/peers
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
Other Opencode sessions (2):
|
|
85
|
+
[waiting] · frontend · /Users/you/app/frontend · started 9m ago
|
|
86
|
+
[idle] · backend · /Users/you/app/backend · started 29m ago
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`[waiting]` = a turn is running there, but peer messages are still injected immediately; `[idle]` = no turn is running. A queued message means an immediate injection attempt needs retry, not that delivery waits for idle, and the sender keeps a pending final ACK meanwhile.
|
|
90
|
+
|
|
91
|
+
**Let the agent talk:**
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
Use send_message to tell "backend" that the login form now posts to /v2/login.
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The receiving session gets the text immediately as a synthetic user message, including the sender's exact endpoint ID and how to reply. `send_message` returns a tracking ID; use `peer_message_status` or `/peers-outbox` to distinguish transport receipt from final delivery.
|
|
98
|
+
|
|
99
|
+
**Review held messages** (when `inboundPolicy` is `"hold"`):
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
/peers-inbox # list held messages
|
|
103
|
+
/peers-inbox accept 2 # deliver message #2
|
|
104
|
+
/peers-inbox drop all # discard all
|
|
105
|
+
/peers-outbox # receipts and final ACK outcomes
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Configuration
|
|
109
|
+
|
|
110
|
+
Options can be passed via the tuple form in `opencode.json`:
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
{
|
|
114
|
+
"plugin": [
|
|
115
|
+
["opencode-collaboration@git+https://gitee.com/cqy0/opencode-collaboration.git", { "inboundPolicy": "hold", "name": "frontend" }]
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
| Option | Default | Description |
|
|
121
|
+
|---|---|---|
|
|
122
|
+
| `inboundPolicy` | `"accept"` | `accept` delivers immediately; `auto` accepts only when sender and receiver directories match and otherwise holds; `hold` parks messages for review; `refuse` rejects them |
|
|
123
|
+
| `peerPermissions` | `"allow"` | Peer-origin permission requests: `allow` auto-approves ordinary requests, `ask` leaves native prompts untouched, `deny` rejects. Even in `allow`, OpenCode/plugin permission configuration, `AGENTS.md`, credentials/secrets and permission escalation are never auto-approved; existing OpenCode deny rules always win |
|
|
124
|
+
| `name` | `<dir>-<hex4>` | display name other peers use to address you; the default appends a short hex suffix (from the instance ID) to the directory basename so same-directory instances are distinguishable, matching Claude Code's `my-app-3f` pattern |
|
|
125
|
+
| `storageDir` | `$XDG_DATA_HOME/opencode-collaboration` | where the registry and held inbox live |
|
|
126
|
+
| `heartbeatMs` | `10000` | registry heartbeat interval |
|
|
127
|
+
| `staleMs` | `30000` | peer is offline if its heartbeat is older than this |
|
|
128
|
+
| `maxQueue` | `50` | queued (accepted, undelivered) message cap |
|
|
129
|
+
| `maxHeld` | `100` | held inbox cap |
|
|
130
|
+
| `heldExpiryMs` | `300000` | held approval expiry; expiry produces a final ACK |
|
|
131
|
+
| `maxMessageBytes` | `8192` | per-message size cap |
|
|
132
|
+
| `sendRatePerMin` | `10` | outbound rate limit per peer |
|
|
133
|
+
| `recvRatePerMin` | `20` | inbound rate limit per sender |
|
|
134
|
+
| `sweepMs` | `15000` | fallback delivery/ACK reliability sweep interval |
|
|
135
|
+
|
|
136
|
+
## How it works
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
OpenCode process A OpenCode process B
|
|
140
|
+
┌──────────────────────────────┐ ┌──────────────────────────────┐
|
|
141
|
+
│ session A1 → endpoint/spool │ │ session B1 → endpoint/spool │
|
|
142
|
+
│ session A2 → endpoint/spool │ │ session B2 → endpoint/spool │
|
|
143
|
+
│ durable outbox ◄── final ACK ├───────────┤ local UDS/TCP listener │
|
|
144
|
+
│ registry v1 + v2 ────────────┼──────────►│ promptAsync(exact session) │
|
|
145
|
+
└──────────────────────────────┘ └──────────────────────────────┘
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
- **Discovery**: protocol v2 publishes one `0600` registry record per session endpoint and one v1 compatibility record for the most recently active root session. Only sessions with signs of life in the publishing process are advertised — busy/retry at startup, any session event or message activity thereafter, or undelivered spool records awaiting recovery. Historical sessions from `session.list()` are never published, so `/peers` shows live sessions only (a closed process disappears within one stale window; a deleted session disappears on the next heartbeat). Readers accept both versions. The default peer name is `<dir>-<hex4>` (e.g. `my-app-a3f2`), making same-directory instances distinguishable; an explicit `name` option or `/peers-name` replaces it entirely.
|
|
149
|
+
- **Transport**: v2 uses an authenticated Unix-domain socket on macOS/Linux or loopback TCP on Windows. A loopback HTTP listener remains available to protocol-v1 senders. Peers never call another process's OpenCode server.
|
|
150
|
+
- **Delivery and recovery**: each message is a `0600` JSON record under `spool/<endpoint>/{queued,held,inflight,done}`. Atomic transitions, process locks, deterministic OpenCode message IDs and durable deduplication make retries and restarts safe. Legacy `inbox.json` is archived without delivery because it has no trustworthy session target.
|
|
151
|
+
- **ACK semantics**: HTTP acceptance is only a receipt. Final `delivered`, `refused`, `expired`, `dropped` or `duplicate` ACKs are durably retried to the sender and stored in `outbox/<sender-endpoint>`.
|
|
152
|
+
- **Loop protection**: messages carry a `via` hop list; chains longer than 4 hops are rejected.
|
|
153
|
+
|
|
154
|
+
## Security model — read this
|
|
155
|
+
|
|
156
|
+
- **Same-machine trust**: any process running as your user can read the registry files and therefore talk to your instances' inboxes. The bearer token protects against other users and accidental connections, not against a malicious process with your UID. This matches the trust level of Claude Code's local IPC.
|
|
157
|
+
- **Prompt injection**: a peer message is untrusted input to the model, exactly like text pasted by a user. Plain text cannot transfer files, history, consent, or executable slash commands. With the backward-compatible default `peerPermissions: "allow"`, ordinary tool requests can run unattended; use `ask`, `hold`, or `refuse` for sensitive projects.
|
|
158
|
+
- **The protected-category guardrail is best-effort, not a boundary**: in `allow` mode the plugin withholds its auto-approval for requests that *mention* permission configuration, `AGENTS.md`, credentials/secrets files, shell startup files, and similar sensitive paths — but it matches on the request text, so a cleverly phrased request can avoid naming those paths (e.g. `npm config set x y` writes `~/.npmrc` without ever showing the path). Treat `allow` as **fully trusting every peer on the machine**; set `ask` (or `inboundPolicy: "hold"`/`"refuse"`) whenever that trust is not warranted.
|
|
159
|
+
- **How auto-allow stays scoped**: the plugin listens for permission-request events and only auto-replies when the requesting turn was started by a message it injected (detected by walking from the tool call's message up to the originating user message and checking its metadata). Permission requests from your own typed turns get no reply and fall through to opencode's normal prompt flow untouched.
|
|
160
|
+
|
|
161
|
+
## Limitations
|
|
162
|
+
|
|
163
|
+
- Same machine only (no cross-host relay yet)
|
|
164
|
+
- OpenCode's `command.execute.before` hook is currently not cancellable. Slash commands are therefore consumed by replacing their prompt text with a harmless handled marker; TUI palette controls add explicit dialogs, but the server hook itself cannot stop downstream command processing.
|
|
165
|
+
- No shared transcript, Remote Control, Agent View, remote-machine relay, or Claude Code-compatible team/task orchestration.
|
|
166
|
+
|
|
167
|
+
## Claude Code comparison
|
|
168
|
+
|
|
169
|
+
| Capability | Claude Code | peers 0.2.0 |
|
|
170
|
+
|---|---|---|
|
|
171
|
+
| Cross-process and same-process session addressing | Native | Yes, local endpoint registry |
|
|
172
|
+
| Exact target with duplicate names | Yes | Yes, endpoint ID required when ambiguous |
|
|
173
|
+
| Message while target is busy | Yes | Yes, immediate one-message `promptAsync` injection |
|
|
174
|
+
| Durable delivery/restart recovery | Product-managed | Yes, filesystem spool and durable ACK/outbox |
|
|
175
|
+
| Permission boundary | Native policy integration | Event-based allow/ask/deny with protected-category guardrails |
|
|
176
|
+
| User approval UX | Native | Explicit host TUI dialogs plus slash wrappers |
|
|
177
|
+
| Remote control / shared task UI | Available in Claude ecosystem | Out of scope |
|
|
178
|
+
|
|
179
|
+
The local plain-text handoff effect is substantially equivalent for discovery, exact targeting, busy delivery, restart recovery and final outcome tracking. It is not a drop-in implementation of Claude Code's product-level orchestration or remote UI.
|
|
180
|
+
|
|
181
|
+
## End-to-end verification
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
# terminal 1
|
|
185
|
+
cd /tmp/proj-a && opencode
|
|
186
|
+
/peers-name alpha
|
|
187
|
+
|
|
188
|
+
# terminal 2
|
|
189
|
+
cd /tmp/proj-b && opencode
|
|
190
|
+
/peers-name beta
|
|
191
|
+
/peers # should show alpha
|
|
192
|
+
|
|
193
|
+
# in beta's session:
|
|
194
|
+
Use send_message to tell "alpha": the deploy keys rotated, pull again.
|
|
195
|
+
|
|
196
|
+
# alpha receives the text immediately, including while its session is busy;
|
|
197
|
+
# transport receipt remains distinct from the final delivery ACK.
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Headless variant used in development:
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
cd /tmp/proj-a && opencode serve --port 14100 &
|
|
204
|
+
cd /tmp/proj-b && opencode serve --port 14101 &
|
|
205
|
+
# then drive both via the HTTP API (POST /session, /session/:id/prompt_async)
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
The credential-free real-host test starts actual OpenCode processes and drives the loaded plugin's event and command hooks. It verifies busy registry state before real `promptAsync` injection, resolves permission provenance through the real stored peer message, checks default `allow` versus `ask`, and checks protected requests are left to native policy. It cannot create a genuine model-provider permission request without provider credentials, so the fixture captures the plugin's reply call instead of claiming an end-to-end native permission prompt; focused tests cover the remaining native-deny and protected-category decisions.
|
|
209
|
+
|
|
210
|
+
## Development
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
npm install
|
|
214
|
+
npm run build # tsc → dist/
|
|
215
|
+
npm test # build + node --test tests/*.test.mjs
|
|
216
|
+
npm run typecheck
|
|
217
|
+
npm run dry-run # npm publish --dry-run
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Zero runtime dependencies beyond `@opencode-ai/plugin` (peer) and `zod` (tool schemas).
|
|
221
|
+
|
|
222
|
+
## License
|
|
223
|
+
|
|
224
|
+
MIT
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# opencode-collaboration
|
|
2
|
+
|
|
3
|
+
[English](./README.md) | **中文**
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/opencode-collaboration)
|
|
6
|
+
[](https://www.npmjs.com/package/opencode-collaboration)
|
|
7
|
+
[](https://gitee.com/cqy0/opencode-collaboration/blob/master/LICENSE)
|
|
8
|
+
|
|
9
|
+
[opencode](https://opencode.ai) 的跨会话消息插件 —— 让同一台机器上彼此独立的 opencode 实例互相发现、互发纯文本消息。设计参考了 [Claude Code 的跨会话消息](https://claudefa.st/blog/guide/mechanics/cross-session-messaging)。
|
|
10
|
+
|
|
11
|
+
并行运行多个 opencode 终端(不同的仓库、worktree 或任务),让它们直接互相传递结论,而不是在窗口之间手动复制粘贴上下文:
|
|
12
|
+
|
|
13
|
+
> 前端会话:*"API 契约变了,字段现在是 `user_id`"*
|
|
14
|
+
> 后端会话:*"迁移已完成,可以安全 rebase 到 main 了"*
|
|
15
|
+
|
|
16
|
+
## 功能特性
|
|
17
|
+
|
|
18
|
+
- `list_agents` / `send_message` 工具 —— Agent 可以发现对端并给它们发消息
|
|
19
|
+
- `/peers`(别名 `/list-agents`)、`/peers-name`、`/peers-inbox`、`/peers-outbox` 命令 —— 面向用户的控制入口
|
|
20
|
+
- 入站消息的 **accept / auto / hold / refuse** 四种门禁策略;`auto` 接受同目录对端,跨目录消息进入待审
|
|
21
|
+
- 每个 OpenCode 会话(包括子会话)都有一个可独立寻址的端点;出现重名时可用精确的端点 ID 区分
|
|
22
|
+
- 持久化机制完善:按会话的队列、待审消息、投递结果和发送方发件箱都能在进程重启后存活
|
|
23
|
+
- 被接受的消息会立即注入 —— 每条消息一次 `promptAsync` 调用,目标会话忙时同样立即注入
|
|
24
|
+
- 消息**仅限纯文本** —— 不能传文件,也不能共享对话历史
|
|
25
|
+
- **由对端消息触发的回合默认无人值守运行**:处理注入的对端消息期间产生的权限请求会被自动批准(`peerPermissions`,参考了 Claude Code 的权限模式)。你自己输入的回合不受影响
|
|
26
|
+
- 命令结果和通知**内联显示在会话中** —— 没有 toast 弹窗
|
|
27
|
+
- **明确的 TUI 控制**:面板操作使用宿主对话框进行选择确认;斜杠命令封装仍可用于自动化和兼容性场景
|
|
28
|
+
- 纯本地运行:一切都在你的机器上(macOS/Linux 使用 Unix 域套接字,Windows 使用回环 TCP,另有一个兼容 v1 对端的回环监听器)
|
|
29
|
+
|
|
30
|
+
## 安装
|
|
31
|
+
|
|
32
|
+
本 fork **未发布到 npm** —— 它作为 git 仓库维护,直接从 Gitee 安装。仓库自带构建好的 `dist/`,安装时不需要构建步骤(opencode 的 Bun 安装器对 git 依赖不会执行 `prepare`)。
|
|
33
|
+
|
|
34
|
+
加入你的 `opencode.json`:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"plugin": ["opencode-collaboration@git+https://gitee.com/cqy0/opencode-collaboration.git"]
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
要求 opencode >= 1.18.0。
|
|
43
|
+
|
|
44
|
+
> **更新方式:** opencode 会把 git 插件缓存在 `~/.cache/opencode/packages/` 下。推送新提交后,删除缓存的 `opencode-collaboration@git+...` 目录(或改动仓库 ref),再重启 opencode 才会拉取最新 —— git 插件不会每次启动都重新拉取。
|
|
45
|
+
|
|
46
|
+
**单回车执行命令(可选但推荐)。** 本包附带一个 TUI 入口,让插件的斜杠命令按一次回车即可执行。opencode 的 TUI 从 `~/.config/opencode/tui.json` 加载插件(这是与 `opencode.json` 相互独立的另一个列表),所以请把插件也加进去:
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
"plugin": ["opencode-collaboration"]
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
不加这个入口一切也照常工作 —— 只是命令会保持 opencode 默认的行为:第一次回车插入 `/name `,第二次回车才提交。说明:
|
|
55
|
+
|
|
56
|
+
- 自动补全仍然为每条命令显示**单独一行** `/peers*`(服务器定义的那个)。立即执行来自 TUI 入口中的一个高优先级回车绑定:当输入框内容恰好是一条插件命令 —— 或能唯一识别某条命令的前缀(如 `/peers-nam`)—— 回车立即执行;其他内容全部原样落回 opencode 的原生绑定。无论在会话内还是开始(主页)界面都有效 —— 主页界面会先创建一个会话,和普通提交完全一样。
|
|
57
|
+
- 携带**参数**输入的命令(如 `/peers-name frontend`)不受影响 —— 回车按正常方式提交,参数会被保留。
|
|
58
|
+
- 旧版 opencode 完全忽略 TUI 入口,保持两次回车的行为。
|
|
59
|
+
|
|
60
|
+
本地从源码目录开发时,把构建产物软链接到全局插件目录:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npm install && npm run build
|
|
64
|
+
ln -sf "$PWD/dist/index.js" ~/.config/opencode/plugins/opencode-collaboration.js
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
(`~/.config/opencode/plugins/*.js` 会在启动时自动加载。)
|
|
68
|
+
|
|
69
|
+
## 使用方法
|
|
70
|
+
|
|
71
|
+
**给实例命名**,让对端可以寻址你:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
/peers-name frontend
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**看看谁在线:**
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
/peers
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
Other Opencode sessions (2):
|
|
85
|
+
[waiting] · frontend · /Users/you/app/frontend · started 9m ago
|
|
86
|
+
[idle] · backend · /Users/you/app/backend · started 29m ago
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`[waiting]` = 该处有一个回合正在运行,但对端消息仍会立即注入;`[idle]` = 没有回合在运行。出现排队消息只表示某次立即注入尝试需要重试,不代表投递会等待空闲;发送方在此期间会持有一个待确认的最终 ACK。
|
|
90
|
+
|
|
91
|
+
**让 Agent 来对话:**
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
Use send_message to tell "backend" that the login form now posts to /v2/login.
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
接收方会话会立即收到这条文本,以一条合成的用户消息形式出现,其中包含发送方精确的端点 ID 以及回复方式。`send_message` 返回一个追踪 ID;用 `peer_message_status` 或 `/peers-outbox` 来区分"传输层已收到"和"最终已投递"。
|
|
98
|
+
|
|
99
|
+
**审阅待审消息**(当 `inboundPolicy` 为 `"hold"` 时):
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
/peers-inbox # 列出待审消息
|
|
103
|
+
/peers-inbox accept 2 # 投递第 2 条消息
|
|
104
|
+
/peers-inbox drop all # 全部丢弃
|
|
105
|
+
/peers-outbox # 回执与最终 ACK 结果
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## 配置
|
|
109
|
+
|
|
110
|
+
可以通过 `opencode.json` 中的元组形式传入选项:
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
{
|
|
114
|
+
"plugin": [
|
|
115
|
+
["opencode-collaboration@git+https://gitee.com/cqy0/opencode-collaboration.git", { "inboundPolicy": "hold", "name": "frontend" }]
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
| 选项 | 默认值 | 说明 |
|
|
121
|
+
|---|---|---|
|
|
122
|
+
| `inboundPolicy` | `"accept"` | `accept` 立即投递;`auto` 仅当发送方与接收方目录相同时接受,否则进入待审;`hold` 暂存消息供人工审阅;`refuse` 直接拒绝 |
|
|
123
|
+
| `peerPermissions` | `"allow"` | 对端来源的权限请求:`allow` 自动批准普通请求,`ask` 保持原生提示不变,`deny` 拒绝。即使在 `allow` 模式下,OpenCode/插件权限配置、`AGENTS.md`、凭据/密钥以及权限升级也永远不会被自动批准;已存在的 OpenCode 拒绝规则始终优先 |
|
|
124
|
+
| `name` | `<dir>-<hex4>` | 其他对端用来寻址你的显示名;默认值在目录名后追加一个短十六进制后缀(取自实例 ID),使同目录的多个实例可以区分,与 Claude Code 的 `my-app-3f` 命名方式一致 |
|
|
125
|
+
| `storageDir` | `$XDG_DATA_HOME/opencode-collaboration` | 注册表与待审收件箱的存储目录 |
|
|
126
|
+
| `heartbeatMs` | `10000` | 注册表心跳间隔 |
|
|
127
|
+
| `staleMs` | `30000` | 心跳早于该时长则视为对端离线 |
|
|
128
|
+
| `maxQueue` | `50` | 排队中(已接受、未投递)消息上限 |
|
|
129
|
+
| `maxHeld` | `100` | 待审收件箱容量 |
|
|
130
|
+
| `heldExpiryMs` | `300000` | 待审消息的批准时限;超时会产生一条最终 ACK |
|
|
131
|
+
| `maxMessageBytes` | `8192` | 单条消息大小上限 |
|
|
132
|
+
| `sendRatePerMin` | `10` | 每个对端的出站限流 |
|
|
133
|
+
| `recvRatePerMin` | `20` | 每个发送方的入站限流 |
|
|
134
|
+
| `sweepMs` | `15000` | 投递/ACK 可靠性兜底扫描间隔 |
|
|
135
|
+
|
|
136
|
+
## 工作原理
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
OpenCode 进程 A OpenCode 进程 B
|
|
140
|
+
┌──────────────────────────────┐ ┌──────────────────────────────┐
|
|
141
|
+
│ 会话 A1 → 端点/spool │ │ 会话 B1 → 端点/spool │
|
|
142
|
+
│ 会话 A2 → 端点/spool │ │ 会话 B2 → 端点/spool │
|
|
143
|
+
│ 持久化发件箱 ◄── 最终 ACK ├───────────┤ 本地 UDS/TCP 监听器 │
|
|
144
|
+
│ 注册表 v1 + v2 ─────────────┼──────────►│ promptAsync(精确会话) │
|
|
145
|
+
└──────────────────────────────┘ └──────────────────────────────┘
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
- **发现**:协议 v2 为每个会话端点发布一条 `0600` 权限的注册表记录,并额外为最近活跃的根会话发布一条 v1 兼容记录。只有在本进程内有活跃迹象的会话才会被公布 —— 启动时的 busy/retry 状态、此后任何会话事件或消息活动,或有未投递 spool 记录等待恢复的会话。`session.list()` 返回的历史会话永远不会被公布,因此 `/peers` 只显示活跃会话(已关闭的进程在一个 stale 窗口内消失;已删除的会话在下一次心跳后消失)。读取方同时接受两个版本。默认对端名为 `<dir>-<hex4>`(如 `my-app-a3f2`),使同目录实例可以区分;显式的 `name` 选项或 `/peers-name` 会完全替换它。
|
|
149
|
+
- **传输**:v2 在 macOS/Linux 上使用带认证的 Unix 域套接字,Windows 上使用回环 TCP。另保留一个回环 HTTP 监听器供协议 v1 发送方使用。对端之间永远不会直接调用对方的 OpenCode 服务器。
|
|
150
|
+
- **投递与恢复**:每条消息是 `spool/<endpoint>/{queued,held,inflight,done}` 下一条 `0600` 权限的 JSON 记录。原子状态转移、进程锁、确定性的 OpenCode 消息 ID 和持久化去重使重试与重启都是安全的。旧版 `inbox.json` 会被归档但不投递,因为它没有可信的会话目标。
|
|
151
|
+
- **ACK 语义**:HTTP 接受只代表"已收到"。最终的 `delivered`、`refused`、`expired`、`dropped` 或 `duplicate` ACK 会持久化重试到发送方,并存入 `outbox/<sender-endpoint>`。
|
|
152
|
+
- **环路保护**:消息携带 `via` 跳数列表;超过 4 跳的链会被拒绝。
|
|
153
|
+
|
|
154
|
+
## 安全模型 —— 请务必阅读
|
|
155
|
+
|
|
156
|
+
- **同机信任**:任何以你的用户身份运行的进程都能读取注册表文件,从而向你实例的收件箱发消息。bearer token 只能防其他用户和误连,防不住拥有你 UID 的恶意进程。这与 Claude Code 本地 IPC 的信任级别一致。
|
|
157
|
+
- **提示注入**:对端消息对模型而言是不可信输入,和你手动粘贴的文本一样。纯文本无法传递文件、历史、授权或可执行的斜杠命令。在兼容默认的 `peerPermissions: "allow"` 下,普通工具请求可以无人值守执行;敏感项目请改用 `ask`、`hold` 或 `refuse`。
|
|
158
|
+
- **受保护类别护栏是尽力而为的,不是安全边界**:在 `allow` 模式下,插件对*提及*权限配置、`AGENTS.md`、凭据/密钥文件、shell 启动文件等敏感路径的请求会保留自己的自动批准 —— 但它匹配的只是请求文本,精心措辞的请求可以不出现这些路径(例如 `npm config set x y` 会写 `~/.npmrc` 但全程不显示该路径)。请把 `allow` 视为**完全信任机器上的每一个对端**;当这种信任不成立时,请设置 `ask`(或 `inboundPolicy: "hold"`/`"refuse"`)。
|
|
159
|
+
- **自动批准如何保持作用域**:插件监听权限请求事件,仅当发起请求的回合是由它注入的消息启动时(通过从工具调用的消息沿 `parentID` 向上追溯到原始用户消息并检查其 metadata 来判定)才会自动回复。你自己输入的回合产生的权限请求不会收到任何回复,原样落回 opencode 的正常提示流程。
|
|
160
|
+
|
|
161
|
+
## 局限性
|
|
162
|
+
|
|
163
|
+
- 仅支持同一台机器(暂不支持跨主机转发)
|
|
164
|
+
- OpenCode 的 `command.execute.before` 钩子目前不可取消。因此斜杠命令通过把提示文本替换为一个无害的已处理标记来"消费";TUI 面板操作提供了显式对话框,但服务器钩子本身无法阻止后续的命令处理。
|
|
165
|
+
- 没有共享对话记录、Remote Control、Agent View、跨机器转发,也没有兼容 Claude Code 的团队/任务编排。
|
|
166
|
+
|
|
167
|
+
## 与 Claude Code 的对比
|
|
168
|
+
|
|
169
|
+
| 能力 | Claude Code | peers 0.2.0 |
|
|
170
|
+
|---|---|---|
|
|
171
|
+
| 跨进程与同进程会话寻址 | 原生支持 | 是,本地端点注册表 |
|
|
172
|
+
| 重名时的精确目标 | 是 | 是,存在歧义时要求使用端点 ID |
|
|
173
|
+
| 目标忙时发消息 | 是 | 是,立即注入一条消息的 `promptAsync` |
|
|
174
|
+
| 持久化投递/重启恢复 | 产品层面托管 | 是,文件系统 spool 与持久化 ACK/发件箱 |
|
|
175
|
+
| 权限边界 | 原生策略集成 | 基于事件的 allow/ask/deny,带受保护类别护栏 |
|
|
176
|
+
| 用户批准交互 | 原生 | 显式的宿主 TUI 对话框加斜杠命令封装 |
|
|
177
|
+
| 远程控制 / 共享任务 UI | Claude 生态可用 | 超出范围 |
|
|
178
|
+
|
|
179
|
+
本地纯文本交接在发现、精确寻址、忙时投递、重启恢复和最终结果追踪这些方面的效果基本等价。但它不是 Claude Code 产品级编排或远程 UI 的平替实现。
|
|
180
|
+
|
|
181
|
+
## 端到端验证
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
# 终端 1
|
|
185
|
+
cd /tmp/proj-a && opencode
|
|
186
|
+
/peers-name alpha
|
|
187
|
+
|
|
188
|
+
# 终端 2
|
|
189
|
+
cd /tmp/proj-b && opencode
|
|
190
|
+
/peers-name beta
|
|
191
|
+
/peers # 应该能看到 alpha
|
|
192
|
+
|
|
193
|
+
# 在 beta 的会话中:
|
|
194
|
+
Use send_message to tell "alpha": the deploy keys rotated, pull again.
|
|
195
|
+
|
|
196
|
+
# alpha 会立即收到这条文本,即使它的会话正在忙;
|
|
197
|
+
# "传输层已收到"与"最终投递 ACK"始终是两个不同的概念。
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
开发中使用的无头(headless)变体:
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
cd /tmp/proj-a && opencode serve --port 14100 &
|
|
204
|
+
cd /tmp/proj-b && opencode serve --port 14101 &
|
|
205
|
+
# 然后通过 HTTP API 驱动两边(POST /session、/session/:id/prompt_async)
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
无凭据的真实进程测试会启动真实的 OpenCode 进程,并驱动已加载插件的事件与命令钩子。它会在真实 `promptAsync` 注入前验证 busy 注册表状态,通过真实存储的对端消息解析权限来源,验证默认 `allow` 与 `ask` 的差异,并检查受保护请求是否被留给原生策略处理。由于缺少模型提供商凭据,它无法产生真实的提供商权限请求,因此测试桩记录的是插件的回复调用,而不是声称完成了端到端原生权限提示;其余的原生拒绝和受保护类别判定由专项测试覆盖。
|
|
209
|
+
|
|
210
|
+
## 开发
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
npm install
|
|
214
|
+
npm run build # tsc → dist/
|
|
215
|
+
npm test # build + node --test tests/*.test.mjs
|
|
216
|
+
npm run typecheck
|
|
217
|
+
npm run dry-run # npm publish --dry-run
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
除 `@opencode-ai/plugin`(peer 依赖)和 `zod`(工具 schema)外,零运行时依赖。
|
|
221
|
+
|
|
222
|
+
## 许可证
|
|
223
|
+
|
|
224
|
+
MIT
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: List same-machine opencode peers you can exchange messages with (alias of /peers, compatible with Claude Code's /list-agents)
|
|
3
|
+
argument-hint: ""
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
$ARGUMENTS
|
|
7
|
+
|
|
8
|
+
If this command was not intercepted by the opencode-collaboration plugin, call the list_agents tool and show the result to the user verbatim.
|