DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

kuyueliuhun-ctrl /

kuyueliuhun-ctrl/dsh-command-queue

Verified

DSH 插件:让 /compact 等斜杠命令在 agent 忙碌时进入命令队列,空闲后自动执行 | Queue slash commands until the agent is idle

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@dca9e010

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」),队列里那行同时消失。

特性

🧩 通用 任何斜杠命令都适用,不限于 /compact —— 不枚举命令名,拦截点在 ctx.commands.execute()
👀 看得见 浏览器队列面板,CSS 与 DOM 取自原生 QueueDock 原文(仅换类名前缀),沿用全局主题变量
🔒 零回归 非命令语法 / 注册表解析不到 / 控制动词(/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/<profile>"          # 例如 ~/.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
→ 2 command(s) queued for this agent, waiting for it to become idle: /compact, /export
→ No queued commands for this agent.

行为契约:什么时候不排队

以下情况一律保持原行为(立即执行),保证零回归:

  • 不是合法命令语法 —— 第 0 字节不是 /、名称含大写或非法字符(如 /Compact)、只有 /;
  • 命令名在注册表里解析不到 —— 客户端本来就会按「未命中」处理,没必要拖到空闲之后;
  • 命令名在立即执行白名单里 —— 默认 stop / cancel / abort / interrupt / halt, 忙碌时敲 /stop 本该立刻中断,排队会失去意义甚至危险;
  • agent 当前就是 idle;
  • 排队逻辑自身抛错 —— 兜底回落成原行为,绝不吞掉用户命令。

只有「合法 + 已注册 + 未豁免 + agent 正忙」才入队。

配置

无 schema,容错读取,全部可选。写在 profile 的 cordis.patch.yml 里对应条目下:

- id: command-queue
  name: 'dsh-command-queue'
  config:
    verbose: true                    # 打开排队/执行日志(默认 false)
    pollIntervalMs: 250              # host 侧等空闲的轮询兜底间隔,50–5000(默认 250)
    exposeState: true                # 注册给浏览器面板的已鉴权路由(默认 true;false = 纯 host)
    immediateCommands:               # 整体替换默认白名单
      - stop
      - cancel
      - abort
    alwaysImmediateCommands:         # 在(默认或自定义的)白名单上追加
      - my-control-command

它是怎么做到的

一句话:在 host 侧包装 ctx.commands.execute() —— 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 或面板确认它还在队列里
/stop 也进了队列 不该发生 —— 控制动词在默认白名单里。若你自定义过 immediateCommands(整体替换),记得把控制动词加回去
不同 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 半边:立即放行(未空闲 / 未注册 / 非命令 / 白名单)、忙碌挂起后执行、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.6-alpha.1 实现,依据其编译产物逐行核对。 只使用公开面:ctx.commands.execute/find/register、agent.status、 agent.ctx.on('agent/status')、ctx.connection.fetch.register、ctx.slots.*。

许可

MIT · 问题与建议欢迎提到 Issues。

—/ 5

No ratings yet

Verified DSH bundle

Commit dca9e010e5cd

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout