dsh-tree-task-flow · 树形任务流
给 DeepSeek Harness 的树形任务流:把一件需要多步做完的事组织成
目标 → 任务 → 子任务三级树,每个节点完成时由模型提交结果,插件随即把这个节点的
执行过程从上下文里折叠掉,只留下那条结果。
安装即启用:dsh plugin add 之后就生效,不需要再改任何配置。
不想用的时候,在 profile 里写一句 enabled: false 就能关掉,关掉后一个字节都不碰会话。
它解决什么
长任务跑到后半程,上下文里绝大多数内容是过程:读过哪些文件、试过哪些错、
执行过哪些命令。这些内容对后面没有用,但会一直占着位置——每多一轮,
喂给模型的上下文就更长一分,而其中真正需要留住的只有寥寥几句。
真正需要留给后面的只有一句话:这一步做完了,它产出了什么。
所以这里的分工是:
| 内容 | 去向 |
|---|
| 过程 | 读文件、试错、命令输出 | 节点完成时整段折叠掉 |
| 结果 | 模型在 tree_task_done 里提交的 result | 留下来,供后续节点引用 |
折叠按什么切
规则只有一条,只看表层,与计划树无关:
从「上一次 tree_task_done 之后的第一条 tree_task_create 调用」之后
→ 到本次 tree_task_done 之前,这一段收走
起点是上一次 tree_task_done 之后的第一条 tree_task_create;
会话里还没有过 tree_task_done 时,就是表层第一条 tree_task_create;
区间里一次 tree_task_create 都没有时,回退到上一次 tree_task_done 之后。
tree_task_plan 不是边界——它的调用与返回跟普通过程一样,随这一段一起收走。
起点那次 create 的调用与返回留在上下文里,本次 tree_task_done 的调用与返回
同样留着(模型靠它们看"计划是什么、下一步干什么")。
折叠只收它们之间的过程,换成一条计数通告:
[tree_task_create 调用] [返回:计划已建立 + 这个目标的树]
[tree_task消息:隐藏了 12 条过程上下文。读取:… 写入:…]
[tree_task_done 调用] [返回:接下来需要进行步骤:「二」(s-4)。]
tree_task_create 与 tree_task_plan 不能合并成一个工具。
起点取的是"上一次 done 之后最早的开工那一次",而 plan 每补一次步骤就调一次;
并成一个工具之后,每次补步骤都会把起点往后推,done 与它之间那段过程就永远收不走。
靠"实参里有没有 parentId"去区分,也只是把认错起点的机会交给模型。
代价是两个工具的实参形状有点像,所以 plan 的说明里专门写了一句"建新目标不归它管"。
两条硬约束:
- 折叠区间里夹着你的消息就不折——往前折丢了需求,往后折丢了回应,
这一段整段跳过,一个节点都不动;
- 区间为空(起点那次调用与
done 紧挨着,中间没有过程)也什么都不注入,
不追加、不留空消息。
每一次 tree_task_done 的调用与它的返回都留在上下文里,一轮轮累积;
模型下一轮还看得到"我刚做完了什么、接下来干什么"。
折叠发生在 agent/pre-step——上一轮已结束、下一个请求还没构造的那一刻。
工具执行中途不能折叠,那时 surface 还在增长,替换会把自己卷进去。
注入消息与 tree_task_done 的返回
一次折叠在上下文里留下两样东西:
一、折叠通告——哪一段被收走了
tree_task消息:隐藏了12条过程上下文。
读取:C:\apps\x\a.js、C:\apps\x\b.js
写入:C:\apps\x\c.js
只报条数与读写了哪些文件:过程收走了,但"这活碰过哪些文件"得留下,
否则模型要从头再找一遍。路径取自工具调用的 file_path / path 参数——
界面列出文件变更用的是同一个来源;pwsh / bash 里碰过什么文件看不出来,不计入。
二、tree_task_done 的返回——下一步干什么
tree_task消息:接下来需要进行步骤:「步骤二」(s-4)。
按情形是三种之一:
| 情形 | 返回的是 |
|---|
| 同层还有下一个 | tree_task消息:接下来需要进行步骤/任务:「标题」(id)。 |
| 同层到头、上一层还没交 | tree_task消息:检查点:任务/目标<id> 的步骤/任务已全部结束,请确认<id> 是否完成,如果完成请调用tree_task_done,如果还需继续,可使用 tree_task_plan 新增步骤/任务继续。 |
| 整棵树都完了 | tree_task消息:请汇报最终结果。 |
两样都不重复提交内容(result 就在这次调用的参数里)。折叠时,这次
tree_task_done 的调用连同它的返回原样留在上下文里,被收走的只是它前面那段过程
——那一段里若夹着 tree_task_plan 调用,它也跟着一起收走。
子任务全部结束,不会让父节点自动完成。 那一刻树进入检查点,
也就是上表第二种返回。
检查点只是提示,不是闸门。 它出现在树上,也出现在 tree_task_done 的返回里,
但插件不会拦住任何工具——"这一层到底做完了没有"由模型判断,插件既不替它定死,
也不靠拒绝别的工具把它逼到墙角。
七个工具
写树分两个工具,不是可以合并的重复。 tree_task_create 与 tree_task_done 是折叠的
两个边界:create 是"开工"那一下,done 是"收工"那一下。create 只在新建目标时调一次,
plan 却在任务中途反复调用——并成一个工具,折叠起点就只能靠实参去猜了(见上一节)。
| 工具 | 用途 |
|---|
tree_task_status | 查看计划树:默认只展开还没结束的目标,已完成的目标只留目标那一行;填 id 就返回那个目标(或该节点所在目标)的完整树 |
tree_task_create | 新建一个目标:这个目标 + 它下面的若干任务。可多次调用,多个目标并存,不替换已有计划。它也是折叠的起点标记 |
tree_task_plan | 给一个节点追加子节点:父节点是目标加的是任务,父节点是任务加的是子任务。建新目标不归它管 |
tree_task_done | 完成一个节点并提交它的结果,result 必填;返回的就是"下一步干什么",这次调用连同返回留在上下文里,被收走的只是它前面的执行过程 |
tree_task_update | 修改一个节点的标题或说明 |
tree_task_drop | 丢弃一个节点:留个记号说「这件事不做了」,节点留在树里可查(划掉)。丢弃目标会连同它下面的任务与子任务一起走,丢弃任务带上它的子任务 |
tree_task_delete | 删除一个节点:把它连同下面的任务或子任务从树里摘掉、不留痕,不看状态(已完成、已丢弃的都删得掉)。清理写错 / 建重 / 结果记错的内容用它 |
丢与删是两件事:丢弃回答"这件事还要不要做"(历史留着),删除是"这条内容本身就是错的"
(凭空摘掉)。一个节点做完之后再想让它消失,只能用删除。
层级固定三级,子任务是最低一级,不能再往下拆。
返回的三条规矩:
- 写树类工具只返回本次动到的那个目标的树,不再每次倾倒整棵树;
- 树用规范的 Markdown 嵌套任务清单渲染(
- [ ] 开头、每层两个空格缩进),
复制出去能正常预览,不会被当成代码块;
- 结果全文给出,一个字都不截。
- [x] **目标** `g-mv50h48v1` 安卓端播放
- **结果**:手机连上 PC 并把声音收下来了。
验收:模拟器上跑通一次端到端。
- [x] **任务** `t-mv50h48v2` 工程骨架
- **结果**:交付物 android\settings.gradle;`cd android; powershell -File tools\build.ps1` 冷构建成功。
- [ ] **子任务** `s-mv50h48v5` 写 build.gradle ← 当前
- [ ] **目标** `g-mv50h48v6` 安卓端来源 ← 当前
- [ ] **任务** `t-mv50h48v7` 采集层
三层怎么分
| 层 | 是什么 | 怎么算分对了 |
|---|
| L1 目标 | 最终要交付的东西 | 一个会话可以有多个,按创建顺序排;每个都写清要交付什么 |
| L2 任务 | 交付节点 | 一件能独立验收的交付内容——一个文件、一条能跑的命令、一份结论,也可以是件需要完成或验证的事、一个检查点;下面覆盖多个步骤,别拆到只剩一两个 |
| L3 子任务 | 步骤 | 任务内部一两次工具调用能做完的事 |
折叠次数跟着 tree_task_done 的次数走:每完成一个节点就折一次,界面也会因此多一张
系统提示词卡片。所以任务别拆得太碎——够厚,done 的次数少,上下文前缀变动的次数也少。
result 分两层写:任务的 result 写交付物 + 怎么验收(文件在哪、怎么跑、验出什么、
已知限制),子任务的 result 一句话说清这步做了什么就够。
安装
需要 Node.js 22.19 以上,以及能运行 dsh。
从 npm 安装:
dsh plugin --profile web add dsh-tree-task-flow
从源码目录安装(装成 link:,改完源码重启即生效)。把仓库克隆到任意目录,
然后指向那个目录:
dsh plugin --profile web add <插件目录>
dsh plugin add 会把包加进 profile 的 dsh.profile.bundles,而本包自带的
cordis.patch.yml(由 package.json 的 dsh.bundle.patch 指定)会顺势把
task-tree 这一行插进插件列表——装上即启用,不需要再改任何配置。装完可以核对:
dsh --profile web --dump-config # 输出里应出现 task-tree 这一行,且不带 config
必须重启 dsh web 才生效——运行中的会话不追溯,新工具要在新会话里才会出现。
关闭
不想要了,除了 dsh plugin remove 卸掉,也可以只把它关掉。在
$DSH_HOME/profiles/<名字>/cordis.patch.yml 里写:
- id: task-tree
config:
enabled: false
然后重启 dsh web。仓库里的 config.example.yml 有可以直接抄的完整版本。
⚠️ profile 这一层按行覆盖时 config 是整体替换,不是逐字段深合并——
覆盖时要把想保留的字段一起写全,没写的会走插件默认值(见下面的配置表)。
关掉之后插件一个字节都不碰会话:不注册工具、不加提示词段落、不折叠、不续行、
不挂暂停闸门。只留一条 /task-tree 命令,让你确认它是被关掉的以及怎么打开。
界面
输入框上方的「树形任务流」条目(和内置的待办、目标条目并排,宽度与消息正文对齐)。
外观照内置条目做——用的是同一套 UI 基座(@deepseek-ai/dsh-client-ui-primitives
的图标、Tooltip 与 CSS 变量),所以它看起来就是内置的一部分:
- 折叠时是目标条那样的 36px 单行条:左边清单图标,中间「阶段标签 + 目标标题 + 进度」,
右边一排圆形图标按钮——暂停/继续、清空计划、展开。
阶段标签四种:进行中 / 已暂停 / 检查点 / 已全部完成。
- 展开后是待办清单那样的卡片:三级树之间有竖线与拐角连线,层级一眼看得出来;
同一层的节点之间、节点内部的各个内容块之间,各有一条分界线。
默认只摊开正在走的那条路径——目标一路展开到当前子任务,其余节点收起,
一打开就能看见正在跑的那一个,不用在一堆已经收尾的节点里翻;检查点所在的节点
也一样默认摊开。想细看哪个就点它行尾的箭头,逐层摊开或收起。
当前节点的虚线圈会匀速转,已完成打勾、丢弃的划掉。
- 节点标题不缩略:有多长写多长,多了自动换行。
- 提交的结果默认只占一行,点一下摊开看全文。
- 节点上可以直接完成、丢弃(划掉,历史留着)、删除(垃圾桶,连子节点一起摘掉),
不用敲命令。删除对任何状态的节点都开着——已完成的那个也在,清理错内容正是它的用途。
- 进度只数还在做的事:被丢弃的节点分子分母都不算,所以丢过几个之后进度照样能满。
- 数据每 4 秒自动拉一次,模型在后台改计划时界面会自己跟上。
没有计划的会话一个像素都不占——读不到计划就返回 null,不会平白挤掉内置的
待办与目标条目。
开关不在界面上,在 profile 的 cordis.patch.yml 里(见上面的「关闭」一节)。
命令
/task-tree 不经过模型,直接执行:
| 命令 | 作用 |
|---|
/task-tree | 查看本会话的任务树与检查点状态 |
/task-tree done <id> <结果> | 提交某个节点的结果并完成它 |
/task-tree drop <id> | 丢弃某个节点:留着可查,标记为不做了 |
/task-tree delete <id> | 删除某个节点:连子节点一起从树里摘掉,不看状态 |
/task-tree pause | 暂停:正在跑的工具跑完就停住,不再往下推进 |
/task-tree resume | 继续:从停住的地方接着跑,不往会话里插消息 |
/task-tree reset | 清掉本会话的计划树 |
配置
默认值全在 lib/index.js 的 DEFAULT_CONFIG 里:
| 字段 | 默认 | 说明 |
|---|
enabled | true | 总开关;装上即启用,写 false 关掉 |
autoContinue | false | 模型停下时是否自动续行(见下节;在 DSH 设置面板里能改) |
maxAutoRounds | 5 | 连续自动续行的轮次上限 |
interruptRecovery | true | 意外中断后是否自动拉起(见下节;在 DSH 设置面板里能改) |
interruptDelaysMs | null | 网络类中断的拉起时刻,null = 1/5/10/30 分钟 |
promptOrder | 1800 | 工具说明段落的排序 |
rootDir | null | 状态目录,默认 $DSH_HOME/dsh-task-tree |
设置
设置在 DSH 自己的设置面板里:打开侧边栏的设置,导航里有一页叫「树形任务流」
(跟「通用」「市场」并排),点开就是这两个开关。改完立刻生效,不用重启。
它不在任务条上。任务条只干两件事:看进度、按暂停 / 继续;偏好属于设置,就该待在设置里。
| 设置 | 默认 | 做什么 |
|---|
| 自动续行 | 关 | 模型自己停下、计划树还没跑完时,要不要推一条"接下来做 X"把它唤醒 |
| 工具出错自动拉起 | 开 | 这一轮不是正常结束(网络断了 / 模型输出坏了 / 工具结果没了)时,要不要自动重来 |
两项是两件事,别混:前者是"要不要往前推",后者是"要不要救"。默认这么定是因为
自动续行会在你没看着的时候自己往下跑,该由人来点;而中断拉起只在"这一轮根本不是正常
结束"时动手,正常停下它一步都不动。
设置写在状态目录的 settings.json 里(不按会话分,整个插件一份),重启后还在。
优先级是 设置面板里改过的 > profile 里的 config > DEFAULT_CONFIG:在面板里点过就以
面板为准,免得界面对不上 YAML。enabled、maxAutoRounds、interruptDelaysMs 这类
"装插件时就该定好"的项不在面板上,仍然只认 profile 配置。
意外中断自动拉起
上一节 autoContinue 管的是"模型自己正常停下"。这一节管的是这一轮没能正常
结束:网络断了、模型 API 报错、或者工具执行到一半进程没了。这两种停法插件原先不管,
会话就一直躺在那里。
判据全部取自 DSH 自己写下的数据,不看文本:
| 中断 | 怎么认 | 什么时候拉起 |
|---|
| 网络 / API | turn/end 的原因是 error,错误码是 TRANSPORT、TIMEOUT、SERVER、RATE_LIMIT、EMPTY_RESPONSE | 中断后 1 分钟、5 分钟、10 分钟、30 分钟各一次 |
| 模型输出损坏 | turn/end 的原因是 error,错误码是 MALFORMED_RESPONSE(模型给出的工具入参不是合法 JSON) | 立即一次 |
| 工具执行 | 这一轮出现过 TOOL_OUTCOME_UNKNOWN / TOOL_NOT_STARTED 的合成工具结果(意思是"这次调用没留下结果") | 立即一次 |
后两类虽然都"立即一次",处置并不一样——差别在于有没有东西要勘察、有没有东西可收:
- 工具执行类:那次调用确实发生过,只是结果没落盘。拉起消息会明确说"它到底做没做
没人知道,先确认那一步的实际影响再决定要不要重做";第二次仍然失败时,把那条拉起消息、
发起该调用的助手消息、以及它的合成错误结果一起收走(和折叠同一套机制,界面上仍可
展开),再拉一次。
- 模型输出损坏类:DSH 是在解析响应流时就判了死刑——整条响应被作废,一个工具都没
执行,连
tool/call 都没落盘,没有任何副作用要勘察。拉起消息只说"原样重做那一步,
把引号括号写全,必要时一次只调一个工具";第二次仍然失败时什么都不收(没东西可收),
直接再拉一次。
两类都是第三次同类中断就停手,链上记 exhausted。
几条边界:
- 余额不足(
QUOTA)不拉。 等再久也不会自己好。
- 你按下的停止,永远不拉。 和自动续行的第 1 条闸门一致。
- 普通工具报错不拉。 比如"文件没找到""edit 没匹配上""网址被拦"——这些模型看到就能
自己改道,本来也没中断这一轮。
- 只在这个会话的计划树还没走完时才动手。等待时刻写在状态目录的
revive/ 下,
重启 dsh web 不会丢。
- 能在设置面板里关掉。 DSH 设置里的「树形任务流」那一页中,"工具出错自动拉起"就是
这个开关,改完立刻生效(关掉之后插件连
revive/ 都不再写)。
暂停与继续
界面上的暂停按钮(或 /task-tree pause)是真暂停,不是"关掉自动续行":
- 正在执行的那个工具会正常跑完,不会被中途掐断;
- 它跑完之后,会话就静静停在原地——不再发起模型请求,也不再往下走一步;
- 全程不往会话里插任何消息,上下文干干净净。
继续(界面按钮或 /task-tree resume)就是从这个岔口放行:模型从它原本要请求的地方
接着请求,同样零新增消息。任务树的进度停在哪儿,就从哪儿接着跑。
重启 dsh web 之后暂停依然有效。 "被按住"这件事写在状态目录的 held/ 下,
重启后条目仍显示「已暂停」,点「继续」即可接着跑。
点「继续」是无条件的。 不管此刻闸门有没有挂在岔口上、会话是不是正忙,点一下,
"被按住"就当场解除——它是一句"接着跑",不是一次"此刻有没有闸门"的查询。区别只在
插件接下来能做什么:
- 闸门正挂在岔口上 → 直接放行那一步,零新增消息;
- 没有岔口可放(进程重启过,或者你点的时候那个工具还在跑)→ 退一步给会话排一条
「恢复续行」的消息把它从
idle 推起来;会话正忙的话连推都不用推,它自己会在下一个
岔口接着跑;
- 那个会话还没被 DSH 加载成实时 agent → 提示你先打开它或在其中发一条消息,
但"被按住"照样解除。
早先不是这样:"继续"只在闸门恰好挂着的那一瞬间才算数;没有闸门可放时又要求会话
正好停在 idle,忙就直接拒绝、并且什么都不清。于是"工具还在跑的时候点的那一下"
被静默吞掉,等闸门真挂上时已经没人在等它——会话就停在原地了。真回归见
verify-pause.mjs 的场景 s-31。
闸门开在 agent 的 agent/pre-step 上——一个 step 走完、工具结果都已落盘、模型还没
发起下一次请求的那一刻。这是唯一同时满足"不打断工具"和"不留痕迹"的位置:再晚一点
的 agent/turn-stopping 一旦放行,就得靠 steer() 推一条消息才能续上,那就留下痕迹了。
闸门只拦自动推进,不拦真人发言。 暂停期间你自己发一条消息,说明你要它跑,
插件会直接放行并解除暂停,不会把你堵在门外。
暂停期间人按界面上的停止(中断本轮)也不会卡住:闸门盯着本轮的取消信号,
信号一 abort 就立刻放行。
自动续行
模型自己停下、计划树却没跑完,插件就推一条"接下来要做 X"把它唤醒。 这只是兜底:
tree_task_done 的返回文本里已经带了"请继续执行下一个子任务",模型通常会在同一轮里接着做。
autoContinue 默认关闭——它会自己往下跑,所以默认由人来点。要开就在 DSH 设置面板的
「树形任务流」那一页里打开(改完立刻生效,不用重启),或者在 profile 里写 autoContinue: true。
开着也不会脱缰,有四道闸门:
- 中断即停——你按下停止,落盘的
turn/end 会记成 reason.kind = "aborted",
插件从那里认,把这个会话标记为不再自动续行(落盘在 held/ 下,跨重启有效),
直到真人再发一条消息。
这里不能用 agent/turn-stopping 的 signal.aborted 当判据。 那个事件只在
"这一轮本来就要正常收尾"时才发(dsh-agent-loop 里唯一一处 dispatch 前面刚做过
throwIfAborted());你按停止会让信号 abort、从别处抛出,catch 里直接记下
turn/end 就重新抛出,那条 dispatch 走不到——signal.aborted 在那里几乎永远是
false,拿它当闸门等于没闸门。
- 轮次上限——连续续行达到
maxAutoRounds(默认 5)就停;只有真人发的消息才重置配额。
- 不抢排队输入——队列里还有你排着的话时,让用户先说。
- 暂停压住它——
/task-tree pause 之后,即使模型自己停了下来,兜底也不会把它拉起来;
/task-tree resume 再放开。
agent/status 只在状态变化时发。 重启 dsh web 之后,一个本来就停在 idle 上的
会话不会产生这个事件(新建的 agent 一开始就是 idle),所以它不会被自动唤醒——
要它动,你得在那个会话里先说一句话。从下一次模型自己停下开始,续行就接手了。
状态文件
全部在 $DSH_HOME/dsh-task-tree/ 下。除 settings.json 外都以 sessionId 为键:
| 文件 | 内容 |
|---|
plans/<sessionId>.json | 计划树(每个会话一棵) |
surfaces/<sessionId>.json | 三层的进度游标 { key, cursor }(只给界面看,不参与折叠) |
held/<sessionId>.json | 暂停 / 停止状态(跨重启保留) |
revive/<sessionId>.json | 意外中断的拉起时刻表(跨重启保留) |
settings.json | 设置面板里改过的设置(整个插件一份,不按会话分) |
目录名沿用插件改名前的标识,为的是不让既有的计划文件失联;插件名与它无关。
计划属于建立它的那个会话。放到会话无关的位置,任何一个会话的计划都会被
所有会话读到——那等于把不相干的节点指派塞进别人的上下文。
写入一律走「临时文件 + rename」,进程崩在写入中途也不会留下半截 JSON。
插件绝不直接写会话日志,会话里的一切都走 session.append()。
你会观察到的行为
-
完成必须写 result。 节点的执行过程会被折叠掉,result 是它唯一的出口;
空 result 会被拒绝。所以要写清"产出了什么",写成能独立看懂的样子——
过程会丢,别把过程写进去。
-
折叠只看表层。 起点是上一次 done 之后的第一条 tree_task_create;
tree_task_plan 不是边界,它的调用与返回跟过程一样会被收走;区间里没有过程时
什么都不注入,夹着你的消息时整段不折——那一段原样留着(往前折丢需求、
往后折丢回应),代价是上下文不收缩。
-
模型看到的工具说明不随计划变化,也不复述工具清单。 那一段只讲什么时候用
这组工具、完成时守什么规矩;每个工具的用法由它自己的 description 承担。
要了解计划就让模型调 tree_task_status。
-
折叠几次,界面就多几张「系统提示词」卡片,但上下文里的系统提示词始终只有一条。
DSH 把"上下文被替换过"记成一次请求序列的边界(下一次请求带 reason=series),
界面在 reason 不是 change 的请求上都会画一张系统提示词卡片;锚点跟着那一轮 step 走,
卡片于是一张张堆起来。上下文里 system/message 自始至终只有一条,折叠没有伪造
任何系统消息。已实测:3 次折叠 → 3 次 series → 界面 3 张卡片。
-
改需求用「丢弃 + 追加」,不要重建整棵树。 丢掉的节点留在树里可查,
它和完成的节点会一起被那一段折叠收走(通告只报条数,不区分完成还是丢弃)。
内容写错了才用删除——删除是摘掉,摘掉的东西查不回来,也没有任何通告替它留痕。
-
暂停不留痕迹。 暂停后模型看到的是"没有下一条请求",看不到任何"你被暂停了"
之类的提示;继续之后也不会有"继续"消息进上下文。想让模型知道中间发生过什么,
得自己发消息说。
-
内置压缩之后会有一条提醒。 DSH 自己的压缩把一大段历史收成一条检查点之后,
如果这个会话里有计划树,插件会注入一条
tree_task消息:上下文刚被压缩过,计划树没有被压缩。用 tree_task_status 取回当前进度…。
计划树本身不在压缩范围内——它存在磁盘上;但模型会忘掉它,所以补这一句。
同一个压缩点只提醒一次,之后再被压缩会再提醒一次。
不做的事
| 不做 | 原因 |
|---|
| 资料 / 文件快照 / 记忆 | 上下文里值得留下的只有结果,其余靠模型自己重读 |
| 文件回退 / 撤销 | 改需求用「丢弃 + 追加」;内容本身写错了才用删除摘掉,摘掉就找不回来 |
| 并行推进多个目标 | 结构上支持一个会话有多个目标(目标层就是兄弟列表),但同一时刻只沿一条活动路径走 |
| 把计划内容注入提示词 | 计划状态由 tree_task_status 现取,提示词里只放不随计划变化的说明 |
卸载
dsh plugin --profile web remove dsh-tree-task-flow
状态目录不会自动清理,需要的话手动删 $DSH_HOME/dsh-task-tree。
许可
MIT