Skills Plugins MCP Prompt Model 导航 博客 资讯 我的中心

dsh-todo-continuity

让没做完的任务清单跨回合保留。DSH 在每个回合开始时清空 todos 投影,指望模型重写整份清单,于是回合一旦被中断,计划虽然durable 地留在会话日志里,界面上却永久消失——而 todo_write 只写不读,用户和模型都拿不回来。本插件只注册一个普通的 session/event 监听器,按会话记住最后一份清单;当 turn/start 到来而那份清单仍有未完成项时,把它补折回去,投影就不再显示空计划。不 fork tool-todo、不注册任何 waterfall:插件换不掉投影(注册表对 stateVersion 不一致直接抛错),追加折叠所反应的那条事件才是够得着的缝。刻意收得很窄——只管未完成的清单、每次回合开始最多补一条、失败即放行。已用真实会话上的受控 A/B 验证:两次运行内容相同,唯一差别是插件装没装,都用真实的投影定义折叠。零依赖。

apex-mochen @apex-mochen ⬇ 2 ★ 0 main

安装

dsh plugin --profile web add github:apex-mochen/dsh-todo-continuity
下载安装清单

需要可复现安装时,可在仓库后追加 #commit 固定提交。

让没做完的任务清单跨回合保留。DSH 在每个回合开始时清空 todos 投影,指望模型重写整份清单,于是回合一旦被中断,计划虽然durable 地留在会话日志里,界面上却永久消失——而 todo_write 只写不读,用户和模型都拿不回来。本插件只注册一个普通的 session/event 监听器,按会话记住最后一份清单;当 turn/start 到来而那份清单仍有未完成项时,把它补折回去,投影就不再显示空计划。不 fork tool-todo、不注册任何 waterfall:插件换不掉投影(注册表对 stateVersion 不一致直接抛错),追加折叠所反应的那条事件才是够得着的缝。刻意收得很窄——只管未完成的清单、每次回合开始最多补一条、失败即放行。已用真实会话上的受控 A/B 验证:两次运行内容相同,唯一差别是插件装没装,都用真实的投影定义折叠。零依赖。

该插件未提供要点说明,请参考仓库 README。

  1. 安装并启动 DeepSeek Harness:npx @deepseek-ai/dsh web
  2. 在终端执行上面的安装命令(CLI 会解析插件并核验来源)
  3. 用 dsh plugins list 确认已安装,必要时重启 Harness 生效

插件以当前 dsh 进程的权限运行,安装时可能执行代码。请先通读仓库源码与许可证,确认无破坏性命令与越权访问;本站只做索引,不对第三方插件安全性作担保。

代码仓库github.com/apex-mochen/dsh-todo-continuity
许可证MIT
主要语言main
下载量2
GitHub 星标0
最近推送2026-09-15
收录日期2026-09-19
分类会话与消息

事实信息来自公开插件目录快照(2026-10-01),介绍文案由本站再加工。

以下为插件仓库 README 全文(原始内容,由公开目录抓取整理)。

# dsh-todo-continuity

**Keeps an unfinished task list visible across turns.**

DSH clears the `todos` projection at the start of every turn, expecting the model to rewrite the whole
list. When a turn is interrupted, the list is durably in the session log but gone from the UI — and
`todo_write` is write-only, so neither you nor the model can read it back. This plugin re-appends the
last list when a turn starts and that list still has unfinished work.

## The behaviour it addresses

`packages/todo/tool-todo/src/index.ts:130-145` — the fold, and its own comment describing it as
intentional:

```ts
// Standing-plan fold: latest whole todo/write list, cleared by the next
// turn/start (turn/end keeps the finished checklist visible); null before the
// first write or after a later turn begins; every other event returns the
// same state reference.
apply: (state, event) => {
  if (event.type === 'todo/write') return event.data.todos
  if (event.type === 'turn/start') return null
  return state
},
stateVersion: 2,
```

Rewriting each turn is a deliberate design — the tool description tells the model to send the entire
list every call. The problem is the interrupted case: the next `turn/start` clears the list anyway, and
`todo_write` (`:203-222`) only appends snapshots and returns counts, so there is no way to read the
previous list back. The plan is not lost — it is in the log — but it is unreachable from the UI, and
the model has no way to recover it either.

This is **community addition #21** to the verified unfixed-issue list in DSH discussion
[#6520](https://github.com/deepseek-ai/deepseek-harness/discussions/6520).

## What the plugin does

Registers one ordinary `session/event` listener. It remembers the last `todo/write` list per session,
and when a `turn/start` arrives whose remembered list still has unfinished items, it appends that list
back as a fresh `todo/write`. A projection is a pure fold over the durable log, so appending the event
the fold reacts to restores the state — nothing else needs to change.

Deliberately narrow:

- **Only unfinished lists.** A list with everything `completed` is left to the built-in behaviour, so
  the plugin changes nothing about the case it does not exist for.
- **Once per turn start.** At most one extra event per `turn/start`.
- **No fork.** It does not disable or replace `tool-todo`. It cannot: the projection registry
  refcounts a repeated key only at an equal `stateVersion` and throws on a mismatch
  (`session-projection/src/index.ts:276-283`), so the first definition always wins. Appending is the
  reachable seam.
- **No waterfall.** It registers no `pre-execute` / `pre-step` / `llm/stream` hook, so it has no
  `next()` obligation and cannot swallow another plugin's behaviour.
- **Fails open.** If the append cannot be made, the caller keeps exactly the built-in behaviour.

## Verified

A controlled A/B on real sessions — two identical headless runs differing only in whether this plugin
was installed, both folded through the **real** `todos` projection definition. Raw output in
[EVIDENCE.md](./EVIDENCE.md):

| | real events | folded final state |
|---|---|---|
| without the plugin | `turn/start#4 → todo/write#24 → turn/end#47 → turn/start#49 → turn/end#51` | `null` — list gone |
| with the plugin | `… → turn/start#49 → **todo/write#51** → turn/end#52` | the 3-item list |

The extra event has no `tool/call` or `tool/result` behind it (unlike the model's own `todo_write`),
and the control run has no such event at all — which is what establishes that the plugin caused it.

## Install

```bash
dsh plugin --profile web add github:apex-mochen/dsh-todo-continuity
```

Restart the profile afterwards.

## Configuration

```yaml
- id: dsh-todo-continuity
  config:
    verbose: false   # log each carry-over
    enabled: true    # set false to keep it installed but inert
```

## Two implementation notes worth knowing

**The append is deferred by a microtask, and that is required, not stylistic.** `Session.append`
publishes its event to listeners while its own acceptance boundary is still open, and rejects a
reentrant append (`core/session/src/index.ts:729-731`, *"session append cannot reenter while another
append is being published"*; the flag is set at `:742`, listeners run at `:752`, cleared in `finally` at
`:757`). A `session/event` listener runs inside that window, so an inline append throws every time — and
because this plugin fails open, it would have silently done nothing. An earlier version made exactly
that mistake; source reading caught it before any run.

**Listener order works out.** The projection registry has already folded `turn/start` to `null` by the
time this plugin's listener runs: `on` pushes unless `prepend` is set (`vendor/cordis/src/events.ts:255`),
`dispatch` preserves that order (`:172-174`), `emit` invokes them synchronously and forward (`:194-196`),
and the registry registers in its own constructor while the base bundle loads.

## Compatibility

- DSH `0.1.x` (peer: `@deepseek-ai/cordis ^4.0.1`)
- Node.js 20+
- One implementation file, zero dependencies, no process/filesystem/network access

## This overrides a designed behaviour

Per-turn clearing is documented as intentional, so this plugin is a deliberate product-semantics
change, not a bug fix — scoped as narrowly as it can be. The alternative fix is upstream: clear only
when the list has nothing left to do. DSH does not accept external pull requests today
(`CONTRIBUTING.md`), so a plugin is the reachable seam.

## License

MIT

数据来源:公开的 DeepSeek Harness 插件目录与各插件 GitHub 仓库。本站为独立第三方目录,与 DeepSeek、幻方(High-Flyer)及插件作者均无隶属或背书关系。

每日精选 Skill 推荐,免费送到你邮箱

输入邮箱,每天接收一个精选 AI Agent 技能推荐。完全免费,持续更新。

提交后我们会发送一封确认邮件,点击邮件里的链接才会开始收信。

完全免费,取消任意时间。我们不会发送垃圾邮件。