dsh-session-messaging 0.0.0-stage → 0.1.2
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/CHANGELOG.md +45 -0
- package/LICENSE +21 -0
- package/README.md +187 -2
- package/README.zh-CN.md +167 -0
- package/assets/icon.svg +11 -0
- package/assets/tools-icon.svg +7 -0
- package/cordis.patch.yml +11 -0
- package/lib/config.d.ts +22 -0
- package/lib/config.js +16 -0
- package/lib/index.d.ts +12 -0
- package/lib/index.js +10 -0
- package/lib/protocol.d.ts +150 -0
- package/lib/protocol.js +216 -0
- package/lib/service.d.ts +85 -0
- package/lib/service.js +190 -0
- package/lib/tools.d.ts +14 -0
- package/lib/tools.js +172 -0
- package/lib/types.d.ts +23 -0
- package/lib/types.js +8 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +90 -4
- package/tools/locale/en.json +6 -0
- package/tools/locale/zh.json +6 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project uses
|
|
5
|
+
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [0.1.2] - 2026-10-18
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Enforce the top-level boundary symmetrically. `session_send`, `session_peers`,
|
|
12
|
+
and `session_reception` now reject subagent callers with
|
|
13
|
+
`caller-not-top-level`; previously a subagent could send one-way messages to
|
|
14
|
+
top-level sessions while top-level sessions could not reply. Subagents keep
|
|
15
|
+
using the existing parent/child `send_message` channel.
|
|
16
|
+
- Targeting a subagent from a top-level session remains explicitly refused with
|
|
17
|
+
`target-not-top-level`.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- README (English and Chinese) now states that the envelope `from` field is the
|
|
22
|
+
trusted identity; any identity claim in the message body is data only.
|
|
23
|
+
|
|
24
|
+
### Tests
|
|
25
|
+
|
|
26
|
+
- Added integration coverage: a subagent caller is rejected without waking the
|
|
27
|
+
target, a top-level session cannot target a subagent, and all previous
|
|
28
|
+
refusals (self-send, cross-directory, non-live target, paused reception)
|
|
29
|
+
still pass.
|
|
30
|
+
|
|
31
|
+
## [0.1.1] - 2026-10-18
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
|
|
35
|
+
- Bilingual plugin-manager metadata (English / 简体中文) for the bundle and its
|
|
36
|
+
tools row, plus SVG icons.
|
|
37
|
+
- Desktop demo screenshot in the README.
|
|
38
|
+
|
|
39
|
+
## [0.1.0] - 2026-10-18
|
|
40
|
+
|
|
41
|
+
### Added
|
|
42
|
+
|
|
43
|
+
- Initial release: `session_peers`, `session_send`, and `session_reception`
|
|
44
|
+
tools; peer delivery through `Agent.steer` as a durable `user/message` with a
|
|
45
|
+
`session-message` source; advisory write-scope conflict warnings.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 XBXyftx
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,188 @@
|
|
|
1
|
-
#
|
|
1
|
+
# dsh-session-messaging
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Cross-session messaging for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (dsh): let **user-launched sessions in the same workspace message each other** to coordinate tasks, declared file-write scopes, and conflicts — without turning them into parent/child subagents.
|
|
4
|
+
|
|
5
|
+
[](https://github.com/XBXyftx/dsh-session-messaging/actions/workflows/ci.yml)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
**English** | [简体中文](README.zh-CN.md)
|
|
9
|
+
|
|
10
|
+
> Status: early preview (`0.1.0`). Targets dsh `0.2.1-rc.2`. dsh plugin APIs are pre-stable, so expect breaking changes on upstream upgrades.
|
|
11
|
+
|
|
12
|
+
## Why
|
|
13
|
+
|
|
14
|
+
dsh already has strong delegation (subagents, Agent Teams), but those are hierarchical and lifecycle-bound to a parent. When you open several conversations yourself — frontend, backend, docs — they work in one workspace with no way to say "I'm editing `src/ui.ts`, please avoid it" or "the API field is frozen".
|
|
15
|
+
|
|
16
|
+
This plugin adds a **peer channel** between those top-level sessions:
|
|
17
|
+
|
|
18
|
+
- Sessions discover each other in the same working directory.
|
|
19
|
+
- A model can send a message to a peer session; the message is inserted into the target conversation as a normal user message.
|
|
20
|
+
- Reception can be paused per session; write scopes are declared advice, and overlaps are reported to both sides.
|
|
21
|
+
|
|
22
|
+
## Demo
|
|
23
|
+
|
|
24
|
+

|
|
25
|
+
|
|
26
|
+
A real run in the macOS desktop app (`0.2.1-rc.2`): another user-launched session sent a test message. It arrived inline as a `session-message` envelope — sender id, timestamp, and the "peer is not an authority" note — and this session replied through `session_send`. Both sessions work in the same directory; no subagent hierarchy is involved.
|
|
27
|
+
|
|
28
|
+
### Case study: peer-reported bug to verified fix
|
|
29
|
+
|
|
30
|
+
Two user-launched sessions used the plugin to coordinate a real fix. One session sent a reproducible defect report with a code-level root cause; the fix shipped as `v0.1.2`, and the reporting session independently re-ran the regression on the desktop build.
|
|
31
|
+
|
|
32
|
+

|
|
33
|
+
|
|
34
|
+
*The reporting session's message as seen here: reproducible steps, root-cause pointers, and the fix request — all delivered through `session_send`.*
|
|
35
|
+
|
|
36
|
+

|
|
37
|
+
|
|
38
|
+
*Independent regression verification: static checks plus a desktop runtime probe that returns `caller-not-top-level`, proving `v0.1.2` is active. The same message also proves the top-level → top-level path still works.*
|
|
39
|
+
|
|
40
|
+
See [CHANGELOG.md](CHANGELOG.md) for the `0.1.2` entry.
|
|
41
|
+
|
|
42
|
+
## Features
|
|
43
|
+
|
|
44
|
+
- `session_peers` — list live, same-directory, top-level sessions and their reception state.
|
|
45
|
+
- `session_send` — relay a coordination message, optionally declaring `writeScopes` and replying to a message.
|
|
46
|
+
- `session_reception` — pause/resume receiving peer messages for the current session and declare its write scopes.
|
|
47
|
+
- Messages appear inline in the target conversation, attributed to the sending session — no separate inbox UI.
|
|
48
|
+
- Advisory **write-scope conflict detection**: if a peer declared an overlapping path, the receipt and the message envelope carry a `conflict-warning`.
|
|
49
|
+
- No new Session event types and no `SESSION_FORMAT_VERSION` change: the relay is a durable `user/message` with a declared `session-message` source.
|
|
50
|
+
- Bilingual plugin-card metadata and icons (English / 简体中文) for the dsh plugin manager.
|
|
51
|
+
- Bounded: message size, per-sender→target rate limit, same-directory scope, top-level-only, live-only, self-send rejected.
|
|
52
|
+
|
|
53
|
+
## How it works
|
|
54
|
+
|
|
55
|
+
```text
|
|
56
|
+
Session A (model) calls session_send
|
|
57
|
+
→ tools.ts uses exec.agent as the only identity source
|
|
58
|
+
→ service.send validates target, body, scopes, reception, rate limit
|
|
59
|
+
→ createUserMessage({ content: envelope + body, source: session-message/relay })
|
|
60
|
+
→ target.steer(message) # next step boundary, or wake an idle agent
|
|
61
|
+
→ await ctx.sessions.flush(target.session)
|
|
62
|
+
Session B's log gains a user/message with source.kind = 'session-message'
|
|
63
|
+
→ deriveMessages() rebuilds it → B's next model request sees it → B can reply
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The envelope always states that the message comes from another session, not the current user, and repeats that a peer is not an authority. Peer text is treated as data, never as higher-priority instructions.
|
|
67
|
+
|
|
68
|
+
## Requirements
|
|
69
|
+
|
|
70
|
+
- DeepSeek Harness `0.2.1-rc.2` (desktop app or source checkout).
|
|
71
|
+
- Node.js `>= 22.19.0`.
|
|
72
|
+
- The plugin needs the host's copies of `@deepseek-ai/{cordis,schemastery,dsh-agent,dsh-llm,dsh-session,dsh-tools}`. They are declared as peer dependencies and resolved from the running dsh installation.
|
|
73
|
+
|
|
74
|
+
## Install
|
|
75
|
+
|
|
76
|
+
### From GitHub
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
dsh plugin --profile <profile> add github:XBXyftx/dsh-session-messaging
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The repository ships the built `lib/` output, so installing from git does **not** run a build. If you prefer a registry, `npm publish` from this repository produces the same package (`dsh-session-messaging`).
|
|
83
|
+
|
|
84
|
+
### From a local checkout
|
|
85
|
+
|
|
86
|
+
```sh
|
|
87
|
+
dsh plugin --profile <profile> add /absolute/path/to/dsh-session-messaging
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Desktop app
|
|
91
|
+
|
|
92
|
+
The macOS/Windows desktop app uses its own profiles (for example `desktop`). Install with the bundled CLI or the agent's `plugin_manager` tool, targeting that profile. In dsh `0.2.1-rc.2` the configuration reloads through HMR, so the two plugin rows usually activate without restarting the app.
|
|
93
|
+
|
|
94
|
+
Verify the plugin is active:
|
|
95
|
+
|
|
96
|
+
- the agent's tool list contains `session_peers`, `session_send`, and `session_reception`;
|
|
97
|
+
- `plugin_manager list_plugins` reports both `session-messaging` and `session-messaging-tools` with `fiberPhase: active`.
|
|
98
|
+
|
|
99
|
+
## Usage
|
|
100
|
+
|
|
101
|
+
Open two sessions in the same working directory, then ask either model to coordinate. The tools are model-facing; no manual UI is required.
|
|
102
|
+
|
|
103
|
+
Example prompts:
|
|
104
|
+
|
|
105
|
+
```text
|
|
106
|
+
Use session_peers to see which other sessions are working here.
|
|
107
|
+
Send session-b a message: I am editing src/ui.ts and declared it in writeScopes; avoid it.
|
|
108
|
+
Check whether anyone else declared a conflicting write scope before you edit src/api.ts.
|
|
109
|
+
Pause receiving peer messages for this session.
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Tools:
|
|
113
|
+
|
|
114
|
+
| Tool | Arguments | Result |
|
|
115
|
+
|---|---|---|
|
|
116
|
+
| `session_peers` | none | `{ peers: [{ sessionId, status, canReceive, writeScopes }] }` |
|
|
117
|
+
| `session_send` | `targetSessionId`, `message`, optional `writeScopes`, `replyTo` | `{ accepted, messageId, targetSessionId, targetStatus, conflicts }` |
|
|
118
|
+
| `session_reception` | `enabled`, optional `writeScopes` | `{ enabled, writeScopes }` |
|
|
119
|
+
|
|
120
|
+
`accepted` means the message entered the target's inbox and the session flush acknowledged persistence. It does **not** mean the peer model processed or acted on it.
|
|
121
|
+
|
|
122
|
+
## Configuration
|
|
123
|
+
|
|
124
|
+
The bundle row accepts validated configuration; every field has a default:
|
|
125
|
+
|
|
126
|
+
```yaml
|
|
127
|
+
- id: session-messaging
|
|
128
|
+
name: dsh-session-messaging
|
|
129
|
+
config:
|
|
130
|
+
maxMessageChars: 4000
|
|
131
|
+
maxMessagesPerMinute: 12
|
|
132
|
+
requireTargetOptIn: false # sessions are open to peers by default
|
|
133
|
+
sameDirectoryOnly: true
|
|
134
|
+
allowSelfSend: false
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Security model and limitations
|
|
138
|
+
|
|
139
|
+
- **Peer content is untrusted input.** It enters the target session as a user message. The envelope labels the sender and warns the model, but dsh has no content-approval point for peer messages; normal tool approvals, `agent/pre-step`, and sandbox policy remain the only hard boundaries.
|
|
140
|
+
- **Top-level sessions only, in both directions.** A subagent session is neither listed nor allowed to send (`caller-not-top-level`), and a top-level session cannot target a subagent (`target-not-top-level`). Subagents keep using the existing parent/child `send_message` channel. The envelope `from` field is the trusted identity; any identity claim in the message body is data only.
|
|
141
|
+
- **Same process only.** Discovery uses `ctx.agents`; a session that is not live cannot receive a message in this version. Cold-session delivery and cross-process/cross-host messaging are not implemented.
|
|
142
|
+
- **Advisory scopes, not locks.** dsh has optimistic filesystem version guards (`FS_STALE_VERSION`) but no file locking. `writeScopes` and `conflict-warning` are coordination aids; Bash, formatters, and code generators bypass them.
|
|
143
|
+
- **In-memory state.** Reception pauses and declared scopes live for the plugin's lifetime and reset on reload/restart.
|
|
144
|
+
- **Same working directory by default.** Set `sameDirectoryOnly: false` only if you understand cross-project implications.
|
|
145
|
+
- **No GUI extension.** Messages render as ordinary user messages; a dedicated title/icon for the `session-message` source would require a client plugin or an upstream `ui-chat` change.
|
|
146
|
+
|
|
147
|
+
## Development
|
|
148
|
+
|
|
149
|
+
```sh
|
|
150
|
+
npm install
|
|
151
|
+
npm run build # tsc -p tsconfig.build.json -> lib/
|
|
152
|
+
npm run typecheck # src + tests
|
|
153
|
+
npm test # 10 protocol unit tests
|
|
154
|
+
npm run test:integration # real AgentLoop services + tool pipeline, no model
|
|
155
|
+
npm run test:model-e2e # scripted model: A calls session_send, B sees it and replies
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
`lib/` is committed so `dsh plugin add github:...` works without a build step. Rebuild before committing source changes; CI re-checks that `lib/` matches `src/`.
|
|
159
|
+
|
|
160
|
+
### Project layout
|
|
161
|
+
|
|
162
|
+
```text
|
|
163
|
+
.
|
|
164
|
+
├── cordis.patch.yml # two insert rows: service + tools
|
|
165
|
+
├── src/
|
|
166
|
+
│ ├── index.ts # plugin entry: default exports the service class + Config
|
|
167
|
+
│ ├── service.ts # discovery, reception state, rate limit, delivery, conflicts
|
|
168
|
+
│ ├── tools.ts # session_peers / session_send / session_reception
|
|
169
|
+
│ ├── config.ts # Schemastery configuration
|
|
170
|
+
│ ├── protocol.ts # pure validation, envelope, scope conflicts, rate limiter
|
|
171
|
+
│ └── types.ts # MessageSourceMap 'session-message' declaration
|
|
172
|
+
├── tests/ # unit, integration, model-driven e2e
|
|
173
|
+
└── lib/ # committed build output
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Compatibility
|
|
177
|
+
|
|
178
|
+
- dsh `0.2.1-rc.2`; the bundle declares `engines.dsh = ">=0.2.1-rc.2 <0.3.0"`.
|
|
179
|
+
- Uses documented extension points only: `ctx.tools.register`, `ctx.agents`, `ctx.sessions`, `MessageSourceMap`.
|
|
180
|
+
- Does not modify `agent-loop` and does not add `SessionEventMap` members.
|
|
181
|
+
|
|
182
|
+
## Contributing
|
|
183
|
+
|
|
184
|
+
Issues and pull requests are welcome. Please keep the "no loop changes, no new session event types, advisory scopes only" boundary unless a design discussion says otherwise. Run `npm run typecheck`, `npm test`, `npm run test:integration`, and `npm run test:model-e2e` before sending a PR.
|
|
185
|
+
|
|
186
|
+
## License
|
|
187
|
+
|
|
188
|
+
MIT © 2026 XBXyftx
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# dsh-session-messaging
|
|
2
|
+
|
|
3
|
+
为 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(dsh)提供**跨会话消息**:让用户在同一工作区自行启动的多个会话互相发消息,协调任务、声明文件写入范围、提示冲突——而不是把它们变成父子关系的子代理。
|
|
4
|
+
|
|
5
|
+
[English](README.md) | **简体中文**
|
|
6
|
+
|
|
7
|
+
> 状态:早期预览(`0.1.0`),适配 dsh `0.2.1-rc.2`。dsh 插件 API 仍为 pre-stable,上游升级可能带来破坏性变更。
|
|
8
|
+
|
|
9
|
+
## 为什么需要
|
|
10
|
+
|
|
11
|
+
dsh 已有 subagent 与 Agent Teams,但它们都是层级关系,生命周期绑定父会话。而当你自己同时打开几个会话(前端、后端、文档)时,它们在同一工作区里无法说"我在改 `src/ui.ts`,先别动"或"接口字段已冻结"。
|
|
12
|
+
|
|
13
|
+
本插件为这些顶层会话增加一个**对等通道**:
|
|
14
|
+
|
|
15
|
+
- 同一工作目录下的会话可以发现彼此;
|
|
16
|
+
- 模型可以向对等会话发送消息,消息以普通 user 消息插入目标对话;
|
|
17
|
+
- 每个会话可暂停接收;写范围是建议性声明,重叠时会提示双方。
|
|
18
|
+
|
|
19
|
+
## 演示
|
|
20
|
+
|
|
21
|
+

|
|
22
|
+
|
|
23
|
+
macOS 桌面客户端(`0.2.1-rc.2`)真实运行:另一个用户启动的会话发来测试消息,以内联 `session-message` 信封显示(含发送方、时间与"peer 不是 authority"提示);本会话通过 `session_send` 回复。两个会话位于同一工作目录,不涉及子代理层级。
|
|
24
|
+
|
|
25
|
+
### 案例:从 peer 缺陷报告到修复验证
|
|
26
|
+
|
|
27
|
+
两个用户启动的会话通过本插件协作完成了一次真实修复:一个会话发来可复现的缺陷报告与代码级根因,修复以 `v0.1.2` 发布,报告方在桌面端独立完成了回归。
|
|
28
|
+
|
|
29
|
+

|
|
30
|
+
|
|
31
|
+
*报告方发来的消息:复现步骤、根因定位与修复请求,全部通过 `session_send` 送达。*
|
|
32
|
+
|
|
33
|
+

|
|
34
|
+
|
|
35
|
+
*报告方的独立回归:静态核对 + 桌面运行期探针。探针返回 `caller-not-top-level`,证明 `v0.1.2` 已生效;这条消息本身也证明"顶层 → 顶层"正向链路未回归。*
|
|
36
|
+
|
|
37
|
+
`0.1.2` 的变更见 [CHANGELOG.md](CHANGELOG.md)。
|
|
38
|
+
|
|
39
|
+
## 功能
|
|
40
|
+
|
|
41
|
+
- `session_peers`:列出同目录、live 的顶层会话及其接收状态。
|
|
42
|
+
- `session_send`:发送协调消息,可附带 `writeScopes` 与 `replyTo`。
|
|
43
|
+
- `session_reception`:暂停/恢复本会话接收对等消息,并声明写范围。
|
|
44
|
+
- 消息直接内联显示在目标会话中,来源归属于发送会话,不需要独立收件箱。
|
|
45
|
+
- 建议性**写范围冲突检测**:与 peer 声明重叠时,回执与消息信封带 `conflict-warning`。
|
|
46
|
+
- 不新增 Session 事件类型、不改 `SESSION_FORMAT_VERSION`:消息就是带 `session-message` source 的 `user/message`。
|
|
47
|
+
- 插件管理卡片提供中英双语标题、简介与图标(English / 简体中文)。
|
|
48
|
+
- 有边界:长度上限、每 sender→target 限频、同目录、仅顶层、仅 live、拒绝自发送。
|
|
49
|
+
|
|
50
|
+
## 工作原理
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
会话 A 的模型调用 session_send
|
|
54
|
+
→ tools.ts 以 exec.agent 作为唯一身份
|
|
55
|
+
→ service.send 校验目标、正文、写范围、接收状态、限频
|
|
56
|
+
→ createUserMessage({ 信封+正文, source: session-message/relay })
|
|
57
|
+
→ target.steer(message) # 最近 step 边界;空闲会话则唤醒
|
|
58
|
+
→ await ctx.sessions.flush(target.session)
|
|
59
|
+
目标会话 B 的日志出现 user/message(source.kind = 'session-message')
|
|
60
|
+
→ deriveMessages() 重建 → B 的下一次模型请求可见 → B 可回复
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
消息信封始终标明"来自另一个会话,不是当前用户",并提示 peer 不是 authority;peer 内容只作为数据,不获得更高指令权限。
|
|
64
|
+
|
|
65
|
+
## 要求
|
|
66
|
+
|
|
67
|
+
- DeepSeek Harness `0.2.1-rc.2`(桌面应用或源码)。
|
|
68
|
+
- Node.js `>= 22.19.0`。
|
|
69
|
+
- 插件依赖宿主提供的 `@deepseek-ai/{cordis,schemastery,dsh-agent,dsh-llm,dsh-session,dsh-tools}`;它们以 peerDependencies 声明,由运行中的 dsh 安装解析。
|
|
70
|
+
|
|
71
|
+
## 安装
|
|
72
|
+
|
|
73
|
+
### 从 GitHub 安装
|
|
74
|
+
|
|
75
|
+
```sh
|
|
76
|
+
dsh plugin --profile <profile> add github:XBXyftx/dsh-session-messaging
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
仓库包含构建好的 `lib/`,从 git 安装**不需要**额外构建。发布到 npm 后也可用包名 `dsh-session-messaging` 安装。
|
|
80
|
+
|
|
81
|
+
### 本地目录安装
|
|
82
|
+
|
|
83
|
+
```sh
|
|
84
|
+
dsh plugin --profile <profile> add /absolute/path/to/dsh-session-messaging
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 桌面应用
|
|
88
|
+
|
|
89
|
+
桌面应用使用自己的 profile(例如 `desktop`),用其内置 CLI 或 agent 的 `plugin_manager` 工具安装到该 profile。dsh `0.2.1-rc.2` 会通过 HMR 重载配置,通常无需重启应用即可激活。
|
|
90
|
+
|
|
91
|
+
确认已激活:
|
|
92
|
+
|
|
93
|
+
- agent 工具列表出现 `session_peers`、`session_send`、`session_reception`;
|
|
94
|
+
- `plugin_manager list_plugins` 中 `session-messaging` 与 `session-messaging-tools` 的 `fiberPhase` 为 `active`。
|
|
95
|
+
|
|
96
|
+
## 使用
|
|
97
|
+
|
|
98
|
+
在同一工作区打开两个会话,直接让模型协调即可,不需要手动操作 UI。
|
|
99
|
+
|
|
100
|
+
示例提示词:
|
|
101
|
+
|
|
102
|
+
```text
|
|
103
|
+
用 session_peers 看看当前工作区还有哪些会话。
|
|
104
|
+
给 session-b 发消息:我在改 src/ui.ts,已经写进 writeScopes,请避开。
|
|
105
|
+
改 src/api.ts 之前先检查有没有别人声明了冲突的写范围。
|
|
106
|
+
本会话暂停接收跨会话消息。
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
工具:
|
|
110
|
+
|
|
111
|
+
| 工具 | 参数 | 返回 |
|
|
112
|
+
|---|---|---|
|
|
113
|
+
| `session_peers` | 无 | `{ peers: [{ sessionId, status, canReceive, writeScopes }] }` |
|
|
114
|
+
| `session_send` | `targetSessionId`、`message`,可选 `writeScopes`、`replyTo` | `{ accepted, messageId, targetSessionId, targetStatus, conflicts }` |
|
|
115
|
+
| `session_reception` | `enabled`,可选 `writeScopes` | `{ enabled, writeScopes }` |
|
|
116
|
+
|
|
117
|
+
`accepted` 表示消息进入目标 inbox 且 flush 确认持久化,**不**表示对等模型已经处理或执行。
|
|
118
|
+
|
|
119
|
+
## 配置
|
|
120
|
+
|
|
121
|
+
```yaml
|
|
122
|
+
- id: session-messaging
|
|
123
|
+
name: dsh-session-messaging
|
|
124
|
+
config:
|
|
125
|
+
maxMessageChars: 4000
|
|
126
|
+
maxMessagesPerMinute: 12
|
|
127
|
+
requireTargetOptIn: false # 默认对 peer 开放
|
|
128
|
+
sameDirectoryOnly: true
|
|
129
|
+
allowSelfSend: false
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## 安全模型与限制
|
|
133
|
+
|
|
134
|
+
- **peer 内容是可信边界外的输入**:它以 user 消息进入目标会话,信封会标注来源并警告模型,但 dsh 没有针对 peer 消息的内容审批点;工具审批、`agent/pre-step` 与 sandbox 策略仍是唯一的硬边界。
|
|
135
|
+
- **只允许顶层会话,收发两个方向都对称**:subagent 会话既不会出现在 peers 里,也不允许发送(`caller-not-top-level`);顶层会话也不能把 subagent 作为目标(`target-not-top-level`)。subagent 继续使用既有的父子 `send_message` 通道。消息信封的 `from` 字段才是可信身份;正文里的任何身份自称都只是数据。
|
|
136
|
+
- **仅同进程**:发现依赖 `ctx.agents`,非 live 会话本版无法接收;冷会话投递与跨进程/跨机器通信未实现。
|
|
137
|
+
- **写范围只是建议,不是锁**:dsh 只有乐观版本守卫(`FS_STALE_VERSION`),没有文件锁;Bash、格式化器、代码生成器会绕过写范围提示。
|
|
138
|
+
- **状态在内存**:暂停接收与写范围声明随插件生命周期存在,重载/重启后重置。
|
|
139
|
+
- **默认同目录**:除非理解跨项目影响,否则不要关闭 `sameDirectoryOnly`。
|
|
140
|
+
- **无 GUI 扩展**:消息按普通 user 消息显示;`session-message` 的专属标题/图标需要 client 插件或上游 `ui-chat` 改动。
|
|
141
|
+
|
|
142
|
+
## 开发
|
|
143
|
+
|
|
144
|
+
```sh
|
|
145
|
+
npm install
|
|
146
|
+
npm run build # tsc -p tsconfig.build.json -> lib/
|
|
147
|
+
npm run typecheck
|
|
148
|
+
npm test # 10 项协议单测
|
|
149
|
+
npm run test:integration # 真实 AgentLoop 服务 + 工具管线,无模型
|
|
150
|
+
npm run test:model-e2e # 脚本化模型:A 发消息,B 收到并回复
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`lib/` 已提交,便于 `dsh plugin add github:...` 直接使用;修改源码后请重新构建并提交,CI 会检查 `lib/` 与 `src/` 一致。
|
|
154
|
+
|
|
155
|
+
## 兼容性
|
|
156
|
+
|
|
157
|
+
- 适配 dsh `0.2.1-rc.2`,`engines.dsh = ">=0.2.1-rc.2 <0.3.0"`。
|
|
158
|
+
- 只使用文档化扩展点:`ctx.tools.register`、`ctx.agents`、`ctx.sessions`、`MessageSourceMap`。
|
|
159
|
+
- 不修改 `agent-loop`,不新增 `SessionEventMap`。
|
|
160
|
+
|
|
161
|
+
## 贡献
|
|
162
|
+
|
|
163
|
+
欢迎 Issue 与 PR。除非经过设计讨论,请保留"不改 loop、不新增 Session 事件、写范围仅建议"的边界。提交前运行 `npm run typecheck`、`npm test`、`npm run test:integration`、`npm run test:model-e2e`。
|
|
164
|
+
|
|
165
|
+
## 许可证
|
|
166
|
+
|
|
167
|
+
MIT © 2026 XBXyftx
|
package/assets/icon.svg
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="Session Messaging">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="bubble" x1="0" y1="0" x2="1" y2="1">
|
|
4
|
+
<stop offset="0" stop-color="#4f8cff"/>
|
|
5
|
+
<stop offset="1" stop-color="#7b5cff"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
</defs>
|
|
8
|
+
<rect width="64" height="64" rx="14" fill="#0d1526"/>
|
|
9
|
+
<path d="M12 21a6 6 0 0 1 6-6h20a6 6 0 0 1 6 6v12a6 6 0 0 1-6 6H26l-9 7v-7h-.5A6.5 6.5 0 0 1 10 32.5z" fill="url(#bubble)"/>
|
|
10
|
+
<path d="M33 35a6 6 0 0 1 6-6h9a6 6 0 0 1 6 6v9a6 6 0 0 1-6 6h-.5v5.5L40 50h-1a6 6 0 0 1-6-6z" fill="#9dbbff" opacity=".9"/>
|
|
11
|
+
</svg>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="Session Messaging Tools">
|
|
2
|
+
<rect width="64" height="64" rx="14" fill="#0d1526"/>
|
|
3
|
+
<path d="M11 20a5 5 0 0 1 5-5h18a5 5 0 0 1 5 5v10a5 5 0 0 1-5 5H24l-8 6v-6h-.5A4.5 4.5 0 0 1 11 30.5z" fill="#4f8cff"/>
|
|
4
|
+
<path d="M36 22h13a5 5 0 0 1 5 5v6a5 5 0 0 1-5 5h-2l-6 5v-5h-1a5 5 0 0 1-5-5z" fill="#9dbbff" opacity=".9"/>
|
|
5
|
+
<circle cx="21" cy="25" r="2" fill="#0d1526"/>
|
|
6
|
+
<circle cx="28" cy="25" r="2" fill="#0d1526"/>
|
|
7
|
+
</svg>
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# dsh-session-messaging bundle patch.
|
|
2
|
+
# Mounts the Host-side service and its model-facing tools. Both rows are
|
|
3
|
+
# inserted over the profile root; later profile/--patch layers can override
|
|
4
|
+
# them by id. The service must load before the tools consume it; activation is
|
|
5
|
+
# service-availability driven, so row order is documentation only.
|
|
6
|
+
- insert:
|
|
7
|
+
- id: session-messaging
|
|
8
|
+
name: dsh-session-messaging
|
|
9
|
+
|
|
10
|
+
- id: session-messaging-tools
|
|
11
|
+
name: dsh-session-messaging/tools
|
package/lib/config.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deployment configuration for the session-messaging plugin. Every value that
|
|
3
|
+
* two deployments may want to set differently is a schema field; the loader
|
|
4
|
+
* validates it at load time and fails loudly on invalid input.
|
|
5
|
+
* @module dsh-session-messaging/config
|
|
6
|
+
*/
|
|
7
|
+
import Schema from '@deepseek-ai/schemastery';
|
|
8
|
+
/** Validated deployment configuration. */
|
|
9
|
+
export interface SessionMessagingConfig {
|
|
10
|
+
/** Maximum relay body length in UTF-16 code units. */
|
|
11
|
+
readonly maxMessageChars: number;
|
|
12
|
+
/** Maximum relays per sender→target pair per minute. */
|
|
13
|
+
readonly maxMessagesPerMinute: number;
|
|
14
|
+
/** Require the target session to opt in before it can receive peer messages. Off by default: sessions are mutually visible and can message each other unless they pause reception. */
|
|
15
|
+
readonly requireTargetOptIn: boolean;
|
|
16
|
+
/** Only allow peers whose working directory equals the sender's. */
|
|
17
|
+
readonly sameDirectoryOnly: boolean;
|
|
18
|
+
/** Allow a session to relay to itself (diagnostics only; off by default). */
|
|
19
|
+
readonly allowSelfSend: boolean;
|
|
20
|
+
}
|
|
21
|
+
/** Schemastery schema for the plugin row's `config` block. */
|
|
22
|
+
export declare const Config: Schema<SessionMessagingConfig>;
|
package/lib/config.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deployment configuration for the session-messaging plugin. Every value that
|
|
3
|
+
* two deployments may want to set differently is a schema field; the loader
|
|
4
|
+
* validates it at load time and fails loudly on invalid input.
|
|
5
|
+
* @module dsh-session-messaging/config
|
|
6
|
+
*/
|
|
7
|
+
import Schema from '@deepseek-ai/schemastery';
|
|
8
|
+
import { DEFAULT_MAX_MESSAGE_CHARS, DEFAULT_MAX_MESSAGES_PER_MINUTE } from "./protocol.js";
|
|
9
|
+
/** Schemastery schema for the plugin row's `config` block. */
|
|
10
|
+
export const Config = Schema.object({
|
|
11
|
+
maxMessageChars: Schema.number().min(1).default(DEFAULT_MAX_MESSAGE_CHARS),
|
|
12
|
+
maxMessagesPerMinute: Schema.number().min(1).default(DEFAULT_MAX_MESSAGES_PER_MINUTE),
|
|
13
|
+
requireTargetOptIn: Schema.boolean().default(false),
|
|
14
|
+
sameDirectoryOnly: Schema.boolean().default(true),
|
|
15
|
+
allowSelfSend: Schema.boolean().default(false),
|
|
16
|
+
});
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin entry: the Host-side session-messaging service. The model-facing tools
|
|
3
|
+
* live in the `./tools` entry. This module intentionally exports no new Session
|
|
4
|
+
* event type; relayed messages reuse `user/message` with a declared source kind.
|
|
5
|
+
* @module dsh-session-messaging
|
|
6
|
+
*/
|
|
7
|
+
export { default } from './service.ts';
|
|
8
|
+
export { SessionMessagingService } from './service.ts';
|
|
9
|
+
export { Config } from './config.ts';
|
|
10
|
+
export type { SessionMessagingConfig } from './config.ts';
|
|
11
|
+
export { SESSION_MESSAGE_KIND } from './protocol.ts';
|
|
12
|
+
export type { MessagingErrorCode, PeerView, SendReceipt, SendRequest, } from './protocol.ts';
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin entry: the Host-side session-messaging service. The model-facing tools
|
|
3
|
+
* live in the `./tools` entry. This module intentionally exports no new Session
|
|
4
|
+
* event type; relayed messages reuse `user/message` with a declared source kind.
|
|
5
|
+
* @module dsh-session-messaging
|
|
6
|
+
*/
|
|
7
|
+
export { default } from "./service.js";
|
|
8
|
+
export { SessionMessagingService } from "./service.js";
|
|
9
|
+
export { Config } from "./config.js";
|
|
10
|
+
export { SESSION_MESSAGE_KIND } from "./protocol.js";
|