🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

分层记忆库 DDDFXYqiming/dsh-layered-memory

DeepSeek Harness
DDDFXYqiming3 天前有提交已提供中文文档扫描:含敏感能力

DeepSeek Harness 的跨会话长期记忆插件

36/100
综合分
3
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/11/3 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

自动兼容检查有告警:未发布到 npm registry,仅可从源码安装。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add DDDFXYqiming/dsh-layered-memory
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · ui
装得上吗
本站已真实安装成功
非静态推断
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 3 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查⚠ 装前注意

未发布到 npm registry,仅可从源码安装

展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✗npm 包@dsh-external/dsh-layered-memory(未发布到 npm,仅可源码安装)
✓Node 引擎要求 >=22.19 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/31 10:22:31

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

读写/删除本地文件发起外部网络请求
查看扫描证据(共 78 处,展示前 66 条)
  • 读取本地文件
    src/apply.js:78
    const version = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version;
  • 发起网络请求
    src/apply.js:181
    requestMaintenance: (namespace, exec, report) => maintenance.request(nsRoot(cfg.memoryDir, namespace), namespace, exec.agent, {
  • 发起网络请求
    src/apply.js:213
    review: (agent, activity) => maintenance.request(resolveRoot(agent.session.header.cwd), resolveNamespace(cfg, undefined, agent.session.header.cwd), ag
  • 读取本地文件
    src/store.js:56
    try { return readFileSync(path, "utf8"); }
  • 读取本地文件
    src/store.js:66
    try { return readdirSync(dir).filter(name => name.endsWith(".md")).sort(); }
  • 写入本地文件
    src/store.js:71
    mkdirSync(root, { recursive: true });
  • 写入本地文件
    src/store.js:73
    for (const dir of ["sops", PENDING_DIR, ARCHIVE_DIR, HISTORY_DIR]) mkdirSync(join(root, dir), { recursive: true });
  • 读取本地文件
    src/store.js:75
    if (!existsSync(join(root, name))) atomicWriteFileSync(join(root, name), content);
  • 读取本地文件
    src/store.js:78
    if (identity && !existsSync(join(root, ".namespace.json"))) atomicWriteFileSync(join(root, ".namespace.json"), JSON.stringify(identity, null, 2));
  • 写入本地文件
    src/store.js:84
    mkdirSync(root, { recursive: true });
  • 写入本地文件
    src/store.js:98
    for (const root of roots) mkdirSync(root, { recursive: true });
  • 删除本地文件
    src/store.js:122
    if (item.previous === null) rmSync(item.path, { force: true });
  • 删除本地文件
    src/store.js:126
    } finally { for (const item of staged) rmSync(item.tmp, { force: true }); }
  • 读取本地文件
    src/store.js:168
    if (existsSync(path)) return null;
  • 读取本地文件
    src/store.js:369
    try { files = readdirSync(join(root, HISTORY_DIR)); }
  • 写入本地文件
    src/store.js:551
    mkdirSync(target, { recursive: true });
  • 读取本地文件
    src/maintain.js:111
    if (includeArchived && existsSync(archive)) {
  • 读取本地文件
    src/maintain.js:112
    for (const file of readdirSync(archive).filter(file => file.endsWith(".md"))) {
  • 读取本地文件
    src/maintain.js:113
    docs.push({ kind: "archive", name: file, title: file, archived: true, text: readFileSync(join(archive, file), "utf8") });
  • 读取本地文件
    src/l1index.js:13
    return existsSync(path) ? migrateIndexPolicy(readFileSync(path, "utf8")) : "";
  • 读取本地文件
    src/l1index.js:13
    return existsSync(path) ? migrateIndexPolicy(readFileSync(path, "utf8")) : "";
  • 读取本地文件
    src/l1index.js:22
    if (!existsSync(join(root, "rules.md"))) return sections(readIndex(root)).rules;
  • 读取本地文件
    src/tools.js:117
    if (existsSync(path)) {
  • 读取本地文件
    src/tools.js:118
    const content = readFileSync(path, "utf8");
  • 读取本地文件
    src/tools.js:251
    const readState = name => existsSync(join(root, name)) ? JSON.parse(readFileSync(join(root, name), "utf8")) : null;
  • 读取本地文件
    src/tools.js:251
    const readState = name => existsSync(join(root, name)) ? JSON.parse(readFileSync(join(root, name), "utf8")) : null;
  • 读取本地文件
    src/tools.js:254
    history_files: existsSync(history) ? readdirSync(history).filter(name => name.endsWith(".md") || name.endsWith(".json") && !name.endsWith(".meta.json"
  • 读取本地文件
    src/tools.js:254
    history_files: existsSync(history) ? readdirSync(history).filter(name => name.endsWith(".md") || name.endsWith(".json") && !name.endsWith(".meta.json"
  • 写入本地文件
    src/tools.js:268
    mkdirSync(join(root, ARCHIVE_DIR), { recursive: true });
  • 写入本地文件
    src/tools.js:269
    copyFileSync(join(root, PENDING_DIR, name), join(root, ARCHIVE_DIR, key));
  • 删除本地文件
    src/tools.js:271
    rmSync(join(root, PENDING_DIR, name));
  • 发起网络请求
    src/events.js:83
    return maintenance.request(root, namespace, agent, { purpose: "batch", trigger: { kind: "automatic", turn, endSeq }, report });
  • 读取本地文件
    src/activity.js:104
    try { runs = JSON.parse(readFileSync(join(nsRoot(cfg.memoryDir, current), "maintenance-runs.json"), "utf8")).runs; }
  • 读取本地文件
    src/store-service.js:35
    const snapshot = JSON.parse(readFileSync(path, "utf8"));
  • 读取本地文件
    src/store-service.js:44
    const file = readFileSync(path, "utf8");
  • 读取本地文件
    src/store-service.js:50
    const sidecar = JSON.parse(readFileSync(path.replace(/ md$/, ".meta.json"), "utf8"));
  • 写入本地文件
    src/atomic-write.js:8
    writeFileSync(tmp, content, { encoding, flag: "wx" });
  • 删除本地文件
    src/atomic-write.js:11
    rmSync(tmp, { force: true });
  • 写入本地文件
    src/atomic-write.js:17
    try { renameSync(tmp, filePath); }
  • 删除本地文件
    src/atomic-write.js:18
    finally { rmSync(tmp, { force: true }); }
  • 删除本地文件
    src/process-lock.js:19
    try { rmdirSync(path); }
  • 读取本地文件
    src/process-lock.js:27
    try { info = lstatSync(path); }
  • 读取本地文件
    src/process-lock.js:33
    const [name] = readdirSync(path);
  • 读取本地文件
    src/process-lock.js:37
    return { directory, ownerPath, owner: JSON.parse(readFileSync(ownerPath, "utf8")) };
  • 删除本地文件
    src/process-lock.js:49
    try { unlinkSync(lock.ownerPath); }
  • 读取本地文件
    src/process-lock.js:52
    if (!lock.directory && error.code === "EPERM" && lstatSync(path).isDirectory()) return true;
  • 写入本地文件
    src/process-lock.js:62
    mkdirSync(candidate);
  • 写入本地文件
    src/process-lock.js:63
    writeFileSync(join(candidate, ownerFile), JSON.stringify({ id, pid: process.pid, host: hostname(), startedAt: new Date().toISOString() }));
  • 写入本地文件
    src/process-lock.js:73
    try { renameSync(candidate, path); acquired = true; break; }
  • 读取本地文件
    src/process-lock.js:77
    try { lstatSync(path); }
  • 删除本地文件
    src/process-lock.js:86
    if (!acquired) { unlinkSync(join(candidate, ownerFile)); rmdirSync(candidate); }
  • 删除本地文件
    src/process-lock.js:86
    if (!acquired) { unlinkSync(join(candidate, ownerFile)); rmdirSync(candidate); }
  • 删除本地文件
    src/process-lock.js:88
    return () => { unlinkSync(join(path, ownerFile)); removeEmpty(path); };
  • 读取本地文件
    src/reflection.js:10
    try { return readFileSync(path, "utf8"); }
  • 读取本地文件
    src/reflection.js:14
    try { return readdirSync(path).filter(name => name.endsWith(".md")).sort(); }
  • 读取本地文件
    src/review.js:24
    try { return JSON.parse(readFileSync(join(root, REVIEW_STATE_FILE), "utf8")); }
  • 读取本地文件
    src/memory-ops.js:209
    if (!existsSync(p)) return null;
  • 读取本地文件
    src/memory-ops.js:210
    const text = readFileSync(p, "utf8");
  • 读取本地文件
    src/search.js:18
    if (!existsSync(memoryDir)) return [];
  • 读取本地文件
    src/search.js:19
    const names = existsSync(join(memoryDir, "rules.md")) || existsSync(join(memoryDir, "facts.md")) || existsSync(join(memoryDir, "index.txt")) ? ["defau
  • 读取本地文件
    src/search.js:20
    for (const dir of readdirSync(memoryDir, { withFileTypes: true })) {
  • 读取本地文件
    src/search.js:23
    if (existsSync(join(root, "rules.md")) || existsSync(join(root, "facts.md")) || existsSync(join(root, "index.txt"))) names.push(dir.name);
  • 读取本地文件
    src/search.js:32
    if (!existsSync(root)) continue;
  • 读取本地文件
    src/maintenance-agent.js:34
    try { return JSON.parse(readFileSync(join(root, MAINTENANCE_HISTORY_FILE), "utf8")).runs; }
  • 读取本地文件
    src/maintenance-agent.js:56
    try { return readFileSync(join(root, "index.txt"), "utf8").trimEnd().length; }
  • 读取本地文件
    src/maintenance-retry.js:13
    try { state = JSON.parse(readFileSync(join(root, MAINTENANCE_RETRY_FILE), "utf8")); }
扫描于 2026/11/3(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-agent@deepseek-ai/dsh-llm@deepseek-ai/dsh-sandbox@deepseek-ai/dsh-scope@deepseek-ai/dsh-session@deepseek-ai/dsh-session-query@deepseek-ai/dsh-storage-domain@deepseek-ai/dsh-subagent@deepseek-ai/dsh-tools@deepseek-ai/dsh-typert-protocol@deepseek-ai/schemastery
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 跨会话长期记忆

README

由 DeepSeek 最新模型翻译生成
description: "DeepSeek Harness 的跨会话记忆。项目与全局索引常驻上下文,条目带结构标识与证据,旧版本可以恢复。" kind: "package-bundle" @dsh-external/dsh-layered-memory 概述 分层记忆把规则、事实和操作经验从一次会话带到下一次。规则保存在 rules.md,事实放在 facts.md 的二级标题下,操作流程放在 sops/*.md;三类条目共用 {namespace, kind, key} 和现有记忆工具,来源与历史版本随条目保存。 目录 - 安装 - 使用 - 记忆管理页 - 配置 - 进一步探索 - 已知限制与暂缓工作 安装 dsh plugin --profile web add github:DDDFXYqiming/dsh-layered-memory "github:DDDFXYqiming/dsh-layered-memory#path:/lib/status" 两条 spec 都要装,因为 bundle 贡献两个组件(记忆插件本体与输入区的状态服务)。pnpm 默认阻止传递依赖里的 git 子包(blockExoticSubdeps),状态包必须作为直接依赖声明,否则新装只会有第一个组件。 桌面端用它随附的 dsh 命令,把 profile 换成 desktop。
展开完整文档(README 剩余 1 节)
description: "DeepSeek Harness 的跨会话记忆。项目与全局索引常驻上下文,条目带结构标识与证据,旧版本可以恢复。"
kind: "package-bundle"

@dsh-external/dsh-layered-memory

概述

分层记忆把规则、事实和操作经验从一次会话带到下一次。规则保存在 rules.md,事实放在 facts.md 的二级标题下,操作流程放在 sops/*.md;三类条目共用 {namespace, kind, key} 和现有记忆工具,来源与历史版本随条目保存。

目录

- 安装
- 使用
- 记忆管理页
- 配置
- 进一步探索
- 已知限制与暂缓工作

安装

dsh plugin --profile web add github:DDDFXYqiming/dsh-layered-memory "github:DDDFXYqiming/dsh-layered-memory#path:/lib/status"

两条 spec 都要装,因为 bundle 贡献两个组件(记忆插件本体与输入区的状态服务)。pnpm 默认阻止传递依赖里的 git 子包(blockExoticSubdeps),状态包必须作为直接依赖声明,否则新装只会有第一个组件。

桌面端用它随附的 dsh 命令,把 profile 换成 desktop。本地开发先执行 npm run build,再直接链接这个仓库与 lib/status,并让 profile 指向它们。

使用

基础工具 memory_search/list/read/write/update 随会话提供。加载 memory skill 或调用 memory_activate({mode:"common"}) 补充状态与冲突登记工具,管理操作用 mode:"manage"。读写权限由用户配置 memoryAccess 和 subagentMemoryAccess 决定,子 agent 默认只读。

条目用 search、list 或 create 返回的 entry 对象定位,不要拿标题重新拼一个身份出来。kind 可选 rule、fact、sop,分别记录后续要求、已知情况与可复用做法;规则依据可引用用户原始要求。已有条目通过 memory_update 修改。

memory_write({
namespace: "my-project",
kind: "fact",
topic: "预览命令", content: "跑 pnpm dev 就能起预览。", evidence: "命令正常启动,页面加载成功。"
})
// 后续调用复用返回的 entry。
memory_read({entry, full: true})
memory_update({entry, content: "修正后的事实", evidence: "新的验证过程"})
memory_activate({mode: "manage"})
memory_history({entry})
memory_rollback({entry, snapshot_id: "填一个返回的快照 id"})

| 要做的事 | 工具 |
| 查找与阅读 | memory_search、memory_list、memory_read |
| 新建与更新 | memory_write、memory_update |
| 查看证据 | memory_expand |
| 恢复历史 | memory_history、memory_rollback |
| 归档与恢复可见性 | memory_archive |
| 共享与迁移 | memory_promote、memory_namespace |
| 处理候选 | memory_pending、memory_accept、memory_discard |
| 状态与维护 | memory_stats、memory_index、memory_maintain、memory_review |

搜索默认只看当前空间和全局空间的活跃条目。要翻归档内容就传 include_archived:true,再用返回的 entry 去读。读取结果会给出行范围、总行数、revision、是否完整以及下一行位置。单条规则使用 kind:"rule";整段规则、完整索引与管理说明分别通过 rules、index、policy 三种只读视图读取。旧索引的规则会在空间首次初始化时逐条迁移,之后索引规则段从活跃规则生成。

记忆管理页

Web 界面左侧栏有一个“记忆”入口,点进去是独立页面:左边是条目列表,右边是详情。可以搜索、按类型过滤、查看已归档条目,也能直接改正文与证据、归档与恢复、看历史快照并回滚。界面文案跟随宿主语言设置,条目类型按语言显示为“规则/事实/经验”或 Rule/Fact/Skill。数据通道与页面规则见记忆管理页接口契约。

记忆管理页

工具行下面那行“索引占用”给出 L1 索引的已用比例和已用/预算字符数,展开后是说明、规则、事实目录、经验目录四段,悬停某一段会说明它的含义与占比。

索引占用的四段构成

主包另有一个可独立启停的“记忆状态”组件,Web 输入区底部那行显示当前会话的核对进度、真实变更条数或上次未完成的原因,点开可以看运行记录与只读历史。

记忆状态

配置

- id: dsh-layered-memory
config:
defaultNamespace: ''
autoNamespace: true
progressive: true
l1MaxChars: 12288
globalL1MaxChars: 2048
indexTargetRatio: 0.9
memoryAccess: write
subagentMemoryAccess: read
autoPending: false
turnReviewEnabled: true
turnReviewMinEvidence: 6
turnReviewReasoningEffort: ''
maintenanceMaxTokens: 16384
maintenanceMaxCalls: 64
maintenanceMaxWrites: 6
maintenanceTimeoutSeconds: 300
maintenanceCooldownMinutes: 30
reflectionMode: notify

自动命名空间来自工作区身份或规范化后的根路径,同一仓库的不同分支共用项目记忆,已有的命名空间要显式迁移。default 是全局空间,项目索引和默认搜索都把它算进来。字符预算同时管索引条目和手写规则,完整文件仍然可以通过工具读到。

主模型在任务中照常查阅和更新笔记,后台照看本轮相关笔记的遗漏、矛盾和重复。收尾核对默认开启,存量整理由 reflectionMode: auto 启用,索引压力作业以水位线为目标(目标字符 = l1MaxChars × indexTargetRatio)。调度、额度与检查点的细节见自动维护。

进一步探索

- 设计说明 讲存储、身份、上下文组装和索引占用的口径。
- 开发与端到端验收 讲怎么构建、载入真实宿主并验收改动。
- 自动维护 讲收尾核对、存量整理和索引压力作业的调度细节。
- 记忆管理页接口契约 讲记忆页与状态服务之间的数据通道、索引占用组件和页面要求。
- 热度排序契约 讲热度计分、排序快照与探索位的硬约束。
- 更新日志 记录已经发布的行为变化。

已知限制与暂缓工作

- 折叠会藏起细节,索引超出字符预算时条目被折叠、描述被截短。完整正文还能通过 memory_read 拿到。
- 索引是会话内的固定开销,项目索引受 l1MaxChars 限制,全局索引受 globalL1MaxChars 限制,超预算时先保热度高的条目。索引在稳定前缀里,写入改动索引会让它后面的缓存 token 失效,细节见设计说明。
- 维护要花模型调用,内部收尾核对与 reflectionMode: auto 都会启动子代理并消耗模型调用,预算按单次维护运行计算。
- 命名空间靠路径识别,项目挪到别的路径就会变成另一个空间,除非显式迁移。
- 工具按会话生效,基础记忆工具随会话提供,补充工具通过 memory 技能或 memory_activate 按需挂载,历史激活只恢复工具模式。
- 占用数据按命名空间给出,占用行只统计当前命名空间,default 空间和项目空间不合并显示。
- 索引超预算只影响提示词视图,磁盘上的 index.txt 始终是完整的活跃目录,超预算不会删除或归档条目,只裁剪注入提示词的那份视图。

开发者备注

无。
预览分享卡片长什么样 ↓DDDFXYqiming/dsh-layered-memory
分享 · DeepSeek Harness Hub
DDDFXYqiming/dsh-layered-memory

DeepSeek Harness 的跨会话长期记忆插件

这是你的仓库?认领条目

回到顶部