Editor's note

CHplus0/dsh-shell-command

DeepSeek Harness (DSH) plugin: a /! command trigger (run one command, analyze output, inspired by Claude Code's ! gesture) and a /terminal command (interactive PTY popup with on-demand history reference).

This is a DeepSeek Harness (DSH) plugin. Review its GitHub README, installation information, maintenance status, and public security signals here.

dsh-shell-command

English | 中文

一个 DeepSeek Harness 插件,把 Claude Code 的 ! 手势带到 DSH,分为两种模式:

命令行为
/! <命令>执行 shell 命令,分析其输出。灵感源自 Claude Code 的 ! 前缀——在会话工作目录执行命令,并把输出交给模型即时分析
/terminal弹出交互式终端窗口;关闭本身从不向模型发送任何内容——若本次会话有过输入,转录落盘后面板会跳转到「历史」Tab 并预选中这条,是否引用给模型分析由你在那里手动决定

注意:DSH 的输入触发系统只支持 /@ 作为触发字符,因此我们用 /! 而不是裸 ! 前缀。

安装

需要 dsh CLI 与 Node >= 22

# 从 npm / 仓库安装
dsh plugin --profile web add dsh-shell-command

# 本地源码(开发用 live link,改源码重启即生效)
dsh plugin --profile web add "link:/path/to/dsh-shell-command"

安装后重启一次 Web 界面(dsh web)让 host 端命令加载;它会自动出现在输入框 / 菜单中。

快速上手

第一次使用 /! 命令

在输入框输入:

/! df -h

命令立即执行,输出交给模型分析。你会看到类似的消息:

Shell Command Output
Command: df -h
[输出内容]

模型随后分析磁盘使用情况,如发现问题会给出建议。

第一次使用 /terminal 会话

  1. 在输入框输入 /terminal
  2. 弹出浮动终端面板,有两个Tab:会话历史
  3. 在会话Tab尝试一些命令:
    pwd
    ls -la
    git status
    
  4. 点击顶部的 退出 按钮关闭终端
  5. 面板保持打开并自动跳转到 历史 Tab
  6. 刚关闭的会话已预选并展开
  7. 选择后续操作:
    • 点击 引用并分析 将其发给模型分析
    • 点击 直接退出,本次不分析 跳过并关闭面板

命令详解

/! <命令> — 单命令分析

在会话工作目录执行命令,并立即把输出交给模型分析。这是 DSH 版的 Claude Code ! 前缀。

何时使用:

  • 快速状态检查:/! git status/! npm test
  • 系统诊断:/! df -h/! free -h/! top -bn1 | head -20
  • 文件搜索:/! find . -name "*.log" -mtime -1
  • 一次性操作,需要立即获得 AI 洞察

示例:

/! git log --oneline -10
# → 模型总结近期提交,可能发现模式

/! npm run build
# → 模型分析构建输出,标记警告或错误

/! ps aux | grep node
# → 模型解释正在运行的 Node 进程

技术细节:

  • 输出有界限(maxOutputBytes,保留尾部)并格式化用于分析
  • 命令原文和生命周期记入轨迹(command/run/command/done
  • 需要活跃的模型对话(在第一条消息、模型请求之前无法使用)

/terminal — 交互式终端

交互式 PTY 弹窗(持久 shell,WebSocket 实时流)。最适合:

  • 探索性调试:运行多个命令,观察行为
  • 迭代测试:修改 → 测试 → 修改 循环
  • 多步骤操作:设置 → 执行 → 验证 工作流

工作原理:

关闭终端永远不会自动向模型发送任何内容:

  • 若本次会话没收到过任何输入 → 完全不留痕迹(不落盘、不进历史列表)
  • 若收到过输入 → 转录落盘到 <工作目录>/.dsh-shell-transcripts/,面板跳转到历史Tab并预选中这条新记录

之后由你决定是否引用它进行分析(见下方历史Tab工作流程)。

会话Tab特性

  • 行式终端:等宽回显 + 输入行
  • 控制键:Ctrl+C/D/Z 发送原始控制字节到 shell
  • 命令历史:方向键上下浏览已提交过的命令(纯客户端,最多 500 条)
  • 限制:不支持 Tab 补全;完整 VT100/xterm(vim、htop)计划后续版本支持

历史Tab工作流程

终端历史Tab

关闭一个收到过输入的终端会话后,面板自动切换到历史Tab:

UI元素说明:

  1. 复选框(左侧):选择一条或多条历史记录用于分析
  2. 时间戳:每个会话的关闭时间
  3. 查看/收起按钮(右侧):展开预览转录内容
  4. 说明文本框(底部):可选的自然语言上下文,帮助模型理解
  5. 默认消息提示:显示不填写说明时模型会收到的默认消息:「请帮我分别分析这些历史终端记录。」
  6. 两个操作按钮
    • 引用并分析:将选中的记录发送给模型立即分析
    • 直接退出,本次不分析:关闭面板,不向模型发送任何内容

典型工作流程:

1. 关闭终端会话(点击「退出」)
2. 面板保持打开,跳转到历史Tab
3. 刚关闭的记录已预选并自动展开
4. 查看转录预览
5.(可选)选择其他历史记录进行对比
6.(可选)在说明框添加上下文:「为什么第二次运行失败了?」
7. 点击「引用并分析」→ 模型分析选中的转录
   或点击「直接退出,本次不分析」→ 面板关闭,不向模型发送任何内容

高级用法:

  • 跨运行对比:选择 2-3 个相关会话(如修复前后)并询问:「这几次尝试之间有什么变化?」
  • 引导式分析:使用说明框引导模型注意力:「重点关注内存使用模式」
  • 选择性共享:并非每个终端会话都需要分析——只引用与当前问题相关的内容

存储:

  • 转录持久化到 <工作目录>/.dsh-shell-transcripts/
  • 每个会话包含:<sessionId>-<timestamp>-<counter>.log + .meta.json 元数据文件
  • 保留策略:每个 session ID 保留最近 10 个会话(通过 terminalTranscriptKeep 配置)
  • 建议将 .dsh-shell-transcripts/ 加入 .gitignore

使用场景

场景1:使用 /! 快速诊断

你:构建失败了,让我检查一下...
你:/! npm run build

[输出显示 TypeScript 错误]

模型:错误表明 auth.ts 第42行缺少类型导入...

场景2:使用 /terminal 交互式调试

你:/terminal
终端:$ npm test
[测试失败]
终端:$ cat test/integration.spec.js | grep -A5 "failing test"
终端:$ ls -la test/fixtures/
终端:$ echo $NODE_ENV
[发现问题:缺少 fixture 文件]
终端:[点击「退出」]

[面板跳转到历史Tab,记录已自动选中]

你:[添加说明:「这个测试为什么失败?」]
你:[点击「引用并分析」]

模型:根据转录,测试失败是因为 test/fixtures/user-data.json 文件缺失...

场景3:对比多次运行

[运行1:/terminal → 安装依赖 → 检查构建时间 → 退出]
[运行2:/terminal → 启用缓存后相同步骤 → 退出]
[运行3:/terminal → 不同 Node 版本相同步骤 → 退出]

[在历史Tab]
你:[勾选全部3条记录]
你:[添加说明:「哪个配置最快,为什么?」]
你:[点击「引用并分析」]

模型:对比三次构建运行:运行2因为 npm 缓存快了3倍...

使用技巧与最佳实践

  • 选择合适的工具:单命令且需要立即反馈用 /!;探索性工作流程且稍后决定是否分析用 /terminal
  • 空会话不持久化:打开 /terminal 但没输入任何命令,不会创建历史记录(这是设计如此,避免混乱)
  • 方向键是你的朋友:终端输入行中,↑/↓ 可回顾最近 500 条命令(客户端、会话级别)
  • 说明增加上下文:好的说明(「对比错误信息」或「关注性能指标」)帮助模型更有效地分析
  • 选择性分析:不必分析每个终端会话——只引用与当前问题相关的内容
  • 历史是每个会话独立的:每个 DSH 对话有自己的终端历史;它们不会混在一起

配置

通过 profile 的 cordis.patch.yml 配置(Web 设置页不暴露第三方插件设置):

- insert:
    - id: shell-command
      name: dsh-shell-command
      config:
        shell: ''            # '' → POSIX 用 /bin/bash,Windows 用 cmd.exe
        shellArgs: []        # [] → POSIX 用 -lc,Windows 用 /d /s /c
        timeoutMs: 60000     # 硬超时,到期终止整个进程树
        maxOutputBytes: 32768  # /! 命令的输出尾部保留量
        graceMs: 3000
        analysisPrompt: ''   # '' → 内置提示词;支持 {command} {cwd} {output} 占位符
        terminalEnabled: true
        terminalMaxTranscriptBytes: 1048576   # 内存转录上限(保留尾部)
        terminalTranscriptDir: '.dsh-shell-transcripts'
        terminalTranscriptKeep: 10

安全

  • 在会话工作目录(agent.session.header.cwd)执行
  • 优先走 harness 的 ctx.subprocess 接缝:环境已清洗(不泄漏 DEEPSEEK_API_KEY/DSH_*),进程树级 SIGTERM → grace → SIGKILL 终止;缺失时回退 node:child_process(同样清洗环境)
  • /! 命令的每个流输出有界(maxOutputBytes,超限保留尾部)
  • 设计上由人驱动:命令原文记入轨迹(command/run),无沙箱审批步骤——与你自己在终端敲命令权限一致

测试

node test/unit.mjs           # 纯解析/格式化测试,零依赖
node test/smoke.mjs          # 完整 apply() + handler,跑在 mock context 上
node test/smoke-terminal.mjs # 终端注册表 + hasInput 追踪 + 历史引用 RPC(mock)

smoke 测试需要真实解析 @deepseek-ai/* 依赖;在 profile 外运行时先软链一次:

mkdir -p node_modules/@deepseek-ai
ln -s "$HOME/.dsh/profiles/node_modules/@deepseek-ai/"* node_modules/@deepseek-ai/

常见问题 FAQ

问:何时该用 /! 而非 /terminal
答:单命令且需要立即 AI 分析时用 /!(状态检查、快速诊断)。需要运行多个命令并稍后决定是否分析时用 /terminal(交互式工作流程)。

问:为什么我的终端会话没出现在历史Tab?
答:空会话(没收到输入)不会持久化。如果你打开了 /terminal 但没输入任何命令,不会创建历史记录。这是设计如此,避免混乱。

问:历史转录存储在哪里?
答:在 <工作目录>/.dsh-shell-transcripts/,每个会话一个 .log 文件加一个 .meta.json 元数据文件。建议将此目录加入 .gitignore。旧记录会自动清理(默认:每个会话保留最近10条)。

问:可以手动删除历史记录吗?
答:可以,直接从 .dsh-shell-transcripts/ 删除对应的 .log.meta.json 文件。历史Tab每次打开时从磁盘读取。

问:为什么 vim/htop/ncurses 在 /terminal 里不能用?
答:当前终端是行式的(回显 + 输入行),不是完整的 VT100/xterm 模拟器。完整终端模拟(使用 xterm.js)计划后续版本支持——需要引入构建流水线。

问:方向键命令回顾会跨会话持久化吗?
答:↑/↓ 历史是客户端的,关闭浏览器Tab或面板后会重置。它的作用域是当前终端窗口,不保存到磁盘。

问:「引用并分析」和直接在对话中问命令有什么区别?
答:「引用并分析」会把实际的命令转录(输出、时间戳、退出码)作为结构化数据发给模型。在对话中问依赖你的描述,可能会遗漏细节。当你希望模型看到原始输出时,用引用分析。

问:可以引用之前 DSH 对话的转录吗?
答:不可以。终端历史是会话级别的。每个 DSH 对话有自己的 .dsh-shell-transcripts/ 命名空间,历史Tab只显示当前 session ID 的记录。

问:如果输出非常长会怎样?
答:/!/terminal 都有输出大小限制(maxOutputBytes / terminalMaxTranscriptBytes)。超限时保留尾部(不是头部)。这确保最近的输出始终可见。

问:为什么 /! 提示「No model request exists yet」?
答:/! 需要活跃的模型对话。先向模型发送至少一条消息(开始对话),然后 /! 就能用了。这是为了避免 UI 渲染时序问题。

已知限制

  • /! 的输出作为 plugin 来源的消息交付(在对话中可见)
  • 终端模式:仅行式显示(vim/htop 需要完整 xterm 模拟,后续版本计划支持)
  • API 面锁定 @deepseek-ai/dsh 0.1.0-rc.x;升级 DSH 时需锁定 peer 并回归

未来优化方向

我们计划在后续版本中进行以下改进:

完整终端模拟(迁移到 xterm.js)

  • 当前:行式终端(回显 + 输入行)
  • 目标:完整 VT100/xterm 模拟,支持 vim、htop、ncurses 应用、oh-my-posh 等丰富终端 UI
  • 需要:引入构建流水线(webpack/vite)以打包 xterm.js 及其插件

国际化支持(i18n)

  • 多语言 UI 支持(英文、中文等)
  • 从用户偏好自动检测语言
  • 可配置的 UI 标签

其他改进

  • 命令输出的语法高亮
  • 会话导出/导入
  • 终端历史内搜索
  • 自定义键盘快捷键

贡献

欢迎贡献!你可以:

License

MIT

REPOSITORY SIGNALS

Security & install evidence

This score is based solely on public repository metadata and the install evidence registered here — it is not a code security audit.

Traceable source

From a public plugin catalog, linked to a public GitHub repository.

License

The repository declares the MIT license.

Maintenance activity

Code updates within the last 180 days.

Install evidence

No verifiable install metadata registered yet — please review the repository instructions manually.

Install lifecycle scripts

The inspected package metadata declares no install lifecycle scripts.