@modusensus/dsh-mneme 0.7.32 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  [![npm version](https://img.shields.io/npm/v/@modusensus/dsh-mneme?color=blue&label=npm)](https://www.npmjs.com/package/@modusensus/dsh-mneme)
6
6
  [![license](https://img.shields.io/badge/license-MIT-green)](LICENSE)
7
7
  [![Awesome](https://awesome-dsh-plugin.com/badge.svg)](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin)
8
- [![tests](https://img.shields.io/badge/tests-916%20passed-success)](https://github.com/modusensus/dsh-mneme)
8
+ [![tests](https://img.shields.io/badge/tests-988%20passed-success)](https://github.com/modusensus/dsh-mneme)
9
9
  [![CI](https://img.shields.io/github/actions/workflow/status/modusensus/dsh-mneme/ci.yml)](https://github.com/modusensus/dsh-mneme/actions)
10
10
  [![node](https://img.shields.io/badge/node-24%2B-blue)](https://nodejs.org)
11
11
  [![npm downloads](https://img.shields.io/npm/dm/@modusensus/dsh-mneme?color=blue&label=downloads)](https://www.npmjs.com/package/@modusensus/dsh-mneme)
@@ -13,15 +13,15 @@
13
13
 
14
14
  > 给 DeepSeek Harness 的跨会话记忆插件:让 Agent 记住你、记住项目、自动整理记忆。**Mneme**(Μνήμη)——希腊记忆女神 Mnemosyne 之名,掌管记忆与梦境,正如 autoDream 在后台巩固记忆。
15
15
 
16
- `dsh-mneme` 是一个 [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/deepseek-harness) 插件,为 Agent 提供持久的跨会话记忆能力。它借鉴了 Claude 的 **Dream 机制** 与 cc-haha / Claude Code 的 **autoDream** 实现思路——不仅**存储**记忆,还会**自动巩固**(去重、合并、冲突裁决、摘要生成),让记忆库越用越精炼。
16
+ `dsh-mneme` 是一个 [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/deepseek-harness) 插件,为 Agent 提供持久的跨会话记忆能力。它借鉴了 Claude 的 **Dream 机制** 与 cc-haha / Claude Code 的 **autoDream** 记忆巩固功能——不仅**存储**记忆,还会**自动巩固**(去重、合并、冲突裁决、摘要生成),让记忆库越用越精炼。完整溯源与致谢见文末「[🙏 致谢](#-致谢)」。
17
17
 
18
18
  ## ⏱️ 30 秒理解
19
19
 
20
- **一句话**:给 Agent 装上跨会话记忆——记住你、记住项目,并在后台自动整理,越用越懂你。
20
+ **一句话**:给 Agent 装上跨会话记忆——记住你、记住项目,并在后台自动整理,越用越懂你;**v0.8.0 起**记忆可按 agent 与工作区隔离(`scopeEnabled`),多 Agent / 多项目互不串台。
21
21
 
22
22
  | ① 写入 | ② 存储 | ③ 进化 |
23
23
  |--------|--------|--------|
24
- | 对话中模型主动记录(`memory_save`);会话结束自动提炼(`autoSummarize`) | SQLite 主库 + 人类可编辑 Markdown 镜像;实体 / 属性 / 时间轴三层结构化 | 新会话自动注入相关记忆;autoDream 后台去重 / 合并 / 归档,记忆库自我精炼 |
24
+ | 对话中模型主动记录(`memory_save`,可带敏感度与事件时间);会话结束自动提炼(`autoSummarize`) | SQLite 主库 + 人类可编辑 Markdown 镜像;实体 / 属性 / 时间轴三层结构化;记忆带 agent / workspace / 敏感度 / 发生时间标注 | 新会话自动注入相关记忆(按当前作用域加权,strictScope 开启后显式收窄的归属硬隔离);autoDream 后台去重 / 合并 / 归档,冲突冻结待人工裁决 |
25
25
 
26
26
  ```bash
27
27
  # 30 秒上手
@@ -49,18 +49,19 @@ dsh web
49
49
  - 逐 type 记录 `committed / failed / pending` 回执,健康端点区分 `ok / degraded / unknown`
50
50
  - 状态写失败不静默:同步失败落日志并留债务,重启自动收敛
51
51
 
52
- ### 模型工具(8 个)
52
+ ### 模型工具(9 个)
53
53
 
54
54
  | 工具 | 功能 |
55
55
  |------|------|
56
- | `memory_save` | 记录一条记忆(自动按标题去重合并) |
57
- | `memory_search` | 全文搜索(中文子串友好,可启用向量语义搜索) |
58
- | `memory_list` | 按类型分页列出(`include_archived=true` 可查看已归档) |
56
+ | `memory_save` | 记录一条记忆(自动按标题去重合并;v0.8.0 起去重键含 agent/workspace/scope 作用域,可选 `sensitivity` / `occurred_at` 参数) |
57
+ | `memory_search` | 全文搜索(中文子串友好,可启用向量语义搜索;可选 `occurred_from` / `occurred_to` 按事件发生时间过滤) |
58
+ | `memory_list` | 按类型分页列出(`include_archived=true` 可查看已归档;可选 `occurred_from` / `occurred_to` 时间过滤) |
59
59
  | `memory_get` | 读取单条记忆完整正文(v0.7.25,按 id;memory_search / memory_list 命中后读全文) |
60
60
  | `memory_update` | 修改已有记忆 |
61
61
  | `memory_delete` | 删除记忆(按记忆 ID 精确删除) |
62
62
  | `memory_forget` | 抑制注入(降权不删除,可恢复) |
63
63
  | `memory_archive` | 归档/恢复记忆(v0.2.5;归档后隐藏于列表/搜索/注入/整理,`archived=false` 可恢复) |
64
+ | `memory_runtime` | 本地推理运行时的状态 / 供给 / 校验(v0.7.32,自管运行时三档取件) |
64
65
 
65
66
  ### 自动注入 + 会话摘要
66
67
 
@@ -69,11 +70,13 @@ dsh web
69
70
 
70
71
  ### autoDream 自动记忆整理 🧠
71
72
 
73
+ > **溯源**:autoDream 的理念源自 Claude Code 的 Auto Dream 记忆巩固功能(Anthropic,Memory 2.0 的后台整理子代理),其「离线巩固」思路与 UC Berkeley & Letta 的 *Sleep-time Compute* 论文([arXiv:2504.13171](https://arxiv.org/abs/2504.13171))一脉相承。dsh-mneme 将其引入 DSH 插件生态,并发展为自己的实现——K-Means++ 聚类预分组、类型化决策清单与可回放的 sha256 摘要审计链,详见文末「[🙏 致谢](#-致谢)」。
74
+
72
75
  - **触发**:记忆数 > 10 或总字符 > 5000 时,异步自动触发(不阻塞写入)
73
76
  - **决策清单式整理**:LLM 输出 `keep` / `merge` / `archive` / `conflict` / `update` 决策清单,服务端校验后逐条应用
74
77
  - `merge`:合并主题相近的条目,保留信息最完整者
75
78
  - `archive`:归档过时/冗余条目(可恢复,不物理删除)
76
- - `conflict`:裁决矛盾信息,胜者保留、败者归档并追加溯源注释
79
+ - `conflict`:裁决矛盾信息,胜者保留、败者归档并追加溯源注释;`conflictFreezeEnabled`(默认关)开启后矛盾对不自动裁决,改为冻结进**冲突队列**(状态页并排对比,人工选保留方,#166)
77
80
  - `update`(v0.2.1):直接修正单条记忆的过时/错误内容(单 id / 必须实际变化 / 非 summary / 24h 保护 / 每次 ≤2)
78
81
  - **失败追踪(v0.2.1)**:用户纠正记忆时写入 `failure_memories` 表(旧值/新值),为后续自进化积累数据
79
82
  - **摘要生成**:整理后生成"记忆库总览"(单一实例),作为下次会话的优先注入
@@ -123,7 +126,7 @@ dsh web
123
126
 
124
127
  - **用户画像**:一段自由文本描述用户自己(角色、背景、偏好),**每轮注入**到系统提示,让 Agent 始终遵循
125
128
  - **规则**:Agent 必须遵守的行为规则列表(如"回答先给结论"),同样每轮注入
126
- - **自定义指令**:注册斜杠命令(`/名称`),触发时把用户定义的指令内容交给 Agent。命令持久化到 SQLite,启动时自动注册到 DSH 命令表,增删实时生效
129
+ - **自定义指令**:注册斜杠命令(`/名称 [补充说明]`),触发时把用户定义的指令内容作为一条用户消息提交给当前 Agent,命令后缀会作为补充说明一并提交;界面仅显示提交回执(宿主不支持 followup 提交时退回旧行为,指令原文会显示在界面,便于复制后手动发送)。命令持久化到 SQLite,启动时自动注册到 DSH 命令表,增删实时生效
127
130
 
128
131
  > 画像与规则通过独立的 `[用户设置]` 注入区块(优先级高于记忆库),即使记忆为空也会注入。
129
132
 
@@ -225,6 +228,8 @@ v0.3.0 起新增**记忆基因**层:从记忆里抽取**命名实体**、**带
225
228
 
226
229
  | 版本 | 亮点 |
227
230
  |------|------|
231
+ | **v0.8.1** | 归属显式声明与人工纠偏 + 插件版本自检:记忆归属三段式可控——per-dim 来源列 + save/update scope 参数 + 面板可编辑(#170 第 1 步,#171);sleep 跨 scope 相似对停车进冲突队列人工裁决(第 2 步,#172);`strictScope` 硬过滤只认显式声明、自动标注降为纯软加权(第 3 步,#173,4.3 已确认);`GET /api/dsh-mneme/version-check` 只读路由 + 设置页偏差横幅(仅 outdated 渲染,registry 精确 host 白名单 + TTL 缓存 + 全失败静默,pnpm 钉子警示 + 市场收录延迟说明,#174 后续);1026 测试全绿 |
232
+ | **v0.8.0** | 作用域隔离(issue #17 批次 A)+ 冲突集中处理 + 斜杠命令提交 Agent + 注入转义回归修复:记忆按 agent 与工作区双维标注(agent_scope / workspace_scope / sensitivity / occurred_at 四列可空),检索按当前会话作用域加权(命中 ×1.25、他 scope ×0.5 保留可见),opt-in `strictScope` 硬过滤贯通检索/注入/列表/单取(fail-closed);`scopeEnabled` / `strictScope` 默认关、面板「作用域隔离」组可启停;去重键扩展含作用域三元——跨作用域同标题不再物理合并;`occurred_at` 事件发生时间 + `occurred_from/to` 过滤贯通搜索与列表;冲突冻结(conflictFreezeEnabled)新增人工出口——状态页冲突队列并排对比 + 保留 A/B/仅标记(#166);斜杠命令经 agent.followup 真正提交模型(#152);恢复 v0.7.4 的注入花括号转义 + hot memory 跳过 reasoning——`{{.Server.Version}}` 类文本不再卡死会话(#165);988 测试全绿 |
228
233
  | **v0.7.32** | 冲突动作集扩展 + 运行时自管化 + 记忆/提示语言 + 候选集 hybrid 档 + 一批修复:`sleepActionSet` 新增 `full` 档(supersede/differentiate/update/merge/conflict/keep 六分支,默认 `conflict` 零行为变化)——supersede 赢家正文干净、输家归档附「已被取代」注记,differentiate 双留+差异注记;sleep 校验接入 `dreamSkipInvalid` 宽容策略(默认 true,一票否决变宽容,严格可关);运行时三档取件(收编/本地 .tgz/registry)+ transformers 转可选 peer(#131);`memory.language`(zh/en)提示/注入/镜像语言可选(#124);summarize 节流 + 产出上限 + 同会话去重(#127);inject 正文读取修复(#129)、#135 五连修(前缀解析/effort 最低档/importance 豁免/ready 语义/覆盖度降级告警)、boot 回填指纹短路修复(#128)、degraded 轮跳过明细落库(#104);916 测试全绿、总覆盖 92.7%(runtime 96%、embedding 100%) |
229
234
  | **v0.7.30** | 状态页向量卡修复(issue #118):改读开放的 `/semantic`——不再吃 `/vector-config` 的 401「加载失败」,ollama/local 模式不再恒显「未启用」;新增「初始化中(embedder 不可达,正在重试)」与「已索引 N / M 条」回填进度显示;legacy OpenAI 兼容 embedder「Object · 0D」显示修复(embedder 显式 `name: "OpenAI"` + 维度回退 `index.dimension`);「已索引 N / M」分子分母同口径(`embeddedCount` 剔除归档/遗忘,与 `count()` 默认过滤对齐);embedder init 失败有界重试(共 5 次,不再一次性永久降级,unload 清理定时器)+ `OllamaEmbedder.ready` 生命周期位 + `/semantic` 新增 `ready` 字段;745 测试全绿 |
230
235
  | **v0.7.29** | 实体抽取路由契约修复 + 面板控件 + 帮助与反馈:`streamEntityText` 抽取为可测试导出的 `createEntityStreamAdapter`——显式 `provider`/`model` 优先、缺省兜底读默认路由选择;实体抽取思考强度 `entityExtractionReasoning` 被模型拒绝时自动去 effort 重试(与 autoDream/sleep 同一降级策略);设置面板新增实体抽取 `provider`/`model`/思考强度三控件;面板底部新增「帮助与反馈」卡片(GitHub issue 预填 + mailto `work@modusensus.space` + 浏览已知问题)+ 配套 `GET /api/dsh-mneme/info`;744 测试全绿 |
@@ -330,7 +335,8 @@ v0.3.0 起新增**记忆基因**层:从记忆里抽取**命名实体**、**带
330
335
  | **v0.7.30** | ✅ 完成 | 状态页向量卡修复 + embedder 有界重试 | 卡片改读 `/semantic`(不再 401「加载失败」、ollama/local 不再恒显「未启用」)+「初始化中 / 已索引 N / M 条」显示(issue #118);legacy OpenAI 兼容 embedder 显式 `name: "OpenAI"` + 维度回退 `index.dimension`(「Object · 0D」修复);`embeddedCount` 对齐 `count()` 默认口径、剔除归档/遗忘(「已索引 269 / 36」修复);embedder init 失败 5 次有界重试不再一次性永久降级 + `OllamaEmbedder.ready` + `/semantic` `ready` 字段;745 测试全绿 |
331
336
  | **v0.7.31** | ✅ 完成 | peerDependencies 宿主版本声明修复 | 原 `^0.1.0-rc.6` 按 node-semver 预发布元组规则不匹配 `0.1.5-rc.1` 等中间预发布版本(当前 dsh 用户安装 ERESOLVE),也违反 awesome-dsh-plugin 的 peer-range 预发布分支规范;改显式三段式预发布分支(覆盖 0.1.0-rc.6 至 0.1.5-rc.1 全部已发布 0.1.x 含预发布 + 0.2 预发布留显式分支 + 0.3+ 待验证后放开);745 测试全绿 |
332
337
  | **v0.7.32** | ✅ 完成 | sleep 冲突动作集扩展 + 运行时自管化 + 候选集 hybrid 档 + 一批修复 | `sleepActionSet` 新增 `full` 档(supersede/differentiate/update/merge/conflict/keep 六分支,默认 `conflict` 零行为变化)+ sleep 校验接入 `dreamSkipInvalid` 宽容策略 + 被跳决策带 phase 落库 `dream_runs.skipped`;运行时三档取件 + transformers 转可选 peer(#131);`memory.language` 提示/注入/镜像语言可选(#124);候选集向量驱动 hybrid 档(#125,PR #147);summarize 节流 + 产出上限 + 同会话去重(#127);inject 正文读取修复(#129)+ #135 五连修 + boot 回填指纹短路修复(#128)+ degraded 轮跳过明细落库(#104);runtime 覆盖统计归一 + 补齐(总覆盖 92.7%);916 测试全绿 |
333
- | **v0.8.0** | 🚧 计划中(9 月末) | 图谱增强 | 兴趣漂移可视化 + scope 隔离(issue #17)+ 跨 workspace 记忆共享 |
338
+ | **v0.8.0** | ✅ 完成 | 作用域隔离 + 冲突队列 | 按 agent 与工作区双维隔离记忆(标注 / 检索加权 / opt-in strictScope 四路硬过滤,issue #17 批次 A);冻结冲突新增人工确认队列(状态页并排对比,#166);斜杠命令真正提交 Agent(#152);注入转义回归恢复 + hot memory 跳过 reasoning(#162)。图谱增强(兴趣漂移可视化)、跨 workspace 记忆共享仍在规划 |
339
+ | **v0.8.1** | ✅ 完成 | 归属显式声明与人工纠偏 + 插件版本自检 | 归属三段式可控:per-dim 来源列 + save/update scope 参数 + 面板可编辑(#170 第 1 步,#171);sleep 跨 scope 相似对停车人工裁决接冲突队列(第 2 步,#172);`strictScope` 硬过滤只认显式声明、自动标注降纯软加权(第 3 步,#173)。插件自报新版本:/version-check 只读路由 + 设置页 outdated 横幅(registry 精确白名单 + TTL 缓存 + 全失败静默,pnpm 钉子警示,#174 后续,#176);1026 测试全绿 |
334
340
 
335
341
  > 新能力一律做成**可开关的功能**(配置启用/关闭),默认保守开启、不破坏现有行为。`failure_memories` 表与 autoDream 决策引擎已为后续反思性成长铺好路。
336
342
 
@@ -456,6 +462,10 @@ dsh web
456
462
  | `searchSemanticDedupThreshold` | `0.95` | 语义去重相似度阈值(v0.5.0,默认 0.95,范围 0.5-1.0):`searchSemanticDedup=true` 时生效,调整可防小模型误折叠 |
457
463
  | `memoryQualityFilter` | `{enabled:true, archiveThreshold:30, degradeThreshold:60, minContentLength:10, exemptImportance:4}` | 记忆质量过滤(v0.4.6,默认开):写库前启发式打分 0-100,元记忆词汇/自指/过短/重复/近似重复扣分;≥60 正常存储,30-60 降权(注入排序按 importance×quality/100),<30 归档标记 `low_quality`(显式搜索仍可召回,永不自动注入;`exemptImportance` 豁免:importance ≥ 该值只降权不归档,#135) |
458
464
  | `llmAudit` | `{enabled:true, retentionDays:90}` | LLM 消耗审计(v0.4.6,默认开):每次后台 LLM 调用(autoDream/autoSummarize)写 `llm_audit_logs`(tokens/duration/status/source);失败记 error 不阻塞;只读 API `/api/dsh-mneme/semantic/llm-audit` + `/llm-audit/stats` |
465
+ | `scopeEnabled` | `false` | 作用域隔离总开关(v0.8.0,issue #17):memory_save 按会话身份写入 agent / workspace 标注(agentPreset / 工作区路径,registry 反查取不到回退 header.cwd,再取不到 NULL);去重键扩展含作用域三元——跨作用域同标题不再物理合并;检索按当前会话作用域加权(命中 ×1.25、他 scope ×0.5 保留可见)。也走 feature_flags 白名单(面板可启停) |
466
+ | `strictScope` | `false` | 作用域硬过滤(v0.8.0 引入,v0.8.1 起只认显式声明;依赖 `scopeEnabled`):检索 / 注入 / 列表 / 单取四路过滤,**显式声明**收窄到他者作用域的记忆完全不可见;载体自动标注只降权保留可见——真正的物理隔离请用 sensitivity。会话身份解析不到时 fail-closed 只挡显式行。关闭时全部为软隔离(降权保留可见)。也走 feature_flags 白名单 |
467
+ | `conflictFreezeEnabled` | `false` | 冲突冻结(v0.4.4):dream 发现矛盾对不自动裁决,冻结进冲突队列;状态页「冲突队列」支持并排对比与人工确认(保留 A / 保留 B / 仅标记已处理,v0.8.0) |
468
+ | `escapePromptVariables` | `true` | 注入文本花括号转义(v0.8.0 恢复,issue #162):注入边界把 `{{...}}` 转义,防止 hot memory / 记忆原文里的 Go template / Vue 语法触发宿主 interpolate 抛错卡死会话(v0.7.4 曾修复、v0.7.11 误删) |
459
469
 
460
470
  > 🔐 **API 安全**:DSH 无内置鉴权且默认仅监听 `127.0.0.1`。插件 API 默认开放(便于 Web 面板即装即用)。如需防护(如局域网暴露),在配置中设置 `apiToken`:写操作(画像/规则/命令)与密钥端点(`vector-config`、`vector-reindex`)需携带 `Authorization: Bearer <token>`(前端设置面板可填入同一 token),只读的 `list` / `search` / `semantic` 保持开放。`/api/dsh-mneme/vector-config` 返回的 `apiKey` 已掩码(`sk-***…`),存储仍保留明文供调用;前端回传空或掩码值表示"不改 key"。
461
471
 
@@ -552,25 +562,29 @@ dsh-mneme config show # 查看当前配置(toke
552
562
 
553
563
  ```
554
564
  src/
555
- ├── store.js # SQLite 存储(CRUD、搜索、归档/遗忘、schema 迁移)
565
+ ├── store.js # SQLite 存储(CRUD、搜索、归档/遗忘、schema 迁移、scope 四列)
556
566
  ├── mirror.js # Markdown 镜像(渲染/解析,人工优先)
557
- ├── service.js # 领域逻辑(去重合并、注入筛选、写入钩子)
567
+ ├── service.js # 领域逻辑(去重合并、注入筛选、写入钩子、scope 加权/硬过滤、冲突队列)
568
+ ├── scope.js # 作用域解析(agentPreset + workspace registry 反查,issue #17)
558
569
  ├── config.js # schemastery 配置 schema
559
- ├── tools.js # 8 个模型工具(defineTool)
560
- ├── inject.js # systemPrompt.context 动态注入
570
+ ├── tools.js # 9 个模型工具(defineTool)
571
+ ├── inject.js # systemPrompt.context 动态注入(含花括号转义)
561
572
  ├── summarize.js # 会话结束 LLM 摘要
562
573
  ├── dream.js # autoDream 调度 + runDream(LLM 决策 + 摘要)
563
574
  ├── dream/decisions.js# 决策校验(fail-safe)+ 决策应用
575
+ ├── dream/clustering.js # 候选集聚类(k-means++ seeding)
576
+ ├── dream/sleep.js # Sleep Mode 分层压缩
564
577
  ├── entities/extractor.js # 实体抽取器(v0.3.0:LLM JSON 抽取 + 去重 + fail-safe)
565
578
  ├── search/bm25.js # BM25 稀疏召回(v0.5.0:分词 + IDF 索引)
566
579
  ├── search/adaptive.js# 自适应相似度阈值(v0.5.0)
567
- ├── hot-memory.js # 会话级短期热记忆(v0.5.0:滚动轮次 + token 预算)
580
+ ├── hot-memory.js # 会话级短期热记忆(v0.5.0:滚动轮次 + token 预算;注入剥离 reasoning)
581
+ ├── runtime/ # 自管本地推理运行时(收编 / 本地 .tgz / registry 三档取件 + 校验)
568
582
  ├── embedding.js # OpenAI 兼容 embeddings 客户端 + 向量检索
569
- ├── api.js # HTTP 路由(Web 面板数据通道)
583
+ ├── api.js # HTTP 路由(Web 面板数据通道,含 /conflicts 冲突队列)
570
584
  └── index.js # 插件接线
571
585
  lib/ # src 的同步分发产物(npm run sync;发布前由 root prepack 的 check-sync.js 校验一致性;唯一手写例外 lib/client.js——Web 面板 bundle,sync 不覆盖)
572
- test/ # 714 个 node:test 测试(审计与三轴线压测不变量;src↔lib 一致性由 scripts/check-sync.js 发布闸门校验)
573
- scripts/ # e2e-dsh.js 端到端演示 · stress-dsh.js 三轴线压测 · sync-lib.js 同步 · check-sync.js 发布闸门 · benchmark-recall.js 召回基准
586
+ test/ # 988 个 node:test 测试(审计与三轴线压测不变量;src↔lib 一致性由 scripts/check-sync.js 发布闸门校验)
587
+ scripts/ # e2e-dsh.js 端到端演示 · stress-dsh.js 三轴线压测 · sync-lib.js 同步 · check-sync.js 发布闸门 · benchmark-recall.js 召回基准 · release-prep.mjs 发布准备
574
588
  ```
575
589
 
576
590
  ## 🧪 开发
@@ -578,7 +592,7 @@ scripts/ # e2e-dsh.js 端到端演示 · stress-dsh.js 三轴线压
578
592
  ```bash
579
593
  cd dsh-mneme
580
594
  npm install # 安装 peer 依赖(以 devDependencies 形式,用于本地测试)
581
- npm test # 运行 714 个测试
595
+ npm test # 运行 988 个测试
582
596
  npm run stress # 三轴线压测:长会话检索 / 冲突仲裁 / 多 Agent 并发(离线 mock LLM)
583
597
  npm run sync # 把 src/ 同步到 lib/(发布时由 prepack 钩子自动执行)
584
598
  ```
@@ -596,6 +610,16 @@ npm run sync # 把 src/ 同步到 lib/(发布时由 prepack 钩子自动
596
610
  - [本地模型部署指南](docs/LOCAL_MODEL.md)
597
611
  - [从 v0.1 升级说明](docs/MIGRATION.md)
598
612
 
613
+ ## 🙏 致谢
614
+
615
+ autoDream 的理念溯源(理念借鉴、实现原创):
616
+
617
+ - **[Claude Code 的 Auto Dream](https://code.claude.com/docs/en/memory)**(Anthropic,Memory 2.0):理念源头——会话间隙由后台子代理整理记忆文件(去重、修矛盾、清衰减)。
618
+ - **[Sleep-time Compute: Beyond Inference Scaling at Test-time](https://arxiv.org/abs/2504.13171)**(UC Berkeley & Letta,arXiv:2504.13171):Auto Dream「离线巩固」思想背后的学术脉络。
619
+ - **cc-haha**:早期实现思路的参照之一。
620
+
621
+ 在上述工作之上,dsh-mneme 做了自己的工程发展:K-Means++ 聚类预分组(`src/dream/clustering.js`)、类型化决策清单(keep / merge / archive / conflict / update,及 sleep 侧 supersede / differentiate)与可回放的 sha256 摘要审计链(`dream_runs` / `receipt_chain`)。如有遗漏的灵感来源,欢迎提 issue 指出。
622
+
599
623
  ## 📜 License
600
624
 
601
625
  MIT
package/lib/api.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import { URL } from "node:url";
2
- import { readFileSync } from "node:fs";
3
2
  import { timingSafeEqual, randomBytes } from "node:crypto";
4
3
  import { FEATURE_FLAG_SPEC } from "./settings.js";
5
4
  import { TYPE_FILE, renderMirrorText, parseHumanEdits } from "./mirror.js";
@@ -8,6 +7,7 @@ import { computeHeat } from "./heat.js";
8
7
  import { describeStreamFailure, resolveRoute } from "./dream.js";
9
8
  import { describeLocalRuntime, publicRuntimeStatus } from "./runtime/loader.js";
10
9
  import { hostModulesDir, provisionRuntime } from "./runtime/provision.js";
10
+ import { classify, fetchLatestVersion, PACKAGE_VERSION } from "./version-check.js";
11
11
 
12
12
  // headers:少数端点(/export 附件下载)需要追加 Content-Disposition 等响应头。
13
13
  function sendJson(res, status, payload, headers = {}) {
@@ -24,16 +24,8 @@ function sendAttachment(res, status, contentType, filename, body) {
24
24
  res.end(body);
25
25
  }
26
26
 
27
- // 导出 JSON 的 version 字段:读插件根的 package.json(src/ 与 lib/ 都在根下
28
- // 一层,相对 import.meta.url 解析一致)。读取失败(打包/受限环境)降级为
29
- // "unknown",导出本身仍然可用。
30
- const PACKAGE_VERSION = (() => {
31
- try {
32
- return JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version ?? "unknown";
33
- } catch {
34
- return "unknown";
35
- }
36
- })();
27
+ // 版本号统一从 version-check.js 取(同一份读 package.json 逻辑,读取失败
28
+ // 同样降级 "unknown")——/info 与 /version-check 两个路由共用,不再各写一份。
37
29
 
38
30
  // Defaults for the standalone external API — keep in step with the schema
39
31
  // defaults in config.js (externalApiPort / externalApiHost).
@@ -175,6 +167,29 @@ export function createApi(ctx, service, settings, commands, embedder, semantic =
175
167
  }
176
168
  });
177
169
 
170
+ // 版本自检(#174 后续):运行版本 vs npm registry latest。只读,宿主围栏
171
+ // 统一鉴权(与 dream-status 同款,面板 apiFetch 直接可用)。registry 查询
172
+ // 全失败时 latest=null、status=unknown——前端对 unknown 完全静默,版本提示
173
+ // 是锦上添花,绝不因它新增故障面。
174
+ register({
175
+ kind: "exact",
176
+ path: "/api/dsh-mneme/version-check",
177
+ handler(req, res) {
178
+ if (req.method !== "GET") {
179
+ sendJson(res, 404, { error: "not-found" });
180
+ return;
181
+ }
182
+ fetchLatestVersion()
183
+ .then((latest) => sendJson(res, 200, {
184
+ version: PACKAGE_VERSION,
185
+ latest,
186
+ status: classify(PACKAGE_VERSION, latest),
187
+ checkedAt: new Date().toISOString()
188
+ }))
189
+ .catch(() => sendJson(res, 200, { version: PACKAGE_VERSION, latest: null, status: "unknown" }));
190
+ }
191
+ });
192
+
178
193
  register({
179
194
  kind: "exact",
180
195
  path: "/api/dsh-mneme/list",
@@ -480,6 +495,19 @@ export function createApi(ctx, service, settings, commands, embedder, semantic =
480
495
  }
481
496
  patch.tags = body.tags;
482
497
  }
498
+ // v0.8.1 底座(issue #170):显式 scope 修正。null=放宽到全局,
499
+ // 字符串=收窄/改标;归一化("global"/"*"/空白→NULL + explicit 章 +
500
+ // 审计行)在 service.updateMemory 内做,路由只做形状校验。
501
+ if (body.agent_scope !== undefined && body.agent_scope !== null && typeof body.agent_scope !== "string") {
502
+ sendJson(res, 400, { error: "invalid-agent-scope" });
503
+ return;
504
+ }
505
+ if (body.workspace_scope !== undefined && body.workspace_scope !== null && typeof body.workspace_scope !== "string") {
506
+ sendJson(res, 400, { error: "invalid-workspace-scope" });
507
+ return;
508
+ }
509
+ if (body.agent_scope !== undefined) patch.agent_scope = body.agent_scope;
510
+ if (body.workspace_scope !== undefined) patch.workspace_scope = body.workspace_scope;
483
511
  if (body.archived !== undefined && typeof body.archived !== "boolean") {
484
512
  sendJson(res, 400, { error: "invalid-archived" });
485
513
  return;
@@ -501,7 +529,7 @@ export function createApi(ctx, service, settings, commands, embedder, semantic =
501
529
  ...history
502
530
  ].slice(0, 20);
503
531
  }
504
- if (Object.keys(patch).length) service.update(id, patch);
532
+ if (Object.keys(patch).length) service.update(id, patch, { actor: "panel" });
505
533
  if (body.archived !== undefined) service.setArchived(id, body.archived);
506
534
  sendJson(res, 200, { memory: service.getById(id) });
507
535
  });
@@ -1014,6 +1042,66 @@ export function createApi(ctx, service, settings, commands, embedder, semantic =
1014
1042
  }
1015
1043
  });
1016
1044
 
1045
+ // --- 冲突集中处理(v0.8.0):队列 + 人工确认 --------------------------------
1046
+ // GET /conflicts:未解决冲突 + 双方当前内容(此前面板只有计数与徽章,
1047
+ // resolveConflictPending 在存储层躺着没有任何调用方)。POST /conflicts/resolve:
1048
+ // {id, winner: "a"|"b"|null, apply}——盖章审计,apply 时按 dream 非冻结
1049
+ // conflict 路径同款处置(service.resolveConflictPending 内部复用
1050
+ // applyDecisions:CAS + 事务 + 注记 + 幂等)。认证与其他写路由一致。
1051
+ register({
1052
+ kind: "exact",
1053
+ path: "/api/dsh-mneme/conflicts",
1054
+ handler(req, res) {
1055
+ try {
1056
+ if (req.method !== "GET") {
1057
+ sendJson(res, 404, { error: "not-found" });
1058
+ return;
1059
+ }
1060
+ if (!requireAuth(req, res, apiToken)) return;
1061
+ const url = new URL(req.url, "http://localhost");
1062
+ const limit = Math.min(200, Math.max(1, Number(url.searchParams.get("limit") ?? 50) || 50));
1063
+ const offset = Math.max(0, Number(url.searchParams.get("offset") ?? 0) || 0);
1064
+ const items = service.listConflictQueue({ limit, offset });
1065
+ sendJson(res, 200, { items, total: service.countConflictPending?.() ?? items.length });
1066
+ } catch {
1067
+ sendJson(res, 500, { error: "internal" });
1068
+ }
1069
+ }
1070
+ });
1071
+
1072
+ register({
1073
+ kind: "exact",
1074
+ path: "/api/dsh-mneme/conflicts/resolve",
1075
+ handler(req, res) {
1076
+ try {
1077
+ if (req.method !== "POST") {
1078
+ sendJson(res, 404, { error: "not-found" });
1079
+ return;
1080
+ }
1081
+ if (!requireAuth(req, res, apiToken)) return;
1082
+ return readBody(req).then((text) => {
1083
+ let body = {};
1084
+ try { body = JSON.parse(text || "{}"); } catch { /* 坏 JSON → 走缺参分支 */ }
1085
+ const id = typeof body.id === "string" ? body.id.trim() : "";
1086
+ if (!id) {
1087
+ sendJson(res, 400, { error: "missing-id" });
1088
+ return;
1089
+ }
1090
+ const winner = body.winner === "a" || body.winner === "b" ? body.winner : null;
1091
+ const apply = body.apply !== false;
1092
+ const result = service.resolveConflictPending(id, { winner, apply });
1093
+ if (!result) {
1094
+ sendJson(res, 404, { error: "not-found" });
1095
+ return;
1096
+ }
1097
+ sendJson(res, 200, { ok: true, conflict: result });
1098
+ }).catch(() => sendJson(res, 500, { error: "internal" }));
1099
+ } catch {
1100
+ sendJson(res, 500, { error: "internal" });
1101
+ }
1102
+ }
1103
+ });
1104
+
1017
1105
  // --- health: mirror sync state (F-NEW-03 / v0.3.6) ---
1018
1106
  // Auth-gated; only returns a sanitized error code (never raw last_error which
1019
1107
  // may leak paths/token-like strings/internal hosts). On state read failure it