SajoLuo
dsh-trellis
Trellis workflow integration for DeepSeek Harness
- Stars
- 0
- Language
- JavaScript
- Created
- Aug 13, 2026
- Updated
- Aug 14, 2026
Introduction
dsh-trellis
DeepSeek Harness (dsh) host 插件:把 Trellis 工作流带进 dsh,并尽量沿用 DSH 原生能力补齐 Codex / Claude Code 级体验:
- 每轮 workflow-state 面包屑注入 — 在每个
agent/pre-step,解析项目.trellis/workflow.md的[workflow-state:*]块 + 活跃任务状态(no_task / planning / in_progress),把对应面包屑注入会话(与dsh-agent-instructions的注入管道相同)。未变化不重复注入;被压缩后自动重注入;提示词里出现独立单词no-trellis可跳过当轮。 - 隔离的原生会话上下文身份 — 从当前 agent 的 DSH 原生 session header 生成受管的
DSH_TRELLIS_CONTEXT_ID,让task.py start/create/current解析到会话级 active-task 指针,并在子代理身份不同于 shell 自身 session 时优先使用被转发的身份;插件命令启动的子进程也显式使用同一个 DSH 身份。 - 原生子代理同步 — 安装插件后,Trellis 角色可用 DSH continuable 后台子代理;主会话先继续独立工作,耗尽后调用事件驱动的
trellis_wait。它监听 DSH 的subagent/end,只在原生 settlement notice 已排入父会话后返回,不用 shell sleep、轮询或job_output。 /trellis命令 —/trellis-status(活跃任务 + git 状态)、/trellis-finish(只读检查 + 安全收尾清单,不提前清 active-task 指针)。命令输出不进模型历史;真正的会话收尾走技能面/trellis-finish-work,由技能先归档再写 journal。
非 Trellis 项目不注入面包屑;命令只有被用户显式调用时才会检查并返回“未初始化 Trellis”。
这是 Trellis DSH 适配的可选伴侣插件,不是使用 trellis init --dsh 的前置条件。workflow 会按能力选择路径:存在 trellis_wait 时才使用 continuable 后台派发和事件汇合;未安装插件时,依赖结果的子代理从一开始就用 run_in_background: false 前台派发。两条路径都禁止 sleep 或轮询,Trellis CLI 也不会自动安装任何 DSH profile 插件。
安装
# 装进实际使用的 profile(均在该 profile 下次启动时生效)
dsh plugin --profile web add dsh-trellis
dsh plugin --profile headless add dsh-trellis
# 如果你维护独立的 tui profile,也需要装进该 profile
dsh plugin --profile tui add dsh-trellis
dsh plugin 会把插件安装到指定 profile;每个实际使用的 profile 都需要单独安装。升级到 npm 上的最新版本:
dsh plugin --profile web update dsh-trellis
dsh plugin --profile headless update dsh-trellis
对 tui profile 使用同样的 update,并在该 profile 下次启动时生效。
如果要从源码开发或验证尚未发布的版本,可以改用本地 file: 安装:
git clone https://github.com/SajoLuo/dsh-trellis.git
cd dsh-trellis
pnpm install --frozen-lockfile
dsh plugin --profile headless add file:C:/path/to/dsh-trellis
file: 插件会作为 profile 内的 pnpm 快照安装;拉取源码更新后,尤其是版本新增文件时,需要先 remove 再 add 刷新该 profile。
配套要求:项目的 Trellis 平台需包含 dsh(trellis init --dsh,见 Trellis-DeepSeekHarness 适配分支),且 .trellis/scripts 需包含读取原生 DSH_SESSION_ID 的适配(已含在同一分支)。插件目标版本为 DSH 0.1.0-rc.6;升级 DSH 时应重跑本仓测试。
配置
在 profile 的 cordis.patch.yml 里覆盖(整行替换):
- id: dsh-trellis
config:
maxBytes: 4096 # 面包屑注入的字节预算(0 = 关闭注入)
skipKeyword: no-trellis # 提示词中的独立单词可跳过当轮注入(空 = 禁用)
pythonCmd: "" # 空 = 自动选择:Windows 先 py -3 再 python;其他系统先 python3 再 python
commandsEnabled: true
工作原理
- 状态解析(
lib/workflow.js):向上找项目根 → 读.trellis/workflow.md解析状态块 → 先看当前会话指针.trellis/.runtime/sessions/dsh_<id>.json。当前指针缺失时只允许 Trellis 官方的“唯一 session 文件”回退;存在 0 个或 2 个以上 session 文件就拒绝猜测,避免多个 DSH 窗口串任务。 - 注入去重:面包屑带 digest,与最近一次注入相同且仍在可见表面则不重复注入。
- 会话身份:DSH 原生提供
DSH_SESSION_ID = agent.session.header.id,并先丢弃环境中已有的DSH_*再重建受管命名空间。Trellis beta 因此会在同时看到DSH_SHELL=1与DSH_SESSION_ID时优先解析当前 DSH 身份,即使没有插件也不会被外层 host 继承的TRELLIS_CONTEXT_ID串任务。插件通过shellEnv为每次执行额外生成DSH_TRELLIS_CONTEXT_ID = dsh_<session-id>,用于转发可能不同于 shell 自身 session 的子代理身份;主会话与子代理仍各自保留 DSH 身份,子代理通过派发 prompt 首行的Active task:和角色 prelude 取得父任务上下文。 - Headless 会话:每次
dsh --profile headless调用都是新的 DSH session。需要跨轮保留 active-task 指针时,应保持同一会话或显式 resume 返回的 session id,不能把多个独立 headless 调用当成同一 session。 - 取消与生命周期:命令和
trellis_wait都继承 DSH invocation 的AbortSignal;取消后命令不会继续尝试另一个 Python 启动器,等待工具也会立即注销临时事件监听器。插件卸载时只注销自己的命令、工具和监听器。 - 子代理并发:workflow 只有在发现
trellis_wait时才使用 DSH 原生 continuable 后台subagent。主会话并行做独立工作;需要汇合时调用一次trellis_wait <subagent_id>等待原生结算事件。没有该工具时,首次派发直接设置run_in_background: false,绝不留下无法事件汇合的后台子代理。
开发
pnpm install
pnpm test # node --test test/*.test.js
无构建步骤:纯 ESM JavaScript,main 直接指向 lib/index.js。
License
MIT