← 返回列表
未验证
DSH 插件:让 /compact 等斜杠命令在 agent 忙碌时进入命令队列,空闲后自动执行 | Queue…
尚未跑自动兼容性验证,可查看页面内的依赖与入口分析。 · 最近上游提交 2026/9/24 · 已提供中文文档
DSH 插件:让 /compact 等斜杠命令在 agent 忙碌时进入命令队列,空闲后自动执行 | Queue slash commands until the agent is idle
综合分
29.9
GitHub 分
29.9
用户评分
—
★ Stars
0
周下载量
—
兼容 / 相关生态插件(非 dsh 原生,请按其对应运行时安装)
git clone https://github.com/kuyueliuhun-ctrl/dsh-command-queue.git信任档位:已验证本站已于 0 天前真实安装成功
- 是什么
- 生态应用(桌面端 / Web 外壳,不以 dsh plugin add 安装)
- 装得上吗
- 本站已真实安装成功(非静态推断)
- 安全吗
- 本站尚未对该插件做风险分级(暂未覆盖,不等同于无风险)
- 还在维护吗
- 活跃:最近一次提交在 1 天前
档位由下列信号合成:本站实装验证(真实安装,当前最高到 L4)· 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。下方各区块是它的证据明细。 验证判据与等级说明 →
🟢实装验证通过· 2026/9/25
由本站实装验证器在真实 dsh 环境安装成功,非静态推断。
数据截至 2026/9/25(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动
README
由 DeepSeek 最新模型翻译生成dsh-command-queue
让 /compact 这类斜杠命令在 agent 忙碌时不再立刻报错,而是进入命令队列,
等 agent 空闲后自动执行 —— 并在浏览器里以复刻原生消息队列的样式展示这份队列。
Queue slash commands until the agent is idle — with a browser queue panel styled after DSH's native message queue.
Release
License
dsh-plugin
DSH
DeepSeek Harness(DSH)插件 · host + client 双面 · 不改 DSH 源码 · 卸载即完全还原
问题:agent 忙碌时 /compact 只会报错
DSH 里普通消息和斜杠命令走两条完全不同的通道:
| | 普通消息 | 斜杠命令 |
|---|---|---|
| 客户端 | session.prompt({ mode }) | remote.commands.execute() |
| host 落点 | agent.followup() / agent.steer() → agent inbox | ctx.commands.execute() → 直接调 handler |
| 忙碌时 | 天然排队,回合结束再消费 | 立即执行,没有任何排队语义 |
/compact 的 handler 调 compactNow() → agent.runMaintenance(),后者在 agent 非 idle 时
同步抛 ManualCompactionError('busy')。于是 agent 正在跑的时候敲 /compact,只会立刻收到:
Compaction is unavailable because this process has an active compaction,
or the agent is not idle.
既没有排队,也没有重试。DSH 作者把「命令自己进队列」当作有意排除的方案记录在案
(Agent Note: "Queue the command itself. Rejected."),所以官方没有开关 —— 这正是本插件补上的那一段。
效果
agent 忙碌时敲 /compact:
1. 命令被排队,输入框不冻结,你可以继续打字、继续排消息;
2. composer 上方、原生消息队列正下方立刻出现一条「命令队列」:
单条直接列出一行 /compact,多条折叠成「已排队命令 · N」可展开,每行带一个移除按钮;
3. 回合结束后命令真正执行,transcript 里出现正常的命令卡片
(「执行中…」→「已完成 · Compacted N history items」),队列里那行同时消失。
特性
| | |
|---|---|
| 🧩 通用 | 拦截点在 ctx.commands.execute(),任何斜杠命令都能按需纳入排队(列进 deferCommands),默认只排 /compact |
| 👀 看得见 | 浏览器队列面板,CSS 与 DOM 取自原生 QueueDock 原文(仅换类名前缀),沿用全局主题变量 |
| 🔒 零回归 | 默认只排 /compact;非命令语法 / 未列入 deferCommands / 强制立即(/stop 等)/ 注册表解析不到 / agent 已空闲 —— 一律照旧立即执行 |
| 🧯 不吞命令 | 排队逻辑自身抛错时回落原行为;卸载时唤醒等待者让在队命令立刻执行完 |
| 🎛 可控 | 按 agent 隔离、严格 FIFO 串行、可随 UI 请求取消、可从面板移除 |
| 🔐 鉴权 | 面板数据走 /api 已鉴权路由(Host/Origin 围栏 + 签名 cookie),不用裸 webServer 路由 |
| ♻️ 可卸载 | 精确还原 execute(含原描述符),不留悬挂 RPC |
安装
本插件是手写 ESM / 浏览器 bundle,没有编译步骤;lib/index.js 与 lib/client.js 就是源码,
npm run build 只做语法校验 + 跑测试。
本包是 host + client 双面插件。 host 半边做排队与执行,client 半边
(exports["./client"],由 package.json 的 dsh.client.platform: "web" 声明)渲染队列面板。
⚠️ 客户端插件是页面加载时装配的 —— 安装/注入后需要刷新页面才会出现面板。
方式 A:从 GitHub 装配进 profile(推荐,重启后仍在)
cd "$DSH_HOME/profiles/" # 例如 ~/.dsh/profiles/web
npm install github:kuyueliuhun-ctrl/dsh-command-queue
然后把包名加进该 profile package.json 的 dsh.profile.bundles 数组:
{ "dsh": { "profile": { "bundles": ["dsh-command-queue"] } } }
本包自带 cordis.patch.yml,bundle 层会把 command-queue 这一行插进 loader,无需手写 patch 条目。
方式 B:本地目录装配(开发)
npm install "file:/path/to/dsh-command-queue"
用了 dsh-super-injector 的话:
dev_install_package { "dir": "/path/to/dsh-command-queue", "profile": "web" }
方式 C:运行时注入(免重启,临时验证)
dev_inject_plugin { "dir": "/path/to/dsh-command-queue" }
dev_plugin_status {}
卸载
dev_uninject_plugin { "match": "dsh-command-queue" }
非注入器环境:从 dsh.profile.bundles 移除该名字,再删除 node_modules 里的包
使用
浏览器队列面板
挂在原生消息队列同一个槽位 conversation.input.dock 上
(原生 id:"queue" / order:20,本插件 id:"command-queue" / order:30),
所以两条队列上下并排。队列为空时面板完全不渲染(返回 null),零视觉占用。
面板每 1.5s 轮询一次 host 快照;行右侧的按钮可以把一条还没执行的在队命令移除
(被移除的命令不会执行)。
/cmdqueue 命令(纯文本路径)
不想开浏览器面板时,用这个只读命令查看同一份队列:
/cmdqueue
→ 1 command(s) queued for this agent, waiting for it to become idle: /compact
→ No queued commands for this agent.
行为契约:什么时候排队
规则是白名单:只有名字明确列在 deferCommands 里的命令才可能被排队,默认只有
/compact —— 它是唯一「忙时必然失败」的命令(compactNow → runMaintenance 的
phase.kind !== 'idle' 同步闸门)。其余命令一律照旧立即执行,这就是零回归的来源。
以下情况任一命中即立即执行,不进队列:
1. 不是合法命令语法 —— 第 0 字节不是 /、名称含大写或非法字符(如 /Compact)、只有 /;
2. 命令名不在 deferCommands 里 —— 默认即绝大多数命令走这里;
3. 命令名在强制立即名单里 —— 内置 stop / cancel / abort / interrupt / halt
永远立即(忙碌时敲 /stop 本该立刻中断,排队会失去意义甚至危险),
用户配置的 immediateCommands / alwaysImmediateCommands 与之取并集;
4. 命令名在注册表里解析不到 —— ctx.commands.find(agent, name) 返回 undefined,
客户端本来就会按「未命中」处理,没必要拖到空闲之后;
5. agent 当前就是 idle。
只有「合法 + 在 deferCommands 里 + 未被强制立即 + 已注册 + agent 正忙」才入队。
此外,排队逻辑自身抛错时兜底回落成原行为,绝不吞掉用户命令。
为什么默认只排 /compact:/permission(切权限预设)、/plan、/goal 是改会话状态的命令,
被推迟到回合结束等于彻底失效 —— 想在 agent 忙着时放宽权限去批准操作,却改不动。
v0.2.0–0.2.1 的「除立即白名单外一律排队」正是这个回归的来源。
配置
无 schema,容错读取,全部可选。写在 profile 的 cordis.patch.yml 里对应条目下:
- id: command-queue
name: 'dsh-command-queue'
config:
deferCommands: # 主开关:只有列在这里的命令才排队(默认 ['compact'])
- compact # 带不带前导 / 都可以
verbose: true # 打开排队/执行日志(默认 false)
pollIntervalMs: 250 # host 侧等空闲的轮询兜底间隔,50–5000(默认 250)
exposeState: true # 注册给浏览器面板的已鉴权路由(默认 true;false = 纯 host)
immediateCommands: # 强制立即:与内置名单取并集(v0.2.2 起不再整体替换)
- export
alwaysImmediateCommands: # 同样是并集,语义上与 immediateCommands 等价
- my-control-command
- deferCommands 是排队的白名单,默认 ['compact'];显式写 deferCommands: []
(空数组)= 没有任何命令排队,等同于关闭排队功能。
- immediateCommands / alwaysImmediateCommands 是强制立即名单,与内置的
stop / cancel / abort / interrupt / halt 取并集 —— 某命令即使同时列在
deferCommands 里也立即执行;两个键语义等价,都只做「加」。
它是怎么做到的
一句话:在 host 侧包装 ctx.commands.execute() —— 只有列入 deferCommands 的命令
(默认只有 /compact)才会在 agent 忙时被挂起,等 agent/status 回到 idle 后调用原方法;
其余命令照旧直通。命令仍由原注册表解析、仍由 CommandRuntime
写 command/run + command/done 生命周期日志,只是执行时机被推迟到空闲窗口。
有两个不查代码就会踩的坑(都与 DSH 内部实现有关):
- ctx.commands 是 cordis 的 traceable Proxy,service.execute === patched 这种身份比较
恒为 false(get trap 对函数每次返回新的 shadow proxy)—— 用它做还原守卫会导致补丁永远摘不掉;
- AgentLoop.kick() 的 finally 是「同步 emit agent/status → wakeDriver()」,
任何跨 promise 边界后再调用都会撞回 running —— 所以「检查 idle」与「调用」必须落在同一个同步块里。
为什么不用 DSH 原生队列? 原生队列(agent inbox)的条目只能是 UserMessage(模型可见内容),
没有「命令项」类型;且队列项在下一个 step 边界就被 claim() 取走,那一刻 agent 仍在 running,
compactNow 照样 busy。即「一直显示在原生队列里」与「等 idle 才执行」互斥 —— 所以本插件
另建一份队列,只把样式与位置复刻成原生队列的样子。
📖 完整调用链、文件:行 证据、实测运行时行为与验证记录见 docs/INTERNALS.md。
故障排查
| 现象 | 原因 / 处理 |
|---|---|
| 刷新了也看不到面板 | 客户端插件只在页面加载时装配。先确认 dev_plugin_status 里本插件是 client ✓;若显示 client ✗,是 pkgMeta 负缓存(见下一行),重启 host 或清缓存 |
| 从 v0.1.0 升级后 client 一直是 ✗ | dsh-client-modules 的 resolveMeta() 有 pkgMeta 负缓存:包在没有 dsh.client 声明的形态下加载过一次,null 就被缓存。重启 host 即可;全新安装不受影响 |
| 排队期间 transcript 里没提示 | 设计如此:command/run 事件在 handler 调用前才写入,而我们在它之前就挂住了。提示在队列面板里,不在 transcript |
| 命令一直不执行 | 它在等 agent 空闲。agent 若一直有排队消息,空闲窗口会被不断占用 —— 用 /cmdqueue 或面板确认它还在队列里 |
| 改动类命令(/permission 换权限预设、/plan、/goal)在 agent 忙的时候不生效,要等回合结束 | v0.2.0–v0.2.1 的排队规则是「除立即白名单外一律排队」,把这些命令也排了。升级到 v0.2.2(默认只排 compact)即可;若你把 immediateCommands 当整体替换用过,注意它现在是与内置名单取并集 |
| /stop 也进了队列 | 不该发生 —— 内置控制动词永远强制立即,immediateCommands 只能往里加、不能把它们替换掉。检查是否把 stop 同时写进了 deferCommands(同时命中时强制立即优先) |
| 不同 agent 互相影响 | 不会。队列按 agent 隔离,一个 agent 空闲不会放行另一个在队的命令 |
开发
npm test # node --test tests/.test.mjs
npm run check # node --check lib/index.js && node --check lib/client.js
npm run build # 语法校验 + 全套测试
| 测试文件 | 覆盖 |
|---|---|
| tests/queue.test.mjs | host 半边:立即放行(未空闲 / 未注册 / 非命令 / 不在 deferCommands / 强制立即)、默认只排 compact、deferCommands 可延展与 [] 关闭排队、immediateCommands 取并集、忙碌挂起后执行、FIFO 串行、多 agent 隔离、取消、卸载不丢命令、轮询兜底、异常回落、traceable Proxy 的 patch 与精确还原、两条 client 路由 |
| tests/client-bundle.test.mjs | 浏览器半边:用最小 React 运行时 + 假 window.__ModuleLoader__ 真正加载并渲染 bundle —— bundle 形态(id / factory / 无 default)、dock 条目 id 与 order、异常自吞、空队列渲染 null、有命令时渲染并能经 drop 路由移除 |
第二道测试不是可选项:DSH 的 boot 审计没有 per-plugin 隔离,
客户端 bundle 抛错会让整个 Web 应用无法 mount。
兼容性
针对运行中的 @deepseek-ai/dsh@0.1.7-alpha.2 实现,依据其编译产物逐行核对
(0.1.6-alpha.1 为原始基线,0.1.7-rc.1 抽样复核结论一致)。
只使用公开面:ctx.commands.execute/find/register、agent.status、
agent.ctx.on('agent/status')、ctx.connection.fetch.register、ctx.slots.。
上游仍未支持「忙时排队命令」:dsh-command-compact 的官方文档明写
"the command itself is not queued",并把 "Queued commands" 列为
undecided / open direction。若某天落地,本插件应默认停用 host 侧包装,
以免同一命令被排队两次。
许可
MIT · 问题与建议欢迎提到 Issues。