dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
DSH 的本地长期记忆库:面板里浏览、检索(BM25 + 同义词)、编辑;文件夹、归档、回收站;逐会话决定注入哪些;模型写入的记忆需你确认;可导入导出备份;可选同步到自己的 Git 或 WebDAV 实现多设备。
DSH 的「长期记忆」面板插件:你自己看得见、改得动、决定要不要给模型用。
DSH_MEMORY_DIR 环境变量 → 面板里记住的选择 → 已有 store.json 的老目录 → 本机 DSH 数据根 /memory → 各盘符 \dsh-data\memory → ~/.dsh/memory」的顺序找,都不行才落临时目录兜底;面板「存储位置」里可以随时改。没有写死任何盘符。plugin_manager install_bundle 安装)。装完用着不对、想要某个功能、或者只是想说说体验?开 Issue 或在 Discussions 里聊。版本号、DSH 版本、报错原文贴上来最快。
git clone https://github.com/LornBerry/dsh-memory-center.gitnode dev/release.mjsplugin_manager,action=install_bundle,target 填打印出来的 .tgz 绝对路径。装完 profile 的 package.json 里是一条 file: 依赖,node_modules/dsh-memory-center 是一份真实目录副本。
node dev/doctor.mjs --url http://127.0.0.1:(核对副本、版本、哈希、接口、目录可写)。装的是固定副本,不是软链——这是有意的:先前用 link: 安装时,源码目录一旦被清空或移动,DSH 下次启动就找不到插件,面板整块消失(2026-10-23 真实发生过)。
更新是显式两步:
node dev/release.mjs # 自测 + 升版本 + 打包,打印 install_bundle 的 target
# 然后 plugin_manager action=install_bundle target=<新 tgz>client.js 改动重新安装后刷新页面即生效;index.js(宿主半)改动需重启 DSH。没有构建步骤。node_modules/dsh-memory-center 里那份副本,下次安装会被覆盖。package.json 的 "private": true → npm version patch → npm publish;市场按 npm latest 展示,与本地 tgz 安装互不影响。git add -A && git commit && git push,并打 tag(如 v0.4.1)作为回滚点。store.json,只是带 deletedAt 隐藏),可单条/批量恢复、彻底删除、清空回收站。彻底删除才写墓碑用于跨设备同步。/backups/corrupt-.json 再重建空库;修好文件后无需重启就能读。/backups/pre-switch-.json。application/json 且同源(或 Origin 缺省 / null),Sec-Fetch-Site 只认 same-origin/none,跨站页面既不能读也不能写。item.batch;导入条目顺序连续编号;超长注入按码点截断;Git 命令 30 秒超时、不弹交互式密码提示;会话记录按 180 天清理。dev/resilience.test.mjs,dev/host-smoke.mjs 覆盖 415/403、无效 groupId、批量与切换合并。三类自动备份统一放在数据目录下的 `backups/`,不再散落在数据目录根上:
备份 · 什么时候产生 corrupt-.json · 读 store.json 失败、自动重建空库之前,把坏文件挪过来(只挪不改) pre-switch-.json · 切换数据目录、且目标目录已有记忆、准备合并之前 pre-purge-.json · 回收站按天自动清理、真要删条目前
store.json.corrupt-* 会在下次加载时自动挪进 backups/。backups.prune(可指定 keep)与 backups.clear 只删这三类文件,store.json / sessions.json / config.json 一个都不碰。…),和 GUI 侧栏标题同源。dev/memory-write.test.mjs。「必须 / 禁止 / 只写 / 切记 / 不要」等 → 完全锚点; 「喜欢 / 尽量 / 统一 / 约定 / 默认」等 → 仅权重; 都没有 → 不启用(普通事实)。硬性优先于软性,判断错了随手改一下即可。 安全类词(密码 / 凭据 / 隐私 / api key / secret / password,大小写不敏感)只要和「不要 / 禁止 / never」同现就一律判完全锚点,避免「别把 API key 提交上去」被当成普通事实。 像「不能超过 260 字符」「不能正常启动」这种描述性否定只算事实;只有和「以后 / 每次 / 一律 / 都要 / 记住」这类立规矩词同现才升级为完全锚点——「默认 / 一般 / 通常」这类技术常见词不算立规矩信号。
〔完全锚点〕 / 〔权重锚点〕 标记,顶部有一行规则说明;面板卡片上也有对应徽标。dev/anchor-infer.test.mjs(判断规则)与 dev/anchor.test.mjs(注入影响)。位置 · 组件 · 作用 左侧栏 · 「记忆」文字入口 · 打开「记忆中心」主面板(收起侧栏时这行只有一个「记忆」小牌子) 设置 → 记忆库 · 设置内页 · 同一个记忆库的完整管理界面(嵌入版,隐藏「返回对话」) 输入框左侧 · 「记忆」chip · 显示本会话加载了几条;点开弹层可一键切 不加载 / 全部 / 某个文件夹,或「按条选…」只挑几条具体记忆 输入框上方 · 记忆卡片 · 新会话(还没决定时)出现:「选记忆…」弹层里既能整组勾文件夹,也能逐条勾记忆,不用分类也不影响 主面板 · 资源管理器式 · 左栏文件夹、右栏条目;拖拽卡片到文件夹即移动、勾选多选后批量移动/停用/删除、右键或悬停「…」出菜单、顶部面包屑回上级 主面板 →「存储位置」 · 存储设置 · 设置页顶部与主面板左栏底部的库路径都可点即复制,旁边「更改…」打开此弹窗;弹窗里路径输入框可直接编辑,旁边有「复制」和「选择…」;改完点「应用」才切换(默认把现有记忆复制过去),选择记在数据目录内的 config.json 主面板 →「云端同步」 · 同步设置 · 三选一:不绑定 / Git 仓库 / WebDAV 网盘。默认「不绑定」,记忆只在本机
首次装好后库里会有一份样例:3 条记忆 + 1 个「项目约定」文件夹,用来演示锚点、标签和文件夹怎么用。样例的 id 是固定的(m-seed-1…m-seed-3、g-seed),所以两台设备各自首装、之后再开同步,合并时能按 id 对齐,不会把样例变成两份;播种也只发生一次(记在 config.json 的 seeded),把条目删干净后重启不会复活。
记忆本体永远在本机的数据目录里,云端只是「多设备共用同一份」。三种选择:
选项 · 适合谁 · 代价 不绑定(默认) · 只在一台机器用,或者接受手动导出导入 · 换设备看不到;一个字节都不外发 Git 仓库 · 有 GitHub / Gitee / 自建 git 的人 · 需要建一个私有仓库、配一次凭据。换来完整历史、可回滚、冲突按条目合并 WebDAV 网盘 · 坚果云 / Nextcloud / 群晖用户 · 没有历史版本,只有一个 store.json;撞车时后写的赢
updatedAt 新的赢;删除会记墓碑,不会在另一台设备上「复活」。store.json 复制成 /backups/conflict--git.json(Git)或 conflict--webdav.json(WebDAV),只保留最近 5 份。同步状态里会显示「已保留本机改动 N 次」,要捞就按时间找这个文件。.git-sync/repo(影子仓库),config.json 和 sessions.json 不入库(前者含本机凭据,后者只对本机会话有意义)。config.json 里(明文);.gitignore 已经把 config.json 排除在 Git 之外,但走 WebDAV 时它就在本机文件里。面板不会把密码原文回传到前端(只显示「已保存,留空则不修改」),改密码留空即保持原密码。store.json;左栏「回收站」里可以单条或批量恢复,也可以彻底删除或清空回收站。只有彻底删除才会写墓碑(跨设备同步时不会在另一台机器上复活)。回收站默认保留 30 天,过期的软删除条目在下次加载时自动彻底删除(同样写墓碑);回收站底栏可以直接改保留天数(不自动清理 / 7 / 30 / 90 / 180 天),写进 config.json 的 recycleDays、改完立即生效,并用「占用约 X 字符」显示回收站体积;也可以用 DSH_MEMORY_RECYCLE_DAYS 固定天数(0 = 永不自动清理,设了环境变量时面板里只读)。改小天数会立刻永久删除,所以下拉不是一点即生效:前端先带 dryRun: true 问后端「按新天数会清掉几条」,有命中就弹确认框写明条数与标题,确认后才真正执行;后端在删除前会把整库复制成 /backups/pre-purge-.json,事后仍可人工捞回。
DSH_MEMORY_TOMBSTONE_DAYS 固定。config.json 的 synonyms,保存后下一次搜索就生效(不用重启)。/config.json 里写 "synonyms": [["说法A", "说法B"], ["另一个", "同义"]],每条是字符串数组,重启 DSH 后生效;内置组始终保留。memory_search 工具、写入前的重复检查用的是同一套检索,所以「搜不到但模型说有」这类不一致不会再出现。includeArchived。excerpt),正文要点开才读(item.get)。归档区和回收站也一样——它们只增不减,整段传正文会让快照越用越大。记忆用久了,难免同时存在两套说法(「记忆放 C 盘」和后来的「记忆放 E 盘」)。两条都启用着时,模型读到旧的那条就会照错的执行,所以这里做了标注:
memory_search 命中的如果是旧版,行尾会写「〔旧版,同主题以「…」为准〕」,避免检索反而加深旧结论。updatedAt),它就变回最新;真正没用的就归档,别让两套说法并存。memory_write 写入的条目先落「待确认」;同一会话第 2 条起会自动放进以会话标题命名的文件夹(仍待确认)。点左栏「待确认」页签,顶部有「全部转正 / 存放到…并全部转正 / 全部删除」兜底,单条也可以右键「存放到文件夹」+「转正」。转正后才参与注入。〔记忆快照 #N〕);如果上下文里还留着上一轮的注入、这一轮又只改了少数几条,就只发变化(〔记忆更新 #N〕 + 新增/改动/移除),不再把全文重发一遍。普通条目在增量里单条最多 400 字,超了会写「还有 N 字没展开」;完全锚点照给全文(最多 4000 字,超了会提示先 memory_search 取完整内容)。宿主压缩上下文或重启之后,下一轮自动回到全量。面板左栏底部会显示「增量 · 上一轮 153 字(省 98%)」或「全量 · 上一轮 6.2k 字」。想先观察再启用,可以设 DSH_MEMORY_RECALL_DRY=1,只记日志不真的注入。memory_search:检索已启用的记忆(标题 / 正文 / 标签子串)。memory_write:写入候选记忆。新记忆先落「待确认」,模型不能指定文件夹;同一会话第 2 条起自动放进「会话标题」文件夹(仍待确认)。你在面板里右键条目「存放到文件夹」或点「转正」即可。/errors.jsonl(最多留 100 条),并在设置页顶部列出最近几条。http:、https:、file: 渲染成可点链接,javascript:、data: 之类一律降级成纯文本。store.json){
"version": 1,
"groups": [{ "id": "g-xxxx", "name": "项目约定", "order": 0, "createdAt": "..." }],
"items": [{
"id": "m-xxxx", "title": "...", "body": "...", "tags": ["约束"],
"groupId": "g-xxxx", "enabled": true, "pinned": false,
"status": "active", "source": "manual", "order": 0,
"createdAt": "...", "updatedAt": "..."
}]
}sessions.json 记录每个会话的选择:{ "": { "mode": "none|all|custom", "groupIds": [], "itemIds": [], "decidedAt": "..." } }。
变量 · 默认 · 说明 DSH_MEMORY_DIR · 自动探测 · 显式指定数据目录(设了就最高优先,面板里锁为只读) DSH_MEMORY_CONFIG · /config.json · 记录面板里选择的配置文件路径(默认就放在数据目录里,切换目录时新老两处都会更新) DSH_MEMORY_MAX_CHARS · 12000 · 单次注入上限(硬上限,超出按码点截断)。面板里也能调:容量弹窗的「注入上限」拉条(4000–50000,步进 1000),拖完点「应用」立即生效并写进 config.json;设了这个环境变量时拉条只读 DSH_MEMORY_COMPRESS_RATIO · 0.8 · 压缩阈值:记忆总量超过「上限 × 该比例」就开始压缩(超出部分只给标题),0.1–1 之间。面板里也能调:容量弹窗有拉条(10%–100%,步进 5%),拖完点「应用」立即生效并写进 config.json;设了这个环境变量时拉条只读 DSH_MEMORY_RECYCLE_DAYS · 30 · 回收站保留天数:过期条目在下次加载时被彻底删除(并写墓碑);0 表示永不自动清理。设了它以后面板底栏的下拉变成只读;不设时以面板里选的天数为准
压缩是怎么工作的:全量注入按 完全锚点 → 权重锚点 → 置顶 → 越新越先 排序装载,装不下的条目退化成「只有标题」的索引,并提示模型需要时用 memory_search 取全文。默认压缩线是上限的 80%,也就是 12000 字符里用到 9600 就进入压缩;正文和「只有标题」的索引清单一起装进这条压缩线以内(索引标题先按码点裁到 60 字、标签裁到 40 字),所以把阈值拖到 30%,注入长度就真的跟着降到 30%——不会出现「怎么拖都一样、都卡在硬上限」那种假滑杆。撑不下的条目先降级成索引,索引也装不下就只报「共 N 条」,硬上限只作最后兜底。面板左下角那条进度条显示的就是「已用 / 压缩线」,变成橙色就说明正在压缩;点它能看到容量画像,容量画像里那条拉条就是改阈值的入口(优先级:环境变量 > 面板里拖的值 > 默认 0.8)。容量画像里「最长的几条」每行都有「定位」(跳到它所在的文件夹并选中)和「归档」(立刻让它退出注入、可随时还原)两个按钮——这就是实际减量的两种动作,不用先在列表里翻。
自动探测的顺序:DSH_MEMORY_DIR → 候选目录里已有的 config.json(记住的选择,不可写则跳过)→ 已经存了 store.json 的老目录 → 已存在的 :\dsh-data\memory(本机 DSH 数据在这个盘上就跟它放一起)→ /memory → 各盘符 \dsh-data\memory → ~/.dsh/memory → 系统临时目录。` 取环境变量 DSH_HOME,其次从 DSH_PROFILE_DIR 上溯两级,最后退回 ~/.dsh。 想先看看会选到哪,可以跑:node dev/paths.test.mjs;宿主半的读写/切换行为可以跑:node dev/host-smoke.mjs`(用临时目录,不碰真实记忆库)。
plugin_manager → remove_bundle → dsh-memory-center;数据目录自行保留或删除。
dev/release.mjs 打出的固定副本;改完源码要重新 release.mjs + install_bundle 才生效。node dev/release.mjs(自测 → 升版本 → 打包 → 打印安装命令);node dev/doctor.mjs --url 做安装/运行期自检。node dev/smoke-client.mjs它内置一个微型 hook 渲染器,逐个渲染各插槽组件并检查注册拓扑与页面文案,输出 SMOKE OK 表示通过。
node dev/paths.test.mjs # 数据目录会探测到哪
node dev/host-smoke.mjs # 宿主半 API 与目录切换
node dev/merge.test.mjs # 两台设备的条目级合并规则
node dev/sync.test.mjs # WebDAV 后端(本地假服务器)
node dev/sync-git.test.mjs # Git 后端(本地裸仓库扮远端,模拟两台设备)
node dev/anchor.test.mjs # 完全锚点 / 权重锚点
node dev/encoding.test.mjs # 无 BOM、无乱码(提交前必跑)
node dev/memory-write.test.mjs
node dev/resilience.test.mjs
node dev/synonyms.test.mjs # 同义词面板:保存即生效、非法输入被拒、重载后仍在
node dev/search-regression.test.mjs # 检索效果回归集:22 条真实记忆 + 26 个查询,改了分词/权重/同义词必须跑
node dev/render-bench.mjs 2000 # 渲染基准(只报数字,不断言):2000 条时面板单次渲染耗时node dev/patrol.mjs --url http://127.0.0.1:<port>检查接口可达、快照不带 body、注入预算自洽、lastInject 字段、数据目录可写、store.json 存在、sync.get 不回传明文密码。输出 PATROL OK 表示运行期全绿;任一项 FAIL 退出码非 0。
node dev/doctor.mjs --url → DOCTOR OK(版本、四文件哈希、接口、数据目录)node dev/patrol.mjs --url → PATROL OK(运行期契约)〔记忆快照 #N〕;改一条记忆后下一轮出现 〔记忆更新 #N〕;不改动则不再重复注入node dev/recall.test.mjs 离线覆盖,升级后跑一次即可curl -X POST http://127.0.0.1:<port>/dsh-memory/api -H "content-type: application/json" -d '{"op":"state"}'可用 op 见 index.js 的 switch (op):state / group.* / item.* / session.* / session.default / budget.set / deleted.prune / import.preview / import.apply / export / search / config.get / config.set / sync.get / sync.set / sync.now / recycle.set / backups.list。