# @xiyiyiru/dsh-state

[dsh](https://github.com/deepseek-ai/deepseek-harness) agent 的会话状态笔记本：基于按会话独立文件的 `add_state` / `read_state` / `compact_state`，外加一个两工具任务栈（`focus_task` / `focus_complete`）。

> English README: [README.md](./README.md)

## 为什么

上下文压缩吃掉工作记忆。agent 刚查明「bug 在重试循环里、用户确认了方案二」，一压缩正好丢这个。自动注入的状态有反向的失败模式：每个请求都烧同样的 token，还训练模型学会无视它。

本插件把工作事实持久化为工作区下的普通文件——抗压缩、跨 resume 存活——并且笔记本不进任何请求，除非 agent 主动去读。五个动词，无存储要管，无 schema 要迁，零会话事件（dsh 会话日志读取方会拒绝词汇表之外的事件类型，所以 0.2.0 起本插件完全不碰日志）。

## 存储

一切都在 `<会话目录>/.mycel/state/<会话ID>/` 下：

- `notebook.md`——笔记本，每条笔记追加一段
- `focus.json`——任务栈，底部帧在前

会话 ID 即容器键：同一工作区里的两个会话绝不共享状态；resume 后（同 ID、同目录）文件原地可寻。

## 笔记本

| 工具 | 动词 | 语义 |
|---|---|---|
| `add_state` | 追加 | 追加一条笔记。写错了就追加一条更正行——没有编辑动词 |
| `read_state` | 读取 | 全文 + 大小；笔记本超 8K 后附带压缩提示 |
| `compact_state` | 替换 | 压缩动词：先 read，再用重写后的摘要覆写整个文件 |

`add_state` 面向模型的描述里带**硬触发**（命中即记，不等任务结束）：

1. 用户做了决策或纠正（「对」「不对，应该这样」落地的瞬间）
2. 查明关键事实/根因（丢了就要重查的路径、原因、数值）
3. 多轮任务入场（记目标 + 验收标准——压缩后的恢复材料）
4. 阶段性完成（结论 + 产物路径；做完不留痕 = 没发生）

## 任务栈

`focus.json`；帧就是单行任务描述。

| 工具 | 动词 | 语义 |
|---|---|---|
| `focus_task` | 压栈 | 锁定一个多步任务；原任务自动压到下面 |
| `focus_complete` | 弹栈 | 宣布完成、带一句结论、回退到上一个任务（没有则清空栈）。在**交付答案之前**调用——任务的完成标准是交付物落地 |

`focus_task` 什么时候**不用**：一句话能答的问答；同一任务内换工作姿态（那是 mode 插件的事——两者正交是设计使然：栈恢复任务，重切换恢复方法论；帧上不载模式快照）。

任务中途被挡？用 `focus_task` 锁定挡路的事，解决后 `focus_complete` 弹回主任务。

便利性：focus 调用同时追加到 `<会话目录>/.mycel/focus.log`——尽力而为，方便 grep 一个工作区的任务史；事实源始终是 `focus.json`。

## 它不做什么

- ❌ 零自动注入：笔记本绝不自行进入请求
- ❌ 无提示词段、对系统提示词零贡献
- ❌ 无模式知识、帧上不载快照（2026-09-03 起 mode 无关）
- ❌ 无编辑/删除动词——追加或整体替换，共两个动词
- ❌ 零会话事件——不向会话日志写入任何事件

## 安装

```bash
dsh plugin --profile <name> add @xiyiyiru/dsh-state
```

peer 依赖（`@deepseek-ai/cordis`、`dsh-agent`、`dsh-session`、`dsh-system-prompt`、`dsh-tools`）自动从你的 dsh 安装解析。

## API

```ts
import {
  ADD_STATE, READ_STATE, COMPACT_STATE,
  FOCUS_TASK, FOCUS_COMPLETE, FOCUS_TASK_DESCRIPTION, FOCUS_COMPLETE_DESCRIPTION,
  SIZE_WARN_THRESHOLD,
} from '@xiyiyiru/dsh-state'
```

| 导出 | 是什么 |
|---|---|
| `SIZE_WARN_THRESHOLD` | 8000——`read_state` 从此大小开始附带压缩提示 |
| `ADD_STATE` … `FOCUS_COMPLETE` | 工具名；`*_DESCRIPTION` 为面向模型的描述 |

invariant 伴生包（`@xiyiyiru/dsh-state/invariant`）仍校验 0.2.0 之前写入存储日志的遗留 `mycel/state` 事件；插件本体不写任何会话事件。

## 设计说明

- **零自动注入**——读取是显式行为；笔记本只在你主动花 token 时才花。
- **追加为主**——两个动词（追加 / 压缩替换）让语义保持完整；更正是新行，不是重写。
- **文件即真相**——状态目录是唯一事实源；`focus.log` 副产物是便利投影，设计上允许有损。
- **零会话事件**——不碰会话日志，因此不涉及任何 harness 词汇表或读取方兼容面。

## 许可

MIT
