memory-eternal 0.9.5 → 0.9.7

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.5",
4
+ "version": "0.9.7",
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.5",
3
+ "version": "0.9.7",
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.5",
3
+ "version": "0.9.7",
4
4
  "description": "璁板繂鏍稿績锛圡emory Eternal锛夛細鐭ヨ瘑鍗¤嚜鍔ㄦ矇娣€/鍙洖锛岀粺涓€ ~/.dsh/memory-vault锛屼細璇濈粨鏉熻嚜鍔ㄥ叆搴撹繘寰呭鏍搞€?,
5
5
  "author": {
6
6
  "name": "EternalNight996",
package/README.en.md CHANGED
@@ -29,10 +29,14 @@
29
29
 
30
30
  ### 🟦 DeepSeek Harness (DSH) — focus
31
31
 
32
- **Install** (dsh-desktop via DSH CLI, one command):
32
+ **Install** (official desktop app via the plugin marketplace, `dsh web` via one CLI line):
33
33
 
34
34
  ```bash
35
- # dsh-desktop (recommended): install via DSH CLI into the profile
35
+ # 1) Official DeepSeek Harness desktop app (recommended): Settings -> Plugins -> search memory-eternal
36
+ # Equivalent CLI (that shell's profile is named "desktop"):
37
+ dsh plugin --profile desktop add memory-eternal
38
+
39
+ # 2) dsh web (browser):
36
40
  dsh plugin --profile web add memory-eternal
37
41
 
38
42
  # or update directly in the profile (pnpm workspace). Use pnpm — `npm install` throws EUNSUPPORTEDPROTOCOL
@@ -41,13 +45,19 @@ cd ~/.dsh/profiles/web && pnpm add memory-eternal@latest
41
45
  # right after a release, @latest can be held back by pnpm's minimum-release-age gate or a cached
42
46
  # packument (it silently stays on the old version): pin the version instead — pnpm adds it to the
43
47
  # workspace's minimumReleaseAgeExclude automatically
44
- cd ~/.dsh/profiles/web && pnpm add memory-eternal@0.9.0
48
+ cd ~/.dsh/profiles/web && pnpm add memory-eternal@0.9.6
45
49
 
46
- # verify the version, then restart dsh web
50
+ # verify the version, then restart the host
47
51
  node -e "console.log(require('memory-eternal/package.json').version)"
48
52
  ```
49
53
 
50
- After **restarting dsh web**, three things are live immediately:
54
+ #### 🖥️ Desktop support policy (read this first)
55
+
56
+ - **The official DeepSeek Harness desktop build is the priority — and the only guaranteed target** (the official Electron release; its profile is named `desktop`). The v0.9.4 → v0.9.6 fixes all target it: the 0.1.7 settings-service rewrite, `schemastery 3.18.4` volatile live references, and window-titlebar avoidance (`data-windows-titlebar`, so a full-screen overlay can no longer cover minimize/maximize/close).
57
+ - **The author's own `dsh-desktop` (`dsh-desktop-shell` / `dsh-ui-*` / `dsh-plugin-marketplace`) is discontinued** and is no longer a support target — the official desktop build covers the same ground, and maintaining two shells only splits compatibility. Note that its profile still pins `dsh-desktop-shell@0.3.0`, which has been unpublished from npm and makes `pnpm install` fail outright; migrating to the official desktop build and dropping those dependencies is recommended.
58
+ - Compatibility matrix (both verified): the official `desktop` profile (schemastery **3.18.4**) and the `web` profile behind `dsh web` (schemastery **3.18.1**) share the same code path.
59
+
60
+ After **restarting the host**, three things are live immediately:
51
61
 
52
62
  | Effect | Where |
53
63
  |---|---|
@@ -244,12 +254,14 @@ npm run build # builds lib/client.js (DSH embed) + web/app.js (standalone web
244
254
 
245
255
  ## 📋 Changelog
246
256
 
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`).
257
+ > **Withdrawn versions**: **v0.9.0 – v0.9.5 are all deprecated on npm, and the release tags for v0.9.1 / v0.9.2 / v0.9.3 / v0.9.4 have been removed from git** (v0.9.5 is merely superseded, so its tag stays) — v0.9.1/v0.9.2 ship the blank-memory-page defect, v0.9.0 false-alarms its capture warnings, 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), v0.9.4 crashes under the official desktop build (schemastery 3.18.4 volatile live references) with `cfg.vaultDir.trim is not a function`, and **v0.9.5's full-screen overlay covers the desktop shell's window controls (its top-right "×" sits on the window Close button — one click quits the whole shell)**. Use **v0.9.6+** (`npm i memory-eternal@latest`).
248
258
 
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.
259
+ > **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); **v0.9.6 keeps full-screen overlays clear of the desktop shell's window controls**. The 0.1.5 line still uses the legacy `settings.register` path; both paths are kept.
250
260
 
251
261
  | Version | Date | Highlights |
252
262
  |---|---|---|
263
+ | **v0.9.7** | 2026-09-28 | **Cards open fully expanded (and can be collapsed) + new body typography**: the reader no longer folds to 300px by default — it **opens showing the whole card**, with a one-click collapse for long ones (and an "Expand ⌄" hint when folded). Frontmatter is lifted out of the body into **colored chips** (kind / audit status / tags / dates / source; kind reuses the graph palette) instead of leaking raw YAML. Body rendering is rewritten (`src/client/markdown.js`, shared by the host and the standalone web page): headings get an **emoji + color group by meaning** (conclusion ✅green / risk ⚠️amber / root cause 🔍blue / plan 🛠️purple / example 💡pink), consecutive `- ` lines become a real `<ul>`, `1.` becomes an `<ol>` with numbered circles, `- [x]` becomes a checkbox, `>` becomes an emoji callout, `---` becomes a divider, short `key: value` lines get an aligned style, and `**bold**` gets a highlighter underline; fenced code is protected so `#` / `-` inside it are no longer re-typeset. **Adds 7 typography unit tests** (XSS escaping, link-protocol allowlist, prose colons must not be misread as key/value). Also carries the PR #8 port: Electron-host subprocess node resolution (`lib/node-bin.js`, fixing "standalone web server never starts → sidebar popup white screen") and API routes registered after `webServer` is ready (fixing "settings page stuck loading") |
264
+ | **v0.9.6** | 2026-09-28 | **Fixed the full-screen overlay covering the desktop shell's window controls (clicking Close quit the whole shell)**: the desktop shell draws minimize / maximize / close at the top of the page and, per the DSH convention, marks `<html>` with `data-windows-titlebar` and publishes `--dsh-windows-titlebar-height` (both confirmed present inside the official desktop build's `app.asar`); the memory overlay used `inset:0` plus an inline `100vh`, covering that whole strip, and our own top-right "×" landed exactly on the shell's window Close — one click quit the entire desktop shell. The full-screen state now uses the `.me-modal-full` class (no inline `100vh`, which CSS cannot override), and under `[data-windows-titlebar]` the `.me-overlay-top` / `.me-overlay` / `.me-modal-full` surfaces are pushed down by `--dsh-windows-titlebar-height` with height `calc(100vh - that)`. Browsers without the attribute get a 0px offset, so behaviour is unchanged there. The export-graph full-screen preview also moved from `100vh` to `100%` so it cannot overflow the shortened overlay. Adds 1 render regression asserting all three avoidance rules ship in the bundle |
253
265
  | **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) |
254
266
  | **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`) |
255
267
  | **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 |
package/README.md CHANGED
@@ -29,24 +29,34 @@
29
29
 
30
30
  ### 🟦 DeepSeek Harness(DSH)—— 重点
31
31
 
32
- **装**(dsh-desktop 用 DSH CLI,一条命令):
32
+ **装**(官方桌面版走插件市场,`dsh web` 用一条 CLI):
33
33
 
34
34
  ```bash
35
- # dsh-desktop 用户(推荐):DSH CLI 直接装进 profile
35
+ # ① 官方 DeepSeek Harness 桌面版(推荐):设置 → 插件 → 搜 memory-eternal 安装
36
+ # 等价 CLI(该壳的 profile 名就是 desktop):
37
+ dsh plugin --profile desktop add memory-eternal
38
+
39
+ # ② dsh web(浏览器端):
36
40
  dsh plugin --profile web add memory-eternal
37
41
 
38
- # 或直接在 profile(pnpm workspace)里更新。注意用 pnpm,npm install 会报 EUNSUPPORTEDPROTOCOL
42
+ # 或在 profile(pnpm workspace)里直接更新。注意用 pnpm,npm install 会报 EUNSUPPORTEDPROTOCOL
39
43
  cd ~/.dsh/profiles/web && pnpm add memory-eternal@latest
40
44
 
41
45
  # 刚发新版时 @latest 可能被 pnpm 的最小发布年龄门槛/元数据缓存挡住(静默停在旧版):
42
46
  # 直接指定版本号最快,pnpm 会自动把它加进 workspace 的 minimumReleaseAgeExclude
43
- cd ~/.dsh/profiles/web && pnpm add memory-eternal@0.9.0
47
+ cd ~/.dsh/profiles/web && pnpm add memory-eternal@0.9.6
44
48
 
45
- # 验版本(应等于上面装的号),然后重启 dsh web 生效
49
+ # 验版本(应等于上面装的号),然后重启对应宿主生效
46
50
  node -e "console.log(require('memory-eternal/package.json').version)"
47
51
  ```
48
52
 
49
- **重启 dsh web** 后,三样东西立即生效:
53
+ #### 🖥️ 桌面版支持策略(先看这条)
54
+
55
+ - **优先、且只保证支持官方 DeepSeek Harness 桌面版**(官方 Electron 发行版,profile 名 `desktop`)。v0.9.4 → v0.9.6 三轮修复全部围绕它:0.1.7 设置服务换血、`schemastery 3.18.4` 的 volatile 活引用、以及窗口标题栏避让(`data-windows-titlebar`,避免全屏浮层压住最小化/最大化/关闭)。
56
+ - **作者自研的 `dsh-desktop`(`dsh-desktop-shell` / `dsh-ui-*` / `dsh-plugin-marketplace` 那一套)已停止维护**,不再作为支持目标 —— 官方桌面版已覆盖同样能力,继续维护两条壳只会分裂兼容性。注意它的 profile 依赖里还钉着已从 npm 撤下的 `dsh-desktop-shell@0.3.0`,会让 `pnpm install` 直接失败;**建议迁到官方桌面版,并从 profile 里删掉这套依赖**。
57
+ - 兼容矩阵(均已实测):官方桌面版 `desktop` profile(schemastery **3.18.4**)+ `dsh web` 的 `web` profile(schemastery **3.18.1**),两条路径共用同一份代码。
58
+
59
+ **重启宿主**后,三样东西立即生效:
50
60
 
51
61
  | 效果 | 在哪看 |
52
62
  |---|---|
@@ -257,12 +267,14 @@ npm run build # 构建 lib/client.js(DSH 内嵌)+ web/app.js(独立 web
257
267
 
258
268
  ## 📋 更新日志
259
269
 
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`)。
270
+ > **版本撤回说明**:**v0.9.0 – v0.9.5 均已在 npm 标记 deprecated;v0.9.1 / v0.9.2 / v0.9.3 / v0.9.4 的 release tag 已从 git 移除**(v0.9.5 只是被取代、tag 保留)—— v0.9.1/v0.9.2 带记忆页白屏缺陷,v0.9.0 沉淀告警误报刷屏,v0.9.3 不支持 DSH v0.1.7-rc.2(升级后插件整体挂不上:设置服务换血 + 客户端 `settingsScope` 消失),v0.9.4 在官方桌面版(schemastery 3.18.4 的 volatile 活引用)下抛 `cfg.vaultDir.trim is not a function`、插件整体挂不上,**v0.9.5 的全屏浮层会盖住桌面版的窗口控制面板(右上角「×」压在窗口「关闭」上,点一下会退出整个桌面壳)**。请一律使用 **v0.9.6+**(`npm i memory-eternal@latest`)。
261
271
 
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` 路径,两条路径都保留。
272
+ > **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,两者都支持);**v0.9.6 起全屏浮层自动让开桌面壳的窗口标题栏**(不再压住最小化/最大化/关闭)。0.1.5 系列仍走旧的 `settings.register` 路径,两条路径都保留。
263
273
 
264
274
  | 版本 | 日期 | 关键改动 |
265
275
  |---|---|---|
276
+ | **v0.9.7** | 2026-09-28 | **打开卡片默认全部展开(可收起)+ 正文排版重做**:卡片阅读器不再默认折成 300px,而是**打开即读全文**,长卡可一键收起(折叠后底部给「展开 ⌄」提示)。frontmatter 从正文里抽出来,改成 kind / 审核状态 / 标签 / 时间 / 来源的**彩色 chips**(kind 沿用图谱配色),不再把一段 YAML 当正文露出来。正文排版换成新方案(`src/client/markdown.js`,宿主与独立 web 共用同一套):小标题按语义自动配 **emoji + 颜色分组**(结论 ✅绿 / 风险 ⚠️琥珀 / 根因 🔍蓝 / 方案 🛠️紫 / 示例 💡粉),连续 `- ` 合成真正的 `<ul>`、`1.` 合成带圆形序号的 `<ol>`、`- [x]` 变复选框、`>` 引用升级成带 emoji 的 callout、`---` 变分隔线、行首「短键:值」渲染成对齐样式、`**加粗**` 加荧光笔下划线;围栏代码整段保护,内部 `#` / `-` 不再被误排版。**新增 7 项排版单测**(含 XSS 转义、链接协议白名单、散文冒号不得误判成 key/value)。另含 PR #8 移植:Electron 宿主下的子进程 node 解析(`lib/node-bin.js`,修「独立 web server 拉不起来 → 侧边栏弹窗白屏」)与 `webServer` 就绪后再注册 API 路由(修「设置页永远加载中」) |
277
+ | **v0.9.6** | 2026-09-28 | **修复官方桌面版全屏浮层挡住窗口控制面板(点「关闭」会退出整个桌面壳)**:桌面壳把「最小化 / 最大化 / 关闭」画在页面顶部,并按 DSH 约定在 `<html>` 上打 `data-windows-titlebar` + 给出 `--dsh-windows-titlebar-height`(已在官方桌面版 `app.asar` 里确认这两个标记确实存在);记忆库全屏浮层原本是 `inset:0` + 内联 `100vh`,整条盖住标题栏,而我们右上角的「×」恰好压在窗口「关闭」上 —— 用户一点就直接退出整个桌面壳。现全屏态改用 `.me-modal-full` 类(不再写死内联 `100vh`:内联样式无法被 CSS 覆盖),并在 `[data-windows-titlebar]` 下把 `.me-overlay-top` / `.me-overlay` / `.me-modal-full` 一律下移 `--dsh-windows-titlebar-height`、高度改为 `calc(100vh - 该高度)`;浏览器里没有该属性时偏移 0px,行为与之前完全一致。导出图谱的全屏预览同步从 `100vh` 改为 `100%`,避免在缩短后的浮层里溢出。新增 1 项渲染回归断言(三处让位规则必须出现在打包产物中) |
266
278
  | **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` 验证 |
267
279
  | **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`) |
268
280
  | **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 以后发不出去 |
package/index.js CHANGED
@@ -30,6 +30,7 @@ import { migrateFromMarkdown, setAuditConfig, backupDb } from './lib/db.js'
30
30
  import { summarizeTurn, extractLastTurn, sliceNewEvents, sessionEvents, sessionEventApi, createCaptureHealth, resolveRoute, captureCard, captureUpdate, pickNeighbors } from './lib/capture.js'
31
31
  import { createApi, json, encodeBody } from './lib/api.js'
32
32
  import { appendCaptureLog, readCaptureLog, rotateCaptureLog } from './lib/capture-log.js'
33
+ import { nodeBinary, childEnv } from './lib/node-bin.js'
33
34
 
34
35
  export const name = 'memory-eternal'
35
36
  export const inject = ['systemPrompt', 'settings']
@@ -631,8 +632,12 @@ export function apply(ctx, config) {
631
632
  let webInfo = { url: 'http://127.0.0.1:7999', port: 7999, alive: false }
632
633
  const refreshWebInfo = (info) => { if (info && info.url) webInfo = { ...info, alive: true } }
633
634
 
634
- const webServer = ctx.get('webServer')
635
- if (webServer !== undefined) {
635
+ // webServer 是「可能晚到」的服务:apply 执行时它常常尚未挂载,同步 ctx.get()
636
+ // 拿不到就整段跳过、且不留任何日志 —— 表现是 /memory-eternal/api/* 恒 404、
637
+ // 客户端设置页永远停在「加载中…」。改用 ctx.inject() 等服务就绪后再注册:
638
+ // 没有该服务的 profile(如 TUI)里子 fiber 保持 pending,主插件照常激活。
639
+ // (DSH 自身的 dsh-client-modules 也是这么写的:ctx.inject(['webServer'], …))
640
+ const registerApiRoutes = (webServer) => {
636
641
  const handleApi = createApi({
637
642
  vaultDir, vaultRoots, getSettings: settings.get,
638
643
  // 自动沉淀运行轨迹 + 健康状态:供「用量/今日」页排查「为什么没写卡」,异常时页面顶部亮红。
@@ -769,6 +774,15 @@ export function apply(ctx, config) {
769
774
  })
770
775
  }
771
776
 
777
+ // 等 webServer 就绪再注册宿主侧 API。注册成功留一条 boot 记录,
778
+ // 便于在「设置 → 记忆 → 用量/今日」里确认路由到底挂上没有。
779
+ ctx.inject(['webServer'], (child) => {
780
+ const webServer = child.get('webServer')
781
+ if (webServer === undefined) return
782
+ registerApiRoutes(webServer)
783
+ logCapture('system', 'boot', '记忆 API 路由已注册(/memory-eternal/api)')
784
+ })
785
+
772
786
  // -- 4. 多宿主常驻:MCP 挂载 + web server 保活(按设置项分层) -----------------
773
787
  // 全部后台异步、静默失败:插件激活不能被外部环境问题卡住。
774
788
  let intervalTimer = null
@@ -835,16 +849,29 @@ export function apply(ctx, config) {
835
849
  import('./lib/watchdog.js')
836
850
  .then((m) => {
837
851
  const port = Number(cfg0.webPort) || 7999
852
+ // 用 nodeBinary() 而非 process.execPath:Electron 宿主下后者是 Electron
853
+ // 主程序,spawn 出来不会执行 watchdog.js(见 lib/node-bin.js)。
854
+ const bin = nodeBinary()
838
855
  const wd = spawn(
839
- process.execPath,
856
+ bin,
840
857
  [path.join(PACKAGE_ROOT, 'lib', 'watchdog.js'), '--port', String(port), '--interval', String(cfg0.webCheckIntervalMs || 5000), '--max-restart', String(cfg0.webMaxRestart || 10)],
841
- { detached: true, stdio: 'ignore', env: { ...process.env, MEMORY_VAULT_DIR: vaultDir() }, windowsHide: true },
858
+ { detached: true, stdio: 'ignore', env: childEnv({ MEMORY_VAULT_DIR: vaultDir() }), windowsHide: true },
842
859
  )
860
+ // spawn 失败默认静默:既写 stderr,也进自动沉淀日志(面板可见)
861
+ wd.on('error', (error) => {
862
+ const why = `watchdog spawn 失败(${bin}):${error?.message || error}`
863
+ console.error(`[memory-eternal] ${why}`)
864
+ logCapture('system', 'fail', why)
865
+ })
843
866
  wd.unref()
844
867
  watchdogProc = wd
845
- console.error(`[memory-eternal] watchdog spawned pid=${wd.pid} port=${port}`)
868
+ console.error(`[memory-eternal] watchdog spawned pid=${wd.pid} bin=${bin} port=${port}`)
869
+ })
870
+ .catch((error) => {
871
+ const why = `watchdog 模块加载失败:${error?.message || error}`
872
+ console.error(`[memory-eternal] ${why}`)
873
+ logCapture('system', 'fail', why)
846
874
  })
847
- .catch(() => {})
848
875
  }
849
876
 
850
877
  return () => {