dsh-memoir 0.9.0 → 0.9.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.en.md CHANGED
@@ -11,14 +11,18 @@
11
11
 
12
12
  No embeddings, vector database, or cloud memory service. The npm package has zero bundled runtime dependencies; DSH and Zod 4 peers are supplied by the host environment; Zod validates session projections and is not bundled.
13
13
 
14
+ > [!WARNING]
15
+ > **0.9.1 fixes session recovery issue #14 affecting receipts written by 0.8.1–0.9.0.** Upgrading prevents new invalid receipts but does not rewrite old logs. The npm package includes `dsh-memoir-repair`. If an old session still fails, follow the [recovery guide](./SESSION_RECOVERY.md#english): audit first, stop every host and back up, then explicitly apply repair. Preserve the logs; do not downgrade their format. Stop old plugin writes before recovery; disabling auto-distillation alone does not stop manual write tools.
16
+ > The fix covers official DSH `0.2.0-rc.1` / `0.2.0-rc.2`; upgrading DSH alone does not fix the old plugin or repair affected logs.
17
+
14
18
  > [!IMPORTANT]
15
- > **0.9.0 requires DSH `>=0.2.0-rc.1 <0.3.0-0`**, built and tested against the published `0.2.0-rc.1` (not an unqualified final 0.2.0 release). Adds a visible plugin guide, native plugin configuration, German/Russian agent copy and offline release highlights. Retains separate distillation turns, provenance, frozen snapshots and zero bundled runtime dependencies. **On DSH 0.1.7, pin `dsh-memoir@0.8.2`; upgrade the host before installing 0.9.0.**
19
+ > **0.9.1 requires DSH `>=0.2.0-rc.1 <0.3.0-0`**, verified with official `0.2.0-rc.1` / `rc.2` (not an unqualified final 0.2.0). Retains the visible guide, native settings, four agent languages, separate distillation turns and frozen snapshots. **The DSH 0.1.7 line is Memoir `0.8.2`, but it remains affected by #14; upgrade the host before installing this 0.9.1 fix.**
16
20
  >
17
21
  > `dsh-memoir@0.7.1` fixes lost session snapshots after restart or RAM eviction (#10), supporting DSH **0.1.5-rc.1 / rc.2**. It requires `>=0.1.5-rc.1 <0.1.6-0`; check your host first. Keep `0.6.2` on DSH 0.1.2, or `0.5.6` on DSH 0.1.1-rc.2; those older lines do not include this fix.
18
22
 
19
23
  ```bash
20
- npm install --global @deepseek-ai/dsh@0.2.0-rc.1
21
- dsh plugin --profile web add dsh-memoir@0.9.0
24
+ npm install --global @deepseek-ai/dsh@0.2.0-rc.2
25
+ dsh plugin --profile web add dsh-memoir@0.9.1
22
26
  ```
23
27
 
24
28
  Restart `dsh web`. Memory remains local and is not automatically deleted when the plugin is updated or removed.
@@ -179,26 +183,26 @@ Choose German agent-facing copy independently of the English GUI; settings and m
179
183
 
180
184
  | Channel | DSH baseline | Installation | Status |
181
185
  | --- | --- | --- | --- |
182
- | npm `latest` (`0.9.0`) | `>=0.2.0-rc.1 <0.3.0-0` | `dsh plugin --profile web add dsh-memoir@0.9.0` | Tested on 0.2.0-rc.1 |
183
- | pinned npm `0.8.2` | `>=0.1.7-rc.1 <0.1.8-0` | `dsh plugin --profile web add dsh-memoir@0.8.2` | Legacy 0.1.7 line |
186
+ | npm `latest` (`0.9.1`) | `>=0.2.0-rc.1 <0.3.0-0` | `dsh plugin --profile web add dsh-memoir@0.9.1` | Tested on 0.2.0-rc.1 / rc.2; fixes #14 |
187
+ | pinned npm `0.8.2` | `>=0.1.7-rc.1 <0.1.8-0` | `dsh plugin --profile web add dsh-memoir@0.8.2` | Legacy 0.1.7 line; still affected by #14 |
184
188
  | pinned npm `0.7.1` | `>=0.1.5-rc.1 <0.1.6-0` | `dsh plugin --profile web add dsh-memoir@0.7.1` | Legacy 0.1.5 line |
185
189
  | pinned npm `0.6.2` | `>=0.1.2-alpha.2 <0.1.3` | `dsh plugin --profile web add dsh-memoir@0.6.2` | Legacy 0.1.2 line |
186
190
  | pinned npm `0.5.6` | `0.1.1-rc.2` | `dsh plugin --profile web add dsh-memoir@0.5.6` | rc2 compatibility line |
187
- | Source `v0.9.0` | `>=0.2.0-rc.1 <0.3.0-0` | local build + `link:` | Development; not compatible with legacy 0.1.x |
191
+ | Source `v0.9.1` | `>=0.2.0-rc.1 <0.3.0-0` | local build + `link:` | Development; not compatible with legacy 0.1.x |
188
192
 
189
193
  Node.js `^22.19.0 || >=24.0.0` is required. 0.7.1 keeps the native `conversation.view` / `settings.section` slots and `snapshotEvents()`. DSH 0.1.5 uses Session log V3, independent of Memoir store v4 / settings v3. Back up DSH_HOME before upgrading DSH; migrated sessions are not guaranteed readable by older hosts. This Memoir release neither migrates nor resets memory and retains frozen session snapshots without enabling new dynamic-prompt behavior.
190
194
 
191
195
  <details>
192
196
  <summary>Install from source</summary>
193
197
 
194
- 0.9.0 source (DSH 0.2.0-rc.1):
198
+ 0.9.1 source (DSH 0.2.0-rc.1 / rc.2):
195
199
 
196
200
  ```bash
197
- git clone --branch v0.9.0 https://github.com/Qinling-Melon-Farmers/dsh-memoir.git
201
+ git clone --branch v0.9.1 https://github.com/Qinling-Melon-Farmers/dsh-memoir.git
198
202
  cd dsh-memoir
199
203
  pnpm install --frozen-lockfile
200
204
  pnpm run build
201
- npm install --global @deepseek-ai/dsh@0.2.0-rc.1
205
+ npm install --global @deepseek-ai/dsh@0.2.0-rc.2
202
206
  dsh plugin --profile web add "link:/absolute/path/dsh-memoir"
203
207
  ```
204
208
 
@@ -219,11 +223,11 @@ dsh plugin --profile web add "link:/absolute/path/dsh-memoir"
219
223
 
220
224
  - Plugin identity, version, GitHub project, documentation and Open memory settings move to the top of Conversation, Settings and sidebar panels, before any long memory or configuration list. Detailed compatibility information stays collapsed; no forced navigation or Star prompt.
221
225
  - Open `dsh-memoir` on the native Plugins page to use the same memory-settings form. No duplicate configuration store or registration pretending to be an official plugin; existing entries still work without this host page.
222
- - Develop and validate against official npm `0.2.0-rc.1`. Check the host version before installation; keep Memoir 0.8.2 on DSH 0.1.7.
226
+ - Develop and validate against official npm `0.2.0-rc.1`. Check the host version before installation. Memoir 0.8.2 for DSH 0.1.7 is also affected by #14; back up and upgrade both host and plugin, following the compatibility and recovery warning above.
223
227
 
224
228
  ## Offline release highlights
225
229
 
226
- The first Memory Conversation opening shows the bundled 0.9.0 highlights without blocking chat. Choose “Got it” to stop automatic display for this version in the same browser origin. Reopen anytime from “About & help → View release highlights”. Settings and sidebar panels never open the notice automatically.
230
+ The first Memory Conversation opening shows the 0.9.1 write fix and old-log recovery boundary without blocking chat. Choose “Got it” to stop automatic display for this version in the same browser origin. Reopen anytime from “About & help → View release highlights”. Settings and sidebar panels never open the notice automatically. The image below is explicitly retained as a historical 0.9.0 preview.
227
231
 
228
232
  The Chinese/English notice is offline: no network requests, uploads, memory changes or conversation edits. Only the acknowledged version is stored locally by the UI. If storage is unavailable, acknowledgment lasts for the current page; Web/Desktop and different origins are not guaranteed to share it.
229
233
 
@@ -309,6 +313,6 @@ pnpm test
309
313
  npm run bench
310
314
  ```
311
315
 
312
- Read [CONTRIBUTING.md](./CONTRIBUTING.md) before submitting changes. See [CHANGELOG.md](./CHANGELOG.md) for version history. Formal packages are published by the tag workflow through npm OIDC. The current version is [v0.9.0](https://github.com/Qinling-Melon-Farmers/dsh-memoir/releases/tag/v0.9.0), targeting DSH 0.2.0-rc.1. Pin 0.8.2 on DSH 0.1.7, or 0.7.1 on DSH 0.1.5.
316
+ Read [CONTRIBUTING.md](./CONTRIBUTING.md) before submitting changes. See [CHANGELOG.md](./CHANGELOG.md) for version history. Formal packages are published by the tag workflow through npm OIDC. The current version is [v0.9.1](https://github.com/Qinling-Melon-Farmers/dsh-memoir/releases/tag/v0.9.1), targeting DSH 0.2.0-rc.1 / rc.2. See the compatibility table above for legacy lines and their risks.
313
317
 
314
318
  Apache-2.0
package/README.md CHANGED
@@ -10,14 +10,18 @@
10
10
 
11
11
  无需 embedding、向量数据库或云端记忆服务;npm 包零捆绑运行时依赖,DSH 与 Zod 4 peer 由宿主环境提供;Zod 用于验证宿主会话投影,不捆绑进插件。
12
12
 
13
+ > [!WARNING]
14
+ > **0.9.1 修复会话恢复问题 #14:0.8.1–0.9.0 写入的旧回执可能导致会话重新打开失败。** 升级阻止新增异常,但不自动重写旧日志;npm 包已内置 `dsh-memoir-repair` 命令。旧会话仍打不开时,按[恢复说明](./SESSION_RECOVERY.md)先只读检查、停机备份后再显式恢复;不要删除日志或降级数据格式。恢复前停止旧插件写入,仅关闭自动蒸馏不能阻止手动工具写入。
15
+ > 修复已覆盖官方 DSH `0.2.0-rc.1` / `0.2.0-rc.2`;仅升级 DSH 不会修复旧插件或已有异常日志。
16
+
13
17
  > [!IMPORTANT]
14
- > **0.9.0 要求 DSH `>=0.2.0-rc.1 <0.3.0-0`**,开发与实测基线为已发布的 `0.2.0-rc.1`(不是无后缀正式 0.2.0)。新增首屏插件导引、原生插件配置、德语/俄语 Agent 文案和离线更新公告;保留独立蒸馏回合、溯源、冻结快照与零捆绑运行时依赖。**DSH 0.1.7 用户请固定 `dsh-memoir@0.8.2`,先升级宿主再安装 0.9.0。**
18
+ > **0.9.1 要求 DSH `>=0.2.0-rc.1 <0.3.0-0`**,已验证官方 `0.2.0-rc.1` / `rc.2`(不是无后缀正式 0.2.0)。保留首屏导引、原生设置、四种 Agent 语言、独立蒸馏回合与冻结快照。**DSH 0.1.7 兼容线为 `0.8.2`,但仍受 #14 影响;使用本修复须先升级宿主,再安装 0.9.1。**
15
19
  >
16
20
  > `dsh-memoir@0.7.1` 修复重启和内存淘汰后旧会话快照丢失(#10),支持 DSH **0.1.5-rc.1 / rc.2**。要求 `>=0.1.5-rc.1 <0.1.6-0`;请先核对宿主版本。旧 DSH 0.1.2 用户固定使用 `0.6.2`,0.1.1-rc.2 用户固定使用 `0.5.6`;这些旧版未包含本次修复。
17
21
 
18
22
  ```bash
19
- npm install --global @deepseek-ai/dsh@0.2.0-rc.1
20
- dsh plugin --profile web add dsh-memoir@0.9.0
23
+ npm install --global @deepseek-ai/dsh@0.2.0-rc.2
24
+ dsh plugin --profile web add dsh-memoir@0.9.1
21
25
  ```
22
26
 
23
27
  重启 `dsh web` 即可。记忆保存在本机,不会随插件升级或卸载自动删除。
@@ -178,26 +182,26 @@ memoir_record / memoir_update
178
182
 
179
183
  | 渠道 | DSH 基线 | 安装方式 | 状态 |
180
184
  | --- | --- | --- | --- |
181
- | npm `latest`(`0.9.0`) | `>=0.2.0-rc.1 <0.3.0-0` | `dsh plugin --profile web add dsh-memoir@0.9.0` | 实测 0.2.0-rc.1 |
182
- | npm 固定版 `0.8.2` | `>=0.1.7-rc.1 <0.1.8-0` | `dsh plugin --profile web add dsh-memoir@0.8.2` | 旧 0.1.7 兼容线 |
185
+ | npm `latest`(`0.9.1`) | `>=0.2.0-rc.1 <0.3.0-0` | `dsh plugin --profile web add dsh-memoir@0.9.1` | 实测 0.2.0-rc.1 / rc.2;修复 #14 |
186
+ | npm 固定版 `0.8.2` | `>=0.1.7-rc.1 <0.1.8-0` | `dsh plugin --profile web add dsh-memoir@0.8.2` | 旧 0.1.7 兼容线,仍受 #14 影响 |
183
187
  | npm 固定版 `0.7.1` | `>=0.1.5-rc.1 <0.1.6-0` | `dsh plugin --profile web add dsh-memoir@0.7.1` | 旧 0.1.5 维护线 |
184
188
  | npm 固定版 `0.6.2` | `>=0.1.2-alpha.2 <0.1.3` | `dsh plugin --profile web add dsh-memoir@0.6.2` | 旧 0.1.2 兼容线 |
185
189
  | npm 固定版 `0.5.6` | `0.1.1-rc.2` | `dsh plugin --profile web add dsh-memoir@0.5.6` | rc2 兼容线 |
186
- | 源码 `v0.9.0` | `>=0.2.0-rc.1 <0.3.0-0` | 本地构建 + `link:` | 开发调试,不兼容旧 0.1.x |
190
+ | 源码 `v0.9.1` | `>=0.2.0-rc.1 <0.3.0-0` | 本地构建 + `link:` | 开发调试,不兼容旧 0.1.x |
187
191
 
188
192
  需要 Node.js `^22.19.0 || >=24.0.0`。0.7.1 继续使用原生 `conversation.view` / `settings.section` 与 `snapshotEvents()`。DSH 0.1.5 的会话日志升级至 V3;其迁移与 Memoir 的 store v4 / settings v3 是独立格式。升级 DSH 前备份 DSH_HOME,迁移后的 DSH 会话不能承诺被旧宿主读取。Memoir 本次不迁移或清空记忆,也不启用新动态提示词行为;既有会话快照语义保持不变。
189
193
 
190
194
  <details>
191
195
  <summary>从源码安装</summary>
192
196
 
193
- 0.9.0 源码(DSH 0.2.0-rc.1):
197
+ 0.9.1 源码(DSH 0.2.0-rc.1 / rc.2):
194
198
 
195
199
  ```bash
196
- git clone --branch v0.9.0 https://github.com/Qinling-Melon-Farmers/dsh-memoir.git
200
+ git clone --branch v0.9.1 https://github.com/Qinling-Melon-Farmers/dsh-memoir.git
197
201
  cd dsh-memoir
198
202
  pnpm install --frozen-lockfile
199
203
  pnpm run build
200
- npm install --global @deepseek-ai/dsh@0.2.0-rc.1
204
+ npm install --global @deepseek-ai/dsh@0.2.0-rc.2
201
205
  dsh plugin --profile web add "link:/absolute/path/dsh-memoir"
202
206
  ```
203
207
 
@@ -218,11 +222,11 @@ dsh plugin --profile web add "link:/absolute/path/dsh-memoir"
218
222
 
219
223
  - 插件名、版本、GitHub 项目、文档和“打开记忆设置”前移到面板顶部,打开会话、设置或右侧记忆面板即可看到,无须先滚过记忆或设置列表。详细兼容信息保持折叠,不强制跳转或请求 Star。
220
224
  - 原生“插件”页面中打开 `dsh-memoir` 详情,即可使用同一套记忆设置表单;不另建一份配置,不向官方插件分组冒充注册。宿主没有此页面时,原有记忆入口仍可用。
221
- - 开发 SDK 与兼容性基线升级到官方 npm `0.2.0-rc.1`;安装前核对宿主版本。旧 DSH 0.1.7 请固定安装 Memoir 0.8.2。
225
+ - 开发 SDK 与兼容性基线升级到官方 npm `0.2.0-rc.1`;安装前核对宿主版本。旧 DSH 0.1.7 的 Memoir 0.8.2 也受 #14 影响,建议备份后一起升级宿主和插件,参见顶部兼容与恢复提示。
222
226
 
223
227
  ## 离线更新公告
224
228
 
225
- 首次打开记忆会话页时展示 0.9.0 更新摘要,不阻塞对话;点击“知道了”后,同一浏览器 origin 的本版本不再自动展示。“关于与帮助 → 查看本版更新”可随时重看。设置页和右侧栏不会自动弹出公告。
229
+ 首次打开记忆会话页时展示 0.9.1 更新摘要,提示会话写入修复与旧日志恢复边界,不阻塞对话;点击“知道了”后,同一浏览器 origin 的本版本不再自动展示。“关于与帮助 → 查看本版更新”可随时重看。设置页和右侧栏不会自动弹出公告。下图保留为已标注版本的 0.9.0 历史预览。
226
230
 
227
231
  公告随包内置、中英双语,不联网、不上传信息、不改变记忆或对话。仅在 UI 本地存储记录已确认版本;存储不可用时退化为当前页面去重,Web/桌面端或不同 origin 的确认状态不承诺同步。
228
232
 
@@ -308,6 +312,6 @@ pnpm test
308
312
  npm run bench
309
313
  ```
310
314
 
311
- 提交前请阅读 [CONTRIBUTING.md](./CONTRIBUTING.md)。版本变化见 [CHANGELOG.md](./CHANGELOG.md),正式包由 tag 工作流通过 npm OIDC 发布。当前版本是 [v0.9.0](https://github.com/Qinling-Melon-Farmers/dsh-memoir/releases/tag/v0.9.0),面向 DSH 0.2.0-rc.1;旧 0.1.7 固定 0.8.2,旧 0.1.5 固定 0.7.1。
315
+ 提交前请阅读 [CONTRIBUTING.md](./CONTRIBUTING.md)。版本变化见 [CHANGELOG.md](./CHANGELOG.md),正式包由 tag 工作流通过 npm OIDC 发布。当前版本是 [v0.9.1](https://github.com/Qinling-Melon-Farmers/dsh-memoir/releases/tag/v0.9.1),面向 DSH 0.2.0-rc.1 / rc.2;旧兼容线与风险见上方兼容性表。
312
316
 
313
317
  Apache-2.0
@@ -0,0 +1,70 @@
1
+ # 会话恢复 / Session recovery (#14)
2
+
3
+ ## 中文
4
+
5
+ ### 原因与边界
6
+
7
+ Memoir 0.8.1–0.9.0 的实际写入回执使用了没有 `ignorable` 标记的 `dsh-memoir/written` 自定义事件。DSH 能追加它,但重新读取持久化日志时会拒绝整份历史。这不等于会话正文或 `dsh-memoir.json` 记忆数据已被删除。
8
+
9
+ **0.9.1 同时包含预防修复和独立恢复工具**。新版不再生成该事件,直接工具调用使用官方 `tool/result.meta`;升级插件不会自动重写旧日志。**恢复前先停止受影响插件的写入并升级至 0.9.1**,否则旧版仍会生成坏回执;只关闭自动蒸馏不够,手动 `memoir_record` / `memoir_update` 也会触发。
10
+
11
+ ### 只读检查
12
+
13
+ 无需 Git 或源码安装:npm 包已包含 `dsh-memoir-repair` 命令、原始脚本和本文。用 Node 24,传入官方 DSH 安装目录和**一个具体会话文件**,不要传记忆 JSON、目录或通配符:
14
+
15
+ ```sh
16
+ npm exec --yes --package=dsh-memoir@0.9.1 -- dsh-memoir-repair --dsh-package "/path/to/node_modules/@deepseek-ai/dsh" "/path/to/session.v4.jsonl.zstd"
17
+ ```
18
+
19
+ - Windows 全局路径可用 `npm root -g` 查出,再附加 `@deepseek-ai/dsh`;WSL 使用自己的 Linux 安装。桌面内置依赖不可直接供 Node 加载时,使用单独安装的官方 npm DSH 作为校验器,不修改桌面文件。
20
+ - 已审计的校验器/锁协议为官方 JSONL backend `0.2.0-rc.1` / `0.2.0-rc.2`,其它版本拒绝执行。它可以检查符合该校验器的原生 v4 旧日志,不运行宿主、不迁移历史格式。
21
+ - 支持 `session.v4.jsonl` / `session.v4.jsonl.zstd`,存储和解压后均最多 128 MiB;Zstandard 每帧必须带校验和。日志截断、损坏、其它未知且不可忽略事件、符号链接/目录联接、硬链接等均拒绝修改。
22
+ - 默认不改文件,不递归扫描用户目录;输出只有路径、计数和固定错误码,不输出正文或密钥。`candidates` 是待修复回执数量。
23
+ - 上述 `npm exec` 可能联网下载 npm 包;恢复脚本本身只在本地运行,不上传日志。若插件已通过 npm 安装,也可完全离线执行 `node "/path/to/profile/node_modules/dsh-memoir/scripts/repair-session-receipts.mjs"`,后接相同参数。
24
+ - 在完整源码开发环境中,也可省略 `--dsh-package`,使用已安装且版本匹配的官方 SDK devDependencies;脚本不自动下载依赖。
25
+
26
+ ### 备份后执行
27
+
28
+ 完全退出使用这份日志的 Web、CLI、桌面和后台宿主,独立备份会话目录。确认只读检查成功,再执行:
29
+
30
+ ```sh
31
+ npm exec --yes --package=dsh-memoir@0.9.1 -- dsh-memoir-repair --dsh-package "/path/to/node_modules/@deepseek-ai/dsh" --apply --host-stopped "/path/to/session.v4.jsonl.zstd"
32
+ ```
33
+
34
+ 脚本取得官方会话写锁,逐项校验原始日志,仅在旧回执最外层补 `ignorable: true`;不删事件、不重排 seq、不改正文/时间/工具数据。受影响压缩帧会重压缩,其它帧原样保留。原始字节写入同目录唯一 `.memoir-repair-<id>.bak`,验证后才以同目录原子替换安装结果。再次执行是无操作;备份不会自动删除。
35
+
36
+ 应用期间必须持续停机,仅使用可信本地文件系统;锁防止遵循同一协议的 DSH 写者,不能对抗任意外部程序绕过锁写文件。检测到并发修改会停止。失败可能保留 `.tmp` 与 `.bak`,请按报告路径人工检查,不批量删除。若错误报告 `committed: true`,替换已经发生,先保存现场和备份再排查。
37
+
38
+ 权限边界:POSIX 要求原文件 uid/gid 与当前进程有效身份匹配,否则拒绝替换。Windows 新建备份、暂存与替换文件继承目录 ACL,**不会保留原文件专属 ACL**;只有目录继承权限已经足以保护全部日志数据时才可执行,否则先单独审查权限。Windows 会话锁在同一登录会话内生效,不支持跨登录会话共享或网络盘。
39
+
40
+ 修复后用**已修复的插件构建**重启并打开原会话。此脚本不修其它损坏,不保证宿主派生索引/缓存的所有故障均随之恢复;不要删除未知缓存或原始日志来掩盖剩余错误。需要回退时先停机,保留修复后文件,再从明确对应的 `.bak` 恢复原始文件。
41
+
42
+ ## English
43
+
44
+ Memoir 0.8.1–0.9.0 appends a custom `dsh-memoir/written` receipt without `ignorable`. DSH can write it but refuses the whole persisted history on reopen. This does not itself delete the raw conversation or the memory store. **0.9.1 includes both prevention and a standalone recovery tool**. It uses official `tool/result.meta`; upgrading never rewrites old sessions automatically.
45
+
46
+ Stop memory writes from affected builds and upgrade to 0.9.1 first: disabling auto-distillation alone does not prevent manual write tools from producing another invalid receipt. The npm package includes the `dsh-memoir-repair` command, its script and this guide; no Git checkout is needed. Use Node 24 and audit one explicitly named file:
47
+
48
+ ```sh
49
+ npm exec --yes --package=dsh-memoir@0.9.1 -- dsh-memoir-repair --dsh-package "/path/to/node_modules/@deepseek-ai/dsh" "/path/to/session.v4.jsonl.zstd"
50
+ ```
51
+
52
+ The official DSH directory supplies the reviewed v4 validators and native lease dependencies (JSONL backends **0.2.0-rc.1 / 0.2.0-rc.2 only**). `npm root -g` locates global packages; Windows and WSL have separate installations. An independently installed official npm DSH can validate desktop logs without editing the desktop installation.
53
+
54
+ `npm exec` may download the package from npm, but the recovery script runs locally and never uploads logs. For an entirely offline invocation of an already installed npm copy, use `node "/path/to/profile/node_modules/dsh-memoir/scripts/repair-session-receipts.mjs"` with the same arguments. In a source checkout with the pinned official SDK devDependencies installed, `--dsh-package` may be omitted. The script never downloads dependencies itself.
55
+
56
+ Default operation is read-only: no home scan, no host startup, no migration, and no content or credentials in diagnostics. It accepts only `session.v4.jsonl` / `session.v4.jsonl.zstd`, capped at 128 MiB both stored and expanded. It refuses torn/corrupt/unsupported logs, unknown required events, nonchecksummed frames, links and ambiguous receipts.
57
+
58
+ Exit **every** Web/CLI/desktop/background host using the file and independently back up the session directory. After a successful audit, apply explicitly:
59
+
60
+ ```sh
61
+ npm exec --yes --package=dsh-memoir@0.9.1 -- dsh-memoir-repair --dsh-package "/path/to/node_modules/@deepseek-ai/dsh" --apply --host-stopped "/path/to/session.v4.jsonl.zstd"
62
+ ```
63
+
64
+ The script takes the official session lease and adds only `ignorable: true` to exact legacy receipt envelopes, preserving event order, seq, timestamps, payloads and untouched compressed frames. A unique adjacent `.memoir-repair-<id>.bak` stores the verified original bytes before atomic replacement. Backups are retained; a second run makes no change.
65
+
66
+ Keep all hosts stopped throughout; use a trusted local filesystem. The lease excludes cooperating DSH writers, not arbitrary external writers. Observed changes abort replacement. Failures can leave `.tmp`/`.bak` files for manual inspection; do not bulk-delete them. `committed: true` means replacement already happened: preserve the current file and backup before troubleshooting.
67
+
68
+ Permissions: POSIX requires source uid/gid to match the effective process identity. On Windows, backup/staging/replacement files inherit directory ACLs; **custom source-file ACLs are not retained**. Apply only where inherited directory permissions already protect all log data; otherwise review permissions separately first. The Windows lease is scoped to the same login session, not cross-login sharing or network filesystems.
69
+
70
+ Reopen with a **fixed plugin build**. The tool does not repair unrelated corruption or promise recovery of every derived index/cache failure. To roll back, stop all hosts, retain the repaired file, and restore the exact matching `.bak`; never delete the raw conversation to silence errors.
package/lib/activity.d.ts CHANGED
@@ -7,6 +7,7 @@ declare const schema: z.ZodObject<{
7
7
  turn: z.ZodNumber;
8
8
  toolCalls: z.ZodNumber;
9
9
  calls: z.ZodArray<z.ZodString>;
10
+ memoirCalls: z.ZodArray<z.ZodString>;
10
11
  recorded: z.ZodBoolean;
11
12
  reminded: z.ZodBoolean;
12
13
  distilling: z.ZodBoolean;
@@ -14,6 +15,14 @@ declare const schema: z.ZodObject<{
14
15
  }, z.core.$strip>;
15
16
  export type MemoirActivity = z.infer<typeof schema>;
16
17
  export declare const emptyActivity: () => MemoirActivity;
18
+ /** Opaque metadata on the host-owned tool/result event, never a new event type. */
19
+ export declare function writeReceiptMeta(persisted: boolean): {
20
+ memoir: {
21
+ version: number;
22
+ persisted: boolean;
23
+ };
24
+ };
25
+ export declare function hasWriteReceipt(meta: unknown): boolean;
17
26
  declare module '@deepseek-ai/dsh-session-projection/types' {
18
27
  interface SessionProjectionStateMap {
19
28
  'dsh-memoir/activity': MemoirActivity;
@@ -21,7 +30,7 @@ declare module '@deepseek-ai/dsh-session-projection/types' {
21
30
  }
22
31
  declare module '@deepseek-ai/dsh-session/types' {
23
32
  interface SessionEventMap {
24
- /** Receipt after the Memoir store commit; no memory content is copied. */
33
+ /** Legacy READ ONLY: repaired 0.8.1–0.9.0 logs. Never append this event. */
25
34
  'dsh-memoir/written': {
26
35
  turn: number;
27
36
  callId: string;
package/lib/activity.js CHANGED
@@ -6,19 +6,28 @@ const schema = z.object({
6
6
  turn: z.number().int().nonnegative(),
7
7
  toolCalls: z.number().int().nonnegative(),
8
8
  calls: z.array(z.string()).max(CALL_LIMIT),
9
+ memoirCalls: z.array(z.string()).max(CALL_LIMIT),
9
10
  recorded: z.boolean(),
10
11
  reminded: z.boolean(),
11
12
  distilling: z.boolean(),
12
13
  originTurn: z.number().int().positive().nullable(),
13
14
  });
14
- export const emptyActivity = () => ({ turn: 0, toolCalls: 0, calls: [], recorded: false, reminded: false, distilling: false, originTurn: null });
15
+ export const emptyActivity = () => ({ turn: 0, toolCalls: 0, calls: [], memoirCalls: [], recorded: false, reminded: false, distilling: false, originTurn: null });
16
+ /** Opaque metadata on the host-owned tool/result event, never a new event type. */
17
+ export function writeReceiptMeta(persisted) { return { memoir: { version: 1, persisted } }; }
18
+ export function hasWriteReceipt(meta) {
19
+ if (typeof meta !== 'object' || meta === null || !('memoir' in meta))
20
+ return false;
21
+ const receipt = meta.memoir;
22
+ return typeof receipt === 'object' && receipt !== null && 'version' in receipt && receipt.version === 1 && 'persisted' in receipt && receipt.persisted === true;
23
+ }
15
24
  export const activityProjection = {
16
25
  key: ACTIVITY_KEY,
17
- stateVersion: 2,
26
+ stateVersion: 3,
18
27
  stateSchema: schema,
19
28
  init: emptyActivity,
20
29
  apply(previous, event) {
21
- if (event.type === 'turn/start' || event.type === 'tool/call' || event.type === 'dsh-memoir/written') {
30
+ if (event.type === 'turn/start' || event.type === 'tool/call' || event.type === 'tool/result' || event.type === 'dsh-memoir/written') {
22
31
  const turn = event.data.turn;
23
32
  if (turn < previous.turn)
24
33
  return previous;
@@ -27,9 +36,17 @@ export const activityProjection = {
27
36
  return state;
28
37
  if (event.type === 'dsh-memoir/written')
29
38
  return state.recorded ? state : { ...state, recorded: true };
39
+ if (event.type === 'tool/result') {
40
+ // A successful dispatch alone is not a commit: needs-resolution can
41
+ // also succeed. Only our explicit receipt on a correlated write counts.
42
+ return !state.recorded && !event.data.message.isError && state.memoirCalls.includes(event.data.message.source.callId) && hasWriteReceipt(event.data.meta)
43
+ ? { ...state, recorded: true } : state;
44
+ }
30
45
  if (state.calls.includes(event.data.callId))
31
46
  return state;
32
- return { ...state, toolCalls: state.toolCalls + 1, calls: [...state.calls, event.data.callId].slice(-CALL_LIMIT) };
47
+ return { ...state, toolCalls: state.toolCalls + 1, calls: [...state.calls, event.data.callId].slice(-CALL_LIMIT),
48
+ memoirCalls: event.data.name === 'memoir_record' || event.data.name === 'memoir_update'
49
+ ? [...state.memoirCalls, event.data.callId].slice(-CALL_LIMIT) : state.memoirCalls };
33
50
  }
34
51
  // next-step is retained for replay of pre-0.8.2 sessions. New reminders
35
52
  // use next-turn, protecting the original turn's compact answer boundary.
@@ -12,6 +12,7 @@
12
12
  */
13
13
  import { createUserMessage } from '@deepseek-ai/dsh-llm';
14
14
  import { DEFAULT_MEMOIR_LANGUAGE, hostCopy } from './i18n.js';
15
+ import { hasWriteReceipt } from './activity.js';
15
16
  /** The follow-up instruction; the originating work turn is not rewritten. */
16
17
  export function distillPrompt(language = DEFAULT_MEMOIR_LANGUAGE, originTurn) {
17
18
  const origin = originTurn === undefined ? '' : hostCopy(language).distillOrigin(originTurn);
@@ -25,6 +26,7 @@ export const AUTO_DISTILL_PLUGIN = 'dsh-memoir';
25
26
  export function turnActivity(events, turn) {
26
27
  let recorded = false;
27
28
  let toolCalls = 0;
29
+ const completedWrites = new Set();
28
30
  for (let i = events.length - 1; i >= 0; i--) {
29
31
  const event = events[i];
30
32
  const data = event.data;
@@ -36,7 +38,12 @@ export function turnActivity(events, turn) {
36
38
  continue;
37
39
  if (event.type === 'tool/call') {
38
40
  toolCalls += 1;
41
+ if ((data.name === 'memoir_record' || data.name === 'memoir_update') && typeof data.callId === 'string' && completedWrites.has(data.callId))
42
+ recorded = true;
39
43
  }
44
+ if (event.type === 'tool/result' && data.message?.isError !== true && typeof data.message?.source?.callId === 'string' && hasWriteReceipt(data.meta))
45
+ completedWrites.add(data.message.source.callId);
46
+ // Read-only support for legacy logs after the explicit recovery tool.
40
47
  if (event.type === 'dsh-memoir/written')
41
48
  recorded = true;
42
49
  }
package/lib/client.js CHANGED
@@ -30,7 +30,7 @@ __export(index_exports, {
30
30
  module.exports = __toCommonJS(index_exports);
31
31
 
32
32
  // <define:__MEMOIR_PACKAGE_INFO__>
33
- var define_MEMOIR_PACKAGE_INFO_default = { version: "0.9.0", hostRange: ">=0.2.0-rc.1 <0.3.0-0", sdkBaseline: "0.2.0-rc.1" };
33
+ var define_MEMOIR_PACKAGE_INFO_default = { version: "0.9.1", hostRange: ">=0.2.0-rc.1 <0.3.0-0", sdkBaseline: "0.2.0-rc.1" };
34
34
 
35
35
  // src/client/index.tsx
36
36
  var import_react5 = require("react");
@@ -170,8 +170,8 @@ var dictionaries = {
170
170
  "notice.title": "\u672C\u7248\u66F4\u65B0",
171
171
  "notice.dismiss": "\u77E5\u9053\u4E86",
172
172
  "notice.reopen": "\u67E5\u770B\u672C\u7248\u66F4\u65B0",
173
- "notice.compat": "\u9002\u914D DSH 0.2.0-rc.1\uFF1B\u65E7\u7248 DSH 0.1.7 \u8BF7\u7EE7\u7EED\u4F7F\u7528 Memoir 0.8.2\u3002",
174
- "notice.features": "\u9996\u5C4F\u9879\u76EE\u5BFC\u5F15\u3001\u539F\u751F\u63D2\u4EF6\u8BBE\u7F6E\u5165\u53E3\uFF1BAgent \u6587\u6848\u65B0\u589E\u5FB7\u8BED/\u4FC4\u8BED\uFF0C\u68C0\u7D22\u652F\u6301\u5BF9\u5E94\u5B57\u7B26\u3002",
173
+ "notice.compat": "\u9002\u914D DSH 0.2.0-rc.1 / rc.2\uFF1B0.9.1 \u4FEE\u590D\u4E86 0.8.1\u20130.9.0 \u5199\u5165\u56DE\u6267\u5BFC\u81F4\u4F1A\u8BDD\u65E0\u6CD5\u91CD\u65B0\u6253\u5F00\u7684\u95EE\u9898\u3002",
174
+ "notice.features": "\u5347\u7EA7\u963B\u6B62\u65B0\u589E\u5F02\u5E38\uFF0C\u4F46\u4E0D\u4F1A\u81EA\u52A8\u6539\u5199\u65E7\u65E5\u5FD7\u3002\u65E7\u4F1A\u8BDD\u4ECD\u6253\u4E0D\u5F00\u65F6\uFF0C\u8BF7\u6309 README \u7684\u5386\u53F2\u6062\u590D\u8BF4\u660E\uFF1A\u5148\u53EA\u8BFB\u68C0\u67E5\uFF0C\u5168\u90E8\u5BBF\u4E3B\u9000\u51FA\u5E76\u5907\u4EFD\u540E\uFF0C\u518D\u663E\u5F0F\u6267\u884C\u6062\u590D\u3002",
175
175
  "notice.privacy": "\u516C\u544A\u968F\u5305\u5185\u7F6E\uFF0C\u4E0D\u8054\u7F51\u3001\u4E0D\u6539\u8BB0\u5FC6\u3002\u786E\u8BA4\u540E\u672C\u7248\u672C\u4E0D\u518D\u81EA\u52A8\u663E\u793A\uFF1B\u53EF\u5728\u201C\u5173\u4E8E\u4E0E\u5E2E\u52A9\u201D\u91CD\u770B\u3002",
176
176
  "about.host": "\u652F\u6301\u7684 DSH \u8303\u56F4",
177
177
  "about.baseline": "\u5F00\u53D1 SDK \u57FA\u7EBF",
@@ -393,8 +393,8 @@ var dictionaries = {
393
393
  "notice.title": "What\u2019s new",
394
394
  "notice.dismiss": "Got it",
395
395
  "notice.reopen": "View release highlights",
396
- "notice.compat": "Supports DSH 0.2.0-rc.1. Keep Memoir 0.8.2 on DSH 0.1.7.",
397
- "notice.features": "Visible project guide and native plugin settings; German/Russian agent copy with matching Unicode retrieval.",
396
+ "notice.compat": "Supports DSH 0.2.0-rc.1 / rc.2. Version 0.9.1 fixes receipts from 0.8.1\u20130.9.0 that prevented sessions from reopening.",
397
+ "notice.features": "Upgrading prevents new invalid receipts; it does not rewrite old logs. If an old session still fails to open, follow the recovery guide linked in README: audit first, stop every host and back up, then explicitly apply the repair.",
398
398
  "notice.privacy": "Bundled offline; no memory changes. Acknowledge once per version, or reopen from About & help.",
399
399
  "about.host": "Supported DSH range",
400
400
  "about.baseline": "Development SDK baseline",
@@ -628,7 +628,7 @@ var import_react2 = require("react");
628
628
  var import_react = require("react");
629
629
 
630
630
  // src/client/announcement.ts
631
- var ANNOUNCEMENT_VERSION = "0.9.0";
631
+ var ANNOUNCEMENT_VERSION = "0.9.1";
632
632
  var ANNOUNCEMENT_KEY = "dsh-memoir:announcement:last-acknowledged";
633
633
  var EVENT = "dsh-memoir:announcement-acknowledged";
634
634
  var acknowledged = /* @__PURE__ */ new WeakMap();