Pular para o conteúdo principal
L

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.

Instalar

dsh plugin --profile web add github:lornberry/dsh-memory-center

README

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 版本、报错原文贴上来最快。

安装

  1. 克隆到本机任意目录:

    git clone https://github.com/LornBerry/dsh-memory-center.git
    
  2. 打包成一份固定副本(自测 → 打 tgz):node dev/release.mjs

  3. 用 DSH 的插件管理装这个 tgz:plugin_manager,action=install_bundle,target 填打印出来的 .tgz 绝对路径。 装完 profile 的 package.json 里是一条 file: 依赖,node_modules/dsh-memory-center 是一份真实目录副本。

  4. 自检一遍:node dev/doctor.mjs --url http://127.0.0.1:<当前端口>(核对副本、版本、哈希、接口、目录可写)。

  5. 刷新 Web GUI:侧栏出现「记忆」,设置里出现「记忆库」。

  6. 刷新 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 秒,代价是超大库里很久没动过的条目不再参与识别。

关键行为

  1. 像 Windows 文件夹那样整理:左栏点文件夹进入(面包屑可点回「记忆」);把卡片拖到左栏文件夹 = 移动;勾选多条 = 批量条(移动到 / 停用 / 启用 / 置顶 / 转正 / 加入本会话 / 删除);文件夹行悬停出「…」、右键也有菜单(带入本会话 / 重命名 / 上移 / 下移 / 删除)。
  2. 新会话默认加载什么,你说了算(v0.8.0):默认是「每次都问」——没决定过的会话不注入任何记忆,输入框上方出现卡片让你选。嫌烦就去面板工具栏「新会话默认」下拉选「不加载 / 全部加载 / 当前会话选的文件夹」,设过一次之后新会话不再弹卡片;想改回来选「每次都问」。单个会话自己的选择永远优先于这个默认。
  3. 两种粒度随便选:不喜欢分类就按条挑——新会话卡片的「选记忆…」、输入框「记忆」弹层的「按条选…」,都能勾整个文件夹(组里以后新增的条目会自动带上),也能只勾几条具体记忆;两种可以混着选(下一轮生效)。
  4. 中途导入:chip 弹层「导入记忆…」或面板工具栏「导入」,都支持粘贴 JSON、合并预览、重复跳过。
  5. 模型写入需你确认:模型调用 memory_write 写入的条目先落「待确认」;同一会话第 2 条起会自动放进以会话标题命名的文件夹(仍待确认)。点左栏「待确认」页签,顶部有「全部转正 / 存放到…并全部转正 / 全部删除」兜底,单条也可以右键「存放到文件夹」+「转正」。转正后才参与注入。
  6. 注入内容可见:每次注入以一条消息出现在对话里(就是你现在看到的这段),面板里也能「预览注入」查看全文。
  7. 手动整理:文件夹改名/上移下移/删除(条目移入未归类或一起删)、条目移动文件夹、置顶、停用、标签自由编辑、搜索、导出 JSON / Markdown。
  8. 临时不想让它带记忆:面板工具栏(设置页也有一处)的「暂停注入」按一下会问你暂停范围——「暂停所有会话」或「只暂停当前会话」。暂停后记忆不再进入对话,库里数据一点不动;再按一下恢复,单会话暂停会原样还原它之前的选择(原本没选过的会话恢复后回到「会先问你」)。多个会话连着做别的事、又不想让记忆掺进来时用它,比逐个会话选「不加载」省事。

模型侧工具

  • 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_CHARS12000单次注入上限(硬上限,超出按码点截断)。面板里也能调:容量弹窗的「注入上限」拉条(4000–50000,步进 1000),拖完点「应用」立即生效并写进 config.json;设了这个环境变量时拉条只读
DSH_MEMORY_COMPRESS_RATIO0.8压缩阈值:记忆总量超过「上限 × 该比例」就开始压缩(超出部分只给标题),0.1–1 之间。面板里也能调:容量弹窗有拉条(10%–100%,步进 5%),拖完点「应用」立即生效并写进 config.json;设了这个环境变量时拉条只读
DSH_MEMORY_RECYCLE_DAYS30回收站保留天数:过期条目在下次加载时被彻底删除(并写墓碑);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。

Plugins relacionados