@modusensus/dsh-mneme 0.8.8 → 0.8.10

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-1404%20passed-success)](https://github.com/slow-stack/mneme)
8
+ [![tests](https://img.shields.io/badge/tests-1431%20passed-success)](https://github.com/slow-stack/mneme)
9
9
  [![CI](https://img.shields.io/github/actions/workflow/status/slow-stack/mneme/ci.yml)](https://github.com/slow-stack/mneme/actions)
10
10
  [![node](https://img.shields.io/badge/node-22%2B-blue)](https://nodejs.org)
11
11
  [![npm downloads](https://img.shields.io/npm/d18m/@modusensus/dsh-mneme.svg?color=blue&label=downloads)](https://www.npmjs.com/package/@modusensus/dsh-mneme)
@@ -432,6 +432,7 @@ dsh web
432
432
  | `llmAudit` | `{enabled:true, retentionDays:90}` | LLM 消耗审计(v0.4.6,默认开):每次后台 LLM 调用(`autoDream` / `autoSummarize` / `sleep` / `entityExtract`,对应 `operation_type` 为 `dream_consolidate` / `dream_summarize` / `dream_narrative`、`summarize_compress`、`sleep_conflict` / `sleep_pattern`、`entity_extract`)写 `llm_audit_logs`(tokens/duration/status/source);失败记 error 不阻塞;只读 API `/api/dsh-mneme/semantic/llm-audit` + `/llm-audit/stats` |
433
433
  | `scopeEnabled` | `false` | 作用域隔离总开关(v0.8.0,issue #17):memory_save 按会话身份写入 agent / workspace 标注(agentPreset / 工作区路径,registry 反查取不到回退 header.cwd,再取不到 NULL);去重键扩展含作用域三元——跨作用域同标题不再物理合并;检索按当前会话作用域加权(命中 ×1.25、他 scope ×0.5 保留可见)。也走 feature_flags 白名单(面板可启停) |
434
434
  | `strictScope` | `false` | 作用域硬过滤(v0.8.0 引入,v0.8.1 起只认显式声明;依赖 `scopeEnabled`):检索 / 注入 / 列表 / 单取四路过滤,**显式声明**收窄到他者作用域的记忆完全不可见;载体自动标注只降权保留可见——真正的物理隔离请用 sensitivity。会话身份解析不到时 fail-closed 只挡显式行。关闭时全部为软隔离(降权保留可见)。也走 feature_flags 白名单 |
435
+ | `writeAdmission` | `{enabled:false, enforce:false}` | 写入准入(issue #254,默认关):把「这条该不该进库」前移到 LLM 之前。第 1 级是零 LLM 的确定性判据——空白 / 纯噪声 + 密钥 / PII(判据来源是 #164 A2,经 `sensitiveScan` 注入,本批只定义接口)。`enabled` 跑判据并落审计行(`llm_audit_logs` 的 `metadata.deny`),`enforce` 才真的拒(`store.save` 之前返回,`memory_save` 返回 `action:"denied"` + `reason`);只开 `enabled` = 仅告警、写入不拦。去重键命中不进第 1 级(归 write-update 放行),G1/G2 阈值只计量。也走 feature_flags 白名单 |
435
436
  | `conflictFreezeEnabled` | `false` | 冲突冻结(v0.4.4):dream 发现矛盾对不自动裁决,冻结进冲突队列;状态页「冲突队列」支持并排对比与人工确认(保留 A / 保留 B / 仅标记已处理,v0.8.0) |
436
437
  | `conflictFreezeMaxPending` | `100` | 冲突冻结队列最大挂起数(1-1000):超出后不再入队(防队列无限膨胀) |
437
438
  | `escapePromptVariables` | `true` | 注入文本花括号转义(v0.8.0 恢复,issue #162):注入边界把 `{{...}}` 转义,防止 hot memory / 记忆原文里的 Go template / Vue 语法触发宿主 interpolate 抛错卡死会话(v0.7.4 曾修复、v0.7.11 误删) |
@@ -583,8 +584,7 @@ src/
583
584
  ├── api.js # HTTP 路由(Web 面板数据通道,含 /conflicts 冲突队列)
584
585
  └── index.js # 插件接线
585
586
  lib/ # src 的同步分发产物(npm run sync;发布前由 root prepack 的 check-sync.js 校验一致性;唯一手写例外 lib/client.js——Web 面板 bundle,sync 不覆盖)
586
- test/ # 1404 个 node:test 测试(审计与三轴线压测不变量;src↔lib 一致性由 scripts/check-sync.js 发布闸门校验)
587
- test/ # 1404 个 node:test 测试(审计与三轴线压测不变量;src↔lib 一致性由 scripts/check-sync.js 发布闸门校验)
587
+ test/ # 1431 个 node:test 测试(审计与三轴线压测不变量;src↔lib 一致性由 scripts/check-sync.js 发布闸门校验)
588
588
  scripts/ # e2e-dsh.js 端到端演示 · stress-dsh.js 三轴线压测 · sync-lib.js 同步 · check-sync.js 发布闸门 · benchmark-recall.js / benchmark-embed.js / benchmark-rerank.js 基准 · sync-test-badge.mjs 测试徽章 · build-runtime-manifest.mjs 运行时清单
589
589
  ```
590
590
 
@@ -593,7 +593,7 @@ scripts/ # e2e-dsh.js 端到端演示 · stress-dsh.js 三轴线压
593
593
  ```bash
594
594
  cd dsh-mneme
595
595
  npm install # 安装 peer 依赖(以 devDependencies 形式,用于本地测试)
596
- npm test # 运行 1404 个测试
596
+ npm test # 运行 1431 个测试
597
597
  npm run stress # 三轴线压测:长会话检索 / 冲突仲裁 / 多 Agent 并发(离线 mock LLM)
598
598
  npm run sync # 把 src/ 同步到 lib/(发布时由 prepack 钩子自动执行)
599
599
  ```
@@ -386,7 +386,7 @@ export function createStandaloneApi({ service, store, config = {}, logger, setti
386
386
  }
387
387
  }
388
388
  try {
389
- const { action, memory } = service.saveWithDedupe({
389
+ const result = service.saveWithDedupe({
390
390
  type: body.type,
391
391
  title: body.title,
392
392
  content: body.content,
@@ -398,6 +398,16 @@ export function createStandaloneApi({ service, store, config = {}, logger, setti
398
398
  ...(body.agent_scope !== undefined ? { agent_scope: body.agent_scope, agent_scope_source: "explicit" } : {}),
399
399
  ...(body.workspace_scope !== undefined ? { workspace_scope: body.workspace_scope, workspace_scope_source: "explicit" } : {})
400
400
  });
401
+ const { action } = result;
402
+ // #254 写入准入:这条 HTTP 路径今天不带会话身份,evaluate 在无 sessionKey
403
+ // 时直接早退,所以拦不到;仍然显式分支——将来真接上会话身份时,落到
404
+ // `toApiList([null])` 上会变成 500,把「被拒」伪装成「服务器出错」,而
405
+ // 这两件事对调用方的处置完全不同(改内容 vs 重试)。
406
+ if (action === "denied") {
407
+ sendJson(res, 422, { error: "write-rejected", reason: result.reason });
408
+ return;
409
+ }
410
+ const { memory } = result;
401
411
  // action 随行透出(created/merged):memory_save 工具语义对齐所需,
402
412
  // 附加键对既有消费方(CLI add 等)向后兼容。
403
413
  sendJson(res, action === "created" ? 201 : 200, { ...service.toApiList([memory])[0], action });
package/lib/api.js CHANGED
@@ -135,9 +135,14 @@ export function createApi(ctx, service, settings, commands, embedder, semantic =
135
135
  ];
136
136
  // 嵌套键在 kv 里按点号平铺("memoryQualityFilter.enabled"),运行时 cfg 里
137
137
  // 是嵌套对象,effective 从对象子字段取值;其余键照旧从 cfg 顶层取。
138
+ // 这张表必须与 settings.js 白名单里的点号键一一对应:#254 加键时漏了这里,
139
+ // effective 会静默少两个键(configFlagValue 取不到 undefined 就不写进去),
140
+ // 面板上看不出来、PUT 也存不进去——test/api.test.js 的计数锁就是钉这件事的。
138
141
  const NESTED_FLAG_PATHS = {
139
142
  "memoryQualityFilter.enabled": ["memoryQualityFilter", "enabled"],
140
- "llmAudit.enabled": ["llmAudit", "enabled"]
143
+ "llmAudit.enabled": ["llmAudit", "enabled"],
144
+ "writeAdmission.enabled": ["writeAdmission", "enabled"],
145
+ "writeAdmission.enforce": ["writeAdmission", "enforce"]
141
146
  };
142
147
  function configFlagValue(key) {
143
148
  const path = NESTED_FLAG_PATHS[key];
@@ -380,7 +385,7 @@ export function createApi(ctx, service, settings, commands, embedder, semantic =
380
385
  {
381
386
  role: "user",
382
387
  content: [{ type: "text", text: "Reply with exactly one word: ok" }],
383
- source: { kind: "plugin", plugin: "dsh-mneme" }
388
+ source: { kind: "plugin:dsh-mneme", plugin: "dsh-mneme" }
384
389
  }
385
390
  ]
386
391
  })) {