dshcode/packages/bundle/headless

90Stars8Forks0Issues1Watchers

为 dsh 增加一次性任务 profile:传入一段任务文本运行 Agent 后打印最终答复并退出,适合脚本与 CI 调用。

Language
TypeScript
License
MIT
Branch
master
agentdeepseekdeepseekharness-plugindsh-pluginharness

Install

$ dsh plugin --profile web add github:whitelonng/dshcode/packages/bundle/headless

Run the command above in your terminal to install this plugin via the dsh CLI. You can switch Profile in the top-right corner. New to dsh? Read the beginner tutorial

入口包名:@deepseek-ai/dsh-headless,落地页 ID:whitelonng/dshcode/packages/bundle/headless。下文统称"headless 组合包"。

一句话定位

它在 dsh 基础组合包之上加一层"一次性任务"驱动,让用户用 dsh --profile headless "<任务文本>" 把一段任务丢给 Agent,Agent 完成(或异常)后打印最终答复并直接退出;它不启动 Host、HTTP server、Web runtime 或浏览器,因此是 CI 与脚本里调用 dsh 的最薄形态。

核心能力

  • 直接叠在 dsh-base 之上,提供编码 persona 与工具模式(cordis.patch.yml:7-20
  • 禁用 HMR,把 Code Mode 的 worker 作为核心执行能力挂上(cordis.patch.yml:14-20:23-26
  • 一个进程只接一个任务:通过 commander 解析位置参数 task(多词用空格合并),缺失或纯空白时打印 usage 错误并退出 1(src/startup.ts:31-57
  • 创建一个全新的持久化 Agent,把任务作为普通用户消息提交,等 Agent 回到 idle 后 flush 会话(src/index.ts:96-127
  • 抽取本次任务区间内最后一条非空 assistant 文本写入 stdout,最终 turn/end 原因是 completed 时退出 0,其他情况退出 1;错误原因时把 code: message 追加到 stderr(src/index.ts:60-134

技术实现

  • 语言: TypeScript(ESM 模块)
  • 关键依赖: @deepseek-ai/dsh-cmdline(命令行宿主)、@deepseek-ai/dsh-code-runtime-worker-thread(Code Mode worker)、@deepseek-ai/schemastery(Config schema)、commander(CLI 解析)(package.json:46-51
  • 架构模式: Cordis bundle patch——通过 package.json#dsh.bundle.patch 声明 cordis.patch.yml,在 base 之上插入 system-prompt/hmr/tools 的覆盖行与三条 insert 行(code-runtime / headless-startup / headless-runner);headless-runner 是普通函数插件,headless-startup 提供 headlessStartup 服务供前者的 lazy config 读取任务(cordis.patch.yml:1-35src/startup.ts:19
  • 入口文件: src/index.ts(runner,name = 'headless-runner')、src/startup.ts(CLI provider,name = 'headless-startup')、cordis.patch.yml(bundle 注入)

适用场景

需要把 dsh 当一个命令行工具来用——比如 CI 里让 Agent 跑一次代码审查、shell 脚本里临时问个文件写法、cron 里把日报生成挂在 dsh 上,而不是开 Web UI 交互。它适合"一次任务-一次答复-进程结束"的场景,不适合需要多轮追问的会话。

前置依赖与兼容性

依赖最低版本说明
DSH未单独声明;与 dsh 1.0.5 同源发布安装到已用 dsh 启动器的 profile 才能激活,runner 强制依赖 launcher 提供的 ctx.appExit
Node^22.19.0 || >=24.0.0源自仓库根 package.json:8-10 的 engines 字段
平台macOS / Linux / Windows跨平台,本包自身不带原生模块
原生模块本包不引入原生模块;base 的 sandbox 等行可能引入

本包通过 workspace 依赖 @deepseek-ai/dsh-agent / @deepseek-ai/dsh-llm / @deepseek-ai/dsh-session 等基础包(package.json:52-59),它们随 dsh-base 间接安装。

安装方式

dsh plugin --profile web add github:whitelonng/dshcode/packages/bundle/headless

配置项

本插件不向用户暴露独立配置面;唯一可调的字段是它从启动器读取的"任务文本":

配置类型说明默认值
headless-runner.taskstringrunner 这一次要执行的提示词文本,从启动器 --profile headless "..." 的位置参数自动填入;空白任务在启动期会被拒由命令行 dsh --profile headless "<task>" 提供
system-prompt.personastring模板字符串,注入 {{model}}{{cwd}} 后给到 system prompt。普通用户无须改,会被自己 profile 覆盖"You are a coding agent powered by the {{model}} model. Your working directory is {{cwd}}."
hmr.disabledbooleanheadless profile 强制关闭 HMR(cordis.patch.yml:14-15true
tools.mode(env DSH_TOOLS_MODEstringCode Mode 进程级开关,与 Web profile 同源取自 process.env.DSH_TOOLS_MODE

常见问题

Q: 这个组合包和 dsh-base 有什么区别?

A: base 把基础工具、模型、持久化等 60+ 能力按"出厂默认集合"全部注入;headless 只在 base 之上叠一层极简驱动层——不挂 Host、HTTP server、Web runtime 或浏览器插件,每一个进程只接一个任务、跑完后打印最终 assistant 文本再退出 0/1。

Q: 进程退出码代表什么?

A: 最终 turn 的原因是 completed 时退出 0;abortederror 时退出 1。错误情况下,stderr 会额外输出一行 dsh: <code>: <message>,成功时 stderr 为空(见 src/index.ts:130-133)。

Q: 不带任务文本直接跑会怎样?

A: 启动器先打印 usage 错误 a task is required, for example: dsh --profile headless "run the tests" 并以 exit 1 结束,runner 在收到服务之前就被拒,不会启动 Agent(见 src/startup.ts:53-55tests/startup.spec.ts:91-97)。

Q: 可以在 dsh launcher 之外使用这个 profile 吗?

A: 不可以。runner 必须在挂载前从宿主拿到退出请求服务;launcher 之外启动会在激活时直接抛 headless-runner: the launcher must provide ctx.appExit before the tree mounts(见 src/index.ts:144-147tests/headless.spec.ts:243-246)。

Q: 一个进程里能跑多个任务吗?

A: 不能。每次 dsh --profile headless 调用只提交一个任务并等待返回到 idle,要再跑只能重新启动一个进程。profile 名义上是一个交互后端,实际上是单发任务运行器(见 README.md:19)。

Q: 默认的 HMR 和 Code Mode 状态是什么?

A: HMR 在 headless profile 下被显式禁用,Code Mode 由 DSH_TOOLS_MODE 环境变量控制——值决定是否启用 worker 线程代码执行,与 Web profile 同源(见 cordis.patch.yml:14-20)。

Q: 会话数据存在哪里?

A: 由 dsh-base 那一层的 session-persistence-jsonl 负责,落到 $DSH_HOME/sessions;headless 自身不另起存储面。

Q: Agent 用什么模型?

A: 跟随 dsh-base 的 agent-default-model 默认值(deepseek-official / deepseek-v4-flash)。要换模型在自己 profile 的 cordis.patch.yml 里按 id 整行覆盖这一行即可。

上手难度

入门 — 命令本身就是一个位置参数;只跑一次的话连配置都不用看,想自定义默认模型或 persona 时在自己 profile 的 patch 文件里覆盖即可。

已知问题与限制

  • 一个进程一个任务:runner 没有交互后续输入,提交完任务后它等到 Agent 返回 idle,并把区间内最后一条非空 assistant 文本打印出来(README.md:19
  • ctx.appExit 由启动器持有:在 dsh 启动器之外启动 headless profile 会在激活时直接抛错,直到宿主提供该退出请求(README.md:20src/index.ts:144-147
  • 空白任务在启动期被拒:纯空白或缺失的 task 不会启动 Agent,进程以 1 退出(src/startup.ts:53tests/startup.spec.ts:91-97
  • headless profile 中的 HMR 不启用:单发进程不需要热更新,patch 显式 disabled: truecordis.patch.yml:14-15