memory-eternal 0.9.4 → 0.9.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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://anthropic.com/claude-code/plugin.schema.json",
3
3
  "name": "memory-eternal",
4
- "version": "0.9.4",
4
+ "version": "0.9.5",
5
5
  "description": "璁板繂鏍稿績锛圡emory Eternal锛夛細鐭ヨ瘑鍗¤嚜鍔ㄦ矇娣€/鍙洖锛岀粺涓€ ~/.dsh/memory-vault锛屼細璇濈粨鏉熻嚜鍔ㄥ叆搴撹繘寰呭鏍搞€?,
6
6
  "author": {
7
7
  "name": "EternalNight996",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memory-eternal",
3
- "version": "0.9.4",
3
+ "version": "0.9.5",
4
4
  "description": "璁板繂鏍稿績锛圡emory Eternal锛夛細鐭ヨ瘑鍗¤嚜鍔ㄦ矇娣€/鍙洖锛岀粺涓€ ~/.dsh/memory-vault锛屼細璇濈粨鏉熻嚜鍔ㄥ叆搴撹繘寰呭鏍搞€?,
5
5
  "author": {
6
6
  "name": "EternalNight996",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memory-eternal",
3
- "version": "0.9.4",
3
+ "version": "0.9.5",
4
4
  "description": "璁板繂鏍稿績锛圡emory Eternal锛夛細鐭ヨ瘑鍗¤嚜鍔ㄦ矇娣€/鍙洖锛岀粺涓€ ~/.dsh/memory-vault锛屼細璇濈粨鏉熻嚜鍔ㄥ叆搴撹繘寰呭鏍搞€?,
5
5
  "author": {
6
6
  "name": "EternalNight996",
package/README.en.md CHANGED
@@ -244,12 +244,13 @@ npm run build # builds lib/client.js (DSH embed) + web/app.js (standalone web
244
244
 
245
245
  ## 📋 Changelog
246
246
 
247
- > **Withdrawn versions**: **v0.9.1 / v0.9.2 are deprecated on npm and their release tags have been removed from git** — both ship the blank-memory-page defect. Use **v0.9.3+** (`npm i memory-eternal@latest`). v0.9.0 is deprecated too (its capture alerts false-alarm).
247
+ > **Withdrawn versions**: **v0.9.0 / v0.9.1 / v0.9.2 / v0.9.3 are all deprecated on npm, and the release tags for v0.9.1 / v0.9.2 / v0.9.3 have been removed from git** — v0.9.1/v0.9.2 ship the blank-memory-page defect, v0.9.0 false-alarms its capture warnings, and **v0.9.3 does not support DSH v0.1.7-rc.2** (the plugin stops mounting entirely: the settings service changed and the client-side `settingsScope` is gone). Use **v0.9.4+** (`npm i memory-eternal@latest`).
248
248
 
249
- > **DSH compatibility**: `>=0.1.5-alpha.2 <0.2.0`. **v0.9.4 adds support for DSH v0.1.7-rc.2**, which replaced the settings service with a forms-only API and removed `@deepseek-ai/dsh-client-runtime` / `settingsScope`. The 0.1.5 line still uses the legacy `settings.register` path; both paths are kept.
249
+ > **DSH compatibility**: `>=0.1.5-alpha.2 <0.2.0`. **v0.9.4 adds support for DSH v0.1.7-rc.2**, which replaced the settings service with a forms-only API and removed `@deepseek-ai/dsh-client-runtime` / `settingsScope`; **v0.9.5 adds support for schemastery ≥3.18.4 volatile live references** (the shape the official desktop profile uses, while the web profile still ships 3.18.1 — both work). The 0.1.5 line still uses the legacy `settings.register` path; both paths are kept.
250
250
 
251
251
  | Version | Date | Highlights |
252
252
  |---|---|---|
253
+ | **v0.9.5** | 2026-09-28 | **Fixed the plugin failing to mount under the official desktop build (schemastery 3.18.4)**: the desktop profile resolves **schemastery 3.18.4**, which turns every `volatile` Config field into a cosmokit **live reference** (`{ get(): snapshot }` branded with `Symbol.for('cosmokit.volatile.write')`), while 0.9.4 treated those fields as plain values — `cfg.vaultDir.trim()` threw `TypeError: cfg.vaultDir.trim is not a function` and the plugin died inside `apply` (the exact desktop error). The plugin now **deep-unwraps** references per the cosmokit protocol (snapshot each reference, recurse through arrays/objects), so `settings.get()` only ever exposes plain values; each read unwraps afresh, so in-place volatile hot updates stay immediately visible, and `JSON.stringify` no longer writes `{}` into the shared config file. Adds 2 regressions (the real 3.18.4 reference shape + nested arrays/objects) and verifies `apply` under the **desktop build's real module-resolution layout** (schemastery 3.18.4 + real cosmokit) |
253
254
  | **v0.9.4** | 2026-09-28 | **DSH v0.1.7-rc.2 support (fixes "the plugin goes dark after the upgrade")**: (1) **The settings service was replaced** — in 0.1.7 `ctx.settings` is a forms-only API (`describe/update/replace/mutate/configure`) with no `register()`; the old `ctx.settings.register(...)` call throws a `TypeError`, so the plugin never mounts (memory page gone, auto-capture dead). A cross-version shim keeps `register` for older hosts while new hosts read the **live config reference** the loader passes in, subscribe to `loader/volatile-update` for hot updates, and write back through `settings.update(entry id, patch, revision)` (revision conflicts map to HTTP 409); it also registers `configure({ auto:false })` so the host does not generate a duplicate form page. (2) **Volatile field marking moved after construction**: no more chained `.volatile()` — that method only exists in schemastery ≥3.18.4, while the plugin actually resolves **3.18.1** at the profile level, so the chain threw `volatile is not a function` at import time and killed the plugin. (3) **Dead client references removed**: `inject` no longer lists `settingsScope`, which disappeared together with `@deepseek-ai/dsh-client-runtime` (0.1.7 has no such service, so the client plugin waited forever and never activated — taking the memory page and the sidebar button with it); `dsh.client.inject` dropped its non-existent package names. (4) New **`tests/settings-compat.test.mjs`** (8 cases: 0.1.7-shaped mount / live-reference reads / volatile hot update / write-back and revision conflict / legacy `register` path / field volatile markers) wired into `npm test`. Verified by booting a **real DSH v0.1.7-rc.2**: the host plugin mounts (config written to `memory-eternal-config.json`) and the client bundle composes into the boot graph (`plugins/??memory-eternal/client.js`) |
254
255
  | **v0.9.3** | 2026-09-12 | **Fixed the blank memory page ("no UI")**: v0.9.1 placed the infinite-scroll `useEffect` **before** the `loadCards` definition — React evaluates the dependency array during render, hitting a TDZ error (`Cannot access 'loadCards' before initialization`) that **crashed the whole memory page on first render**. It now comes after the definition. Added a **render smoke test** (`tests/ssr.test.mjs`: renders the built bundle through all four entry points — cards / settings / usage / graph — wired into `npm test`) so "green build, blank page" bugs cannot ship again |
255
256
  | **v0.9.2** | 2026-09-12 | **Log visibility + false-alarm fix**: the capture log is now **persisted to disk** (`~/.dsh/memory-eternal-capture.jsonl`, last 500 entries) — the standalone web page no longer says "log only available inside the DSH host" but shows the records, and history survives a host restart (read back on boot); fixed **stall-detector false alarms flooding the panel** (mismatched turn counters are normal: sub-agent turns and cancelled turns emit no `turn-stopping`; it now requires "turns running **and** no capture activity for 15 minutes" to alert once, and the alarm clears as soon as activity resumes — no more one `fail` line every 10 minutes permanently turning health red); when distillation returns nothing / unparseable JSON the content is **saved as a raw card instead of being dropped** |
package/README.md CHANGED
@@ -257,12 +257,13 @@ npm run build # 构建 lib/client.js(DSH 内嵌)+ web/app.js(独立 web
257
257
 
258
258
  ## 📋 更新日志
259
259
 
260
- > **版本撤回说明**:**v0.9.1 / v0.9.2 已从 npm 标记 deprecated 并从 git 取回(release tag 已删除)** —— 这两版带记忆页白屏缺陷,请使用 **v0.9.3+**(`npm i memory-eternal@latest`)。v0.9.0 同样标记 deprecated(沉淀告警会误报刷屏)。
260
+ > **版本撤回说明**:**v0.9.0 / v0.9.1 / v0.9.2 / v0.9.3 均已在 npm 标记 deprecated;v0.9.1 / v0.9.2 / v0.9.3 的 release tag 已从 git 移除** —— v0.9.1/v0.9.2 带记忆页白屏缺陷,v0.9.0 沉淀告警误报刷屏,**v0.9.3 不支持 DSH v0.1.7-rc.2**(升级后插件整体挂不上:设置服务换血 + 客户端 `settingsScope` 消失)。请使用 **v0.9.4+**(`npm i memory-eternal@latest`)。
261
261
 
262
- > **DSH 兼容性**:`>=0.1.5-alpha.2 <0.2.0`。**v0.9.4 起适配 DSH v0.1.7-rc.2**(该版本把设置服务换成纯表单 API,并移除了 `@deepseek-ai/dsh-client-runtime` 与 `settingsScope`)。0.1.5 系列仍走旧的 `settings.register` 路径,两条路径都保留。
262
+ > **DSH 兼容性**:`>=0.1.5-alpha.2 <0.2.0`。**v0.9.4 起适配 DSH v0.1.7-rc.2**(该版本把设置服务换成纯表单 API,并移除了 `@deepseek-ai/dsh-client-runtime` 与 `settingsScope`);**v0.9.5 起兼容 schemastery ≥3.18.4 的 volatile 活引用**(官方桌面版 profile 即此形态,web profile 仍是 3.18.1,两者都支持)。0.1.5 系列仍走旧的 `settings.register` 路径,两条路径都保留。
263
263
 
264
264
  | 版本 | 日期 | 关键改动 |
265
265
  |---|---|---|
266
+ | **v0.9.5** | 2026-09-28 | **修复官方桌面版(schemastery 3.18.4)下插件整体挂不上**:桌面版 profile 解析到的是 **schemastery 3.18.4**,它会把标了 `volatile` 的 Config 字段解析成 cosmokit 的**活引用**(`{ get(): snapshot }`,品牌 `Symbol.for('cosmokit.volatile.write')`),而 0.9.4 的业务代码把字段当普通值用 —— `cfg.vaultDir.trim()` 当场抛 `TypeError: cfg.vaultDir.trim is not a function`,插件在 `apply` 里就崩(桌面版实测报错原文)。现按 cosmokit 协议统一**深解引用**(引用取快照、数组/对象递归展开),`settings.get()` 对外只给普通值;每次读取都重新解,loader 原地提交的 volatile 热更新照样立刻可见,`JSON.stringify` 写共享配置也不再变成 `{}`。新增 2 项回归(3.18.4 真实引用形态 + 嵌套数组/对象),并用**桌面版真实模块解析布局**(schemastery 3.18.4 + 真 cosmokit)跑通 `apply` 验证 |
266
267
  | **v0.9.4** | 2026-09-28 | **适配 DSH v0.1.7-rc.2(修复「升级后插件整体失联」)**:① **设置服务换血** —— 0.1.7 的 `ctx.settings` 只剩表单 API(`describe/update/replace/mutate/configure`),不再有 `register()`;旧代码 `ctx.settings.register(...)` 直接抛 `TypeError`,插件根本挂不上(记忆页消失、自动沉淀停摆)。现改为跨版本兼容层:旧版仍走 `register`,新版读 loader 传进来的**活配置引用**、订阅 `loader/volatile-update` 做热更新、写回走 `settings.update(条目 id, patch, revision)`(revision 冲突映射 HTTP 409),并注册 `configure({ auto:false })` 免得宿主再生成一张重复的表单页。② **字段 volatile 标记改为构造后统一打**:不再链式写 `.volatile()` —— 该方法 schemastery ≥3.18.4 才有,而插件在 profile 层实际解析到的是 **3.18.1**,链式调用会在 `import` 期抛 `volatile is not a function`,把插件整个打挂。③ **客户端去死引用**:`inject` 移除已随 `@deepseek-ai/dsh-client-runtime` 一起消失的 `settingsScope`(0.1.7 客户端服务表里已无此服务,插件会永远等待服务而永不激活 → 记忆页与侧边栏按钮全部不见);`dsh.client.inject` 同步去掉不存在的包名。④ 新增 **`tests/settings-compat.test.mjs`**(8 项:0.1.7 形状挂载 / 活引用读值 / volatile 热更新 / 写回与 revision 冲突 / 老版本 `register` 路径 / 字段 volatile 标记),已并入 `npm test`。已在**真实 DSH v0.1.7-rc.2** 上启动验证:宿主插件正常挂载(配置落盘 `memory-eternal-config.json`)、客户端 bundle 正常进入 boot graph(`plugins/??memory-eternal/client.js`) |
267
268
  | **v0.9.3** | 2026-09-12 | **修复记忆页白屏("没画面")**:v0.9.1 把「滚动续拉」的 `useEffect` 写在了 `loadCards` 定义**之前**——React 在渲染期求值依赖数组,触发 TDZ(`Cannot access 'loadCards' before initialization`),**整个记忆页一渲染就崩**;现已移到定义之后。**新增渲染冒烟测试**(`tests/ssr.test.mjs`:真跑打包产物、把卡片/设置/用量/图谱四个入口各渲染一遍,已并入 `npm test`)——「构建全绿、页面白屏」这类 bug 以后发不出去 |
268
269
  | **v0.9.2** | 2026-09-12 | **日志可见性 + 误报修复**:自动沉淀日志**落盘持久化**(`~/.dsh/memory-eternal-capture.jsonl`,最多 500 条)——独立 Web 页不再显示「日志仅在 DSH 宿主内可用」而是直接能看到记录,宿主重启后历史也不丢(启动时读回);修复**停滞探测误报刷屏**(轮次计数对不上其实是常态:子代理轮次、被取消的轮次都不发 `turn-stopping`;现在要求「有轮次在跑 **且** 15 分钟无任何沉淀活动」才报一次,活动恢复即自动撤销,不再每 10 分钟刷一条把面板挤满、健康状态永久亮红);蒸馏无输出/JSON 解析失败时**改为原文卡兜底**,内容不再白丢 |
package/index.js CHANGED
@@ -132,13 +132,41 @@ function settingsEntryId(ctx) {
132
132
  return entry?.options?.id || 'memory-eternal'
133
133
  }
134
134
 
135
+ // schemastery ≥3.18.4 会把 Config 里标了 volatile 的字段解析成 cosmokit 的「活引用」
136
+ // (形如 { get(): snapshot },品牌是全局注册的 Symbol.for('cosmokit.volatile.write')),
137
+ // 而 ≤3.18.1 完全忽略 volatile、直接给普通值 —— 同一份 Config 在两种宿主上形状不同:
138
+ // • 官方桌面版 profile 解析到 schemastery 3.18.4 → cfg.vaultDir 是引用对象,
139
+ // 旧代码 cfg.vaultDir.trim() 当场抛 "trim is not a function",插件整体挂不上;
140
+ // • 早期 web profile 解析到 3.18.1 → 普通值,碰巧能跑(所以一开始没暴露)。
141
+ // 官方插件的写法是每次取用都 .get()(如 dsh-agent-default-model 的 this.config.model.get())。
142
+ // 业务代码要的是普通值,这里统一深解引用:既拿到快照,又因为每次读都重新解,
143
+ // loader 原地提交的 volatile 热更新依然立刻可见。JSON.stringify 也因此不再写出 {}。
144
+ const VOLATILE_WRITE = Symbol.for('cosmokit.volatile.write')
145
+
146
+ function isVolatileRef(value) {
147
+ return typeof value === 'object' && value !== null && VOLATILE_WRITE in value
148
+ }
149
+
150
+ /** 深拷贝一份「普通值」配置:volatile 引用解引用,数组 / 对象递归展开。 */
151
+ function plainConfig(value, depth = 0) {
152
+ if (depth > 8) return value
153
+ if (isVolatileRef(value)) return plainConfig(value.get(), depth + 1)
154
+ if (Array.isArray(value)) return value.map((item) => plainConfig(item, depth + 1))
155
+ if (value !== null && typeof value === 'object') {
156
+ const out = {}
157
+ for (const [key, item] of Object.entries(value)) out[key] = plainConfig(item, depth + 1)
158
+ return out
159
+ }
160
+ return value
161
+ }
162
+
135
163
  // 无 Loader 挂载、apply 又没拿到 config 时,用标准 schema 校验空对象取默认值。
136
164
  function schemaDefaults(schema) {
137
165
  try {
138
166
  const std = schema?.['~standard']
139
167
  if (std && typeof std.validate === 'function') {
140
168
  const result = std.validate({})
141
- if (result && !result.issues) return result.value
169
+ if (result && !result.issues) return plainConfig(result.value)
142
170
  }
143
171
  } catch { /* 拿不到默认值就用空对象 */ }
144
172
  return {}
@@ -150,7 +178,7 @@ function bindSettings(ctx, schema, config) {
150
178
  return service.register('memory-eternal', schema, { base: config ?? {} })
151
179
  }
152
180
  const fallback = schemaDefaults(schema)
153
- const read = () => config ?? fallback
181
+ const read = () => (config === undefined || config === null ? fallback : plainConfig(config))
154
182
  const entryId = settingsEntryId(ctx)
155
183
  // dsh ≥0.1.7 的表单页策略:本插件自带「记忆」设置页(client 侧注册 settings.section),
156
184
  // 声明 auto:false,免得宿主再按 schema 自动生成一张重复的表单页。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memory-eternal",
3
- "version": "0.9.4",
3
+ "version": "0.9.5",
4
4
  "description": "记忆核心(Memory Eternal):自研的 DeepSeek Harness 记忆插件,不移植任何既有记忆框架——对话结束后自动沉淀知识卡到本地 Markdown Vault(自研去重、自研 CJK 检索、可 git 管理),设置页提供图形化知识库(统计 / 搜索 / 知识图谱 + 侧边栏一键弹窗),Agent 通过 memory_recall 工具按需召回历史上下文。零人工干预。",
5
5
  "license": "MIT",
6
6
  "repository": {