<div align="center">

# dsh-light-memory

**四个 Markdown 文件 + 两个动作（append / distill）。零外部部件，由 code agent 自行维护。**

一个为 DeepSeek Harness（DSH）Web GUI 设计的轻量记忆系统插件：没有数据库、没有向量库、没有 MCP、没有 Python——记忆就是你能看见、能编辑、能 git 管理的纯文本。

[![npm version](https://img.shields.io/npm/v/dsh-light-memory?color=6f83ff&style=flat-square&label=npm)](https://www.npmjs.com/package/dsh-light-memory)
[![DSH](https://img.shields.io/badge/DSH-web-blue?style=flat-square)](https://github.com/deepseek-ai/deepseek-harness)
[![MIT License](https://img.shields.io/badge/license-MIT-536990?style=flat-square)](LICENSE)

</div>

---

<img src="https://github.com/chidaic/dsh-light-memory/raw/main/assets/img/Hero.png" width="100%" alt="dsh-light-memory 宣传图"/>

## ✨ 亮点

### 极致轻量

没有数据库、没有向量库、没有 MCP、没有 Python —— 只有 4 个 Markdown 文件，用编辑器就能改，用 git 就能管理。插件自身只用一个 `state.json` 记录增量窗口与拼接选择。

- 只用 Node 内置模块：无数据库、无 embedding、无外部 API、无 MCP、无 Python。
- 操作记录（流水）与持久结论（结论库）分离，是两类不同性质的文件。

### 定制化

记忆规约不是写死的：怎么记、记什么、沉淀到哪，全由你自己编辑 `CONVENTION.md` 定义。改完保存即生效，你的记忆你做主。

### 可插拔

用户级、项目级、操作流水、记忆规约——每一块都能单独开关。不想要 WORKLOG？点一下。只想留项目结论？再点一下。真正的按需注入，让上下文永远轻。

> **一句话**：dsh-light-memory — 4 个 Markdown 文件，为你的 Agent 装上一套可定制、可插拔、极轻量的持久记忆。零数据库、零依赖、零遥测，全部是你能看见、能编辑、能 git 管理的纯文本。

## 🚀 安装

```sh
# 方式一：DSH 插件命令（推荐）
dsh plugin --profile web add dsh-light-memory

# 方式二：npm / pnpm
npm install dsh-light-memory
pnpm add dsh-light-memory
```

重启 `dsh web` 后生效。首次使用会自动创建 `~/.dsh/memory/`（USER.md / CONVENTION.md / state.json）；在你的项目根创建 PROJECT.md / WORKLOG.md。

## 🔄 运行时数据流

<img src="https://github.com/chidaic/dsh-light-memory/raw/main/assets/readme/flow.svg" width="100%" alt="dsh-light-memory 运行时数据流"/>

- 左：User 与 Assistant 的会话内容流入中间三个记忆文件——`append` 机械写入流水；`distill` 在任务边界把结论沉降进 USER/PROJECT。
- 中：记忆本体就是三个 Markdown（`USER.md` 用户级 / `PROJECT.md` 项目级 / `WORKLOG.md` 操作流水），`CONVENTION.md` 定义规约。
- 右：DSH 核心通过 `systemPrompt.section`（静态，字节稳定）+ `systemPrompt.context`（动态，user-role 快照）注入记忆；蒸馏回调复用核心的模型判断后回写。

## 📁 四个文件

| 文件 | 位置 | 性质 | 生命周期 |
|---|---|---|---|
| `USER.md` | `~/.dsh/memory/USER.md` | 用户级持久结论（身份/偏好/跨项目教训） | 永久，跨项目 |
| `PROJECT.md` | `<项目根>/PROJECT.md` | 项目级持久结论（项目说明 / 约定 / 决策 / 踩坑） | 随仓库，git 分享 |
| `WORKLOG.md` | `<项目根>/WORKLOG.md` | 操作记录（append-only 流水，段为粒度） | 只读最近 n 段，老段可归档 |
| `CONVENTION.md` | `~/.dsh/memory/CONVENTION.md` | 记忆规约（四段，可随时编辑） | 用户维护 |

## ⚙️ 两个动作

- **append（机械，无 AI 判断）**：`memory_append` 每轮/每任务结束追加一段 `## YYYY-MM-DD HH:MM + 要点` 到 WORKLOG.md。只记录事实（做了什么/踩坑/验证/提交边界），插件强制段格式、单段上限与密钥扫描。
- **distill（语义，任务边界）**：`memory_distill` 读 CONVENTION → 扫「本次会话新增段」（**只扫增量，绝不扫历史全量**）→ 连同 USER/PROJECT 现状返回，由模型判断：有结论 → 用 write/edit 去重更新 USER.md / PROJECT.md；无结论 → 明说"无需沉降"。

## 🧰 四个工具

| 工具 | 参数 | 作用 |
|---|---|---|
| `memory_append` | `content` | 追加一段操作记录到 WORKLOG.md（段格式/size/secret 强制） |
| `memory_read` | `target: user\|project\|worklog`, `n?` | 读 USER/PROJECT 全文或 WORKLOG 最近 n 段 |
| `memory_convention` | — | 读 CONVENTION.md 全文 |
| `memory_distill` | `settle?`（默认 true） | 任务边界沉降（只扫本次新增段） |

## 💉 注入工程（prefix-cache 友好，三层）

| 层 | 内容 | 位置 |
|---|---|---|
| 静态 | CONVENTION 摘要 + append/distill 义务（字节稳定） | `systemPrompt.section` —— 唯一进 system prompt 的规约内容（order 155） |
| 动态 | USER + PROJECT 正文（按各自字节上限截断）+ WORKLOG 拼接段 | `systemPrompt.context`（官方动态上下文通道 → user-role 快照，不塞进 system prompt，order 300） |
| 按需 | CONVENTION 全文、更早的流水段 | 工具/编辑器按需读 |

即：**项目规约（CONVENTION）只有摘要拼进 system prompt；PROJECT.md 等文件内容走动态上下文注入**，保证 system prompt 字节稳定、prefix-cache 友好。

另注册运行时 skill `light-memory`（body = CONVENTION 摘要 + 完整协议），可被 `skill` 工具发现。

## 🎨 UI

- **输入区记忆控件**：「🧠 记忆」按钮 + 浮层。浮层展示各段标题/首行摘要，勾选要拼接的段——**勾选即保存**，选几段就拼几段；「恢复默认」回到默认行为（自动拼接最近 n 段）；「取消拼接」保存空选择（0 段，仅保留用户级/项目级注入）。段数多时列表区固定高度内部滚动，超过 6 段自动出现搜索框。段标题自动唯一化，重复标题不会互相捆绑。
- **设置页「记忆」**：内置编辑器（USER / CONVENTION / PROJECT，保存即生效、可恢复模板，卡片式布局显示路径与当前/上限）；「注入与上限」tab：生效开关（用户级/项目级/更新记忆，默认全开）+ 参数预填默认值直接改。
- 颜色全部走主题语义 token（`--dsw-alias-*`），随明暗主题自适应。

## 🛡️ 安全边界（机械强制）

- **上限守卫**：`ctx.tools.guard()` 只拦「持久结论文件增长越上限」的 write/edit 写（按文件分上限：USER 默认 2048 字节 / PROJECT 默认 8192 字节，另有条目上限，均可在设置页调整），**放行缩小写**（允许增量压缩，不误伤 read）。
- **secret 扫描**：append / 结论库写前拦截 API key、token、私钥块等模式，命中提示改记"去哪找"。
- **路径逃逸防护**：realpath 后必须落在允许根内，拒 symlink / `..` / 绝对路径逃逸；路由只接受会话 cwd 或已注册工作区。

## 🧾 配置（cordis.patch.yml 行内 config，为默认值；设置页可运行时覆盖）

```yaml
userRoot: ~/.dsh/memory    # USER.md + CONVENTION.md + state.json
projectName: PROJECT.md    # 项目根
worklogName: WORKLOG.md    # 项目根（append-only，不设硬上限）
recentSegments: 3          # 默认拼接最近 n 段（1–20）
recentBytes: 8192          # 拼接字节上限（512–65536）
userMaxBytes: 2048         # USER.md 字节上限（512–16384）
projectMaxBytes: 8192      # PROJECT.md 字节上限（1024–65536）
userMaxEntries: 60         # USER.md 结论条数上限（5–500）
projectMaxEntries: 80      # PROJECT.md 结论条数上限（5–500）
maxBytes: 25600            # CONVENTION.md 字节上限（兜底）
maxSegmentBytes: 4096      # 单段操作记录字节上限
injectUser: true           # 用户级（USER.md）是否注入生效
injectProject: true        # 项目级（PROJECT.md）是否注入生效
memoryActive: true         # 更新记忆（规约提示 + append/distill 工具）是否生效
```

## 📂 目录

```
dsh-light-memory/
  lib/index.js         # host 端：store + 工具 + guard + 双层注入 + skill + 路由（零依赖 ESM）
  lib/client.js        # browser 端：输入区记忆控件 + 设置页编辑器
  templates/           # 首启落盘模板（CONVENTION/USER/PROJECT）
  assets/img/Hero.png  # 宣传图
  assets/readme/flow.svg  # 运行时数据流图
  cordis.patch.yml     # bundle patch（insert 行 + config）
  package.json         # dsh.bundle.patch / dsh.client 声明
  test/                # 纯逻辑单测 + host 冒烟测试
```

## 📄 License

[MIT](LICENSE) © chidaic
