@a9i5k4/dsh-auto-memory 3.1.4 → 3.1.5

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.
@@ -3,7 +3,7 @@
3
3
  * 零 IO、零依赖(node:crypto);不接 Host、不碰 prompt/request、不启动 Python。
4
4
  *
5
5
  * 组成:
6
- * 1) 策略/预算常量(REFERENCE_TAIL_BUDGET_V1 / 注入卫生 guard v1)
6
+ * 1) 策略/预算常量(REFERENCE_TAIL_BUDGET_V1 / 注入卫生 guard v2)
7
7
  * 2) ActivationCandidatePre / ActivationRequestPre validator(JS 硬校验;不重算语义分)
8
8
  * 3) 候选去重(跨 memoryId 同 recordDigest 保最高分,M4 同语义)
9
9
  * 4) Reference Tail 渲染器(固定边界;provenance 身份行永不截断;整体 UTF-8 byte 预算)
@@ -152,16 +152,40 @@ export function dedupeCandidates(candidates) {
152
152
 
153
153
  // ========== §6 Reference Tail 渲染器 ==========
154
154
 
155
- /** 注入卫生 guard v1:控制符剔除/注释语法剥离/换行折叠为 '; '。变更必须升级 guard 版本。 */
155
+ /**
156
+ * 注入卫生 guard v2:控制符剔除/注释语法剥离/多空格折叠/换行折叠为分号空格/模板变量双花括号中和。
157
+ * 变更必须升级 guard 版本。
158
+ *
159
+ * ★guard v2(2026-09-22,issue #132):新增双花括号 → 全角双花括号的中和。
160
+ * 本尾注经 systemPrompt.context() 注入,与记忆主快照共用同一个**严格插值**装配器:宿主
161
+ * dsh-system-prompt 的 interpolate() 会把 context 文本当模板做变量替换 —— 组正则的
162
+ * 字符类要求括号内不含花括号,命中后先校验变量名(须匹配小写名规则,含大写即判 malformed),
163
+ * 再查变量表(未注册即判 unknown),两条都**抛错**并中止整轮装配。
164
+ * 症状与记忆主快照 0.1.39 病例完全一致:该会话**每一轮的模型请求都在组装阶段失败**,
165
+ * 而模型无从自救(它改不了自己的记忆正文)。
166
+ * 中和口径与 lib/index.js 的 neutralizePromptTemplateVars(0.1.39)逐字相同:1:1 等长全角
167
+ * 替换,对人仍可读,且**逐字节确定** ⇒ build 与重渲染两侧 exactDigest 自然一致。
168
+ * 取「无差别双花括号」而非「成对形态」:宿主只在文本仍含开口双花括号时才可能抛错,不含则
169
+ * 走不到校验分支 ⇒ 本口径对任意输入均**不可能残留可抛错形态**;成对替换会漏掉嵌套形态
170
+ * (双花括号内再套花括号),而那恰是宿主判 malformed 的真实输入。
171
+ */
156
172
  export function sanitizeTailText(text) {
157
- return String(text == null ? '' : text)
173
+ return neutralizeTailTemplateVars(String(text == null ? '' : text)
158
174
  .replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F]/g, '')
159
175
  .replace(/<!--|-->/g, '')
160
176
  .replace(/ {2,}/g, ' ')
161
177
  .split(/\r?\n/)
162
178
  .map((s) => s.trim())
163
179
  .filter(Boolean)
164
- .join('; ')
180
+ .join('; '))
181
+ }
182
+
183
+ /**
184
+ * guard v2 内核:双花括号 → 全角等长替换(与 lib/index.js 注入端 neutralizePromptTemplateVars 同口径)。
185
+ * 纯函数、无 IO、逐字节确定;幂等(中和结果不再含 ASCII 双花括号)。
186
+ */
187
+ function neutralizeTailTemplateVars(text) {
188
+ return text.replace(/\{\{/g, '{{').replace(/\}\}/g, '}}')
165
189
  }
166
190
 
167
191
  /**
@@ -279,7 +303,13 @@ export function renderReferenceTail(items, opts = {}) {
279
303
  if (!blocks.length) return { ok: false, reason: 'packet-oversize', dropped }
280
304
  // 提示行在 Verify 之前:先给"需要时取全文"的引导,再以 Verify 收尾(固定边界契约不变)
281
305
  const parts = skillBlock ? blocks.concat([skillBlock]) : blocks
282
- const text = parts.join('\n') + '\n' + TAIL_FETCH_HINT_LINE_V1 + '\n' + TAIL_VERIFY_LINE_V1
306
+ // ★guard v2 唯一出口兜底(2026-09-23 二次修复,issue #132 残余):**必须整段中和,不能只净 reference**。
307
+ // 实测漏网(memoryId/scope/sourceVersion/recordDigest 直接拼进 Source: 身份行,
308
+ // skill.procedureId / skill.level 同理):任一字段含双花括号即穿透,宿主照样抛
309
+ // malformed prompt variable reference "{{ }}"。故在此对**整段渲染文本**过一次中和——
310
+ // 这里是 build 与重渲染的**共同出口**,两侧逐字节一致 ⇒ exactDigest 不受影响;
311
+ // 且对所有既有/未来字段一次性兜住,不再依赖"记得净化每个字段"。
312
+ const text = neutralizeTailTemplateVars(parts.join('\n') + '\n' + TAIL_FETCH_HINT_LINE_V1 + '\n' + TAIL_VERIFY_LINE_V1)
283
313
  return {
284
314
  ok: true, text, truncated: dropped.length > 0, dropped, reason,
285
315
  usedBytes: Buffer.byteLength(text, 'utf8'),
package/lib/client.js CHANGED
@@ -7,7 +7,7 @@
7
7
  * 3. settings.section — 自动记忆设置页(存储位置、注入、反思风格)
8
8
  * Data flows over /api/dsh-auto-memory/* (loopback-only host routes).
9
9
  */
10
- console.log('[dsh-auto-memory] client v3.1.4 fingerprint: ci-restore-and-migrate-safe-import')
10
+ console.log('[dsh-auto-memory] client v3.1.5 fingerprint: tail-brace-neutralize')
11
11
  window.__ModuleLoader__.load({
12
12
  id: '@a9i5k4/dsh-auto-memory',
13
13
  factory: (require) => {
@@ -806,6 +806,19 @@ window.__ModuleLoader__.load({
806
806
 
807
807
  // ───────────────────────── 更新弹窗 / 首次指导 ─────────────────────────
808
808
  var CHANGELOG = {
809
+ '3.1.5': { zh: [
810
+ '★ 修复:记忆正文里出现半角双花括号(例如记下「Vue 模板用 {{ count }} 做插值」),会让该会话之后**每一次模型请求全部失败**。现在渲染尾注前会先把它们换成同形全角字符,不再触发宿主插值抛错。',
811
+ '说明:代价是这类括号在注入文本里会显示成全角形({{ count }}),内容不丢、含义不变。',
812
+ '本次只动尾注渲染器,宿主入口一行未改 ⇒ 不需要重启 dsh web。',
813
+ '站点:落地页按模板整体重写(浅色为基准、中文默认),动效按统一 token 刻度重排;贡献者页补动效层。',
814
+ '修复:落地页首屏「安装」按钮点一次会丢图标与两段文字(复制反馈误用 textContent 整体替换),已改为保留原有结构。',
815
+ ], en: [
816
+ '★ Fix: a memory entry containing double curly braces (e.g. recording "the Vue template interpolates {{ count }}") used to make **every subsequent model request in that session fail**. The tail renderer now folds them into full-width look-alikes before injection, so the host interpolator no longer throws.',
817
+ 'Note: the trade-off is that such braces render as full-width characters in the injected text ({{ count }}) — nothing is dropped, the meaning is unchanged.',
818
+ 'Only the tail renderer changed; the host entry point is untouched, so dsh web does NOT need a restart.',
819
+ 'Site: the landing page was rebuilt from the template (light first, Chinese default) and its motion realigned to one token scale; the contributors page gained a motion layer.',
820
+ 'Fix: the hero "install" button lost its icon and both text spans after one click (copy feedback replaced textContent wholesale); it now preserves the original structure.',
821
+ ] },
809
822
  '3.1.4': { zh: [
810
823
  '★ 修复:白板重写不再「每次都重试」。此前模型不知道锚点契约、注入快照又被截断,首轮必被拦一次;现在工具描述写明「先读磁盘原文抄回锚点」,被拦时还会把缺失卡片的原文块一并回吐,一轮即可补齐。',
811
824
  '★ 变更:白板丢卡从「拒绝写入」改为「照写 + 显式警示」——放行但绝不静默,警示会说明丢了哪几张、从哪找回。用户手写备注区被覆盖、以及卡片 id 重复,仍然硬拒(这两类是真丢数据/结构错误)。',
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@a9i5k4/dsh-auto-memory",
3
3
  "description": "Proactive associative memory for DSH: zero-prompt recall injected before the model speaks, three-layer auto-consolidation, skill crystallization, and Astra-style context management - handoff ledgers, PLAN whiteboard, water-level sensing. Local-first, model-agnostic, zero deps. 主动联想记忆+Astra 式上下文管理:自动唤回/自动沉淀/技能固化/交接账本与白板跨窗口续命/水位感知。",
4
- "version": "3.1.4",
4
+ "version": "3.1.5",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "exports": {