dsh-timem-memory 底层原理(高中小白友好版)

August 18, 2026 · View on GitHub

目标读者:没有任何编程背景、只想弄懂「这个插件到底是怎么被安装、被启动、被使用的」的人。 读完这篇,你能向别人讲清楚三件事:包是什么、安装装到了哪里、DSH 是怎么把它「叫醒」的。


0. 一句话总览

npm 装的是「货物」,cordis 条目负责「开灯」。 装包只是把文件搬到你电脑上; 让 DSH 真正使用它,需要在配置文件里写一条「启动指令」。


1. 包(Package)是什么:App Store 里的一个 App

我们的插件本质是一个 npm 包——一个按照固定格式打包的文件夹。

dsh-timem-memory/
├── package.json   ← 「商品说明书」:名字、版本、入口文件、随包附带的文件清单
├── lib/index.js   ← 「发动机」:apply() 函数,DSH 叫醒它时执行的代码
├── skills/        ← 「附赠的说明书包」:5 份教 AI 何时搜记忆/写记忆的 SKILL.md
├── README.md      ← 使用说明
└── LICENSE        ← 授权协议

npm registry(registry.npmjs.org)就是软件界的 App Store。 npm install dsh-timem-memory 的含义 = 「从 App Store 下载这个 App」。

  • 下载的方式有三种,货物都一样,只是「发货渠道」不同:
    渠道命令(由 DSH 转交给 pnpm)
    npm 官方商店(发布后)dsh plugin add dsh-timem-memory
    GitHub 仓库dsh plugin add git+https://github.com/auuduu/dsh-timem-memory.git
    本地打包文件dsh plugin add ./dsh-timem-memory-0.1.0.tgz

dsh plugin add 内部其实就是把参数转交给 pnpm(另一个包管理器), pnpm 负责下载、解压、放到正确位置。


2. 安装装到了哪里:node_modules 货架与「找包规则」

每个项目/每个 DSH profile 都有一个 node_modules 目录——货架。 pnpm 把包解压进货架:

~/.dsh/profiles/<profile>/node_modules/
├── dsh-timem-memory/          ← 我们的插件被放在这里
└── @deepseek-ai/…             ← DSH 官方组件也在同一个货架

Node.js 找包的规则很像学校失物招领:你在 3 班丢了东西, 先查 3 班的失物柜,没有就查年级的,再查全校的。

  • 插件代码里写 import '@deepseek-ai/dsh-mcp-client'(「我要用 MCP 客户端组件」)时, Node 从插件自己所在的目录开始,一层一层往上找 node_modules,找到为止。
  • 所以一个包里写了依赖什么,只要货架上(任意一层)有货,就能找到。

关键点:npm install 到此为止——货物上架了。但还没有人用它。


3. DSH 怎么「叫醒」它:cordis 条目 = 启动器里的勾选框

DSH 是一个基于 Cordis 的「插件启动器」。像游戏启动器管理 mod 一样, 它读一份配置文件,决定「哪些插件要启用、按什么顺序启用」。

我们在 cordis.patch.yml 里写的这条:

- insert:
    - id: timem-memory        # 起个内部名字
      name: 'dsh-timem-memory'  # 告诉启动器:去货架上找这个包

就是那个勾选框。启动时(或配置热更新时)启动器执行三步:

  1. 找货:按 namenode_modules 里找到这个包;
  2. 验货:读 package.json,找到入口文件(main: lib/index.js);
  3. 点火:调用入口文件导出的 apply(ctx, config) 函数,并给它一个「上下文遥控器」(ctx)。

apply() 一跑起来,插件就活了:

apply() 干两件事:
① 向「凭证管家」ctx.credentials 要 TiMEM 的钥匙(X-API-Key / X-TiMEM-User-Id)
   → 用钥匙拨通 TiMEM 云端 MCP 服务器
   → 把服务器的 17 个工具登记到 AI 的工具清单里(mcp__timem__search_memories …)
② 读包内 skills/*/SKILL.md
   → 把 5 份「记忆使用说明书」注册进 DSH 的 skill 体系
   → AI 看到它们后,学会「每回合先搜记忆、干完活写记忆」

4. MCP 是什么:给 AI 配的「统一遥控器接口」

AI 模型本身只会「说话」,不会做事。工具(tools) 是它的手。

  • 每个工具都有名字和参数表。DSH 的 MCP 客户端把 TiMEM 服务器的工具 以 mcp__timem__搜索记忆 的形式登记:mcp__timem__search_memories
  • 双下划线命名的含义:mcp__<服务器名>__<工具名>——像「遥控器__空调__制冷」, 这样即使两个服务器都有叫 search 的按钮也不会混淆。
  • AI 决定调用 mcp__timem__search_memories 时,DSH 通过 MCP 协议 (一套标准化的 JSON 对话格式)把请求发到 TiMEM 服务器,拿到结果再喂回给 AI。

5. 密钥为什么安全:保险箱 + 管家模式

坏设计:把 API Key 直接写进配置文件 → 配置文件一分享就泄密。

我们的设计

配置文件只写:       「钥匙名叫 TiMEM_API_KEY」(一句引用,不是钥匙本身)
真正的钥匙存在:      ~/.dsh/.credentials.yaml(权限 0600 = 只有你本人可读写)
运行时有一个「凭证管家」服务 ctx.credentials:
  插件问管家「我要 TiMEM_API_KEY」→ 管家按优先级查找 → 递上钥匙

优先级:启动时注入的环境变量 > 凭证保险箱 > 项目 .env > 用户 .env。

更妙的是:你在网页端改了钥匙,管家会广播「钥匙换了」事件, 插件听到后自动断开旧连接、用新钥匙重连——不用重启


6. skill 是什么:贴在 AI 脸上的「工作流程便签」

17 个工具只是「手」。但 AI 需要知道什么时候用哪只手——这就是 skill 的作用。

  • skill = 一份 Markdown 说明书(SKILL.md),写着「何时触发、按什么步骤做、何时跳过」。
  • DSH 的 skill 注册表(ctx.skills)把所有说明书汇总成一个目录发给 AI。
  • 我们的插件用 ctx.skills.register() 把 5 份说明书注册进去 (provider 标记为 runtime,表示「由插件在运行时提供,而非散落在磁盘上」)。
  • AI 看到 timem-coding-memory 的说明后,编码时就会自动执行: 「回答前先 search_memories → 干活 → 回答后 create_memory」。

7. 三个值得记住的坑(工程实践)

  1. 装包 ≠ 启用:npm install 只是上架;cordis 条目才是勾选框。两者缺一不可。
  2. ESM 模块缓存:运行中的 DSH 进程「记住」了旧插件代码; 改完插件要重启 dsh web 冷启动才生效(配置热更新对已缓存的模块无能为力)。
  3. 一条命令的两半dsh plugin add <包> 管「上架」,改 cordis.patch.yml 管「勾选」。 DSH 会热加载配置文件,所以改勾选不用重启——但新勾选的包如果进程里没缓存,稳妥起见也重启一次。

8. 把整个链路串起来(一句话版)

别人拿到你的仓库 → dsh plugin add git+https://github.com/auuduu/dsh-timem-memory.git 把货架上架 → 在 cordis.patch.yml 写一条 dsh-timem-memory 条目(勾选)→ 填好两把钥匙(TiMEM_API_KEY / TiMEM_USER_ID)→ 重启 → AI 就有了 17 只手(mcp__timem__* 工具)+ 5 张便签(记忆 skill),开始自动记忆。