Skip to content

Releases: ace202321-cloud/dsh-agent-chat

v0.5.0 - 需回执/优先级/阶段/范围 + 长对话窗口化

Choose a tag to compare

@ace202321-cloud ace202321-cloud released this 25 Oct 05:15

v0.5.0

搜了一圈同类,借了三条协议

项目 借了什么
sbnsec/parallel-claude-agents ack-required 规则:标了需回执的消息,超时未应答自动升级
brianyu18/devteam 7 阶段词汇(think/plan/build/review/test/ship/reflect)—— 编排器没借,dsh-agent-teams 已经干那活了
simonecamerano/workflow-multiagents 人工闸门 —— 我们本来就有(你每次都在看面板)

四个新字段(全是可选,向后兼容)

字段 取值 面板效果
**需回执** yes 超 5 分钟没回应 → 红色「⚠ 超时未应答」,标题栏「⚠ N 超时」
**优先级** info / critical critical 红色「紧急」徽章
**阶段** think…reflect 对应颜色的阶段徽章
**范围** 任意文本 「📁 范围」,悬停看全文
node post.mjs --sig DSH --body-file task.md --assign CX --status open \
                --ack --priority critical --phase build --scope "README_EN.md"

⭐ 长对话不会再变卡

渲染窗口化:只挂最近 200 条,更早的用「↑ 加载更早」按需追加。

卡顿的真凶一直是渲染层(上千条 = 上万个 DOM 节点),不是解析层(parseThread 是 O(n) 行扫,1 MB 也就几十毫秒)。

验证

#1 DSH  ack=true  prio="critical"  phase="build"  scope="README_EN.md"  status="open"

host node --check 干净,客户端 bundle 26.21 kB,__ModuleLoader__ 特征在。

dsh plugin --profile <你的profile> add ./dsh-external-dsh-agent-chat-0.5.0.tgz

v0.4.4 - post.mjs 支持 --body-file 和 --close

Choose a tag to compare

@ace202321-cloud ace202321-cloud released this 25 Oct 05:08

v0.4.4

两个洞(真跟 Codex 打招呼时踩出来的)

① 多行 --body 在 Windows 下被截断

cmd /c "... --body "多行内容" --model xxx --reply 15"

正文里的换行把命令行切断了,后面所有参数都丢了 —— 实测写出来是 model=- replyTo=- status=(空)。

修法:--body-file <路径>,从 UTF-8 文件读正文(自动剥 BOM、统一换行),优先于 --body。不用引号,就不会有引号问题。

② 回复不会关掉原单

状态 是每条消息自己的字段,回一条新的不会改原来那条。实测 Codex 回了 #16,待办数还是 1 —— 因为 #15 还是 open,只能手工去改。

修法:--close N —— 新消息落盘后,把 #N 的 **状态** 行改成 done。只改这一行,在写锁内完成;如果 #N 根本没有状态行,它不会擅自插一行,只打印提示 —— 没选择加入状态机的消息保持原样。

验证

node post.mjs --sig DSH --body-file mybody.md --assign CX --status open --model deepseek-flash
# -> #1 多行正文完整(空行、列表都在)

node post.mjs --sig CX --body-file reply.md --reply 1 --status done --close 1
# -> #1 状态翻成 done,#2 追加,replyTo=1

解析器回读:#1 done/CX/deepseek-flash、#2 done/replyTo=1 —— 全对。

dsh plugin --profile <你的profile> add ./dsh-external-dsh-agent-chat-0.4.4.tgz

v0.4.3 - 修掉 cordis 的 inject 守卫,终于能注册进 + 菜单

Choose a tag to compare

@ace202321-cloud ace202321-cloud released this 25 Oct 05:04

v0.4.3

用户贴的报错(原文)

Error: cannot get property "betterSidebar" without inject

cordis 会拦裸读服务:不先声明就直接读 ctx.betterSidebar 会抛异常。v0.4.2 是在 effect 里直接读的,所以注册根本没执行,tab 自然进不了 + 菜单。

正确写法(dsh-agent-teams 里就是这么写的)

ctx.inject(["sidebarRight", "sidebarRightTabs"], (scoped) => {
  scoped.effect(() => scoped.sidebarRightTabs.register({ /* ... */ }))
})

这一版

  • 注册改成 ctx.inject(["betterSidebar"], scoped => ...),服务存进模块级变量
  • 头部按钮通过 getter 读那个变量,再也不碰 ctx.betterSidebar
  • 原生 sidebarRightTabs 注册保留(没装 better-sidebar 的机器走这条)
  • openOurTab 的三级降级链不变

装完

重启 DSH → 右侧栏点 + → 应该能看到「代理对话」。

dsh plugin --profile <你的profile> add ./dsh-external-dsh-agent-chat-0.4.3.tgz

v0.4.2 - 让「代理对话」出现在右侧栏的 + 菜单里

Choose a tag to compare

@ace202321-cloud ace202321-cloud released this 25 Oct 04:59

v0.4.2

前一版错在哪

v0.4.1 加了头部按钮,但点了没反应;而且用户关掉 tab 后,在右侧栏的 + 菜单里根本找不到「代理对话」。

根因:装了 dsh-better-sidebar 之后,右侧栏是它的侧边栏。它 README 原话:

Since v0.4.0 the plugin exposes the ctx.betterSidebar service — other plugins can register sidebar pages and file viewers.

它的 + 菜单列的是它自己的注册表,不是 DSH 原生的 sidebarRightTabs。我们只注册了原生通道,所以在用户实际看到的那份列表里不可见。

这一版

  • 注册进 ctx.betterSidebar.registerTab() —— 字段取自它自己的 lib/types/client/service.d.ts(id / title / description / order / single / component),不是猜的
  • 原生 sidebarRightTabs 注册保留,作为没装 better-sidebar 时的兜底
  • openOurTab() 改成三级降级:betterSidebar.openTab({ type }) → sidebarRight.openTab({ kind, ... }) → sidebarRightTabs.openTab({ id }),全失败时把三个服务各自的方法名打进控制台

安装后

重启 DSH → 右侧栏点 + → 列表里应该有 「代理对话」(带一行说明「多代理对话流(只读渲染 thread.md)」)。

dsh plugin --profile <你的profile> add ./dsh-external-dsh-agent-chat-0.4.2.tgz

v0.4.1 - 关掉的 tab 能叫回来了 + 写后回读 + 防重复

Choose a tag to compare

@ace202321-cloud ace202321-cloud released this 25 Oct 04:51

v0.4.1

🐛 修掉一个真窟窿:tab 关掉后打不开

sidebarRightTabs 没有 openTab。真正能用的是原生 surface:

sidebarRight.openTab({ sessionId?, kind, params, revealIfOpened: true })

v0.3.1 里我把 openTab 删了,理由是「一直静默失败」—— 实际是签名传错了(我传的是 { id },它要的是 { sessionId, kind, params })。

现在:会话头部出现「💬 代理对话」按钮,点一下就把 tab 叫回来。成功变绿,失败变红并打印实际可用的方法名 —— 不再猜。

🔁 从 agent-postbox 借的两条

搜了一圈,文件邮箱类项目有 5 个(agent-postbox / agent-mailbox / cimux / walkie-talkie / skill-claude-relay),都还没做成 DSH 侧边栏面板。从 agent-postbox 借了两条硬的:

借来的 落地
写后回读 appendFileSync 之后重读文件,断言新头行存在;不在就退出码 3 —— 「报成功但没写进去」再也蒙混不过去
防重复 同署名 + 同正文 60 秒内重发被拒(退出码 2),确要发加 --force

🐛 顺带修掉一个致命 bug

做防重复时测出来的:process.exit() 不执行 finally,所以「拒绝重复」这一条路径会把 thread.md.lock 永久留下 —— 之后所有发送都报「拿不到写锁」,整个邮箱瘫痪。

修法:拿到锁之后立刻挂 process.on('exit') 兜底清锁,任何退出路径都清。

测试

  • 四条发送路径:首发 0 / 重复 2 / --force 0 / 换内容 0 —— 全对
  • 锁文件无残留
  • node --check 干净,客户端 bundle 重建后 __ModuleLoader__ 特征在

安装

dsh plugin --profile <你的profile> add ./dsh-external-dsh-agent-chat-0.4.1.tgz

⚠️ 客户端改了,装完记得 F5 刷新。

v0.4.0 - 借鉴 ai-memory:指派/状态追踪、brief.mjs、诚实的限制声明

Choose a tag to compare

@ace202321-cloud ace202321-cloud released this 25 Oct 04:31

v0.4.0 — 从 ai-memory 借来的四个设计

这次不是加功能,是移植思路。参考了 akitaonrails/ai-memory(给 coding agent 做长期记忆的系统),把它里面适用于公告板场景的四条搬了过来。

# 借来的 在我们这变成了什么
1 typed handoff(有归属的交接) 消息可写 **指派**:CX 和 **状态**:open/claimed/done;标题栏「N 条待办」徽章按人分组;卡片显示彩色状态徽章,done 自动变淡
2 冷记忆压缩 「只看未完成」一键过滤,已完成的历史不再淹没当前任务
3 bounded brief(有界摘要) 新增 brief.mjs:输出「未完成 + 最近 N 条」,新代理读它而不是读整个 thread;API 也暴露 brief 字段
4 对自己诚实 README 新增「已知限制」表,明说不做什么

顺手修掉的老 bug

**回复给**:- 匹配不上 \d+,会把 bodyStarted 置真,导致后面所有元信息行被吞进正文。这个坑从 v0.3.x 就在,只是那时没有后续字段所以看不出来。现在所有元信息行都走「认出就 skip」的显式路径。

向后兼容

指派 / 状态 都是可选字段。v0.3.x 写的老消息照样解析,只是 status 为空、不参与待办计数。

测试

  • 解析器 10/10 断言全过
  • post.mjs --assign/--status 与 brief.mjs 在真实生成的邮箱上端到端验证

安装

dsh plugin --profile <你的profile> add ./dsh-external-dsh-agent-chat-0.4.0.tgz

v0.3.2 — 修复新消息不自动滚动

Choose a tag to compare

@ace202321-cloud ace202321-cloud released this 18 Oct 10:23

v0.3.2 — 修复「新消息来了但列表停在顶部」

问题

新消息追加后,面板停在第一行,必须手动往下翻才能看到 —— 而且新消息还会被误判为「已读」。

原因

在 v0.3.1 重写未读逻辑(seenUpTo)时,把「自动滚到底」那段代码弄丢了。
不是"跳回顶部",是根本没跟着滚 —— 列表一直停在 scrollTop = 0。

修法

  • useLayoutEffect 做贴底跟随 —— 绘制前完成,不闪
  • 只在「你原本就在底部」时才滚 —— 翻历史时不会被打断
  • visibilitychange 监听 —— 页签重新可见时再贴一次底(keepMounted 下页签可能一直挂着)

升级

dsh plugin --profile <你的profile> add github:ace202321-cloud/dsh-agent-chat

装完刷新页面(client 改动)或重启 DSH(如果刷新不生效)。

v0.3.1 — 两轮独立审阅后的 11 个修复

Choose a tag to compare

@ace202321-cloud ace202321-cloud released this 18 Oct 09:36

v0.3.1 — 两轮独立审阅后的 11 个修复

审阅者:Codex CLI + Claude Code 各独立审一遍,交叉验证。

修复清单

# 问题 修法
1 署名含空格会静默丢消息 post.mjs 校验 --sig 不含空白和 ·
2 BOM 吞掉首条消息 新增 stripBom(),读取与解析两处都剥
3 --file 路径穿越(可写任意文件) 词法校验 + realpath 双检,挡住 symlink/junction
4 代码围栏不跟踪 parseThread 与 post.mjs 都维护 inFence;支持 ``` 和 ~~~
5 未读计数错 seenUpTo + localStorage;页签不可见时不推进
6 轮询竞态 + 无超时 inFlight 锁 + 序号 + AbortController(6s)
7 重复 #N React key 加序号;post.mjs 加排他锁,并发不撞号
8 API 抛错后响应永不结束 handler 整段 try/catch,catch 回 500
9 每 2 秒同步解析整个文件 按 mtime:ctime:size 缓存
10 openTab 静默失败 删掉那次调用(服务未注入)
11 每条消息末尾多一条横线 解析时剔除尾部分隔线;post.mjs 不再写 ---

新增

  • dispatch.mjs:向 Codex / Claude Code 派活,并把「派发 → 执行 → 回答」整条流程写回 thread.md,
    面板上能追完整链路

验证

11 项回归测试全绿(BOM / 围栏 / 尾部分隔线 / 署名校验 / --reply 校验 / 路径穿越 / 并发不撞号)。

安装

dsh plugin --profile <你的profile> add github:ace202321-cloud/dsh-agent-chat

v0.3.0 — 多代理对话面板首发

Choose a tag to compare

@ace202321-cloud ace202321-cloud released this 18 Oct 08:59

v0.3.0 — 第一次公开发布

给 DSH 右侧栏加一个「代理对话」tab:多个 AI 代理(DSH / Claude Code / Codex / 其他)共用一个 thread.md,面板只读渲染它。

功能

  • 多代理共用一条对话线 —— 署名不写死,新代理接进来零配置
  • 署名自动分色 + 首字母徽标 —— 一眼看出谁在说
  • 未读计数 / 回复跳转 / 按署名筛选 / 折叠 / 自动滚底
  • 轻量 Markdown 渲染 —— 代码块、表格、标题、列表、加粗、行内代码
  • 2 秒轮询 + 容错 —— 文件没了只显示提示,不拖崩界面

配置(v0.3.0 新增)

  • 邮箱路径三级解析:插件配置 → 环境变量 DSH_AGENT_MAILBOX → 默认 ~/.dsh/agent-mailbox(跨平台)
  • 首次运行自动生成 thread.md / README.md / post.mjs / attachments/,已存在的不覆盖
  • post.mjs 发消息脚本 —— 自动算序号、加时间戳,格式不会写错

修复

  • 解析器不再让 ### [#N] 待填 这类占位块覆盖上一条消息的 replyTo

安装

dsh plugin --profile <你的profile> add github:ace202321-cloud/dsh-agent-chat

或下载下面的 dsh-external-dsh-agent-chat-0.3.0.tgz:

dsh plugin --profile <你的profile> add ./dsh-external-dsh-agent-chat-0.3.0.tgz

要求

  • DSH 0.2.x
  • Node >= 20