终端原生 · 开源 · MIT
agent 在你的终端里,而不是取代你的终端。
dshline 是 DeepSeek Harness 插件生态的终端原生前端,让 agent(智能体)在你已经打开的终端里工作。已完成的输出会写入终端自身的滚动历史,因此向上翻阅、选中文本、重定向到文件都照常可用。只有输入行和状态行会重绘。
安装
npm install -g @deepseek-ai/dsh @dshline/dshline
dshline一个带边框的输入行,左侧标签为 dshline,右侧为工作区名称,提示文字为“ask anything · / menu”。其下方的状态行显示:ready、当前模型、归零的 token 计数器、上下文窗口读数,以及换行、输出分页器和退出所用的按键。
01
一次会话,从头到尾
下面每一帧都是 dshline 实际打印的内容——同样的横幅、同样的输入行、同样的状态段、同样的浮层。向下滚动即可推进会话;文本记录会像你实际使用时那样增长。
打开
dshline 在你已经打开的终端里启动。横幅显示工作区,以及当前 Harness 配置档(profile)注册的路由——dshline 本身不附带提供方列表,也不附带模型列表。
终端文本记录: 终端会话已打开。带边框的横幅显示 dshline 及其版本、工作区路径和当前模型路由。下方是以工作区名称为标签的输入行,提示文字为“ask anything”。再下方的状态行显示“ready”、模型名称、归零的 token 计数器,以及换行、输出分页器和退出的按键提示。
提问
已完成的行会被写入终端自身的滚动历史,之后不再改动。只有底部区域——正在到达的回复、输入行、状态行——会原地重绘。滚动、选择和复制照常可用,因为没有任何东西替换掉你的终端。
终端文本记录: 提交了一个提示:“why does the token refresh drop the retry header?”。模型的推理过程先以暗色斜体出现,随后是一段已提交的回答,指出相关文件与行号。状态行已切换为“working”,显示已用时间、收发 token 数、累计费用和上下文窗口读数。
委派
委派属于 Harness:dshline 观察的是与提供方无关的子代理(subagent)生命周期,而不是自己运行一套引擎。它增加的是——这一行会说明该工作者正在做什么、由哪个模型驱动,状态行则统计正在进行的数量。
终端文本记录: 一次子代理工具调用被提交到文本记录中,显示所委派的描述。状态行现在还会在已用时间和费用之外,报告有一个代理正在运行。
查看
/work 就是输入框自身的框架被展开——同一个锚点、同一宽度,导航提示位于下边框内。没有备用屏幕(alternate screen),也没有全屏接管:上方的文本记录仍然是你的滚动缓冲区,关闭视图后它还在原处。
终端文本记录: /work 视图以带边框的面板形式覆盖在输入行上方,标题为 Work。它列出子代理和后台任务:一个正在运行的子代理,显示它当前正在读取的内容以及驱动它的模型;一个已完成;以及一个排队中的任务。下边框内的导航提示提供移动选择、中断和关闭。
发现
输入 / ,列表就是当前 Harness 配置档所挂载的内容。dshline 不携带需要与上游保持同步的功能清单:缺少某个服务的配置档照样能启动,对应的视图只是不可用,而不会导致启动失败。
终端文本记录: 输入斜杠会在输入行下方打开命令面板。它以程序自身的单行摘要列出各命令——查看工作流与子代理、浏览并恢复会话、通过 Harness 配置提供方、浏览运行中代理的插件组合——下方带有计数器和补全按键。
02
你的终端仍然是终端
大多数终端应用会接管整个屏幕并自行重建。你的滚动缓冲区不再属于你:文本记录活在程序内部,向上翻阅、用鼠标选中一段调用栈、把这次运行重定向到文件——这些都得由程序自己重新实现,或者干脆没有。
已完成的输出只写一次
一行内容一旦提交,就会写入终端的滚动历史,之后不会被重写、移动或虚拟化。这正是上方的滚动缓冲区之所以是真正的滚动缓冲区的原因:它由你的终端模拟器持有,因此搜索、选中和复制的行为与任何其他命令完全一致。
只有有界区域会重绘
正在到达的回复、输入行、状态行以及任何已打开的视图构成实时区域,它始终位于屏幕最下方。它上方的一切都已定型。一次重绘只触及已知数量的行,而不是整个显示区域——这也是为什么长会话不会越看越卡。
从不使用备用屏幕
dshline 从不把终端切换到备用屏幕(alternate screen),也从不启用鼠标协议。两者都是有意为之:一旦它捕获鼠标,终端自身的文本选择就会失效。关闭一个视图后,你的滚动缓冲区还在原处。
渲染器完全不了解 agent
负责显示宽度、CJK 与 emoji、转义清理、按键解码和安全重绘的部分是一个独立的包,没有任何依赖,也不了解 Harness。它可以在没有终端、没有模型、没有插件上下文的假屏幕上被测试——实际做法正是如此:把真实输出喂给一个无头终端模拟器,然后断言一个人真正会看到的每一行以及每个单元格的颜色。
设计文档:终端不变量03
基于 DeepSeek Harness 构建
DeepSeek Harness 是 DeepSeek 开源的 agent harness(智能体框架),其设计使得每个组成部分——模型适配器、工具注册表、会话日志、乃至 agent loop(智能体循环)本身——都是可以通过配置替换的插件。dshline 就是其中一个插件。它与 agent loop 运行在同一进程中,读取当前 profile 所挂载的能力。
deepseek-ai/deepseek-harnessHarness 负责
生命周期、状态、持久化、提供方选择、权限与策略。对每一项,dshline 只读取最窄的权威表面,并且都不重新实现。
- agent、会话,以及仅追加的事件日志
- 模型与提供方适配器
- 工具及其执行流水线
- 权限、审批与密钥存储
- 委派:subagent、后台任务、工作流
- 会话持久化、搜索与恢复
- token 用量核算与上下文窗口折叠
- agent 组装:插件、preset、profile
dshline 负责
如何把上述每一项变成你能在终端里读懂、驱动并信任的东西——以及让这一切成立所必需的终端正确性。
- 构建界面其余部分所依托的终端呈现表面
- 真实的滚动缓冲区,以及高度已知的实时区域
- 输入框:历史、撤销、反向搜索、排队或中途引导
- 选择器、检查器与浮层,共用同一个框架
- 状态行会整段丢弃,而不是把内容截断
- 显示宽度、CJK 与 emoji、转义清理、按键解码
- 按角色着色、五套配色,且每套都有 16 色形态
- 让 Harness 的能力只需输入一个斜杠即可发现
它通过能力集成,而不是通过提供方集成
dshline 不附带提供方列表,也不附带登录协议。它的连接视图会展示已挂载适配器声明为可配置的一切,并运行 Harness 已注册的任意授权流程,全部基于同一份设置文档和同一个密钥存储——也正是官方 Web UI 所写入的那一份。一个新到达 Harness 的提供方,无需 dshline 发布新版本即可从终端访问。
一次只采纳一个代际
Harness 自述为开发者预览版,会引入破坏兼容性的变更,并且每隔几天就发布一次。dshline 对它的策略是激进跟进、窄口支持:一次只采纳一个代际,用精确版本而非版本范围锁定,过时的假设直接删除,而不是藏在兼容层背后。持续集成会从源码检出那个确切的上游修订版,如果 dshline 无法基于它构建,就阻止合并。
架构文档:能力模型04
五个视图,看见运行中的 agent
这些都是覆盖在输入行之上的浮层,用同一个框架绘制,用同一个按键关闭,且不会改动你的滚动缓冲区。它们每一个都读取 Harness 的能力,而不是各自保存一份答案。
/work观察被委派的工作
subagent、后台任务和工作流运行都在一个视图里。每一行会说明该工作者当前正在做什么、由哪个模型驱动,因此一个悄然卡住的委派看起来会和一个正在思考的委派不同。
读取Harness 的 subagent、任务与工作流服务。dshline 观察的是与提供方无关的生命周期;它自己不运行任何引擎,也不持有运行句柄——取消任务的权限仍留在 Harness 所安排的位置。
一个标题为 Work 的面板列出两个 subagent 和一个任务。第一个 subagent 正在运行,显示它当前正在读取的文件、所用模型和已用时间;第二个已完成。下方有一个排队中的后台任务。下边框提供移动选择、中断和关闭。
/sessions重新进入一个会话
浏览、筛选并全文搜索 Harness 保留的每一个会话,追溯一个会话与它派生的子会话之间的谱系,重命名,并从上次离开处重新打开。先选择器、后检查器:先找到会话,再查看它。
读取Harness 的会话查询服务,它会在活跃会话与已持久化会话之间解析出一次一致的观测。dshline 不会再建一个数据库,也不会自己索引任何内容。
一个标题为 Sessions 的面板显示一个搜索框和最近会话列表。每一行包含标题、所属工作区,以及最后活跃时间。下边框提供移动选择、在会话内容中搜索、筛选、查看选中项的详情、重新打开和关闭。
/connect配置提供方
已挂载适配器声明为可配置的每一条提供方路由,连同每一条在能够应答之前还缺什么,以及 Harness 已注册的登录流程。请求头可以按路由逐条整理。这里没有需要等待更新的提供方列表:Harness 新增的一切都在这里。
读取Harness 的模型、设置、密钥与授权服务。dshline 只询问某个密钥是否已配置、是否可写;它从不持有密钥值,也不附带自己的登录协议。
一个标题为 Connect 的面板显示一个搜索框,随后是提供方路由分组和登录分组。一条路由处于 active,并报告其密钥来源;另一条处于 dormant;第三条虽为 active,但报告其环境变量未设置。登录分组下,有一个流程尚未登录。下边框提供移动选择、刷新、配置选中行和关闭。
/usage看清这次会话花掉了什么
这次会话消耗了什么,以及提供方从自身缓存中提供了多大比例的输入。配套视图 /context 则显示当前占用模型上下文的内容。状态行会呈现同一批数字的一眼读数,并且在终端变窄时整段丢弃,而不是给你半个单词。
读取Harness 自身的会话投影——它为上下文压力、组成结构和 token 用量发布的常数时间折叠值。dshline 从不统计 token,也从不做分词;组成结构的数字被呈现为近似值,因为 Harness 本身就是这样说明它的。
一个标题为 Usage 的面板列出输入 token,并细分为未缓存、缓存读取和缓存写入,随后是输出 token、缓存读取占比,以及累计费用。接着是性能分组,包含轮次与步骤计数、首个 token 的平均时间、平均输出速率,以及在模型和工具上分别花费的时间。
/plugins看清 agent 由什么组成
Harness 的构建方式使其每个组成部分都是插件——包括工具注册表和 agent loop。这个视图可以浏览并搜索运行中 agent 所使用的组装,在多个 preset 之间切换,并显示哪些行处于开启状态。另一个配套视图对本机上的 profile 做同样的事。
读取Harness 的 agent preset 注册表,以及它自身的 home 路径服务(用于 profile 名册)。每一次变更都会转交给 Harness 的插件命令,而不是由 dshline 直接写入 profile 清单。
一个标题为 Plugins 的面板显示当前使用的 preset 和默认 preset,随后是搜索框和匹配的组装行。每一行给出插件名称及其所属包,并以标记显示是否开启。下边框提供导航、搜索、切换某一行、切换 preset、设为默认和关闭。
05
安装
两个包:DeepSeek Harness,以及这个界面。然后在任何你想工作的目录里运行它。
npm install -g @deepseek-ai/dsh @dshline/dshline # harness,以及这个界面
dshline # 在任何目录、任何机器上首次运行会做什么
它只会询问一次——也仅此一次——是否允许 Harness 为 dshline 创建一个 profile 并把这个包安装进去,然后继续执行你原本输入的内容。没有终端可供询问时它不会运行;它从不修复已存在的 profile;如果你自己指定了 profile,它什么都不做。全新安装且尚未配置模型时,它会打开设置视图,而不是一个无法发送的输入行。
其他安装方式
免询问安装
用于脚本、重试和源码检出。
dshline --setup自行安装到某个 profile
同样的事,直接通过 Harness 完成。
dsh plugin --profile dshline add @dshline/dshline
dsh --profile dshline从源码安装
仓库是一个包含两个包的工作区,因此不支持通过 git URL 安装。
git clone https://github.com/riesbri/dshline && cd dshline
pnpm install && pnpm build
dsh plugin --profile dshline add ./packages/dshline验证是否成功
出现横幅、输入行和 ready 状态行,就说明完成了。
dshline --version # 提交问题时需要的版本号
dshline --dump-config # 查找 “# == dshline” 段落