npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

dsh-plugin-memory

v0.7.0

Published

Long-term memory plugin for DeepSeek Harness: persistent cross-session markdown memory with a soul/persona file, auto-injected at every session start, plus remember/recall/consolidate/forget workflows and portable migration tooling.

Readme

dsh-plugin-memory

DeepSeek Harness 长期记忆插件:跨会话、可迁移、带「灵魂」的 markdown 记忆库。

English TL;DR — A Cordis plugin for DeepSeek Harness that gives agents a persistent, cross-session, migratable long-term memory: a markdown + git store (inspired by Karpathy's LLM Wiki pattern) with a SOUL.md persona file, auto-injected at every session start via the system-prompt runtime context, plus remember / recall / consolidate / forget workflows and portable CLI tooling.

特性

  • 开机强制注入(带路由表保护):插件通过 ctx.systemPrompt.context() 把记忆 boot 块(SOUL.md 人格 + MEMORY.md 协议 + index.md 目录 + 最近动态)注入会话上下文。宿主按投影去重:记忆不变就不重复注入,变化时新快照自动取代旧的——这是"新会话必先加载记忆"的硬保障,不需要模型碰运气调技能。总预算是 bootMaxChars按文件分配:每个文件先拿一份均分(受实际大小封顶),剩余额度优先给 index.md、再给尚有内容未注入的文件——所以记忆库长大时,目录的尾部不会先被截掉(详见「boot 预算分配」)。默认还带两道礼貌闸门deferUntilUserSpeaks(用户开口后才注入)与 activeSessionOnly(只注入当前激活会话),见「配置」。
  • last_access 自动戳记MEMORY.md 的 salience 衰减规则依赖 last_access,而它以前纯粹靠自觉——模板里有字段、规则里提到它,但没有任何代码去写它,于是每个页面都原地变老、衰减表形同虚设。现在会话收到第一条真实用户消息时,插件会把 boot 块实际注入过的页面SOUL.md / MEMORY.md / index.md + 目录里被引用到的页)戳成当天,每会话一次、按天幂等,只改 last_access 一行;dsh-memory touch <pages...> 可手动补记,trackPageAccess: false 可关闭。
  • SOUL.md 铸魂:安装后首要任务是和用户对话定义灵魂(名字、性格、价值观、语气、边界)、确认身份与关系(BOOTSTRAP.md 清单驱动,complete 前优先于常规任务)。
  • 铸魂自动引导:记忆库还没有灵魂(BOOTSTRAP.md 非 complete,或 SOUL.md 仍是占位模板)时,boot 块会自动前置一段第一人称引导词——「我的首要任务是确认我是谁,还有你是谁:我叫什么名字、怎么称呼你、你我是什么关系、我该是什么样的性格」——像 OpenClaw 初始化那样,由 agent 在对话里主动发起铸魂,逐项问、逐项写回,而不是等用户来喂。铸魂完成后引导词自动消失,零开销。
  • 复利记忆:遵循 Karpathy 的 LLM Wiki 约定——记忆是"一次编译、持续保鲜"的持久产物,不是每次查询重新 RAG。remember / recall / consolidate / forget 四操作 + salience 三级衰减。
  • 可迁移:记忆本体是纯 markdown + git + 自描述 schema,任何能读 markdown 的 agent 都能接手。dsh-memory pack/unpack 打包迁移。
  • 内嵌技能:通过 ctx.skills.register() 注册 memory 技能(操作协议随插件分发);项目级 .dsh/skills/memory 文件技能仍可覆盖它。
  • 防懒 digest 唤醒:每轮结束后,若 agent 空闲且记忆库超过 digestNudgeAfterMinutes 未写入,插件注入一条 digest 提醒(合成消息,走 agent.followup),把"会话收尾沉淀"从靠自觉变成有机制兜底;带冷却与每会话限次,不骚扰。独立于 dsh-plugin-heartbeat,两插件各自可装、互不依赖。
  • 主动追忆(拟人化):对话空下来时,插件会以第一人称主动提起一件真实记得的、关于用户或你们之间的事(偏好、往事、未了的决定、最近的进展),把记忆从"只写回"变成"也用起来"——像老友自然想起那样,而非报状态。间隔在最短/最长之间随机取值(不固定节奏),配合每会话限次,不骚扰、不编造、不硬聊;纯对话行为,不写记忆库。同样独立于 heartbeat
  • git 自动提交:记忆库变更静默 autoCommitQuietSeconds 后自动 git add -A && git commit(无 .git 则跳过)——历史可回滚不再依赖 agent 记得 commit。
  • 设置面板:在 DSH 设置页提供「记忆 Memory」区块——总开关、记忆目录、开机注入、技能注册、主动追忆(开关 + 随机间隔范围 + 每会话次数)均可热改,立即生效,无需重启。
  • index 自动整理(声明式编译):索引行不再手写。页面在 frontmatter 里声明 summary:dsh-memory index --write 把行重写为它的投影(标签 ≤32 / 摘要 ≤48 / 整行 ≤132 字符),只改行内容,分节与顺序逐字节保留,且幂等。index --check 给机器判定(有漂移退出码非 0),index --sync-frontmatter 把已写在 index 里的摘要回填进页面(老库一次性迁移)。digest 提醒会在索引漂移时附一句提示,agent 顺手就能修。
  • 记忆图谱:设置页里一张只读关系图 —— 不只是 index.md 那种"索引连着所有页"的星形,而是把页面已经编码但没人画出来的关系画出来:索引路由index.md 指向每一页——这是全库最大的边集,43 条;先前版本跳过了元文件,导致 index 在图上孤立无援)、页间显式 markdown 链接(含相对路径解析)、共享 frontmatter tag(通用容器 tag 如 project/skill 会被忽略,稠密 tag 走锚点链而非全连接)。坐标由服务端 lib/graph-layout.js 一次性算好(确定性、无随机、无依赖),客户端只负责画 SVG。可交互:滚轮缩放(以光标为中心,缩放范围 0.4×–2.5×,非 passive 监听所以不会连带滚动设置页)、拖空白处平移、重置视图 回到全图;按住节点即可拖走,直接邻居按距离轻微跟随,松手后带缓动滑回原布局——拖动期间暂停过渡做到 1:1 跟手,用 O(邻居数) 的局部松弛而不是逐帧全量力导向(后者在几百页时会卡)。悬停高亮邻里,首次渲染从中心绽开(尊重 prefers-reduced-motion)。图谱每 25 秒自动刷新(面板开着时记忆变更会自己出现,副标题显示「更新于 HH:MM:SS」);取数失败保留上一张图而不是清空。视图数学(zoomAt/panBy/toGraphPoint)在 lib/graph-view.js 里是纯函数并有测试——缩放中心不漂移这件事必须被钉住。GET /api/memory/graph(只读、实时,?types=1 追加同类型弱边)。三类边在图上可区分:页间互链=实线蓝、索引路由=灰色虚线、共享 tag=细线。
  • 记忆健康看板:同一区块下方是一张只读看板——记忆页数 / index 路由数 / 记忆字数、访问新鲜度条形图(今天 / ≤7 / ≤30 / ≤90 / >90 天)、四项体检结论(index 链接、孤儿页、frontmatter、新鲜度)与健康分、陈旧页候选、最近 5 条动态。数据来自新增的 GET /api/memory/insights(每次请求实时统计,不缓存),体检口径与 dsh-memory lint 同源,所以看板与 CLI 不会互相打脸。
  • 零构建:纯 ESM JavaScript,无编译步骤,pnpm add 即用。

架构

插件只拥有工作流,不拥有数据格式

dsh-plugin-memory(本插件)
├── lib/index.js        # Cordis 入口:boot 注入 + 运行时技能注册 + settings 热改
├── lib/boot.js         # boot 块渲染(SOUL/MEMORY/index + 最近 log,按文件分配预算)
├── lib/pages.js        # 页面访问记账:extractReferencedPages / touchPages(last_access)
├── lib/insights.js     # 记忆健康看板的数据层(页数/分布/新鲜度/体检,只读)
├── lib/activity-tracker.js # 两道礼貌闸门:用户是否开口 + 当前激活会话
├── lib/digest-guard.js # 防懒 digest 唤醒(空闲 + 记忆库久未写 → followup 提醒)
├── lib/recall-nudge.js # 主动追忆(空闲 → 第一人称提起一件真实往事,纯对话不写库)
├── lib/scaffold.js     # 记忆库脚手架(模板只建不覆盖)
├── lib/client.js       # 客户端半:设置面板「记忆 Memory」区块 + 记忆健康看板
├── skills/memory.md    # 内嵌技能的操作协议正文
└── scripts/memory.mjs  # CLI:init/search/touch/lint/status/pack/unpack

记忆库(用户数据,默认 ~/.memory)
├── SOUL.md       # 人格与灵魂(用户主导)
├── BOOTSTRAP.md  # 铸魂清单(complete 前优先)
├── MEMORY.md     # schema 与维护协议(自描述)
├── index.md      # 页面目录    log.md # 时间线(append-only)
├── identity/ user/ skills/ decisions/ projects/{active,archive}/ concepts/
└── raw/          # 不可变源材料

安装

dsh plugin --profile <profile> add dsh-plugin-memory

(包内置 dsh.bundle manifest,dsh plugin add 会把它自动挂进 profile 的 bundles 层;dsh-market 里的一键安装同此通道。)

重启 profile(DSH Desktop 重启应用)后生效。

⚠️ 不要再往 profile 的 cordis.patch.yml 里手写 - insert: {id: dsh-memory, ...}: 那会与 bundle manifest 的自动挂载产生两条同名 entry,整个 profile 会以 duplicate loader entry id "dsh-memory" 启动失败(2026-08-18 实机事故)。 运行期配置(enabled / memoryDir / autoInject / registerSkill / recallEnabled)改走 <dshHome>/memory.json(设置面板热改);composition 配置见下表。 如需覆盖某个 composition 键,用不带 insert 的 id 覆盖条目(见配置一节)。

配置

| 键 | 默认值 | 含义 | |---|---|---| | enabled | true | 总开关:关闭后不注入 boot 块、不注册 memory 技能 | | memoryDir | ~/.memory | 记忆库绝对路径(~ 自动展开) | | bootFiles | [SOUL.md, MEMORY.md, index.md] | 开机注入的文件 | | bootMaxChars | 12000 | boot 块总字符预算(防止占用过多上下文);按文件分配见下文 | | bootFileBudgets | — | 逐文件字符上限,例如 { index.md: 3500 };未列出的文件分剩余额度(composition 层,改完需重启) | | trackPageAccess | true | 会话首条用户消息时,把 boot 块实际注入的页面戳 last_access(关闭后衰减表需手动维护) | | autoInject | true | 会话开始时注入 boot 块 | | deferUntilUserSpeaks | true | 用户发出第一条真实消息后才注入(boot 块 / 追忆 / digest 提醒都遵守);面板可热改 | | activeSessionOnly | true | 只对「当前激活会话」(最近收到用户消息的会话)注入,后台会话不打扰;面板可热改 | | registerSkill | true | 注册内嵌 memory 技能 | | scaffold | true | 记忆库缺失时自动创建模板(只建不覆盖) | | configFile | <dshHome>/memory.json | 用户可改配置的 JSON 文件路径(设置面板读写它) | | digestNudgeEnabled | true | 防懒 digest 提醒总开关(composition) | | digestNudgeAfterMinutes | 120 | 记忆库超过多久未写入就提醒 | | digestNudgeCooldownMinutes | 180 | 两次提醒的最小间隔 | | digestNudgeMaxPerSession | 2 | 每个会话最多提醒次数 | | recallEnabled | true | 主动追忆总开关(面板可热改) | | recallIntervalMinMinutes | 30 | 随机间隔下限(分钟,面板可热改) | | recallIntervalMaxMinutes | 240 | 随机间隔上限(分钟,面板可热改) | | recallMaxPerSession | 3 | 每个会话最多追忆次数(面板可热改) | | autoCommit | true | 记忆库 git 自动提交开关(composition) | | autoCommitQuietSeconds | 60 | 变更静默多久后提交(防抖) | | autoCommitIntervalSeconds | 60 | 变更轮询间隔 |

设置面板(热改)

enabled / memoryDir / autoInject / deferUntilUserSpeaks / activeSessionOnly / registerSkill / recallEnabled / recallIntervalMinMinutes / recallIntervalMaxMinutes / recallMaxPerSession 十项在 DSH 设置页的「记忆 Memory」区块中可改,即时生效:boot 注入、两道礼貌闸门、技能注册、主动追忆(含随机间隔与次数)随修改立即生效;记忆目录切换时自动为新目录初始化脚手架(scaffold: true 时)。其余键(bootFiles / bootMaxChars / bootFileBudgets / trackPageAccess / scaffold / configFile / digestNudge* / autoCommit*)只在 composition 配置层生效,改完需重启。

boot 预算分配(为什么 index 不会先被截掉)

bootMaxChars 是总预算,按文件分配而不是简单平摊:

  1. bootFileBudgets 条目的文件先拿自己的额度;
  2. 其余文件各拿一份均分额度,以文件实际大小封顶——短文件把用不完的额度退回池子;
  3. 池子再补给「还有内容没注入」的文件(每个最多补到均分额度的两倍):index.md 优先,其余按体积降序——所以截断落在哪个文件上由体积决定,而不是由 bootFiles 的书写顺序决定。

当每个文件都小于均分额度时,结果与旧的平摊规则逐字节相同;只有记忆库长大后才会不同。这也意味着:index.md 是路由表,别把它写成摘要表——它会被完整注入,膨胀的代价是挤掉人格与其他记忆。

「当前激活会话」怎么判? DSH 宿主侧没有「浏览器当前聚焦的会话」信号(激活会话是前端概念)。插件用最近一次收到真实用户消息的 live root agent作为激活会话的代理:你在哪个会话里说话,哪个会话就激活;切到别处但不发消息时,宿主感知不到「切换」这个动作(这是代理的已知边界)。若日后需要精确到「展开/聚焦」级别,需补一小段客户端 focus 上报。

记忆健康看板

设置页「记忆 Memory」区块下方是一张只读看板,数据来自 GET /api/memory/insights

| 展示 | 含义 | |---|---| | 记忆页 / index 路由 / 记忆字数 | 记忆库规模(字数按字符计,中文不会按字节虚高 3 倍) | | 健康分(0–100) | 由孤儿页、缺 salience/type、陈旧页、失效 index 链接加权得出 | | 访问新鲜度条形图 | 今天 / ≤7 / ≤30 / ≤90 / >90 天 / 从未戳记(驱动自 last_access 自动戳记) | | 四项体检 | index 链接完整、无孤儿页、frontmatter 完整、访问新鲜度——口径与 dsh-memory lint 同源 | | 陈旧页候选 | 超过 90 天或从未戳记的页面,按陈旧度排序(前 8) | | 最近动态 | log.md 最新 5 条标题 |

看板是实时的:每次打开设置页(或改完任一配置项后)重新拉取,不落盘、不缓存、不写记忆库。头less 部署没有 webServer 时该路由与看板都不存在,其余功能不受影响。

覆盖 composition 键(例如把 boot 块预算调大),在 profile 的 cordis.patch.yml 里写不带 insert 的 id 覆盖条目

- id: dsh-memory
  config:
    bootMaxChars: 12000

实现说明:DSH 的 settings wire 只服务硬编码的命名空间白名单,插件命名空间写不进去,因此本插件走自建通道——配置存 <dshHome>/memory.json(schema 校验 + 原子落盘),由插件自注册的 GET/POST /api/memory/config 路由服务,客户端区块 fetch 直连。

首次使用:铸魂

插件安装后,第一次会话里 agent 的首要任务不是干活,而是与你对话定义它的灵魂:名字、性格、价值观、语气、边界,以及你的身份与你们的关系。逐项确认并写回 SOUL.md / user/profile.md,直到 BOOTSTRAP.mdstatus 变为 complete。你可以随时跳过或暂缓。

四个操作

  • remember(记):把值得持久化的内容蒸馏成页面,同步更新 index.md、追加 log.md。维护 index 时守路由表纪律:一行一页、一句话摘要(≤ 80 字)+ salience
  • recall(忆):会话开始读 boot 块;查询时先查 index.md 再钻页;必要时 dsh-memory search <关键词>
  • consolidate(整理)dsh-memory lint 查矛盾、孤儿页、该归档的冷页;dsh-memory status 看陈旧页分布。
  • forget(忘):显式遗忘立即执行;自动衰减按 salience + last_access(冷页优先归档)。last_access 由插件自动维护,无需手改。

CLI

dsh-memory init [dir]                 # 创建记忆库脚手架
dsh-memory search <query> [--touch]   # 全文检索(--touch 给命中页戳 last_access)
dsh-memory touch [pages...]           # 手动戳 last_access(不带参数 = 全部页面)
dsh-memory lint                       # 完整性体检
dsh-memory status                     # 健康概览(含陈旧页统计)
dsh-memory pack [out.tar.gz]          # 打包导出(含 manifest)
dsh-memory unpack <archive> [--force] # 从归档恢复

存储定位顺序:$MEMORY_DIR./.memory(存在时)→ ~/.memory

迁移

记忆库是纯 markdown + git:拷贝即迁移。跨机器 / 跨 agent / 能力降级档位见 docs/MIGRATION.md

常见问题

Q:和手写的 .dsh/skills/memory 文件技能(skill 版)什么关系? skill 版是"软保障"(技能目录只注入简介,正文靠模型主动加载);本插件是"硬保障"(boot 块随系统提示词运行时上下文自动注入)。两者可共存:文件技能(rank 100)会覆盖插件内嵌技能(rank 250)的协议。如果你之前为了软保障改过系统提示词 persona(如 profile 补丁里的开机指令),装上本插件后建议移除那段 persona,避免双份注入。

Q:boot 块会不会每次请求都重复注入、烧 token? 不会。运行时上下文按投影去重:内容不变只注入一次;记忆更新后新快照取代旧快照。

Q:记忆库放在哪里最合适? 默认 ~/.memory(全局、跨项目)。需要按项目隔离时,把 memoryDir 配到项目内,或让 agent 在项目里维护 .memory/

Q:可以加密吗? 记忆含敏感内容时,可把 memoryDir 放进加密卷 / 私有仓库。格式不变,插件无感知。

开发

git clone https://github.com/LittleBlackTong/dsh-plugin-memory.git
cd dsh-plugin-memory
node scripts/memory.mjs --self-test   # 冒烟测试(无需安装依赖)

零构建:lib/ 直接是运行时代码,lib/types/index.d.ts 供 TS 消费方使用。boot.js / scaffold.js 只依赖 node:* 内置模块,可独立复用。

路线图

  • [ ] TypeScript 重写(带完整类型与构建步骤)
  • [ ] embedding/BM25 检索(规模超过几百页后替代 index 先行)
  • [ ] MCP server(让非 DSH 的 agent 也能用同一套记忆库)
  • [ ] GitHub Actions CI(跑 --self-test 与 lint)
  • [ ] 记忆加密存储选项

欢迎在 Issues 里提需求、报 bug、交 PR。

License

MIT