dsh-multi-session 0.3.4 → 0.5.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/CHANGELOG.md +56 -0
- package/README.md +37 -8
- package/assets/screenshot-board.jpg +0 -0
- package/assets/screenshot-board.png +0 -0
- package/client.js +1014 -57
- package/index.js +437 -5
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,62 @@
|
|
|
2
2
|
|
|
3
3
|
版本号遵循语义化版本;`0.x` 期间接口仍可能变。
|
|
4
4
|
|
|
5
|
+
## 0.5.3
|
|
6
|
+
|
|
7
|
+
**换截图 + 补文档。**
|
|
8
|
+
|
|
9
|
+
- 截图换成实拍面板:左侧总览(待查看 / 会话数、按工作区归组、卡片底部 `+ 并排看` / `打开`),右侧钉住两列,能看到助手靠左、你靠右的双色气泡,以及每条消息旁的「转发」按钮。裁掉了底部与本插件无关的配额状态条。原始分辨率 1054×786、198KB。
|
|
10
|
+
- README 补两节设计说明:「为什么气泡一左一右」「为什么『在等你』值得单独做」,并把架构图、路由表、缓存键版本、搜索兜底、图标说明都更新到当前实现。
|
|
11
|
+
- 缓存键文档从 `v4:` 校正到 `v5:`(0.5.0 加字段时已升过,文档漏改)。
|
|
12
|
+
|
|
13
|
+
## 0.5.2
|
|
14
|
+
|
|
15
|
+
**修:总览模式下搜索完没反应。**
|
|
16
|
+
|
|
17
|
+
0.5.1 把搜索的取数修好了,但结果只在「钉住了会话」的并排模式下显示得出来。
|
|
18
|
+
|
|
19
|
+
根因是面板底部的两个分支写得不一致:并排模式走 `listPane`(里面才有「有搜索结果就换成命中列表」这段判断),总览模式却直接铺 `listContent`,把 `listPane` 整个跳过了。于是总览里输入、回车、请求也发了、结果也回来了,界面上什么都没有 —— 看起来就是搜索没反应。
|
|
20
|
+
|
|
21
|
+
改成两个分支都走 `listPane`。
|
|
22
|
+
|
|
23
|
+
离线测试补了真实的交互回归(之前只断言了"有输入框"):找到搜索框 → 输入 → 回车 → 等请求回来 → 断言面板树里确实挂上了 `SearchResults` 且拿到 2 条命中。这个断言在修复前会失败,修复后通过。
|
|
24
|
+
|
|
25
|
+
## 0.5.1
|
|
26
|
+
|
|
27
|
+
**修两个问题。**
|
|
28
|
+
|
|
29
|
+
- **搜索在关掉索引的部署上直接失败**。原来只走 `sessionController.search`,但有些部署把 session-query 索引配成 `openAt: "never"`,这个接口会报 `session search is disabled`,整个搜索功能不可用。现在优先用索引,索引不可用时自动退化为**直接读磁盘上的会话日志**再扫。
|
|
30
|
+
- 顺带发现一个必须记下来的事实:DSH 的会话日志是**多个 zstd 帧拼接**的(单个会话实测 281 帧)。Node 的 `zstdDecompressSync` 和 `createZstdDecompress` 都只解第一帧就停,必须按 magic `0x28B52FFD` 切开逐帧解压,否则解出来只有几百字节。
|
|
31
|
+
- 性能:1041KB 日志解成 2744KB 文本只要 33ms,全文扫 31ms;对比 `sessionQuery.filterEvents` 的 3.35 秒/会话,快约 50 倍。
|
|
32
|
+
- 只扫客户端点名的那批会话(面板里看得到的,最多 40 个),并且只匹配 `user/message` 与 `assistant/message`,避免 `agent/inbox/spliced` 把同一条用户消息再抄一遍造成重复命中。
|
|
33
|
+
- **转发按钮看不见**。原来是 `border:none + transparent + opacity:0.75`,在深色背景上等于隐形。改成品牌色的描边药丸(`rgba(59,108,246)` 底 + 边框 + 加粗字),和其它按钮一致。
|
|
34
|
+
|
|
35
|
+
## 0.5.0
|
|
36
|
+
|
|
37
|
+
**四个「不用点开就能判断」的能力。**
|
|
38
|
+
|
|
39
|
+
- **卡片标出「等你回话 / 等你批准」**。会话卡在等你回话时 `running` 仍然是 `true`,光看运行中根本分不出来 —— 它可能在空转十几分钟,你却以为它在干活。现在从事件流判断最后一条工具调用是不是 `ask_user_question`、有没有未决的 `approval/asked`,卡片顶部标出琥珀色的等待标记,状态点也一起变琥珀色,与运行中的绿、待查看的蓝一眼分开。
|
|
40
|
+
- **跨会话全文搜索**。面板顶部加了搜索框,走 `sessionController.search` —— 官方语义是"Search visible Session content without resuming an Agent",**不会激活会话、不烧 token**,找到的只是历史上已经写下的文字。结果按会话归组、显示命中的原句,点标题直接跳过去。
|
|
41
|
+
- **卡片显示「改了什么文件」**。走 `workspaceChanges.summary`,显示这一轮改了几个文件、增删多少行、头几个文件名。对同时跑五六个会话改代码的场景,这比读对话更快判断它到底干完没有。注意 `summary()` 只认 `workspace/changes` 事件自己的 seq,所以 seq 是在折叠事件流时顺带记下来的。
|
|
42
|
+
- **会话间传话**。并排列里每条消息旁边有「转发」,点了之后底部出现目标选择条,选一个会话就把它当输入发过去(默认 `queue`,不打断对方正在跑的回合)。省掉"复制 → 切过去 → 粘贴"三步。
|
|
43
|
+
|
|
44
|
+
新增 Host 路由 `/plugins/dsh-multi-session/search`(GET,`?q=`,过 connection gate,20 秒超时);`/digest` 响应新增 `waiting` 与 `changes` 两个字段,缓存键升到 `v5:`。
|
|
45
|
+
|
|
46
|
+
## 0.4.0
|
|
47
|
+
|
|
48
|
+
**界面与对话显示重做。**
|
|
49
|
+
|
|
50
|
+
- **卡片不再是整块可点区域**。原来整张卡片绑定了跳转会话的 `onClick`,手指稍微偏一点就会跳到别的会话,
|
|
51
|
+
而那个 12px 的透明 `⊞` 钉住按钮根本躲不开它。现在整卡不可点,卡片底部是两个明确的药丸按钮:
|
|
52
|
+
`+ 并排看`(已钉住时变 `− 移出并排`)和 `打开`,都带边框与底色,不会再误触。
|
|
53
|
+
- **并排对话改为渲染 Markdown**。以前正文用 `white-space: pre-wrap` 当纯文本直出,于是 `**加粗**`、
|
|
54
|
+
`## 标题`、```` ``` ```` 代码围栏全都以源码形式堆在面板里,看起来又长又乱。现在支持标题、粗体、斜体、
|
|
55
|
+
行内代码、代码围栏(带语言标签、横向滚动)、有序/无序列表、表格、引用、分割线和链接,
|
|
56
|
+
单条正文上限从 6000 字放宽到 20000 字。渲染全程用 React 元素构造,不拼 HTML、不用 `dangerouslySetInnerHTML`。
|
|
57
|
+
- 已知边界:DSH 没有向插件暴露任何"嵌入官方 Chat 渲染器"的入口(`conversation.chat.node` 是 keyed 插槽,
|
|
58
|
+
key 已被官方 node 类型占满,既不能新增也不能复用),所以并排视图无法做到与官方会话视图像素级一致;
|
|
59
|
+
改为用 Markdown 渲染尽量还原观感。工具调用与思考过程仍按「只保留你和 AI 的对话」的既定取舍丢弃。
|
|
60
|
+
|
|
5
61
|
## 0.3.4
|
|
6
62
|
|
|
7
63
|
仅文档与素材变更,无代码改动。
|
package/README.md
CHANGED
|
@@ -7,22 +7,26 @@ DSH 原生只给你当前这一个会话的界面。开了五六个会话并行
|
|
|
7
7
|
|
|
8
8
|

|
|
9
9
|
|
|
10
|
-
<sub>左边是总览:待查看、会话数,按工作区归组,每张卡片带状态点、轮数、子代理数、token
|
|
10
|
+
<sub>左边是总览:待查看、会话数,按工作区归组,每张卡片带状态点、轮数、子代理数、token 与模型,底部是 `+ 并排看` / `打开`。右边钉住两列,每列直接显示该会话「我 ↔ 助手」的对话正文(左侧助手、右侧是你,一眼分得清谁在说话),每条消息旁边有「转发」,底部输入框可以直接往里发消息。</sub>
|
|
11
11
|
|
|
12
12
|
## 它解决什么
|
|
13
13
|
|
|
14
14
|
| 痛点 | 这个插件 |
|
|
15
15
|
| --- | --- |
|
|
16
|
-
| 想知道别的会话在聊什么,得点开再点回来 |
|
|
17
|
-
| 分不清哪些在跑、哪些在等我 | 面板按「运行中 → 刚完成 → 其余」排序,带状态点、轮数、token
|
|
18
|
-
| 会话一大堆,找不到 | 按工作区(cwd
|
|
16
|
+
| 想知道别的会话在聊什么,得点开再点回来 | 点卡片上的 `+ 并排看` 钉住最多 3 个会话,并排看它们的**对话正文**(渲染成 Markdown) |
|
|
17
|
+
| 分不清哪些在跑、哪些在等我 | 面板按「运行中 → 刚完成 → 其余」排序,带状态点、轮数、token、模型、相对时间;**卡在等你回话的会标出琥珀色的「等你回话 / 等你批准」** |
|
|
18
|
+
| 会话一大堆,找不到 | 按工作区(cwd)分组,子代理会话与归档会话默认折叠、可单独打开;顶部搜索框**跨全部会话全文搜索**,不激活会话、不烧 token |
|
|
19
19
|
| 不想点开就想知道结果 | 运行中/刚完成的卡片直接显示该会话最后一句助手结论 |
|
|
20
|
+
| 不知道它到底干完没有 | 卡片显示**这一轮改了什么文件**:几个文件、增删多少行、头几个文件名 |
|
|
20
21
|
| 切来切去只为说一句话 | 并排列底部就是输入框,直接给那个会话发消息或打断它 |
|
|
22
|
+
| 想把一段结论给另一个会话 | 消息旁边的「转发」按钮,选个目标会话就发过去,省掉复制粘贴再切换 |
|
|
21
23
|
|
|
22
24
|
## 界面在哪
|
|
23
25
|
|
|
24
26
|
- **「多会话」页签**:任意会话顶部视图切换条里,点进去是总览面板。
|
|
25
|
-
-
|
|
27
|
+
- **钉住并排**:卡片底部有 `+ 并排看` 按钮(已钉住时变 `− 移出并排`),最多钉 3 个。整张卡片本身不可点击,
|
|
28
|
+
不会再有"想点按钮结果跳走了会话"的误触;要跳转请点同一个动作行里的 `打开`。
|
|
29
|
+
钉住的选择存 localStorage,关掉面板再回来还在。
|
|
26
30
|
- **并排输入框**:每列底部一个输入框,`Enter` 发送(排进收件箱,不打断当前回合),`Shift+Enter` 插话(立刻打断当前回合);运行中的列另有「停止」按钮。
|
|
27
31
|
|
|
28
32
|
## 架构
|
|
@@ -38,12 +42,15 @@ Host 半边和 Client 半边各管一段,边界很清晰:
|
|
|
38
42
|
│ 数据:插槽 standardProps 的 useWorkspaces / useSessions │
|
|
39
43
|
│ 对话:fetch /plugins/dsh-multi-session/digest │
|
|
40
44
|
│ 操控:fetch /plugins/dsh-multi-session/prompt │
|
|
45
|
+
│ 搜索:fetch /plugins/dsh-multi-session/search │
|
|
41
46
|
└──────────────────────────┬───────────────────────────────┘
|
|
42
47
|
│ HTTP(同源,带 cookie,过 connection gate)
|
|
43
48
|
┌──────────────────────────┴───────────────────────────────┐
|
|
44
49
|
│ Host(index.js) │
|
|
45
50
|
│ /digest ── sessionQuery.observeSession → foldDigest │
|
|
51
|
+
│ + workspaceChanges.summary(改了什么文件) │
|
|
46
52
|
│ /prompt ── sessionController.prompt / .cancel │
|
|
53
|
+
│ /search ── sessionController.search,索引禁用时扫日志 │
|
|
47
54
|
│ /report ── 客户端异常落盘(仅诊断用) │
|
|
48
55
|
│ /probe ── 仅 dev:开发期探针 │
|
|
49
56
|
│ /stamp /reload ── 仅 dev:发布新 bundle + 页面自动重载 │
|
|
@@ -84,6 +91,22 @@ Host 侧 `foldDigest` 做三层过滤后才进面板:
|
|
|
84
91
|
|
|
85
92
|
客户端 `renderDigestItem` 再兜一层:类型不是 `user` / `assistant` 的一律不渲染。
|
|
86
93
|
|
|
94
|
+
### 为什么气泡一左一右
|
|
95
|
+
|
|
96
|
+
早期把两侧都靠左、只加个左边框,实际看下来很难一眼分清谁说的——尤其连续几轮长文之后。
|
|
97
|
+
现在:**助手靠左**(浅灰气泡、左下角圆角收)、**你靠右**(品牌蓝底、右下角圆角收),
|
|
98
|
+
每条消息上方一个小药丸标「我」或「助手」。正文走一个自写的极简 Markdown 渲染器
|
|
99
|
+
(标题 / 粗体 / 斜体 / 行内代码 / 代码围栏 / 列表 / 表格 / 引用 / 链接),
|
|
100
|
+
全程用 React 元素构造,**不拼 HTML 字符串、不用 `dangerouslySetInnerHTML`**——
|
|
101
|
+
会话内容里的任何标签都只会被当成文字显示。
|
|
102
|
+
|
|
103
|
+
### 为什么「在等你」值得单独做
|
|
104
|
+
|
|
105
|
+
会话卡在等你回话时,`running` 仍然是 `true`。光看「运行中」,它可能在空转十几分钟,
|
|
106
|
+
你却以为它在干活——这比「跑完了不知道」更浪费时间。判定只看两个信号:
|
|
107
|
+
未决的 `approval/asked`(没有对应的 `approval/decided`)、未返回的 `ask_user_question`
|
|
108
|
+
(有 `tool/call` 没有 `tool/result`)。**刻意不做超时猜测**,慢工具不会被误报成卡住。
|
|
109
|
+
|
|
87
110
|
### 数据从哪来(客户端)
|
|
88
111
|
|
|
89
112
|
| 需要的东西 | 来源 |
|
|
@@ -101,7 +124,8 @@ selector 必须是**模块级稳定引用**(`const identity = (state) => state
|
|
|
101
124
|
|
|
102
125
|
| 路由 | 方法 | 说明 |
|
|
103
126
|
| --- | --- | --- |
|
|
104
|
-
| `/plugins/dsh-multi-session/digest` | GET | `?sessionId=&limit=&live=1&fresh=1&mode=` → `{ok, ms, source, turns, endReason, items}` |
|
|
127
|
+
| `/plugins/dsh-multi-session/digest` | GET | `?sessionId=&limit=&live=1&fresh=1&mode=` → `{ok, ms, source, turns, endReason, waiting, changes, items}` |
|
|
128
|
+
| `/plugins/dsh-multi-session/search` | GET | `?q=&sessions=id1,id2` → `{ok, ms, query, via, hasMore, items:[{sessionId, snippet, count, hits}]}`。优先走 `sessionController.search`(不激活会话);索引被禁用时退化为读磁盘日志扫描 `sessions` 点名的那些会话 |
|
|
105
129
|
| `/plugins/dsh-multi-session/prompt` | POST | `{sessionId, text, mode:'queue'\|'steer'}` 发消息;`{sessionId, action:'cancel'}` 停止 |
|
|
106
130
|
| `/plugins/dsh-multi-session/report` | GET/POST | 客户端异常上报,落盘到系统临时目录(保留最近 40 条) |
|
|
107
131
|
| `/plugins/dsh-multi-session/probe` | GET/POST | **仅 dev**:开发期探针 |
|
|
@@ -111,7 +135,7 @@ selector 必须是**模块级稳定引用**(`const identity = (state) => state
|
|
|
111
135
|
所有业务路由都过 `connection.requestRejection(req)` 鉴权闸门(缺失 → 503,未授权 → 401/403)。
|
|
112
136
|
`curl` 直接请求会得到 `{"error":"unauthorized"}`,这是正常的——只有浏览器同源 fetch 带 cookie 才过。
|
|
113
137
|
|
|
114
|
-
`digest` 的 Host 侧缓存:键 `
|
|
138
|
+
`digest` 的 Host 侧缓存:键 `v5:${mode}:${live?'live':'idle'}:${sessionId}:${limit}`,
|
|
115
139
|
`live=1` 用 800ms TTL、空闲用 60 秒,`fresh=1` 绕过缓存,最多 200 条。
|
|
116
140
|
`live` 必须进键——否则会话刚跑完那一刻,空闲请求会命中「助手最后一句话还没写进去」的旧 payload。
|
|
117
141
|
|
|
@@ -147,7 +171,8 @@ plugin_manager action=install_bundle target=<插件目录或包名>
|
|
|
147
171
|
(`remove_bundle` 对本插件返回 `not-removable`;`set_plugin` 不接受 `include:` 前缀的 entryId。)
|
|
148
172
|
装完页面**不会**自动重载,得手动刷新。
|
|
149
173
|
- 语法自检:`node --check index.js`、`node --check client.js`。
|
|
150
|
-
-
|
|
174
|
+
- 图标两套:`icon.svg`(界面内用)与 `icon.png` 512×512 位图(市场收录要求位图,SVG 会被拒)。
|
|
175
|
+
- 截图 `assets/screenshot-board.jpg` 由 `screenshots.json` 声明,市场详情页与本站页面都会展示。
|
|
151
176
|
|
|
152
177
|
## 已知限制
|
|
153
178
|
|
|
@@ -156,6 +181,10 @@ plugin_manager action=install_bundle target=<插件目录或包名>
|
|
|
156
181
|
- 运行中每 1.2 秒刷新一次;停下后降频到 8 秒继续跟(不会停),避免刚跑完那一刻停在旧结果上。
|
|
157
182
|
- 子代理会话默认折叠(实测 761 个会话里 639 个是子代理,全放出来会淹没面板)。
|
|
158
183
|
- 冷启动补标是启发式的:空闲会话若只是被改名(`updatedAt` 前移),也可能被误标成「待查看」。
|
|
184
|
+
- 「在等你」靠事件流推断(未决 `approval/asked`、未返回的 `ask_user_question`),不做超时猜测 —— 慢工具不会被误报成卡住。
|
|
185
|
+
- 「改了什么文件」依赖 `workspaceChanges.summary()`,只有该轮真有 `workspace/changes` 事件才有数据;纯对话的轮次不显示。
|
|
186
|
+
- 跨会话搜索优先走 `sessionController.search`(只能搜到"可见"的会话正文);**如果部署把 session-query 索引配成 `openAt: "never"`,会自动退化为直接读磁盘会话日志再扫**——此时只扫面板里看得到的会话(最多 40 个),每个约 60ms,所以整体要 2–3 秒,面板上会显示扫了几个、用了多久。
|
|
187
|
+
- 会话间传话固定用 `queue`(排进对方收件箱),不提供打断式转发 —— 传话语义是补充信息,不是抢占。
|
|
159
188
|
- 纯 Web 插件,页面关掉就看不到任何东西;要关页面也收得到得另接 webhook。
|
|
160
189
|
|
|
161
190
|
## License
|
|
Binary file
|
|
Binary file
|