<p align="center">
  <img src="https://raw.githubusercontent.com/yindf/taskfold/master/assets/banner.zh.png" width="100%" alt="taskfold —— 给你的编程智能体，近乎无限的上下文" />
</p>

<p align="center"><b>给你的编程智能体，近乎无限的上下文</b></p>

<p align="center">
  <a href="README.md">English</a> ·
  <a href="https://github.com/yindf/taskfold/releases/latest">Releases</a> ·
  <a href="CHANGELOG.md">更新日志</a>
</p>

<p align="center">
  <a href="https://github.com/yindf/taskfold/releases/latest"><img src="https://img.shields.io/github/v/release/yindf/taskfold?style=flat-square&color=4c8dff" alt="最新版本"></a>
  <a href="https://www.npmjs.com/package/dsh-taskfold"><img src="https://img.shields.io/npm/v/dsh-taskfold?style=flat-square&color=cb3837" alt="npm"></a>
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue?style=flat-square" alt="MIT 许可"></a>
  <a href="https://github.com/topics/dsh-plugin"><img src="https://img.shields.io/badge/DeepSeek%20Harness-plugin-4c8dff?style=flat-square" alt="DeepSeek Harness 插件"></a>
</p>

让长时间的 AI 编程会话保持快速、便宜、可读：完成的工作被折叠成一条短摘要，完整原始内容随时一条命令取回。

面向 [DeepSeek Harness](https://www.npmjs.com/package/@deepseek-ai/dsh)（DSH）。

> **当前支持的最新 dsh 版本：`0.2.1-rc.5`。** dsh 的 rc 版本在本分支（master）支持；dsh 的 alpha 版本在 [`alpha` 分支](https://github.com/yindf/taskfold/blob/alpha/README.zh.md#支持的-dsh-版本)支持。

## 快速开始

### 在 dsh Desktop 里安装（推荐）

1. 打开 dsh Desktop，在侧边栏进入 **插件** 页。
2. 点右上角的 **添加插件**。
3. 在 **包名或地址** 一栏填 `dsh-taskfold`——安装框自己调 pnpm，不用你手工装依赖：
   - **想在新版本一发布就装上？钉住它**——`dsh-taskfold@<版本>`（版本号从 [npm 版本列表](https://www.npmjs.com/package/dsh-taskfold?activeTab=versions) 取）。dsh Desktop 自带的 pnpm 11 会让发布不满 24 小时的版本对裸包名不可见，显式写版本即可绕过，pnpm 还会把它记进 profile 的 `minimumReleaseAgeExclude`。**0.37.7 与 0.38.0 千万别装**——它们从注册表装不上（`ERR_PNPM_LINKED_PKG_DIR_NOT_FOUND`），npm 上已标记 deprecated；
   - **完全绕过 npm**：直接粘[最新 Release](https://github.com/yindf/taskfold/releases/latest) 里预构建的 `.tgz` 直链，tarball 不受发布时长策略限制；
   - **跟分支走**：`github:yindf/taskfold#master`（rc 通道）/ `github:yindf/taskfold#alpha`（alpha 通道），要求本机能直连 GitHub；
   - **本机路径**必须指向**副本**，绝不能指向你的工作检出：装进来的目录，插件管理器会当成自己的（会在旁边留下 `dsh-taskfold.frozen-*.bak` 快照，升级时整个替换）。
4. **安装源** 保持「默认安装源」；中国大陆网络若拉取失败，改选「中国大陆镜像源」再试。
5. 点 **安装**，等它显示「已安装，下次启动后加载。」，再点 **立即启用**。
6. **重启 dsh Desktop**——插件组合只在启动时求值。重启后回到 **插件** 页，应看到 **Taskfold** 卡片写着 `包含的组件 · 共 2 个 · 2 运行中`（`taskfold` 与 `taskfold-client` 两行）；折叠下限与任务栏开关就在这张卡片里（见[设置](#设置)）。
7. 升级请先 **卸载** 再装新版：界面明确说明暂不支持自动更新；卸载后它提供的功能即消失。

这个安装框做的和下面的命令行是同一件事：把依赖与 bundle 条目写进当前 profile（dsh Desktop 用 `desktop`），此外不需要任何手工配置。

### 用命令行安装

`dsh plugin --profile <profile 名> add` 就是上面对话框的命令行等价物。`desktop` 是 dsh Desktop 的 profile，`web` 是 DSH Web GUI 的——按你实际跑的那个改：

```sh
# npm 上的最新发布
dsh plugin --profile desktop add dsh-taskfold

# 钉住某个版本——发布不满 24 小时时必须钉；0.37.7 / 0.38.0 装不上
dsh plugin --profile desktop add dsh-taskfold@<版本>

# 跟某个通道的分支（引号不能省：# 在 sh 里是注释）
dsh plugin --profile web add "github:yindf/taskfold#master"
dsh plugin --profile web add "github:yindf/taskfold#alpha"
```

无论走界面还是命令行，装完都要**重启 dsh**。

### 通道、npm 包与支持范围

npm 上的 [`dsh-taskfold`](https://www.npmjs.com/package/dsh-taskfold) 是**预构建包**——免去 dsh 的 `allowBuilds` 构建授权；0.37.6 起由发布流程发布，但**只发 rc 通道（`master`）**：alpha 通道的发版只出 GitHub Release，从不进 npm。裸包名因此跟随 rc 通道的最新版本；要确定性就用 `@版本` 钉住，或直接填分支的 Git 地址。

`master` 分支承载 rc 通道、`alpha` 分支承载 alpha 通道：本分支记录 rc 通道的支持范围（见[支持的 dsh 版本](#支持的-dsh-版本)），alpha 通道的记录在 [alpha 分支的 README](https://github.com/yindf/taskfold/blob/alpha/README.zh.md#支持的-dsh-版本)。

重启 dsh——该 profile 下的每个会话都拥有这些工具。之后智能体用命名任务包住自己的工作：

```
task_begin("修复登录 bug")   … 干活 …   task_end("修复登录 bug")
```

整段来回就此折叠成一条带标题的摘要，`fold_recall` 随时能读回原始内容。

## 它解决什么问题

长会话会被自己的历史淹没：每个请求都在重发几小时前就完成的工作——旧的工具输出、调试日志、失败的尝试。成本越滚越高，模型注意力被稀释，上下文窗口迟早被塞满。

taskfold 用“好笔记本”的方式解决：干活前，智能体先用 `task_begin("修复登录 bug")` 开一个任务；做完后 `task_end` 关闭任务，**同时**把整段来回替换成一条带标题的短摘要：

```
之前：  [800 条原始调试消息……]
之后：  「修复登录 bug」— 摘要：试了什么、为什么失败、改了什么、
        用户拍板了什么。（约一屏）
```

会话保持可读，每个请求都更便宜，模型带走的是**经验**而不是**流水账**。

**什么都不丢。** 每次折叠都会把原始消息原样存成文件，`fold_recall({ fold: N })` 随时能重新生成。先折叠、后查阅——像合上一本随时能翻开的书记。

## 与 dsh 内置压缩的关系

同一个目标，不同的时机——两者可以叠加。

- **dsh 内置压缩是自动的、由压力驱动的。** 它在窗口快满时触发，按 token 压力选出一段区间替换成摘要；原始事件仍留在会话日志里，只是被 shadow 掉，而不是删除。
- **taskfold 是显式的、按任务划分的。** 每完成一个任务就顺手折叠一次，摘要是趁那一段还在上下文里时写下的——天然准确——而且带标题，会话始终可导航。
- **因为你折叠得早，窗口很少被塞满。** 下面实测会话的峰值是 20.7% 而不是 59.5%，于是压力压缩要么更晚触发、要么根本不触发；真触发时，需要总结的东西也更少。
- **每一次折叠都可寻址。** `fold_recall({ fold: N })` 取回的是原始消息，不是二手摘要。

## 原理（通俗版）

- **命名任务。** 智能体开工前开任务、完工后关任务。开启状态跨重启不丢；关闭按嵌套顺序（内层先关）；关闭失败不会破坏任何状态——重试即可。
- **折叠 = 关闭 + 总结，一次调用完成。** 摘要在原始内容还在上下文里时一次性写好，所以准确——不是“摘要的摘要”。
- **摘要保留要紧的东西。** 总结指令明确要求保留用户的关键决策与反馈（措辞重要处原文照录）、踩过的坑和*为什么*失败、改了什么、最终结果。
- **温和护栏。** 智能体忘记纪律时，上下文里会出现一条简短提示。提示是事件而非状态：只在条件出现或措辞变化时发布一条；条件解除后什么都不发（模型已经照做了，不需要再被告知）；没有包装标签、没有取代声明、也没有过期通知——流程健康时零噪音。
- **对缓存友好。** 折叠只改写历史中段；稳定前缀（系统提示词、工具、更早的上下文）保持缓存命中。

## 省了多少（实测）

一次真实会话——411 个模型步、26 次折叠——数字直接读自 harness 自己的用量记录：

| | 不折叠 | 用 taskfold |
| --- | --- | --- |
| 提示 token 总量 | 142,654,308 | 52,127,098（**−63.5%**） |
| 单次请求最大体积 | 594,909 | 206,896（−65%） |
| 峰值上下文窗口占用 | 59.5% | 20.7% |

机制：折叠把 **441,100 token** 的已完成工作移出表层。这些历史本来会在之后每个请求里被重发一遍，累计下来就是 **90,527,210 token 从未发出**。生成那 26 条摘要本身花了 3,550,270 token（相当于节省量的 3.9%，且其中大部分是缓存读取）；单次折叠最多一次性移走 40,422 token。

这些被省下的 token 大多是缓存**读取**而非全新输入——单价更低，但依然计费、依然占窗口。会话再长一些，这就成了「还在窗口内」和「已经塞满」的区别。

一次会话、一种任务形态——你的数字会不同；关键是机制：完成的工作离开表层，稳定前缀持续命中，模型带走经验而不是流水账。

## 它添加了什么

四个智能体工具（加上上述提醒机制）：

| 工具 | 一句话 |
| --- | --- |
| `task_begin({ name })` | 开一个命名任务。 |
| `task_end({ name })` | 关闭它，并把整段折叠成一条带标题的摘要。 |
| `list_folds` | 列出全部折叠（编号、大小、标题）。 |
| `fold_recall({ fold })` | 按需取回任意折叠的原始内容。 |

在 Web GUI 中，当前打开的 task 栈还可以以常驻 dock 显示在输入框上方（和 todo 面板一样）——默认隐藏，在插件页用 `showTaskBar` 打开：外层任务在前、最内层高亮，附带 folding/pending 计数——直接读会话的 `taskMarks` 投影，不追加任何事件。

<img src="https://raw.githubusercontent.com/yindf/taskfold/master/assets/screenshot-tasks.png" width="100%" alt="常驻输入框上方的任务栈：嵌套的打开任务、最内层高亮，每个已结束任务各占一行 folding">

<img src="https://raw.githubusercontent.com/yindf/taskfold/master/assets/screenshot-tasks-collapsed.png" width="100%" alt="同一任务栈折叠成一行，以及 lifecycle 提示交给模型的任务栈行">

## 设置

折叠有一个用户可配置的下限，在宿主**插件页**的 “Taskfold” 卡片中配置（宿主服务该命名空间期间由浏览器端注册）——不用环境变量，也无需重启：

- **`minSpanTokens`**（默认 `2000`）——任务关闭后，其折叠区间携带的估算 token 数需要达到的最小值，才值得发起一次摘要调用。token 按区间消息文本估算（区分中日韩字符的启发式，速率常数已按实测 `shadowedTokenCount` 校准，估算值整体偏低约 7%，方向保守），在任何模型调用之前即可算出。低于下限的区间**不折叠直接关闭，且判定在关闭当时做出、记录在 `Task ended` 结果文本里**（0.37.6）：该区间根本不进入归档队列，跳过由构造保证永久——不存在可被触发的重开路径，因为回溯折叠已落定的区间要改写表面、使其后方的 provider 前缀缓存整体失效，这笔代价任何小折叠都省不回来。关闭消息若还携带其他工具调用（其结果在 `task_end` 执行时尚未落地），则回退为 drain 侧的内存落定，重启后按当时下限重测。`0` 折叠一切；无法计量的区间始终折叠。非法值（非整数、负数）回退到默认值，绝不抛错。修改由表单 schema 校验、持久化到当前 profile 配置，并**即时生效**——下一次关闭（或兜底落定）即按新下限判定。默认值及其推导见 [docs/fold-floor.md](docs/fold-floor.md)——对最近两周会话日志的实测表明，摘要调用的固定开销使 ~1000 token 以下的区间稳亏，默认 2000 保留了 2 倍安全边际。
- **`showTaskBar`**（默认 `false`）——同一张卡片上的开关，控制是否在对话输入框旁显示任务栏。默认隐藏：新 profile 不打开开关就没有这条 banner；显示或隐藏都不影响折叠行为。唯一的兜底可见是有意保留的——命名空间未被服务或设置服务缺失时仍然显示，因为 dock 的注册本身不依赖设置服务。

## 本地化

所有用户可见界面均提供英文与简体中文。设置卡片文案经宿主 locale 服务解析（字典 `settings.taskfold`）。任务栏 dock 的注册刻意不声明 locale 依赖——locale 服务可用时由 bundle 接线绑定读取器（字典 `ui.taskfold`），缺失时打印内置英文，因此在任何部署上都能渲染。包同时导出 `locale/en.json` 与 `locale/zh.json`（插件页页头与 npm 简介），并为每个挂载组件提供一份行级 locale——宿主行用 `plugins/locale/*.json`（经它挂载的子路径 `dsh-taskfold/plugins` 解析）、客户端行用 `client/locale/*.json`（经它自己的裸包名 `dsh-taskfold-client` 解析）——插件页因此按当前语言显示每一行的标题与一行简介，而不再回退到 `package.json` 的英文文案。两行的标题都刻意不同于行 id 与模块名：`client.js` 只在标题与行 id 不同时才打印 id、与模块名不同时才打印模块名，于是每一行都渲染出同样的四行——标题、简介、行 id、模块名——与官方 bundle 的行形态一致。客户端包的 `package.json` 依旧不写简介，因此行内简介只会来自它那份 locale。包自身的简介继续服务于插件页页头与 npm 页面。

## 其他安装方式

每个 Release 都附带预构建的 `dsh-taskfold-<版本>.tgz`。插件市场会优先提供该资产（或 npm 包）而不是源码构建命令，同时也免去 dsh 的 `allowBuilds` 构建授权——见[最新 Release](https://github.com/yindf/taskfold/releases/latest)。

## 支持的 dsh 版本

- **rc 通道 —— 支持到 `0.2.1-rc.5`**（2026-10-30 实测——两次补丁级前进且宿主面没有实质变化：monorepo 从 0.2.1-rc.3 → 0.2.1-rc.5（rc.4 同日发布后即被取代；本条记录验证的是 rc.3 → rc.5 的累计差异，`latest` 与 `next` 现均指向 `0.2.1-rc.5`），`@deepseek-ai/*` 闭包仍是**同一套 307 个包**——零新增、零移除——其中 297 个锁定在 `0.2.1-rc.5`，10 个非同版本节奏的包原样未动（`cordis 4.0.5`、四个 `cordis-plugin-*`、`cosmokit 1.8.6`、`libreoffice-kit 0.1.5`、`node-addon-system 0.1.2`、`schemastery 3.18.5`）。对插件触及的 19 个包逐文件比对（排除 `.map`）显示：**17 个只改了 `package.json` 的版本号与依赖锁定**；该集合内真正的代码变化都在客户端——`dsh-client-ui-conversation`（每个 View 标签改为按自身字形估算宽度、仅当估算超过 88px 单元格时才显示全名 tooltip，且 More 按钮不再在 tooltip 中命名已收起的活动 View——该文案已移除）与 `dsh-client-modules`（只改了内嵌的 commit 常量）——而在整个 307 个包的面上共有 327 个文件变化、新增 1 个客户端类型声明、无删除，因此宿主面是重新探测而非沿用旧结论。shell 这次**没有重新构建**：`dsh-web-frontend/dist/assets/index-BXV-oxvX.js` 与 rc.3 逐字节相同（941436 B，sha256 `0f3fc6b8…2ef0`），所以客户端契约扫描针对的是完全相同的 bundle 工厂。兼容门禁用真实的 `evaluatePluginCompatibility` 复核（`@deepseek-ai/dsh-app-boot@0.2.1-rc.5`，`getDshRuntimeVersion()` → `0.2.1-rc.5`）：现有 `^0.2.0-rc.1` 下界在三个 peer 上全部通过——门禁内部的 `satisfies()` 以 `includePrerelease: true` 运行 semver，0.2.x 预发布版被接纳在 caret 的 `<0.3.0-0` 范围内，不要求同 minor 下界——无需改插件，v0.39.1 原样加载；三个负例对照（三个 peer 全用 `^0.1.7-rc.1`、只改一个 peer、把真实 manifest 按 0.1.7-rc.1 运行时评估）均被拒绝并返回 unmet-requirements 对象，说明该通过并非空转。针对真实 0.2.1-rc.5 包的宿主 API 形状探针——**52/52**：`BasicCompactionEngine` 默认导出、原型上 `compactRegion`（arity 4）与 `summarize`（arity 3），按 fold engine 的方式子类化，并真驱动 `BlockAssembler` 产出 `blocks()` 结果（dsh-llm）；schemastery CJS 链与插件自身 `Config` 元数据（`minSpanTokens` 0..1000000、默认 2000、volatile；`showTaskBar` 默认 `false`、volatile）完好；插件用到的 7 个 service、3 个 hook（`agent/pre-step`、`agent/turn-stopping`、`compaction/summary-error`）与 6 个方法全部存在；引用的 4 个 `@deepseek-ai` specifier 均可解析。客户端契约扫描——**19/19 存在、0 缺失**（`conversation.input.dock`、`plugins.bundle.config`、configForms 的 `whileServed`、`window.__ModuleLoader__`、`SettingsFormModel`、`settingsNumberField`、`slots`/`configForms`/`locale`、`inject(key, callback)`、`register(...)`），且这套未变的 shell 的 loader 工厂仍然提供 bundle 需要的两个 specifier（`react`、`@deepseek-ai/dsh-client-ui-primitives`）。端到端探针宿主（真实 0.2.1-rc.5 构建，运行在本树 `7a82d65` 的哈希锚定副本上，使用隔离的 `DSH_HOME`）：副本 8/8 通过 sha256 校验；stderr 为 **0 字节**，插件禁用行为 0 条——两种措辞都检查过（0.2.1+ 打印 `disabling profile plugin ${label}`，0.2.0 打印 `disabling profile plugin row "<id>"`），并把宿主自身的输出字面量引为对照以证明扫描不是空转；`--dump-config` 列出两行（`taskfold` → `dsh-taskfold/plugins`，`taskfold-client` → `dsh-taskfold-client`），均无 disabled 标记；`settings/describe` 提供 `taskfold` 命名空间（行 id，而非历史上的 `cmpct-region`），值为 `{"minSpanTokens":2000,"showTaskBar":false}`、`applies: live`，且 schema 就是插件自己声明的那份（两个叶子 description 均可回溯到 `plugins/taskfold.mjs`）；`window.__DSH_BOOT__` 图共 71 条，其中 `dsh-taskfold-client` 拥有自己的 application 批次行；实际下发的 bundle 为 32805 B / 756 行，其中 **753 行内容与 `client/taskfold-client.mjs` 逐字节相同**（尾部多出的是宿主的 `;`、`//# sourceMappingURL=…` 和一个空行）。离线测试套件——14 个套件、239 个测试、0 失败。本条记录所在的桌面负载本身已是 `0.2.1-rc.5`（其运行清单里的 `desktopVersion`），运行着本插件已发布的构建（0.38.2，同一 `^0.2.0-rc.1` 下界），任务标记、折叠与 `fold_recall` 均活跃。隔离探针宿主中没有跑真实的折叠/摘要往返（该环境无模型提供方凭据）：engine 形状、子类化、解析器、shim 的构造与被真驱动的 `BlockAssembler` 共同替代。`dsh`、`dsh-compaction-basic`、`dsh-llm` 同版本锁定，因此一个版本号即可覆盖整个宿主面。
- **alpha 通道 —— 请用 `#alpha` 安装**（`dsh plugin --profile web add "github:yindf/taskfold#alpha"`，即 alpha 分支）；alpha 构建的支持版本记录在 [alpha 分支的 README](https://github.com/yindf/taskfold/blob/alpha/README.zh.md#支持的-dsh-版本)。
- **边界：下界已强制，上界未测试。** 插件把宿主耦合面写进 `peerDependencies`（`@deepseek-ai/dsh`、`@deepseek-ai/dsh-compaction-basic`、`@deepseek-ai/dsh-llm`，均为 `^0.2.0-rc.1`）：dsh 0.2.0+ 宿主在安装与启动/重组合时检查这些范围，不兼容的宿主将得到 `incompatible-version` 判定、bundle 被跳过，而不是带着不兼容加载——0.1.7-rc.* 宿主请安装 v0.37.0（其 `^0.1.7-rc.1` 下限与之匹配）。早于该检查机制的宿主没有任何协商——在那些宿主上，折叠会降级（任务照常关闭、不折叠），不会损坏数据。每次 dsh 升级后，请复核本节并按实测结果更新。
- **可选钩子：`agent/turn-stopping`** —— 0.26.0 起归档排干还会在回合结束时运行，让回合末交付的折叠赶在 provider 前缀缓存还热时执行。没有该钩子的宿主保持原来的纯 pre-step 语义（折叠照常发生，只是晚一个回合）；注册语句整体包裹，钩子缺失不会破坏 `apply()`。

## 维护者须知

- 目录：`plugins/`（**一个**挂载宿主行 `taskfold.mjs`，以包子路径 `dsh-taskfold/plugins` 挂载——bundle patch 只声明一个宿主组件，所以插件页显示两个：该行与以自身组件包名 `dsh-taskfold-client` 挂载的客户端行；`compact-stats.mjs` 是它 import 的普通模块，不是行；以及它们共享的纯模块 `events.mjs`、`task-marks.mjs`、`fold-instruction.mjs`、`fold-engine.mjs`、`fold-drain.mjs`、`fold-settings.mjs`、`lifecycle-nudges.mjs`、`lifecycle-injection.mjs`、`span-preview.mjs`，以及浏览器端：`task-stack-ui.mjs`——dock 的唯一事实源——与 `fold-settings-ui.mjs`——插件页设置卡，均由 `scripts/build-client.mjs` 生成到 `client/taskfold-client.mjs`）、`client/`（嵌套的 `dsh-taskfold-client` 子包——浏览器 bundle 的唯一属主行；一个客户端包只能有一个属主 Loader 行，而宿主端已占用根包的行；它**作为独立 npm 包发布**，根 `package.json` 以注册表版本范围把它声明进 `dependencies`，于是 dsh-app-boot 的依赖闭包会发布该名字，客户端行以裸包名挂载而非 `file:///` 路径，且消费方的 pnpm 能真正装上它——`file:`/`link:` 这类路径说明符是相对**安装者**的 workspace 根解析、而非相对本包解析，这正是 0.38.0 完全装不上的原因；行标题由 `client/locale/*.json` 提供）、`scripts/release.mjs`、`scripts/verify-cache.mjs` 与 `scripts/build-client.mjs`、`test/`（`npm test`）、`assets/`（README banner、仓库设置里上传的社交预览图，以及 `screenshots.json` 列出的商店截图）、`docs/`（`docs/README.md` 索引，以及 `docs/design/` 设计笔记与 `docs/adr/` 决策记录——有意不随 npm 包发布）、`CHANGELOG.md`。
- 发版：`node scripts/release.mjs draft` → 审阅 CHANGELOG 条目 → `node scripts/release.mjs release`（CHANGELOG 是版本唯一事实源）。`release`（及其 PENDING 续跑）在 `NPM_TOKEN` 环境变量存在时还会把版本发布到 npm——须为 **Automation 类型**令牌（开了 2FA 的账号会在发布时拒绝 granular 令牌的 OTP）；该步骤幂等（注册表上已有的版本直接跳过），失败也绝不回滚 git 侧的发布；令牌取自进程环境，Windows 上还会回落到用户级变量。若该步骤被跳过或失败，用 `node scripts/release.mjs npm [--version X.Y.Z]` 单独补发——四道守卫（`package.json` 版本、本地 `v<版本>` tag、干净工作区、工作区与 tag 内容一致）全部满足才肯发。**发布的是两个包，且客户端包必须先发**：根包 manifest 里写着 `dsh-taskfold-client` 的版本号，若根包先于客户端包发布，在客户端包落地前所有消费者都会 404（两个包各自探测、各自发布，重跑只会补上缺的那一半）。发布前 `assertClientDependencyResolvable` 会拒绝任何非注册表版本范围形式的客户端依赖——`file:`/`link:`/`workspace:` 这类说明符相对**消费者**的 workspace 根解析，会让每一次安装都失败，这正是 0.38.0 发布出去的样子。**通道分支**（0.34.6 起）：`master` 只承载 rc 通道发版——它停留在最新的已验证 rc 版本；alpha 通道发版在 `alpha` 分支上进行，其提交与 tag 承载 alpha 验证过的工作（在 `alpha` 分支上跑 draft/release；脚本推送当前分支与 tag）。若本次发版改变了支持的 dsh 版本范围，发版前先更新**两份** README（README.md + README.zh.md）的“支持的 dsh 版本”一节——release 脚本会提醒。每个分支只记录**本分支构建**的实测：本通道一条最新验证版本（被取代的条目删掉），另一通道只放一条指向对方分支 README 的**链接**——绝不抄版本号。
- **折叠缓存校验是流程的一部分。** 每次 dsh 升级后——以及任何触及折叠信封的发版前——对一份 live 会话日志跑 `node scripts/verify-cache.mjs --since-restart`，并把数字记进 CHANGELOG 条目。若某次折叠的摘要调用重新付费了它的 span——判据是 `uncached − span > --tail-budget`（tail 为正）——脚本以非零码退出，这正是前缀信封不再匹配宿主摘要输入的 signature。离线测试只能钉住结构前提（只有一个 system 消息、严格前缀）；真实缓存命中只能由 live 日志给出。
- 设计决策与历史见 `CHANGELOG.md`，以及仓库内的 `docs/`（索引见 `docs/README.md`；`docs/design/` 设计笔记与 `docs/adr/` 决策记录随仓库走，不随 npm 包发布）。

## 如果它帮你省下了 token

点一个 star 能让更多 dsh 用户找到它——在这个生态里，插件就是靠这个被发现的。你自己会话里的实测数字，欢迎贴到 [Discussions](https://github.com/yindf/taskfold/discussions)。

## 许可

MIT。基于 DeepSeek Harness（`@deepseek-ai/*`，MIT）公开包开发。
