dsh-memory-center
lornberry/dsh-memory-center
Local long-term memory for DSH: browse, search (BM25 + synonyms) and edit entries in a panel; folders, archive and a recycle bin; choose per session what to inject; model-written memories need your approval; import/export backups; optionally sync across devices via your own Git or WebDAV.
インストール
dsh plugin --profile web add github:lornberry/dsh-memory-centerREADME
dsh-memory-center(记忆中心)
DSH 的「长期记忆」面板插件:你自己看得见、改得动、决定要不要给模型用。
- 数据位置:自动探测——按「
DSH_MEMORY_DIR环境变量 → 面板里记住的选择 → 已有store.json的老目录 → 本机 DSH 数据根<DSH_HOME>/memory→ 各盘符\dsh-data\memory→~/.dsh/memory」的顺序找,都不行才落临时目录兜底;面板「存储位置」里可以随时改。没有写死任何盘符。 - 代码位置:本目录(本地 bundle,通过
plugin_manager install_bundle安装)。 - 依赖:无。不联网、不调外部 API、不需要 token;只有一个本地 JSON 存储。
装完用着不对、想要某个功能、或者只是想说说体验?开 Issue 或在 Discussions 里聊。版本号、DSH 版本、报错原文贴上来最快。
安装
-
克隆到本机任意目录:
git clone https://github.com/LornBerry/dsh-memory-center.git -
打包成一份固定副本(自测 → 打 tgz):
node dev/release.mjs -
用 DSH 的插件管理装这个 tgz:
plugin_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:<当前端口>(核对副本、版本、哈希、接口、目录可写)。 -
刷新 Web GUI:侧栏出现「记忆」,设置里出现「记忆库」。
-
刷新 Web GUI:侧栏出现「记忆」,设置里出现「记忆库」。
更新与本地开发
装的是固定副本,不是软链——这是有意的:先前用 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里那份副本,下次安装会被覆盖。 - 想发 npm 包:去掉
package.json的"private": true→npm version patch→npm publish;市场按 npm latest 展示,与本地 tgz 安装互不影响。 - 每次改完记得
git add -A && git commit && git push,并打 tag(如v0.4.1)作为回滚点。
面板增强(v0.5.0)
- 批量操作二次确认:删除、全部转正、清空回收站这类一次改动多条的动作,都会先弹窗写清「影响几条、能不能撤销」,不再是点一下就执行。
- Markdown 实时预览:编辑记忆时可在「编辑 / 预览」之间切换,支持标题、列表、加粗、行内代码、代码块、引用、链接、分割线;保存后卡片里也按 Markdown 渲染。
- 底部批量操作条:勾选后从底部浮出「已选 N 条」,移动、打标、启停、置顶、转正、加入本会话、删除都在手边。
- 排序:工具栏一个下拉,四个选项:「默认顺序 / 按首字母顺序 / 按修改时间顺序 / 按创建时间顺序」;置顶条目无论正倒序都恒在最前。
- 回收站:删除先移入回收站(数据仍在
store.json,只是带deletedAt隐藏),可单条/批量恢复、彻底删除、清空回收站。彻底删除才写墓碑用于跨设备同步。 - 搜索:命中的标题与正文高亮;搜不到时给空状态提示和「清空搜索」。
- 锚点配色:完全锚点用橙红 + 实心点(硬性规则),权重锚点用蓝绿(软性倾向),一眼能分清。
- 空状态引导:空文件夹、待确认为空、回收站为空、搜不到,各有文案与「新建 / 导入 / 清空搜索」按钮。
- 视图切换:工具栏可切「卡片 / 列表」——卡片看长文本,列表一屏扫二十条标题。
- 没有引入 Alpine.js 之类的第二套框架:整个 Web GUI 由 React 渲染,再挂一套模板框架会抢同一个 DOM、导致重复渲染与状态错乱。这里的局部刷新由插件自己的 store + React 状态更新完成,效果等价且不破坏宿主页面。
加固(v0.2.1)
- 库文件坏了不再让插件永久卡死:第一次请求报错并指出文件路径(文件不动),第二次把坏文件挪进
<数据目录>/backups/corrupt-<时间>.json再重建空库;修好文件后无需重启就能读。 - 切换数据目录落到一个已有记忆的目录时改为合并而不是覆盖,先把目标原文件备份成
<目标目录>/backups/pre-switch-<时间>.json。 - 注入去重同时检查那条 recall 消息是否还在上下文里,被压缩裁掉后会重新注入。
- 面板接口要求
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、批量与切换合并。
备份(v0.7.7)
三类自动备份统一放在数据目录下的 backups/,不再散落在数据目录根上:
| 备份 | 什么时候产生 |
|---|---|
corrupt-<时间>.json | 读 store.json 失败、自动重建空库之前,把坏文件挪过来(只挪不改) |
pre-switch-<时间>.json | 切换数据目录、且目标目录已有记忆、准备合并之前 |
pre-purge-<时间>.json | 回收站按天自动清理、真要删条目前 |
- 每种只留最近 5 份(按文件修改时间),超出自动删掉,不会无限堆积。
- 老版本留在数据目录根上的
store.json.corrupt-*会在下次加载时自动挪进backups/。 - 面板「存储位置」/回收站区域可看备份数量与占用体积,并提供「清理旧备份」;接口
backups.prune(可指定keep)与backups.clear只删这三类文件,store.json/sessions.json/config.json一个都不碰。
会话自动归档(v0.3.0)
- 同一个会话里模型写到第 2 条记忆时,自动建一个「与会话标题同名」的文件夹,把这批候选记忆一起放进去;状态仍是「待确认」,还是要你点「转正」才生效。
- 第 1 条留在「未归类」;第 2 条起自动连同前面的同会话条目一起归档,不用手动拖。
- 会话标题优先取宿主给的标题;没有就取本轮第一条用户消息(压空白、超 24 字截断加
…),和 GUI 侧栏标题同源。 - 同名文件夹直接复用;你自己手动拖过的条目不会被覆盖。自测见
dev/memory-write.test.mjs。
锚点:完全 / 仅权重(v0.4.0,v0.7.0 起自动初判)
- 每条记忆有一个「锚点」:不启用、完全锚点、仅权重。
- 完全锚点 = 必须完全照此执行/表达,不得偏离(适合硬规矩,如「只用中文回答」「接口必须带 X 头」)。
- 仅权重 = 只作为输出倾向的权重,影响措辞与优先级、允许偏离(适合语气、风格、偏好)。
- 新建时自动判断:不用每条都手动点。插件看标题/正文/标签里的措辞——
「必须 / 禁止 / 只写 / 切记 / 不要」等 → 完全锚点;
「喜欢 / 尽量 / 统一 / 约定 / 默认」等 → 仅权重;
都没有 → 不启用(普通事实)。硬性优先于软性,判断错了随手改一下即可。
安全类词(密码 / 凭据 / 隐私 /
api key/secret/password,大小写不敏感)只要和「不要 / 禁止 / never」同现就一律判完全锚点,避免「别把 API key 提交上去」被当成普通事实。 像「不能超过 260 字符」「不能正常启动」这种描述性否定只算事实;只有和「以后 / 每次 / 一律 / 都要 / 记住」这类立规矩词同现才升级为完全锚点——「默认 / 一般 / 通常」这类技术常见词不算立规矩信号。 - 判断有理由:徽标上悬停能看到「插件按内容初判:命中硬性措辞:必须」,或「你手动设置」。
- 你改过就归你:手动设过锚点的记忆以后改正文不会被自动改掉;插件判的那类,内容变了会自动重判。
- 右键「更多… → 锚点」里可以手动三选一,或点「↻ 按内容重新判断」;批量选中后底部栏也有「重判锚点」。
- 注入时条目行前会带
〔完全锚点〕/〔权重锚点〕标记,顶部有一行规则说明;面板卡片上也有对应徽标。 - 自测见
dev/anchor-infer.test.mjs(判断规则)与dev/anchor.test.mjs(注入影响)。
你会看到什么
| 位置 | 组件 | 作用 |
|---|---|---|
| 左侧栏 | 「记忆」文字入口 | 打开「记忆中心」主面板(收起侧栏时这行只有一个「记忆」小牌子) |
| 设置 → 记忆库 | 设置内页 | 同一个记忆库的完整管理界面(嵌入版,隐藏「返回对话」) |
| 输入框左侧 | 「记忆」chip | 显示本会话加载了几条;点开弹层可一键切 不加载 / 全部 / 某个文件夹,或「按条选…」只挑几条具体记忆 |
| 输入框上方 | 记忆卡片 | 新会话(还没决定时)出现:「选记忆…」弹层里既能整组勾文件夹,也能逐条勾记忆,不用分类也不影响 |
| 主面板 | 资源管理器式 | 左栏文件夹、右栏条目;拖拽卡片到文件夹即移动、勾选多选后批量移动/停用/删除、右键或悬停「…」出菜单、顶部面包屑回上级 |
| 主面板 →「存储位置」 | 存储设置 | 设置页顶部与主面板左栏底部的库路径都可点即复制,旁边「更改…」打开此弹窗;弹窗里路径输入框可直接编辑,旁边有「复制」和「选择…」;改完点「应用」才切换(默认把现有记忆复制过去),选择记在数据目录内的 config.json |
| 主面板 →「云端同步」 | 同步设置 | 三选一:不绑定 / Git 仓库 / WebDAV 网盘。默认「不绑定」,记忆只在本机 |
跨设备(可选,默认关闭)
记忆本体永远在本机的数据目录里,云端只是「多设备共用同一份」。三种选择:
| 选项 | 适合谁 | 代价 |
|---|---|---|
| 不绑定(默认) | 只在一台机器用,或者接受手动导出导入 | 换设备看不到;一个字节都不外发 |
| Git 仓库 | 有 GitHub / Gitee / 自建 git 的人 | 需要建一个私有仓库、配一次凭据。换来完整历史、可回滚、冲突按条目合并 |
| WebDAV 网盘 | 坚果云 / Nextcloud / 群晖用户 | 没有历史版本,只有一个 store.json;撞车时后写的赢 |
- 开了之后:打开面板时自动拉取(可关),改动后 4 秒自动上传(可关),也可以随时点「立即同步」。
- 冲突规则:按条目合并——同一条记忆两边都改,
updatedAt新的赢;删除会记墓碑,不会在另一台设备上「复活」。 - 输掉的那一版不会凭空消失:每次自动拉取把本地覆盖掉之前,都会把本机的
store.json复制成<数据目录>/backups/conflict-<时间>-git.json(Git)或conflict-<时间>-webdav.json(WebDAV),只保留最近 5 份。同步状态里会显示「已保留本机改动 N 次」,要捞就按时间找这个文件。 - 大小:一条记忆几百字节,一万条也就几 MB;Git 侧只存增量,不会越存越满。
- Git 侧的实现细节:数据目录下会多出
.git-sync/repo(影子仓库),config.json和sessions.json不入库(前者含本机凭据,后者只对本机会话有意义)。 - WebDAV 的账号密码存在本机
config.json里(明文);.gitignore已经把config.json排除在 Git 之外,但走 WebDAV 时它就在本机文件里。 - 新装第一次打开时,「待确认」里会有一条「跨设备记忆需要开同步」的提醒,说明去哪绑、不绑也能用;它不参与注入,删掉也不会补回,绑定入口一直在面板工具栏和设置页里。
整理与安全(v0.5.0)
- 回收站:删除只是软删除,条目从列表和注入里消失,但仍留在
store.json;左栏「回收站」里可以单条或批量恢复,也可以彻底删除或清空回收站。只有彻底删除才会写墓碑(跨设备同步时不会在另一台机器上复活)。回收站默认保留 30 天,过期的软删除条目在下次加载时自动彻底删除(同样写墓碑);回收站底栏可以直接改保留天数(不自动清理 / 7 / 30 / 90 / 180 天),写进config.json的recycleDays、改完立即生效,并用「占用约 X 字符」显示回收站体积;也可以用DSH_MEMORY_RECYCLE_DAYS固定天数(0= 永不自动清理,设了环境变量时面板里只读)。 改小天数会立刻永久删除,所以下拉不是一点即生效:前端先带dryRun: true问后端「按新天数会清掉几条」,有命中就弹确认框写明条数与标题,确认后才真正执行;后端在删除前会把整库复制成<数据目录>/backups/pre-purge-<时间>.json,事后仍可人工捞回。 - 删除记录(墓碑)也会过期:彻底删除会留一条「这条删过」的记录,用于跨设备同步时阻止旧副本复活。这些记录默认保留 90 天,回收站底栏会显示条数,并提供两个按钮:「清理 90 天前」只清够老的,「清空删除记录」则一次清空全部(都要二次确认)。急着腾空间可以提前清,但还有设备很久没同步过时别清——那台设备上的旧副本可能因此被推回来。天数可用
DSH_MEMORY_TOMBSTONE_DAYS固定。 - 二次确认:批量删除、彻底删除、全部转正、清空回收站这类一次影响多条的动作,都会先弹窗写明「影响 N 条、能否撤销」,点错了按取消即可,不产生任何改动。
- 底部操作栏:勾选任意卡片后,屏幕底部浮出「已选 N 条 | 移动到… / 打标 / 停用 / 转正 / 加入本次会话 / 删除」,不用再回到顶部找按钮。
- 打标:批量添加标签时只往里加,不覆盖已有标签,也不会重复。
- Markdown 预览:编辑弹窗里可在「编辑 / 预览」之间切换,列表、加粗、代码块直接看到渲染结果。
- 排序:默认顺序 / 按首字母顺序(A→Z)/ 按修改时间顺序(新→旧)/ 按创建时间顺序(新→旧);置顶的条目恒在最前。
- 视图:卡片视图适合读长文本,列表视图一屏能扫二十多条标题,顶部一键切换。
- 空状态:空文件夹、没有待确认、回收站为空、搜不到结果,都会给出对应文案与下一步操作,不会是空白页。
- 锚点颜色:〔完全锚点〕用橙红、〔权重锚点〕用蓝色,扫一眼就能分清硬性要求和倾向性备注。
检索(v0.6.0)
- 相关度排序,不再「包含这个字才算」:分词(中文二元组 + 拉丁词)后按 BM25 打分,标题命中权重更高,长文不会因为字数多就压过短标题;结果按分数排序,并给出一段命中的原文片段。
- 同义词扩展:内置「存哪 / 放哪 / 路径 / 目录」「转正 / 确认 / 生效」「删了 / 回收站」等常见口语组,查询会自动按半权重扩展召回,说「存哪」也能找到写着「存储位置」的条目。你自己的说法可以在「设置 → 记忆库 → 同义词…」里加:一行一组、词之间用空格或逗号隔开,存进
config.json的synonyms,保存后下一次搜索就生效(不用重启)。 - 可以加自己的说法:在
<数据目录>/config.json里写"synonyms": [["说法A", "说法B"], ["另一个", "同义"]],每条是字符串数组,重启 DSH 后生效;内置组始终保留。 - 面板搜索框、
memory_search工具、写入前的重复检查用的是同一套检索,所以「搜不到但模型说有」这类不一致不会再出现。 - 归档与回收站里的条目默认不参与检索,需要时在参数里显式带上
includeArchived。 - 列表只传摘要(v0.10.3):面板拿到的每个条目只有标题、标签、状态和正文前 120 字(
excerpt),正文要点开才读(item.get)。归档区和回收站也一样——它们只增不减,整段传正文会让快照越用越大。
同主题新旧标注(v0.9.0)
记忆用久了,难免同时存在两套说法(「记忆放 C 盘」和后来的「记忆放 E 盘」)。两条都启用着时,模型读到旧的那条就会照错的执行,所以这里做了标注:
- 会自动认出「讲同一件事」的几条:按标题/正文的词集合重叠度判断(偏保守,宁可漏判也不硬凑),只在都启用、都没归档的条目之间比较。
- 注入时标〔旧版〕:同一组里按修改时间取最新,最新的正常显示,其余在标题下面加一行「〔旧版,YYYY-MM-DD 有过更新;同主题以「…」为准〕」,整段头部还会多一句统一说明。
- 检索结果也带标注:
memory_search命中的如果是旧版,行尾会写「〔旧版,同主题以「…」为准〕」,避免检索反而加深旧结论。 - 面板上看得见:条目上出现黄色「旧版」徽标,悬停能看到最新的是哪条;左栏底部会显示「同主题 N 组 · 旧版 M 条 → 点此选中」,一下选中所有过时条目,方便归档或改写。
- 改一下就不算旧版了:直接编辑旧版那条(改内容会更新
updatedAt),它就变回最新;真正没用的就归档,别让两套说法并存。 - 同一分钟内写入的不标新旧(同一批写入,没有谁更权威)。
- 快,但有上限:每条记忆只分词一次,候选对靠倒排表筛(只比「至少共享一个词」的对),3000 条以内打开面板即可出结果(1000 条约 40ms)。超过 3000 条时只对最近更新的 3000 条做识别,其余条目不标旧版——1 万条实测从 5.2 秒降到 0.3 秒,代价是超大库里很久没动过的条目不再参与识别。
关键行为
- 像 Windows 文件夹那样整理:左栏点文件夹进入(面包屑可点回「记忆」);把卡片拖到左栏文件夹 = 移动;勾选多条 = 批量条(移动到 / 停用 / 启用 / 置顶 / 转正 / 加入本会话 / 删除);文件夹行悬停出「…」、右键也有菜单(带入本会话 / 重命名 / 上移 / 下移 / 删除)。
- 新会话默认加载什么,你说了算(v0.8.0):默认是「每次都问」——没决定过的会话不注入任何记忆,输入框上方出现卡片让你选。嫌烦就去面板工具栏「新会话默认」下拉选「不加载 / 全部加载 / 当前会话选的文件夹」,设过一次之后新会话不再弹卡片;想改回来选「每次都问」。单个会话自己的选择永远优先于这个默认。
- 两种粒度随便选:不喜欢分类就按条挑——新会话卡片的「选记忆…」、输入框「记忆」弹层的「按条选…」,都能勾整个文件夹(组里以后新增的条目会自动带上),也能只勾几条具体记忆;两种可以混着选(下一轮生效)。
- 中途导入:chip 弹层「导入记忆…」或面板工具栏「导入」,都支持粘贴 JSON、合并预览、重复跳过。
- 模型写入需你确认:模型调用
memory_write写入的条目先落「待确认」;同一会话第 2 条起会自动放进以会话标题命名的文件夹(仍待确认)。点左栏「待确认」页签,顶部有「全部转正 / 存放到…并全部转正 / 全部删除」兜底,单条也可以右键「存放到文件夹」+「转正」。转正后才参与注入。 - 注入内容可见:每次注入以一条消息出现在对话里(就是你现在看到的这段),面板里也能「预览注入」查看全文。
- 手动整理:文件夹改名/上移下移/删除(条目移入未归类或一起删)、条目移动文件夹、置顶、停用、标签自由编辑、搜索、导出 JSON / Markdown。
- 临时不想让它带记忆:面板工具栏(设置页也有一处)的「暂停注入」按一下会问你暂停范围——「暂停所有会话」或「只暂停当前会话」。暂停后记忆不再进入对话,库里数据一点不动;再按一下恢复,单会话暂停会原样还原它之前的选择(原本没选过的会话恢复后回到「会先问你」)。多个会话连着做别的事、又不想让记忆掺进来时用它,比逐个会话选「不加载」省事。
模型侧工具
memory_search:检索已启用的记忆(标题 / 正文 / 标签子串)。memory_write:写入候选记忆。新记忆先落「待确认」,模型不能指定文件夹;同一会话第 2 条起自动放进「会话标题」文件夹(仍待确认)。你在面板里右键条目「存放到文件夹」或点「转正」即可。- 判断顺序是「关键词为主、自判为辅」:用户明说「记一下」直接写;命中偏好/固定事实/拍板决策的关键词就写(只排除明显只对这一次有效的临时状态);没命中关键词再四问自判是否跨会话有用。单次对话最多 3 条,标题写结论、正文带具体值与原因。
模型写入的护栏(v0.9.6)
- 同一会话里模型最多写 5 条待确认记忆;写第 6 条会被直接拒绝并提示先转正或清理。防的是模型循环写入把待确认区塞爆。
- 后台动作失败(备份、清理、同步、回收站定时清理)不再静默吞掉:记进
<数据目录>/errors.jsonl(最多留 100 条),并在设置页顶部列出最近几条。 - 记忆正文里的 markdown 只把
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 记录每个会话的选择:{ "<sessionId>": { "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 就进入压缩,剩下 20% 留给统计行、索引进清单和以后新增的记忆,避免"刚加一条就爆"。面板左下角那条进度条显示的就是「已用 / 压缩线」,变成橙色就说明正在压缩;点它能看到容量画像,容量画像里那条拉条就是改阈值的入口(优先级:环境变量 > 面板里拖的值 > 默认 0.8)。容量画像里「最长的几条」每行都有「定位」(跳到它所在的文件夹并选中)和「归档」(立刻让它退出注入、可随时还原)两个按钮——这就是实际减量的两种动作,不用先在列表里翻。
自动探测的顺序:DSH_MEMORY_DIR → 候选目录里已有的 config.json(记住的选择,不可写则跳过)→ 已经存了 store.json 的老目录 → 已存在的 <盘符>:\dsh-data\memory(本机 DSH 数据在这个盘上就跟它放一起)→ <DSH_HOME>/memory → 各盘符 \dsh-data\memory → ~/.dsh/memory → 系统临时目录。<DSH_HOME> 取环境变量 DSH_HOME,其次从 DSH_PROFILE_DIR 上溯两级,最后退回 ~/.dsh。
想先看看会选到哪,可以跑:node dev/paths.test.mjs;宿主半的读写/切换行为可以跑:node dev/host-smoke.mjs(用临时目录,不碰真实记忆库)。
卸载
plugin_manager → remove_bundle → dsh-memory-center;数据目录自行保留或删除。
开发与自测
-
装进 profile 的是
dev/release.mjs打出的固定副本;改完源码要重新release.mjs+install_bundle才生效。 -
一键发版:
node dev/release.mjs(自测 → 升版本 → 打包 → 打印安装命令);node dev/doctor.mjs --url <端口>做安装/运行期自检。 -
离线自测(不需要浏览器、不需要 react,Node 22+ 即可):
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 条时面板单次渲染耗时 -
接口自测(端口换成你当前 DSH Web GUI 的端口):
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。 -
需求与验收标准:见 SPEC.md。