# dsh-keep-memory **Repository Path**: yfymdkj/dsh-keep-memory ## Basic Information - **Project Name**: dsh-keep-memory - **Description**: 蓝色大肥鱼工作记忆保存插件,不一定好用hhh - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-10-18 - **Last Updated**: 2026-10-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # dsh-keep-memory 给 [DSH(DeepSeek Harness)](https://github.com/deepseek-ai/deepseek-harness) 用的**跨会话记忆插件**: 把记忆库的读写固化成八个 `memory_*` 工具,**记忆位置可配置**、不随会话工作区漂移, 并且在受限沙箱模式下**不需要逐次授权**。 > **第一次用?** 看 [GETTING-STARTED.md](GETTING-STARTED.md)。 > **想知道它为什么这么设计?** 看 [DESIGN.md](DESIGN.md)。 > **你是 AI / 想让 AI 正确使用它?** 看 [PROTOCOL.md](PROTOCOL.md)(这份也会被写进你的记忆库)。 --- ## 一分钟了解它是什么 DSH 的每个会话都是**白纸开局**:转录落盘是为了审计,模型再也看不到它。这个插件补上那一层—— 一个**位置固定、跨会话、跨项目**的记忆库,加八个让 AI 读写的工具。 ``` <记忆目录>\ ├─ INDEX.md 目录层:一天一行(日期|一句话摘要|关键收获) ├─ FACTS.md 稳定层:跨天有效、会变的事实;同名小节原地更新 ├─ PROTOCOL.md 协议层:告诉 AI 该写什么、写到哪一层 └─ YYYY-MM-DD.md 当天层:一次性经历;只追加,永不覆盖 ``` 外加两个**记忆库之外**的文件: ``` ~/.dsh/AGENTS.md 常驻段(约 1.1 KB,上限 2 KB)——让 AI 知道有这套记忆、怎么用 ~/.dsh/dsh-keep-memory.json 记忆位置配置(可选,不写就用出厂默认) ``` --- ## 它解决什么问题 DSH 的文件沙箱只作用于**工具调用**,其可写根是硬编码的: ```js function writableRoots(policy) { if (policy.mode !== "workspace-write") return []; return [...new Set([policy.workspaceRoot, "/tmp", tmpdir()].map(canonicalPath))]; } ``` —— 只有「会话工作区 + `/tmp` + 用户临时目录」,**没有任何配置项可以追加路径**, 也没有「记住这次授权」的持久白名单。 而记忆库放在工作区之外才合理(它要跨会话、跨项目复用)。于是产生矛盾: **合理的位置写不进去,能写的位置不合理**,每次写记忆都得点一次同意。 **解法**:插件属于**可信宿主代码**,直接用 `node:fs` 读写、不经过 `ctx.fs` 那道围栏, 所以能把记忆读写做成"位置可配置、写入免审批"的工具。这不是钻空子—— DSH 自己的设计文档就写着:围栏拦的是「模型控制的路径」,「对抗性宿主进程不在范围内」。 **装插件本身就是一次授权。** 代价是插件写文件**没有沙箱兜底**,所以护栏必须比"提示词里的君子协定"更硬—— 见下面[护栏](#护栏),那些约束写在**代码**里,不是写在提示词里。 --- ## 安装 ```powershell pwsh -File .\install.ps1 ``` 脚本做三件事:语法自检源码 → 用官方 CLI 装进 profile → 打印确认。**装完需要重启 DSH。** 重启后,插件页里打开本插件,底部有一块「第一次启动」清单(实时显示记忆库与常驻段状态,两步操作带复制按钮)——从那里跟着走就不会漏掉初始化。 **脚本免配置** —— 它按下述顺序自己找 `dsh` CLI,不写死任何人的安装路径: 1. `-DshCmd` 参数 2. 环境变量 `DSH_CLI` 3. **从运行中的 DeepSeek Harness 进程推断**(装在哪儿都能找到) 4. 常见安装位置 都找不到时它会停下来,告诉你该传什么。手动等价命令(把 `<项目目录>` 换成你的路径): ```powershell dsh plugin --profile desktop add "<项目目录>" ``` **从 npm 安装**(已发布,包页:)——等价,只是来源换成 registry,不用先放目录: ```powershell dsh plugin --profile desktop add dsh-keep-memory ``` 升级用 `add dsh-keep-memory@latest`(profile 记的 `^` 范围不跨 minor),或卸载后重装;插件页对第三方插件没有「更新」按钮。装完都需要重启。 **从 Gitee 源码安装**(不经过 npm 时;**需要本机已装 git**,pnpm 要用它拉仓库): ```powershell dsh plugin --profile desktop add "git+https://gitee.com/yfymdkj/dsh-keep-memory.git#<40 位 commit>" ``` 把 `` 换成仓库里的完整 SHA(锁 commit 可复现);图省事用 `#master` 也行,但会跟着分支走。仓库在 。 卸载(**不会动你的记忆文件**): ```powershell pwsh -File .\uninstall.ps1 ``` --- ## 装完必须做的一步 ⚠️ **光装上插件,AI 不会知道有这套记忆系统**,也就不会主动用它。让 AI 跑一次: > 调 `memory_init`,把记忆库和常驻协议建起来 它会: 1. 建出 `INDEX.md` / `FACTS.md` / `PROTOCOL.md` 骨架(**已存在的绝不动**) 2. 在**用户全局 `~/.dsh/AGENTS.md`** 里幂等补一节「跨会话记忆」常驻段 —— 这段每轮都注入,是"让 AI 知道有记忆库"的唯一入口 3. 报告常驻段占用字节数(上限 2000) 之后随便开新会话,AI 都会带着这套协议。常驻段的文案就是 [PROTOCOL.md](PROTOCOL.md) 的浓缩版;想自定义可以拿 [AGENTS-TEMPLATE.md](AGENTS-TEMPLATE.md) 改。 --- ## 八个工具 | 工具 | 作用 | 会写盘吗 | | --- | --- | --- | | `memory_recall` | 读入口:INDEX + FACTS + 当天状态(scope: index/facts/today/all) | 否 | | `memory_note` | 追加一条到当天日记,自动建文件、自动补 INDEX 行;给了 `summary`/`takeaway` 会一并写进索引行 | 是(日记**仅追加**;摘要只动 INDEX) | | `memory_facts` | 写 FACTS.md:同名小节原地替换 / 唯一锚点字面替换 | 是 | | `memory_search` | 跨所有文件的字面检索(日期倒序优先,**含 INDEX 摘要行**) | 否 | | `memory_tidy` | 整理建议;`mode=apply` 才补 INDEX 缺行 + 回填「(待补)」摘要 | 仅 apply(只动 INDEX,不碰正文) | | `memory_check` | 体检:字节、BOM、死链、孤儿文件、常驻记忆块字节数 | 否 | | `memory_init` | 一键建起 INDEX/FACTS/PROTOCOL 骨架,并给**用户全局 AGENTS.md** 补常驻段(已存在的绝不动;`force=true` 才覆盖那一段) | 仅缺失时 | | `memory_config` | 记忆位置:`show` 查看 / `set` 只改指向 / `migrate` 复制并切换 | set、migrate | **摘要为什么重要**:`INDEX.md` 是给人(和 AI)扫的目录层,只记"有什么、在哪、值不值得看"。 摘要空缺时目录只剩骨架,也就失去意义。所以: - **推荐**:写日记时带 `summary`(人写,能放可检索的关键词) - **兜底**:`memory_tidy mode=apply` 从当天日记首行**机械回填**——适合救活历史遗留的空摘要, 但它**会覆盖已有摘要**,别对着人写过的摘要跑 --- ## 配置:记忆存哪里 **解析优先级(高 → 低)** | 顺序 | 来源 | 位置 | | --- | --- | --- | | 1 | **设置文件** | `$DSH_HOME\dsh-keep-memory.json`(即 `C:\Users\<你>\.dsh\dsh-keep-memory.json`) | | 2 | 环境变量 | `DSH_MEMORY_DIR` / `DSH_PERSONA_DIR` | | 3 | 出厂默认 | 记忆 = `$DSH_HOME\memory`;人设 = `$DSH_HOME`(全局 `AGENTS.md` 就在那儿) | 空白字符串不算有效设置(防止手滑写成空路径而把记忆指到盘符根目录)。 **为什么默认是 `$DSH_HOME\memory`,而不是「DSH 安装目录同级」**:安装目录可能在 `C:\Program Files`(普通用户**没有写权限**),也可能随卸载/重装被清理或搬走。 `$DSH_HOME` 是 DSH 自己的用户数据目录(会话、凭据、插件都在这儿),**一定可写**, 且不随安装位置变化。 **改地址** ``` memory_config action=show # 看当前生效路径与来源 memory_config action=set memoryDir=<新路径> # 只改指向,不搬文件 memory_config action=migrate memoryDir=<新路径> dryRun=true # 先预演,一个字节都不写 memory_config action=migrate memoryDir=<新路径> # 复制 + 校验 + 切换指向 ``` 也可以直接在**设置页 →「记忆位置」面板**上操作(显示当前路径/来源/文件数, 三个按钮:只改指向 / 预演迁移 / 迁移过去)。 **迁移的安全语义**(都写进代码,不靠自觉) - **原件一律保留** —— 永不移动、永不删除 - 目标同名且**内容相同** → 跳过(幂等,重跑安全) - 目标同名但**内容不同** → **报冲突,绝不静默跳过** (静默跳过会让你在"搬过去又搬回来"之后,悄悄搬来一份过期数据) - 冲突文件默认**不覆盖**;确认要用源覆盖时显式加 `overwrite=true` - 每个文件复制后**立刻比对字节数**,不一致记入失败清单 - **只要有失败或冲突,就不切换指向**(仍指向原目录,绝不留"搬了一半"的中间态) - `dryRun` 连目标目录都不创建,但**照样报冲突**(预演就该看见真问题) --- ## 护栏 写在**代码**里,不是写在提示词里。违反时的行为是明确的: | 护栏 | 违反时 | | --- | --- | | 日记**只追加**,无覆盖 API | 能力上不存在"清空今天" | | **只写当天** | 传过去/未来日期 → 直接拒绝并说明理由 | | 一律 **UTF-8 无 BOM** | 写入天然不带,`memory_check` 事后核验 | | FACTS **同名小节原地替换** | 不会出现两个版本的真相 | | 替换要求**锚点唯一** | 出现多次/找不到 → 抛错,**文件原样** | | INDEX 摘要**唯一定位**才改 | 缺行/重复 → 拒绝,不留半改 | | 摘要清洗 `\|` 与换行 | 不会撑坏 markdown 表格 | | `tidy` 默认 dry-run | 不写盘;`apply` 也**永不碰正文** | | `migrate` **只复制不移动** | 有冲突或失败 → **不切换指向** | --- ## 它**不会**做什么(重要) - **不会自动往记忆里写东西**。每次都是 AI 明确调用工具才写。 判断"什么值得记"的是**模型**,插件只负责落盘、去重、原地更新、防格式崩坏—— 它只有"手",没有"脑子"。 - **不会在会话开始时自动注入记忆内容**(这是 DESIGN 里的明确非目标)。 `AGENTS.md` 常驻段提供的是**操作协议**,不是自动喂记忆。 - **不会动你已有的记忆正文**。归档策略未定之前,`tidy` 只补索引、不改正文。 --- ## 测试 ```powershell node --test test/store.test.mjs test/search.test.mjs test/config.test.mjs test/integration.test.mjs test/tools.test.mjs test/settings.test.mjs test/routes.test.mjs ``` **共 80 个用例,分七层:** | 文件 | 覆盖 | | --- | --- | | `store.test.mjs` | 无 BOM 写入、追加语义、索引自动维护、FACTS 原地替换不吃掉邻节、唯一锚点替换的拒绝路径、AGENTS.md 常驻段的幂等插入与 force 覆盖边界、INDEX 摘要回填的唯一性/清洗/拒绝路径、手写索引行的判重/就地规范化/原文保留、`proposeSummary` 的表格安全 | | `search.test.mjs` | 检索排序与大小写、截断标记、片段裁剪、孤儿文件与死链识别、tidy 幂等 | | `config.test.mjs` | 本地日期(跨天/月末不串位)、路径解析与优先级、来源标记 | | `integration.test.mjs` | 四条端到端流程:初始化→记录→搜索→体检、tidy 幂等、被拒后文件原样、追加不乱序 | | `tools.test.mjs` | **工具层本身**:八个工具的名字与说明、真实落盘、拒绝路径、report 不写盘、`memory_init` 补 AGENTS.md 常驻段(幂等 + force)、`memory_config` 的 show/set/migrate | | `settings.test.mjs` | 设置文件读写与容错(缺失/损坏/非对象一律回退)、优先级、迁移的复制/校验/跳过/预演 | | `routes.test.mjs` | 设置页面板用的 HTTP 路由:`GET /config`、`POST /config`(只改指向)、`POST /migrate`(预演/冲突不切换指向)、未知路由 404 | `tools.test.mjs` 用 `test/resolve-stub.mjs` 把宿主包 `@deepseek-ai/dsh-tools` 解析到本地 stub, 所以**不需要安装插件、不需要宿主**就能测工具层。全部用例都在系统临时目录里跑, 并同时重定向 `DSH_HOME` 与 `DSH_MEMORY_DIR`(双保险),**绝不触碰真实记忆库**。 --- ## 已知边界 - 记忆位置**可配置**;不配则用出厂默认 `$DSH_HOME\memory` - 插件写文件**没有沙箱兜底** —— 这是免审批付出的代价,安全靠上面的护栏 - 改插件源码或装卸插件后**需要重启 DSH** 才生效(`link:` 形式不热更新已加载的模块) - `memory_init` 会写**用户全局 `AGENTS.md`**;它对所有会话生效、每轮注入, 所以常驻段预算严格限制在 2000 字节(`memory_check` 会核验) - GUI 设置面板需要宿主 `webServer` 服务;**headless profile 下只提供工具,不挂面板** - 安装脚本是 PowerShell,**目前只在 Windows 验证过** --- ## 授权 [MIT](LICENSE)