dsh-openwrite 0.2.27 → 0.2.33

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.
Files changed (130) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +55 -6
  3. package/THIRD_PARTY_NOTICES.md +4 -3
  4. package/companions.mjs +508 -0
  5. package/cordis.patch.yml +0 -2
  6. package/docs/CLOSED_ISSUE_FOLLOWUPS.md +5 -3
  7. package/docs/COMPANION_PLUGINS.md +142 -0
  8. package/docs/CONTEXT_SLOTS.md +60 -0
  9. package/docs/COST_MEASUREMENT.md +2 -2
  10. package/docs/DEVELOPMENT.md +6 -11
  11. package/docs/DSH_STORE.md +14 -2
  12. package/docs/EDITOR_SAFETY_REPAIRS.md +17 -0
  13. package/docs/INSTALL.md +112 -4
  14. package/docs/ISSUES_121_123.md +97 -0
  15. package/docs/ISSUES_140_142.md +58 -0
  16. package/docs/ISSUES_149_150_151.md +77 -0
  17. package/docs/ISSUES_98_100.md +2 -0
  18. package/docs/ISSUE_123_FOLLOWUP.md +55 -0
  19. package/docs/ISSUE_146_REVIEW_EVIDENCE.md +53 -0
  20. package/docs/LEARNING.md +1 -1
  21. package/docs/MOBILE_READINESS.md +62 -0
  22. package/docs/PLUGIN_MAINTENANCE.md +1 -3
  23. package/docs/RELEASE_ACCEPTANCE.md +90 -3
  24. package/docs/REVIEW_ROUND_22.md +67 -0
  25. package/docs/REVIEW_ROUND_23.md +48 -0
  26. package/docs/REVIEW_ROUND_25.md +51 -0
  27. package/docs/SELECTION_UPGRADE_REPAIRS.md +16 -0
  28. package/docs/TOOLS.md +933 -0
  29. package/docs/WORKFLOWS.md +5 -5
  30. package/package.json +18 -21
  31. package/packages/openwrite-bridge/lib/client.d.ts +0 -1
  32. package/packages/openwrite-bridge/lib/client.js +90 -9
  33. package/packages/openwrite-bridge/lib/contracts-generated.js +2 -1
  34. package/packages/openwrite-bridge/lib/dog-delivery.d.ts +1 -0
  35. package/packages/openwrite-bridge/lib/dog-delivery.js +10 -4
  36. package/packages/openwrite-bridge/lib/dog-review.js +15 -3
  37. package/packages/openwrite-bridge/lib/domain.d.ts +27 -0
  38. package/packages/openwrite-bridge/lib/domain.js +250 -29
  39. package/packages/openwrite-bridge/lib/host-llm.d.ts +188 -0
  40. package/packages/openwrite-bridge/lib/host-llm.js +657 -0
  41. package/packages/openwrite-bridge/lib/host-web.d.ts +61 -0
  42. package/packages/openwrite-bridge/lib/host-web.js +166 -0
  43. package/packages/openwrite-bridge/lib/index.d.ts +4 -0
  44. package/packages/openwrite-bridge/lib/index.js +150 -6
  45. package/packages/openwrite-bridge/lib/managed-runtime.d.ts +47 -2
  46. package/packages/openwrite-bridge/lib/managed-runtime.js +179 -35
  47. package/packages/openwrite-bridge/lib/tool-policy.js +39 -12
  48. package/packages/openwrite-bridge/lib/tools.js +1238 -1219
  49. package/packages/openwrite-bridge/package.json +7 -5
  50. package/packages/studio-panel/lib/client.js +116667 -114773
  51. package/packages/studio-panel/lib/client.js.map +1 -1
  52. package/packages/studio-panel/lib/types/client/LaunchOpenWrite.d.ts +10 -0
  53. package/packages/studio-panel/lib/types/client/ModelView.d.ts +28 -4
  54. package/packages/studio-panel/lib/types/client/OpenWriteSettings.d.ts +64 -0
  55. package/packages/studio-panel/lib/types/client/SceneWorkbench.d.ts +2 -0
  56. package/packages/studio-panel/lib/types/client/SearchSettings.d.ts +2 -0
  57. package/packages/studio-panel/lib/types/client/SerialWritingView.d.ts +2 -1
  58. package/packages/studio-panel/lib/types/client/TurnMutationSummary.d.ts +2 -0
  59. package/packages/studio-panel/lib/types/client/VditorBody.d.ts +8 -2
  60. package/packages/studio-panel/lib/types/client/api.d.ts +41 -2
  61. package/packages/studio-panel/lib/types/client/browser-download.d.ts +4 -0
  62. package/packages/studio-panel/lib/types/client/companions.d.ts +46 -0
  63. package/packages/studio-panel/lib/types/client/dto.d.ts +22 -0
  64. package/packages/studio-panel/lib/types/client/locales.d.ts +1 -1
  65. package/packages/studio-panel/lib/types/client/manuscript-annotations.d.ts +2 -1
  66. package/packages/studio-panel/lib/types/client/manuscript-overlay.d.ts +2 -1
  67. package/packages/studio-panel/lib/types/client/manuscript-selection.d.ts +18 -5
  68. package/packages/studio-panel/lib/types/client/selection-coordinates.d.ts +15 -0
  69. package/packages/studio-panel/lib/types/client/workspace-chrome.d.ts +41 -0
  70. package/packages/studio-panel/package.json +5 -3
  71. package/plugin.mjs +159 -20
  72. package/preset-definition.mjs +144 -4
  73. package/presets/openwrite/agent.cordis.yml +7 -9
  74. package/presets/openwrite/ops-integration.mjs +28 -0
  75. package/presets/openwrite/preset.yml +2 -1
  76. package/presets/openwrite/skills/canon/SKILL.md +3 -3
  77. package/presets/openwrite/skills/delivery-artifact-query/SKILL.md +41 -0
  78. package/presets/openwrite/skills/dialoguequality/SKILL.md +16 -17
  79. package/presets/openwrite/skills/dog-delivery-verification/SKILL.md +113 -0
  80. package/presets/openwrite/skills/export-book/SKILL.md +3 -3
  81. package/presets/openwrite/skills/foreshadow/SKILL.md +1 -1
  82. package/presets/openwrite/skills/foreshadowing-system/SKILL.md +16 -25
  83. package/presets/openwrite/skills/import-artifact-query/SKILL.md +30 -0
  84. package/presets/openwrite/skills/learn/SKILL.md +3 -3
  85. package/presets/openwrite/skills/novel-creator/SKILL.md +10 -10
  86. package/presets/openwrite/skills/novel-reviewer/SKILL.md +11 -11
  87. package/presets/openwrite/skills/progress/SKILL.md +1 -1
  88. package/presets/openwrite/skills/review-artifact-query/SKILL.md +41 -0
  89. package/presets/openwrite/skills/review-chapter/SKILL.md +2 -2
  90. package/presets/openwrite/skills/revise-span/SKILL.md +5 -5
  91. package/presets/openwrite/skills/style-system/SKILL.md +13 -6
  92. package/presets/openwrite/skills/truth-validation/SKILL.md +9 -12
  93. package/presets/openwrite/skills/workflow-manager/SKILL.md +13 -13
  94. package/presets/openwrite/skills/world-query/SKILL.md +16 -11
  95. package/presets/openwrite/skills/write-next/SKILL.md +1 -1
  96. package/release/{openwrite-5.8.16-py3-none-any.whl → openwrite-5.8.30-py3-none-any.whl} +0 -0
  97. package/release/runtime-manifest.json +4 -12
  98. package/release/source.json +21 -21
  99. package/release/wheels/licenses/OPENSSL-3.6.3-LICENSE.txt +225 -0
  100. package/scripts/maintenance.mjs +67 -7
  101. package/scripts/plugin-doctor.mjs +179 -0
  102. package/scripts/prepare.mjs +11 -2
  103. package/scripts/safe-upgrade.mjs +141 -13
  104. package/dog-tools.mjs +0 -11
  105. package/presets/openwrite/skills/dog-delivery-query/SKILL.md +0 -42
  106. package/presets/openwrite/skills/dog-import-query/SKILL.md +0 -29
  107. package/presets/openwrite/skills/dog-review-query/SKILL.md +0 -42
  108. package/scripts/dog/delivery-stage.js +0 -32
  109. package/scripts/dog/import-chapter.js +0 -20
  110. package/scripts/dog/import-record.js +0 -35
  111. package/scripts/dog/review-dimension.js +0 -41
  112. package/scripts/dog/review-record.js +0 -42
  113. package/vendor/dsh-dog/LICENSE +0 -29
  114. package/vendor/dsh-dog/README.md +0 -114
  115. package/vendor/dsh-dog/UPSTREAM.md +0 -30
  116. package/vendor/dsh-dog/cordis.patch.yml +0 -14
  117. package/vendor/dsh-dog/lib/client.js +0 -2960
  118. package/vendor/dsh-dog/lib/client.js.map +0 -1
  119. package/vendor/dsh-dog/lib/core-BAlgZpLq.js +0 -2074
  120. package/vendor/dsh-dog/lib/core-BiEBMLz3.d.ts +0 -495
  121. package/vendor/dsh-dog/lib/core.d.ts +0 -2
  122. package/vendor/dsh-dog/lib/core.js +0 -2
  123. package/vendor/dsh-dog/lib/index.d.ts +0 -143
  124. package/vendor/dsh-dog/lib/index.js +0 -1279
  125. package/vendor/dsh-dog/package.json +0 -110
  126. package/vendor/dsh-dog/schemas/schema-0.2/graph.schema.json +0 -139
  127. package/vendor/dsh-dog/schemas/schema-0.2/report.schema.json +0 -87
  128. package/vendor/dsh-dog/schemas/schema-0.2/run.schema.json +0 -259
  129. package/vendor/dsh-dog/schemas/schema-0.2/runtime-event.schema.json +0 -105
  130. package/vendor/dsh-dog/schemas/schema-0.2/verification.schema.json +0 -40
@@ -0,0 +1,58 @@
1
+ # #140 / #142 跟进:自备 Python 与旧包选择
2
+
3
+ 目标版本为 **0.2.29 候选**,尚未发布。Core 保持已验收的 5.8.20,wheel 字节及来源提交不变。
4
+
5
+ ## #140:自备 Python
6
+
7
+ 在 managed 模式增加 `pythonPath`,或通过 `OPENWRITE_PYTHON` 选择解释器;显式配置优先。
8
+ 可用 `pythonModulePaths` 列出作者准备的依赖目录,对应报告中的 Android `pyroot`。
9
+ 选定解释器后,即使 manifest 没有当前平台,也不会下载 uv 或 python-build-standalone。
10
+
11
+ 插件校验随包 Core/依赖清单,将纯 Python Core wheel 解包到自己的环境目录,
12
+ 用所选解释器导入检查 Python >=3.10、Core 和 API 版本,再启动已有的 stdio 鉴权后端。
13
+ 不执行 pip、不自动解析依赖、不修改作者解释器;显式依赖目录与解释器路径参与缓存标识。
14
+ `-I` 隔离、UTF-8 和 `-B` 禁止字节码写入同时生效。
15
+ 共享构建的原生库搜索路径仅在自备解释器模式下传入;凭据仍按原有环境白名单过滤。
16
+
17
+ 依赖缺失或不匹配时给出诊断,保留旧 active 记录,不回退到隐式下载。
18
+ 每次使用已有环境启动前也重做导入检查,以免作者改动依赖后仍把旧缓存当成可用环境。
19
+ 启动后的鉴权、随机端口、健康检查、取消、重启上限和 owned-process 清理继续使用原有生命周期。
20
+
21
+ 真实 Python 的 7 项新增集成覆盖:启动/鉴权/恢复及依赖目录不写入;缺依赖与旧环境保留;
22
+ 缓存环境重新检查;Core 版本不匹配;环境变量与配置优先级;绝对路径校验;安装取消。
23
+ 完整 managed 工具与生命周期测试本地 **41 passed / 0 skipped**。
24
+ 真实随包 Core 5.8.20 的健康接口、鉴权和 Studio 静态资源另通过本地自备解释器验收;
25
+ 相同验收加入正式安装矩阵,新增集成测试也对确切 tarball 内代码执行。
26
+
27
+ ## #142:旧包选择
28
+
29
+ 报告环境是 DSH 0.2.1-rc.3;实际报错版本为 OpenWrite 0.2.25。
30
+ 0.2.25 的 peer 声明确实不覆盖该宿主。官方 npm 当前 latest 0.2.28 的根包及三个内嵌子包
31
+ 均声明精确支持 0.2.1-rc.3;不能把旧包拒绝诊断改成放宽新包兼容范围。
32
+
33
+ 使用本地模拟 registry、真实 pnpm 和隔离 profile,构造 0.2.25 精确依赖、registry latest 0.2.28:
34
+
35
+ | 操作 | 结果 |
36
+ | --- | --- |
37
+ | install 初始精确依赖 | 0.2.25 |
38
+ | add dsh-openwrite | 仍为 0.2.25 |
39
+ | add dsh-openwrite@latest | 0.2.28 |
40
+
41
+ 这证明一种能导致相同错误的旧包选择条件;报告者具体的 spec/锁/registry 缓存仍需原场景确认。
42
+ 商城本身属于外部项目,OpenWrite 不改变其全局安装策略。
43
+
44
+ 本仓库补修:停机升级工具将裸 `dsh-openwrite` 规范为显式 `dsh-openwrite@latest`,
45
+ 精确版本与本地 tarball 继续保持原意。doctor 单独显示 requested spec、resolved version、
46
+ 诊断工具版本及精确重装目标,避免只看商城目录或笼统的“已安装”。对应维护/升级测试本地 **20 passed**。
47
+ 安装指南补充官方 registry 检查、停机备份和已验收 0.2.28 的精确升级路径。
48
+ 未给旧包添加兼容豁免,也未清空用户缓存、profile 或会话。
49
+
50
+ ## #123:验收边界
51
+
52
+ [#140](https://github.com/LiPu-jpg/Openwrite/issues/140) 附件给出 Android/aarch64/bionic、
53
+ 宿主 Python 3.14.8、pydantic 2.14.1 / pydantic-core 2.50.1、插件 0.2.26 的第三方实机记录,
54
+ 包括 Studio 启动及 `GET / -> 200`。文档据此补全手机本地 external Studio 的步骤。
55
+ 附件脚本作为证据阅读,未直接执行其下载或安装逻辑。
56
+
57
+ 这仍不等于候选 0.2.29 在 Android 上的插件面板、Workspace、实际工具调用和鉴权已完整通过。
58
+ #123 的 Android/Termux 完整验收与宿主原生升级保护正式发布两项继续保留,不能因为此 PR 自动关闭。
@@ -0,0 +1,77 @@
1
+ # #149 / #150 / #151 跟进:预设别名噪声与 rc.4/rc.5 兼容声明
2
+
3
+ 目标版本为 **0.2.29 候选**,尚未发布。Core 保持已验收的 5.8.20,wheel 字节及来源提交不变。
4
+
5
+ ## #150 / #151 / #142:宿主 rc.4 / rc.5 被版本闸门拒绝
6
+
7
+ 报告现象:`dsh plugin --profile desktop add dsh-openwrite` 在 DSH `0.2.1-rc.5` 上直接失败,
8
+ 错误为 `plugin does not support the DSH version in use`。这是宿主读取
9
+ `package.json` 的 `peerDependencies`(`@deepseek-ai/dsh-*`)范围后拒绝加载,
10
+ `dsh.compatibility.dsh` 只是展示元数据,因此两处都必须同步扩展。
11
+
12
+ 本版在根包与三个内嵌子包(`@dsh-novel/openwrite-bridge`、`@dsh-novel/studio-panel`、
13
+ `@dsh-external/dsh-dog``)的 `peerDependencies`、`dsh.compatibility.dsh`、`dshReleases`
14
+ 以及四个 lock 文件中加入精确宿主 `0.2.1-rc.4` 与 `0.2.1-rc.5`;
15
+ 发布矩阵(`.github/workflows/release-validation.yml`、`scripts/release-report.mjs`)
16
+ 新增这两个宿主的客户端验收,并保留各自的 `--before` 截止时间,
17
+ 避免上游部分发布时把更新的依赖批次带进旧宿主验收。
18
+
19
+ `0.1.2-rc.1`、`0.1.5-alpha.1`、`0.2.0-rc.2`、`0.2.1-rc.2`、`0.2.1-rc.3` 的 peer 匹配集合
20
+ 逐项对比无变化(只增不改),旧宿主不受影响。`0.2.2-alpha.2`、`0.3.0` 仍不声明,保持未知。
21
+
22
+ 本地实测(macOS arm64 / Node v24.15,真实官方 registry 的精确宿主包,0 次模型调用):
23
+
24
+ - `node scripts/preset-smoke.mjs --host-cli=<rc.4|rc.5 宿主>` 通过:29 行 entry list、24 个技能目录、宿主模块全部可解析。
25
+ - `node scripts/client-boot-smoke.mjs dsh-openwrite-0.2.29.tgz --host-cli=<rc.4|rc.5 宿主>` 通过:
26
+ 版本闸门无豁免、客户端激活、预设选择、工作台三页签、DoG 面板与其他插件共存。
27
+ - 复现路径已验证:用改动前打包的同一源码 tarball 启动 rc.5 宿主,日志出现与报告完全一致的
28
+ `incompatible with dsh 0.2.1-rc.5`;改用本版声明的包后同一命令通过。
29
+
30
+ 候选包 SHA-256(本地 `npm pack --ignore-scripts` 产物):
31
+ `a9acf18ce7177fde459b3cd7ca92cdd5d71bab7a1a7695a01c8740cd66a14f26`。
32
+ 三份 `client-report-0.2.1-rc.{3,4,5}.json` 均绑定该哈希。未发布 npm/GitHub 新版本。
33
+
34
+ ## #149:新建会话选择器里的 27 条「历史会话」别名
35
+
36
+ 0.2.26 为修 #105 引入「旧 id 作别名」,`preset-definition.mjs` 里硬编码了全部已发布版本号,
37
+ `plugin.mjs` 无条件为其中每一个注册别名。宿主 `dsh-agent-preset-registry` 的 `list()`
38
+ 返回全量定义且没有 hidden/selectable 字段,`order: 1000` 只能排序、不能隐藏,
39
+ 于是磁盘上只有当前版本目录的用户也会看到 27 条同名别名,手机窄屏下几乎无法滚动。
40
+
41
+ 本版把别名集合从「所有已发布版本」改为「会话存储里真实引用过的 id」:
42
+
43
+ - 启动时扫描 `<DSH_HOME>/sessions` 下的会话日志,只解每个日志的**第一帧**(会话头就在第一帧),
44
+ 收集其中形如 `openwrite-\d+-\d+-\d+...` 的 `agentPreset` 值,去掉当前版本后注册别名。
45
+ `node:zlib` 的 `zstdDecompressSync` 只解首帧并忽略追加的事件帧,纯文本 `.jsonl` 同样支持;
46
+ 每次只读前 256 KB。Node `>=22.15` 起内置 zstd,插件 `engines` 要求 `>=22.19.0`,无需新增依赖。
47
+ - 指纹缓存落到 `~/.dsh/openwrite/preset-aliases.json`(会话数 + 最新 mtime),
48
+ 存储未变化时不再解压任何日志。
49
+ - 扫描整体失败(例如会话根目录不可读)时回退到原来的全量别名表,#105 的恢复能力不会丢失。
50
+ - 别名显示名改为可自解释的 `OpenWrite 创作(旧版 0.2.24 · 仅用于恢复历史会话)`,
51
+ 不再把内部 id 直接暴露给作者;`order: 1000` 保持沉底。
52
+ - 当前发布自身的 id 不再注册别名:它已经以稳定 id `openwrite` 注册,其目录也由本插件管理。
53
+ 工作台入口原先固定选择发布 id,现改为优先选择稳定 id `openwrite`,仅在宿主只注册发布 id 时回退,
54
+ 因此选择器里 OpenWrite 只剩一条。
55
+
56
+ 实测(真实 DSH `0.2.1-rc.5` 宿主 + Playwright,种子会话引用 `openwrite-0-2-24`):
57
+
58
+ - 改动前:选择器列出 `OpenWrite 创作` 加 27 条 `OpenWrite 创作(历史会话 openwrite-0-2-N)`。
59
+ - 改动后:只列出 `OpenWrite 创作` 与 `OpenWrite 创作(旧版 0.2.24 · 仅用于恢复历史会话)`。
60
+ - 该断言已进入 `scripts/client-boot-smoke.mjs`(`preset-selector-single-entry`):
61
+ 空会话存储下 OpenWrite 必须只出现一次,且不得出现 `历史会话`/`旧版` 条目。
62
+
63
+ 新增回归(`scripts/preset-lifecycle.test.mjs`,真实 zstd 多帧会话日志作夹具):
64
+
65
+ - 别名集合跟随会话引用;未引用的发布 id 不进选择器;`standard` 等其它预设被忽略。
66
+ - 会话存储不可读时保留全量别名表(#105 不回归)。
67
+ - 指纹缓存:存储不变时即使单条日志损坏仍返回缓存结果;新增会话后重新推导。
68
+ - 升级不重写会话日志(逐字节比对),作者自定义预设优先,卸载后只移除本插件注册的定义。
69
+
70
+ 本地验证(当时):`node --test scripts/preset-lifecycle.test.mjs` **8 passed**;
71
+ `npm run test:maintenance` **58 passed**;`npm run docs:check`、`npm run doctor` 通过;
72
+ `npm --prefix packages/studio-panel run test:components` **344 passed**;
73
+ `npm run test:epochs` 通过;`npm --prefix vendor/dsh-dog test` **63 passed / 1 skipped**(该 vendored 包随后在「移除内置 DoG」改动中删除,此命令已不存在);
74
+ rc.3 / rc.4 / rc.5 三宿主客户端验收通过(含上述新增断言)。
75
+ `npm run test:contracts` 需要 `OPENWRITE_ROOT` 指向 OpenWrite 引擎检出,本机未配置,未运行。
76
+
77
+ #123 跟踪项中的「宿主正式发布」与「Android/Termux 真机验收」两项依旧保留,未因本轮修复勾选。
@@ -33,6 +33,8 @@ node /path/to/package/scripts/safe-upgrade.mjs --profile desktop --package /abso
33
33
 
34
34
  可用 `npm pack dsh-openwrite@0.2.25` 下载官方包,或从对应 GitHub Release 获取相同字节的附件。`DSH_HOME` 必须指向实际宿主的 home;默认 `~/.dsh`。Windows 另设 `DSH_BIN` 为已验收宿主运行时的绝对 `lib/bin.js` 路径,使用 Node 直接执行而非 `.cmd` shell。其余平台可通过 DSH_BIN 指定同一受信任 CLI。
35
35
 
36
+ 候选 0.2.28 的工具可从解压目录读取所选已安装 profile 中的运行依赖;本地 tgz 会先保存到 `<DSH_HOME>/openwrite/packages/<sha256>.tgz`,再传给安装器,避免新依赖和锁文件指向临时下载。此改进尚未发布,旧包解压入口缺少依赖时应使用已安装包内的工具。pnpm 11 的 store/构建授权及既有失效锁文件仍属于宿主安装路径限制,失败时查看操作日志;不要把源码 tarball 与预编译发行包混用。详见 [#123 回复补修](ISSUE_123_FOLLOWUP.md)。
37
+
36
38
  安装在旁路 profile 中进行;整个旧 profile(包括其他插件、锁文件及设置)在切换前保持可用。只有 OpenWrite 的必要文件和 manifest 校验成功才进入目录切换。切换为两次同盘 rename,**不是整个目录树的单次原子交换**;停机状态避免读取窗口,中断由持久事务记录恢复。锁覆盖本工具的并发操作,不能阻止未经协调的原生安装器或用户重新启动宿主。
37
39
 
38
40
  记录保存在 `<DSH_HOME>/openwrite/upgrades/upgrade_*/`:`operation.json`、`pnpm.log`、成功切换后的 `previous-profile/`。stdout/stderr 实时落盘;安装 180 秒超时终止子进程。保留目录可能占用较多空间,确认升级稳定后再人工清理。
@@ -0,0 +1,55 @@
1
+ # #123 回复补修与验收(候选 0.2.28 / Core 5.8.18,未发布)
2
+
3
+ 这些补修已包含于正式 0.2.28(最终 Core 5.8.20)。下文保留 Core 5.8.18 的历史候选验收;该候选未单独发行。最终公开下载与哈希见[发布验收](RELEASE_ACCEPTANCE.md)。#123 的两项外部/真机条件仍未完成。
4
+ 依据报告者的[升级、会话与模型调用记录](https://github.com/LiPu-jpg/Openwrite/issues/123#issuecomment-6422870871)及 [B-13 Windows 实测](https://github.com/LiPu-jpg/Openwrite/issues/123#issuecomment-6423904648)更新结论。回复是有版本、入口和结果的外部验收证据;不把其中推测当成已证实根因。
5
+
6
+ ## 两项原待办已有实机证据
7
+
8
+ - #105:报告者确认 Windows Desktop 按手工替换路径升级到 0.2.26 后,旧会话正常打开;旧 0.2.24 预设目录缺失时兼容注册仍可解析。此证据不代表宿主原生安装器安全。0.2.27 已补齐 0.2.26/27 的永久别名,当前候选覆盖至 0.2.28;发布回归要求每个版本身份进入永久列表,新会话使用稳定 ID `openwrite`。
9
+ - #109 B-13:报告者在 Windows 11、DSH Desktop、插件 0.2.27 / Core 5.8.16 上确认行中/行首 `>`、混合行尾预览均可匹配,读取指纹与原始文件字节一致。NBSP 与普通空格不等属于精确匹配的预期拒绝。保留精确字节匹配,不自动归一化再写文件;候选增加混合行尾的 HTTP 预览、应用、撤销回归。
10
+
11
+ ## 本轮代码补修
12
+
13
+ | 问题 | 最终行为 | 验证 |
14
+ | --- | --- | --- |
15
+ | `thinking_modes.chapter_write` 漏传 | Writer 的草稿、分段、重试、事实提取和结算都默认传 `chapter_write`;显式 operation 仍优先。usage 的阶段名独立保留。 | 直接检查实际提供方请求参数:enabled / disabled / omit;草稿、观察、结算及重试均覆盖,不只检查配置对象。 |
16
+ | 同类修订漏传 | 正文修订模型请求传 `revision`。Dante 的章节生成仍经 Writer;Goethe/通用 ReAct 的规划及工具选择没有冒用写章开关。 | 真实 LLMClient 调用到提供方边界的替身检查;旧冻结源码三个用例失败,新实现通过。 |
17
+ | 修订选择的原文不匹配 | `OLD_TEXT_NOT_FOUND` / HTTP 400,带当前范围、原始字节版本、唯一精确候选与空白差异提示。真正的 apply 版本漂移仍为 `DOCUMENT_CONFLICT` / 409。 | LF 请求与 CRLF/混合文件不符时零模型调用、磁盘不变;既有 apply 冲突回归保留。 |
18
+ | `similarity:1` 但匹配失败 | 增加 `similarity_basis=whitespace_collapsed`、`mismatch_kind`;该相似度不承诺字节相等。范围锚点失败也给各缺失锚点的诊断,不自动重定位/应用。 | NBSP 与换行提示保留准确原文;不确定时不伪造唯一候选。 |
19
+ | 预览 `changed:true` 误读 | 保留兼容字段 `changed`,增加 `would_change`;`applied:false` 明确还没有写入。锚点不匹配返回 400,版本冲突仍返回 409。 | 公共 HTTP 测试逐字节核对预览无写入、确认后写入、撤销恢复。 |
20
+ | 已有正文时错误过于泛化 | 直接写章预检返回 `CHAPTER_ALREADY_EXISTS`、章节 ID 和打开正文/创建修订的恢复提示。 | 预检拒绝且不调用模型;不再依赖泛化的 `STUDIO_ERROR` 推断原因。 |
21
+ | 健康检查版本不一致 | 当前源码已使用同一版本来源;新增 health / workspace / pyproject 元数据一致性检查。 | 不把旧 5.8.14 环境的字符串误报当成新候选仍存在的缺陷。 |
22
+ | 解压包运行升级工具找不到依赖 | 延迟解析依赖,先查工具自身,再查明确选择的 profile;不加载已安装插件、不修改凭据。 | 解压目录没有 node_modules,依赖只存在于目标 profile 时仍完成受控暂存/切换。 |
23
+ | 升级后引用被删除的 tgz | 先按 SHA-256 将本地 tgz 固定到 `<DSH_HOME>/openwrite/packages/`,再交安装器写依赖与锁文件。 | 原下载目录在安装过程中删除后,稳定缓存和提交后的 file: 引用仍可读。 |
24
+
25
+ ## 升级路径与边界
26
+
27
+ 在宿主原生保护正式发布前,继续使用[停机旁路工具](ISSUES_98_100.md#离线升级和损坏修复),先完全退出 Desktop(含托盘)及 dsh/managed runtime,并备份 profile。使用正式预编译 tgz,不把 GitHub 源码包当成相同的离线安装包;源码包可能需要构建授权。
28
+
29
+ 这轮修复了解压工具的依赖入口,并避免新安装记录引用易删除的 tgz;**不承诺修复宿主的 pnpm 11 store、构建授权或既有损坏锁文件**。遇到安装器失败,活动 profile 保持原样,保留操作日志与旧完整目录;不要反复改 profile 的依赖、store 配置和锁文件拼凑安装成功。
30
+
31
+ #124/#125 的首次评审输出预算与 B-20 的运行历史留存是两件事;后者已由 #126/#127 补修。这里的 Core 5.8.18 产物当时为未发布候选;后续补修及完整验收已形成正式 0.2.28(最终 Core 5.8.20),此早期候选包未单独发行。
32
+
33
+ ## 继续保留的两项
34
+
35
+ - #98.1:原生宿主升级保护补丁进入正式宿主,插件旁路工具不替代该条件。
36
+ - #111:Android/Termux 真机及受信任外部 Studio 连接验收。
37
+
38
+ #123 保持打开跟踪以上两项。代码、原始环境确认、CI 产物与正式发布分别记录。
39
+
40
+ ## 最终验收与合并
41
+
42
+ [Core PR #131](https://github.com/LiPu-jpg/Openwrite/pull/131) 和 [插件 PR #132](https://github.com/LiPu-jpg/Openwrite/pull/132) 已合并。最终 **22 项 CI 全部成功**:[三系统回归](https://github.com/LiPu-jpg/Openwrite/actions/runs/40437762040)、[安装/客户端验收](https://github.com/LiPu-jpg/Openwrite/actions/runs/40437761963)、[插件检查](https://github.com/LiPu-jpg/Openwrite/actions/runs/40437762138)。
43
+
44
+ | 项目 | Linux | macOS | Windows |
45
+ | --- | --- | --- | --- |
46
+ | 固定 Core 全量 | 1541 passed / 32 skipped | 1541 passed / 32 skipped | 1541 passed / 32 skipped |
47
+ | 真实 HTTP dry-run / 归档历史 | 2 passed | 2 passed | 2 passed |
48
+ | 真实 Electron 44.7.0 脚本 | 5 passed | 5 passed | 5 passed |
49
+ | wheel 源码 / 应打包 Python 文件 | 498 / 163 一致 | 498 / 163 一致 | 498 / 163 一致 |
50
+
51
+ 32 项跳过均为缺失旧样例/checkout 的既有跳过,新增回归未跳过。另有混合行尾的公开 HTTP 预览/应用/撤销测试包含在 Core 全量中。本地插件完整检查、310 项组件、34 项原生预设/升级/运行时组合通过。最终 8 份安装/源码、5 份客户端、6 份原生报告已下载复核,安装包报告绑定同一 tarball,源码安装固定插件提交。
52
+
53
+ Core 固定提交 `43cb604a7583b7268f47e54ceb8a0c30b95e82b2`,wheel SHA-256 `09f9baef5fe0d502510c8542f20c6abaf6893f02e2d069d7f0d7cc50c7aeea93`。候选 tarball SHA-256 `4bcde6d6f535906a5a04490218a0d972e84329ff750af6803a4214fbf609024e`;CI 来源提交 `ecfb7c34c5b0a29d395136da775bb964c3c91d11` 与主分支修复合并提交 `14dd3a5dbc7d1661adb9b684e0f137298bf2591f` 的 tree 同为 `67042838daf11f5c7fc27e0ffe158677a73c3196`。
54
+
55
+ 本轮没有发起真实付费模型请求,thinking 参数通过实际 LLMClient 到提供方请求边界的替身验证;不把它描述为真实服务商计费或输出质量验收。这份 5.8.18 候选产物仅作历史验收证据,未单独发行;代码已包含于正式 0.2.28,最终公开包与校验值以 [发布验收](RELEASE_ACCEPTANCE.md) 为准。
@@ -0,0 +1,53 @@
1
+ # #146:审稿证据回填与状态批注隔离
2
+
3
+ 面向 0.2.29 候选 / Core 5.8.22,尚未发布。
4
+ 报告:[OpenWrite Core 5.8.20 B-28 / B-29](https://github.com/LiPu-jpg/Openwrite/issues/146)。
5
+
6
+ ## B-28:同条判据已有引用却被判未定论
7
+
8
+ 审稿模型有时把有效的原文引用放进 criterion 自己的 `issues[].evidence`,
9
+ 却漏填 `criterion.evidence`。旧实现只检查后者,正分会被清零并将该项判为 `inconclusive`。
10
+
11
+ 修复先在送审正文中验证引用。若 criterion 没有有效的直接证据,则从**同一 criterion** 的有效问题
12
+ 回填引用;保留模型给出的 `evaluated` 状态和分值上限,并在返回值标记
13
+ `evidence_source: "criterion_issues"`。直接证据若误填为一个字符串,按一整条引用处理,
14
+ 避免逐字符迭代后把碰巧存在的单字当成原文证据。
15
+
16
+ 同时将 criterion 内的问题纳入完整问题列表,包含有原文依据的 `critical`。
17
+ 缺少 `dimension` 时沿用所属 criterion 的第一个 legacy check 标签;显式越出该 criterion 的标签、
18
+ 无效严重度和无法在正文中定位的引用不参与回填。
19
+
20
+ 真正缺少引用、模型明确给出 `inconclusive`、硬门禁未定论或严重问题,仍不能通过交付。
21
+ 没有放宽正典门禁、评分完整性要求或最小覆盖率策略。修复的目标是使已有证据进入正确字段,
22
+ 让正常的完整评审能获得正确状态;真实未完成的检查仍须补齐。
23
+
24
+ 报告中提到的部分审稿,当前实现已有 `scope_status: partial`、`scope_quality_score`、
25
+ `scope_passed` 与 `unreviewed_dimensions`;整章 `delivery_status` 保持 `inconclusive`,
26
+ `quality_score` 为 null。新增回归再次覆盖仅请求 coherence 的情况,避免误报整章通过。
27
+
28
+ ## B-29:机器批注进入送审正文
29
+
30
+ 审稿入口在术语检查、规则检查、AI 痕迹分析、模型评审和正文统计前调用
31
+ `strip_character_state_annotations`。各域、硬门禁及旧分批审稿入口也执行同一处理,
32
+ 确保上下文检查器等直接调用路径一致。
33
+
34
+ 清理范围沿用现有阅读/导出契约:有效的角色状态和关系注册从读者正文移除;
35
+ 正常代码示例与不符合批注契约的作者文本保留。原稿和状态批注文件都不会被重写。
36
+ 已有审稿记录保持原样,需要用新版本重新审稿才能得到修复后的结果。
37
+
38
+ ## 回归方法
39
+
40
+ `tests/test_issue146_review_evidence.py` 覆盖:
41
+
42
+ - 三项 criterion 漏填直接证据、同条问题有原文时,恢复到完整 80 分并允许交付。
43
+ - 缺失/伪造引用、显式未定论、硬门禁未定论、嵌套严重问题继续阻断。
44
+ - 不借用相邻判据的引用、不接受无效证据类型或越界标签。
45
+ - 仅审 coherence 明确保持部分审稿。
46
+ - 所有七次正常评审请求,以及直接域/门禁/旧版分批请求,都不包含机器批注。
47
+ - 真实 `execute_review_chapter` 管线将正确结果存入 ReviewStore,原稿保持不变。
48
+
49
+ 相同测试在修复前的冻结源码上为 **8 failed / 5 passed**,修复后全部通过。
50
+ 所有模型响应均由测试夹具提供,没有调用真实或付费模型,也不读写作者作品和真实项目登记。
51
+
52
+ 本地完整 Core 回归:1564 passed / 32 existing skipped;定向组合回归 52 passed。
53
+ Core wheel 从冻结 Git 提交归档构建,打包后逐文件核对运行时源码。
package/docs/LEARNING.md CHANGED
@@ -62,7 +62,7 @@
62
62
  | 编辑器选区润色(扩写/缩写/去 AI 味/按审稿改这段) | done | 选区动作走 `/revisions/selection`(expand/compress/naturalize)与 `/revisions/from-review`;hunk 应用走 `/revisions/{id}/apply` + `selected_hunk_ids`,不 PUT 正文;源 revision 不一致时拒绝覆盖 |
63
63
  | 正文提及高亮与资料卡 | done | 创作页用现有 `/assets` 的人物/地点名与别名做最长匹配;点击在创作视图打开只读资料卡;切章/切 Workspace 清卡;不进资料库、不 POST 资产更新 |
64
64
  | 斜杠命令 / 7 个作者入口 | done | `presets/openwrite/skills/{progress,write-next,review-chapter,revise-span,foreshadow,canon,export-book}` 接到 `novel_*`;persona 默认工作流为看进度 → 写下一章 → 审这一章 → 改这段;其余技能 `user-invocable: false`;`npm run test:preset` 断言入口存在并拒绝旧 Python 命令名 |
65
- | 项目级 `/learn` 写法记忆 | done | `presets/openwrite/skills/learn`:风格/成功钩子/作者偏好走 `novel_source_action` 与 `novel_structured_change_plan`,随 Workspace 资产走;无 cwd 时现有工具返回 `WORKSPACE_CONTEXT_MISSING`;`npm run test:preset` 24 skills / 8 author entries |
65
+ | 项目级 `/learn` 写法记忆 | done | `presets/openwrite/skills/learn`:风格/成功钩子/作者偏好走 `novel_source_action` 与 `novel_change_plan(action="structured")`,随 Workspace 资产走;无 cwd 时现有工具返回 `WORKSPACE_CONTEXT_MISSING`;`npm run test:preset` 24 skills / 8 author entries |
66
66
  | 网文可选审稿维(钩子/黄金三章/追读力) | done | `form: web_novel` 时六域上附加 `max=0` 的钩子/黄金三章/追读力;37 项与质量分不变;黄金三章仅第 1–3 章;非网文项目不附加 |
67
67
  | 每 50 章规划窗口 | done | `novel_rolling_plan_action` 默认/上限 50 章;`accepted_window` 只含已接纳正文,`planned_window` 只含未接纳大纲计划;create 不改正文/事实 |
68
68
  | 写作冲刺统计 | done | 创作动态页从工作简报字数目标 + 已知 `writing_units_delta` 推导新增/删减/净增;修订净增只来自 `revision_applied`;无 delta 的事件不猜来源;不另建冲刺账本 |
@@ -0,0 +1,62 @@
1
+ # 手机浏览器开发验收(0.2.29 候选,未发布)
2
+
3
+ 此轮改善电脑托管、手机浏览器访问时的编辑可靠性,以及 Android 自备 Python / external
4
+ Studio 的前端体验。正式发行版本仍为 0.2.28;没有新增 iOS App 或 Android 原生 Python/ONNX 包。
5
+
6
+ ## 已实现
7
+
8
+ - 原生工作台监听页面隐藏和 `pagehide`,在编辑器延迟回调到达之前收集最后输入,沿用按作品、
9
+ 文档隔离的本机恢复草稿。触屏点选区操作时保留选中的正文。
10
+ - 修正真实 Vditor 初始化期间提前读取 Lute 的竞态;首次读取等编辑器 `after` 就绪。
11
+ - 手机与平板的章节栏、参考栏关闭时不可交互;窄屏保持可用编辑高度、触控按钮和表单字号。
12
+ - 导出先挂载下载链接,再延迟回收 Blob 地址,覆盖中文文件名、UTF-8 `filename*` 和含 `%` 的旧文件名。
13
+ - 独立 Core Studio 的正文也增加本机恢复草稿。草稿按作品路径、作品 ID、文档和服务器版本隔离;
14
+ 刷新后明确提示恢复或下载。服务器版本变化时禁止直接恢复,保留副本供作者比对。
15
+ 编辑新版正文不会覆盖旧版冲突草稿。
16
+ - 手动保存先读取最后输入;保存请求绑定原作品和文档。切章后晚到的响应不能替换当前正文;
17
+ 请求途中继续输入的内容保留为待保存草稿。保留现有服务器版本冲突检查。
18
+
19
+ 本机草稿保存在该浏览器、该站点的 localStorage,不能替代作品备份,也不会在设备间同步。
20
+ 浏览器禁用存储或空间不足时会提示手动保存。独立 Studio 这一轮恢复范围为正文;资料表单
21
+ 仍按既有保存流程使用。手机系统强制结束浏览器不保证触发生命周期事件,建议看到保存成功再离开。
22
+
23
+ ## 自动回归
24
+
25
+ `packages/studio-panel/scripts/mobile-browser.mjs` 使用真实 Vditor,分别运行 Chromium 和 WebKit,
26
+ 检查 320 / 390 / 768 像素宽度及 480 像素可视高度。隔离夹具不打开作品,不调用模型。
27
+
28
+ 覆盖后台前的中文与 emoji 输入、模拟组合输入、触屏选区、中文下载文件和内容、窄屏抽屉、
29
+ 刷新恢复、服务器版本冲突、显式恢复、立即保存、切章后的旧保存响应,以及保存途中继续输入。
30
+ 组合输入事件是模拟值,不能代替真机中文输入法。
31
+
32
+ CI 从待发布 tgz 提取 Core wheel,核对原生编辑器源码与包内 source map、编译 CSS 及供应商资源,
33
+ 再运行上述用例。两种引擎的报告均为发布验收前置条件,记录安装包 SHA-256 和输入来源。
34
+ WebKit 是浏览器引擎测试,不等于 iPhone Safari、iOS 模拟器或 Android/Termux 验收。
35
+
36
+ 本地源码验证:
37
+
38
+ ```sh
39
+ node packages/studio-panel/scripts/mobile-browser.mjs --browser=webkit --core=/absolute/core/tools/studio_assets
40
+ node packages/studio-panel/scripts/mobile-browser.mjs --browser=chromium --core=/absolute/core/tools/studio_assets
41
+ ```
42
+
43
+ ## 之后的真机验收
44
+
45
+ iPhone / iPad 可以测试电脑托管的 Web 工作台或独立 Studio。电脑需保持运行,手机通过受信任的
46
+ 私有网络或经过认证的 HTTPS 入口访问;手机上的 `127.0.0.1` 指向手机自身。不要直接公开未鉴权的
47
+ Core 端口。DSH 的远程入口与访问控制按所用宿主版本设置;OpenWrite 不提供独立的 iOS 本地后端。
48
+
49
+ 在测试作品中逐项记录设备、系统、浏览器、宿主和候选包版本:
50
+
51
+ 1. 打开章节、人物与设定,确认关闭的抽屉不能挡住正文;竖屏、横屏和软键盘弹出时能继续编辑。
52
+ 2. 用中文输入法连续输入、选择候选词并加入 emoji;立即保存,刷新确认最后一句和格式完整。
53
+ 3. 输入后立即切 App、锁屏再回来;检查服务器保存状态。未保存时刷新,应能恢复本机草稿。
54
+ 4. 在另一浏览器修改同章后回来,检查版本冲突提示;旧草稿只下载对比,不覆盖新版正文。
55
+ 5. 长按选择正文后使用扩写或审稿入口,确认作用范围。先检查预览;实际模型请求另计。
56
+ 6. 导出 Markdown / EPUB,确认下载名称和文件内容,再检查“文件”App 中的文件。
57
+ 7. 快速切章、切作品,在网络较慢时保存,确认正文和草稿归属正确。
58
+
59
+ Android / Termux 另需按照 [安装说明](INSTALL.md#android--termux) 验收解释器、原生依赖、
60
+ external 鉴权、Workspace 路径绑定及实际工具调用。iOS 测试不能替代这部分。
61
+
62
+ 上述真机项目仍待完成,继续在 [#123](https://github.com/LiPu-jpg/Openwrite/issues/123) 跟踪。
@@ -9,8 +9,6 @@ npm ci --ignore-scripts
9
9
  node scripts/prepare.mjs
10
10
  npm run check:plugin
11
11
  npm run test:managed
12
- npm --prefix vendor/dsh-dog run typecheck
13
- npm --prefix vendor/dsh-dog test
14
12
  node scripts/release-provenance.mjs
15
13
  npm pack --ignore-scripts
16
14
  node scripts/release-check.mjs
@@ -23,7 +21,7 @@ node scripts/release-smoke.mjs
23
21
 
24
22
  ## 发布产物
25
23
 
26
- 根包 `dsh-openwrite` 组合运行时、bridge、panel、DoG 和版本预设。Core 使用 `native-core` 固定 commit 的 wheel;用户无需切换分支。版本、来源和所有平台下载哈希记录在 runtime manifest。
24
+ 根包 `dsh-openwrite` 组合运行时、bridge、panel 和版本预设。Core 使用 `native-core` 固定 commit 的 wheel;用户无需切换分支。版本、来源和所有平台下载哈希记录在 runtime manifest。
27
25
 
28
26
  Python 主依赖从该 wheel 的 METADATA 导出到 `release/core-requirements.in`,用固定 uv 重建:
29
27
 
@@ -1,12 +1,99 @@
1
1
  # 发布验收记录
2
2
 
3
- ## 0.2.27(待发布)
3
+ ## 0.2.28
4
+
5
+ 本轮捆绑 Core **5.8.20**,固定源码 `9611c654e5d77bcb5968105a7adfa8e9b4f9624a`。修复正文延迟输入漏存、按审稿修订越过作者选区,以及真实 Vditor 换行规范化导致的选区拒绝,详见[补修范围](EDITOR_SAFETY_REPAIRS.md)。
6
+
7
+ 本地 Core **1550 passed / 32 skipped**、真实 HTTP **14 passed**、界面 **336 passed**、managed **34 passed**、完整插件检查通过。新增真实候选包编辑器浏览器场景 **9 组通过**。wheel 的 499 个运行时文件与固定源码逐字节一致,163 个应打包 Python 文件无遗漏,SHA-256 为 `aa1f25f3c615497cd73c3c059fd2acc4e71ba2e936765d02331d1382df4b201a`。最终跨平台验收与产物复核结果如下。
8
+
9
+ [Core PR #137](https://github.com/LiPu-jpg/Openwrite/pull/137) 和 [插件 PR #138](https://github.com/LiPu-jpg/Openwrite/pull/138) 已合并。最终 **22 项检查全部通过**:[三系统回归](https://github.com/LiPu-jpg/Openwrite/actions/runs/40453781968)、[安装/客户端验收](https://github.com/LiPu-jpg/Openwrite/actions/runs/40453781862)、[插件检查](https://github.com/LiPu-jpg/Openwrite/actions/runs/40453781876)。下载原始报告后核对:
10
+
11
+ | 验收 | Linux | macOS | Windows |
12
+ | --- | --- | --- | --- |
13
+ | 固定 Core 全量 | 1550 passed / 32 skipped | 1550 passed / 32 skipped | 1550 passed / 32 skipped |
14
+ | 真实 HTTP 路由与选区上限 | 14 passed | 14 passed | 14 passed |
15
+ | 真实 Electron 44.7.0 | 5 passed / 0 skipped | 5 passed / 0 skipped | 5 passed / 0 skipped |
16
+ | wheel 源码字节 / 应打包 Python 文件 | 499 / 163 一致 | 499 / 163 一致 | 499 / 163 一致 |
17
+
18
+ 8 份安装/源码、5 份客户端、6 份原生报告全部通过。每组原生验收运行 40 项预设/升级/运行时回归,并对同一 tarball 内的真实 Vditor、独立编辑器包装、Core 与原生面板映射器验证 9 组场景,editorSerialization 字段全部为通过。Core 的 32 项跳过仍来自缺失旧样例或外部 checkout,新增回归无跳过;本轮不调用付费模型。
19
+
20
+ macOS ARM 首次 npm ci 从第三方镜像下载依赖超时;只重跑失败任务和依赖的汇总步骤后通过,构建产物保持相同。没有放宽验收或替换依赖版本。
21
+
22
+ 候选 tarball SHA-256:`3a50ad3cb080eec50b28f3196d5c0cd476643db894b06df0dfc8c394fec1bcfd`。CI 提交 `9390c7826024ee78cc91d5a144825a55ca0016e0` 与插件合并提交 `6117a19a26b60ab6d55bff23fdfb46f84fd02320` 的源码 tree 同为 `d59236a0d5dd77ce0d960586cd7c59eeaf0b96c9`。Core 固定来源保留于 native-core 合并提交 `40e25b7a27a4b0f9430d0cc15b775c601f28a91e`。
23
+
24
+ [GitHub 0.2.28](https://github.com/LiPu-jpg/Openwrite/releases/tag/v0.2.28) 与 [npm 0.2.28](https://www.npmjs.com/package/dsh-openwrite/v/0.2.28) 均已正式发布,npm `latest` 为 **0.2.28**。GitHub 四份公开附件的服务端 digest 和无认证下载字节均与 CI 原件一致;官方 npm registry 无认证下载的完整 **10,232,555 字节**包也逐字节一致,SHA-256、SHA-1 及 SHA-512 integrity 已核对。发布使用上述 CI 原始包,没有重新构建。#123 的两项仍未验收,不因发行而标为完成。
25
+
26
+ 下方为形成最终版本之前的历史候选证据;早期暂停与未发布状态反映当时情况,各早期候选未单独发行,最终发布仅使用 Core 5.8.20 的上述产物。
27
+
28
+ ### 前轮候选证据(Core 5.8.19,未发布)
29
+
30
+ 本轮捆绑 Core **5.8.19**,固定源码 `d2b3cbe6009a1ab4f1064dca0115cb44ba080a3f`。修复 CRLF/emoji 选区坐标、独立 Studio 原始片段保留、中断升级无依赖恢复与损坏 tgz 缓存重试,详见 [补修记录](SELECTION_UPGRADE_REPAIRS.md)。
31
+
32
+ 本地 Core 全量 **1542 passed / 32 skipped**,修订服务与真实 HTTP 23 passed,原生预设/升级/运行时 40 passed,managed 33 passed,界面 319 passed,插件完整检查通过。wheel 的 499 个运行时文件与固定源码逐字节一致,163 个应打包 Python 文件无遗漏,SHA-256 为 `9d5307201bea47be3675b2d968ab444503479ff71d2b7ad9b3922a998889ba3a`。本地测试不计作 Windows/Android 真机验收。
33
+
34
+ [Core PR #134](https://github.com/LiPu-jpg/Openwrite/pull/134) 与 [插件 PR #135](https://github.com/LiPu-jpg/Openwrite/pull/135) 已合并,最终 **22 项检查全部成功**:[三系统回归](https://github.com/LiPu-jpg/Openwrite/actions/runs/40446870919)、[完整安装/客户端验收](https://github.com/LiPu-jpg/Openwrite/actions/runs/40446870931)、[插件检查](https://github.com/LiPu-jpg/Openwrite/actions/runs/40446870954)。下载原始报告后再次核对:
35
+
36
+ | 验收 | Linux | macOS | Windows |
37
+ | --- | --- | --- | --- |
38
+ | 固定 Core 全量 | 1542 passed / 32 skipped | 1542 passed / 32 skipped | 1542 passed / 32 skipped |
39
+ | 真实 HTTP 路由与选区保护 | 10 passed | 10 passed | 10 passed |
40
+ | 真实 Electron 44.7.0 脚本 | 5 passed / 0 skipped | 5 passed / 0 skipped | 5 passed / 0 skipped |
41
+ | wheel 源码字节 / 应打包 Python 文件 | 499 / 163 一致 | 499 / 163 一致 | 499 / 163 一致 |
42
+
43
+ 8 份安装/源码、5 份精确宿主客户端、6 份原生回归报告全部通过。六组原生安装测试对同一 tarball 中的预设、升级与运行时脚本运行 40 项回归。32 项 Core 跳过项沿用缺失样例/外部 checkout 限制,新增回归没有跳过;测试不调用真实模型。
44
+
45
+ 候选 tarball SHA-256:`b73ed0a87da44f93f804ded3c5fffe6c83c29a9d6bf9c64fe9141eefc5a3a85b`。CI 提交 `7c91429693dd672bd1d426fa54a1bc075cad13b4` 与插件合并提交 `3c51627bf2a21a4e7c22fc3e77ab0e61f0db891f` 的源码 tree 均为 `879b9f30ed0c812d5b3aca34571a186f86670471`。Core 来源提交保留于 native-core 合并提交 `1ff7d699a456b90b7315eccfcf63c042cbf37d99`;候选包保留为验收证据,未发布。
46
+
47
+ #123 的宿主正式发布与 Android/Termux 真机两项继续保留,暂停发布。公开 npm/GitHub 版本仍为 **0.2.27**。
48
+
49
+ ### 前轮候选证据(Core 5.8.18,未发布)
50
+
51
+ 本轮根据 #123 新回复捆绑 Core **5.8.18**,固定源码 `43cb604a7583b7268f47e54ceb8a0c30b95e82b2`。本地全量 **1541 passed / 32 skipped**,真实 HTTP 2 passed;wheel 的 498 个打包源文件与固定源码逐字节一致,163 个应打包 Python 文件无遗漏,SHA-256 为 `09f9baef5fe0d502510c8542f20c6abaf6893f02e2d069d7f0d7cc50c7aeea93`。
52
+
53
+ 写章/修订 thinking 模式的三个回归在旧冻结源码失败,新实现通过。原生预设/升级/运行时本地 34 passed。报告者已补齐旧会话与 B-13 的 Windows 验收;余下宿主正式发布和 Android/Termux 真机两项仍暂停新版本发布。具体修复、来源和边界见 [#123 回复补修](ISSUE_123_FOLLOWUP.md)。
54
+
55
+ [PR #131](https://github.com/LiPu-jpg/Openwrite/pull/131) / [#132](https://github.com/LiPu-jpg/Openwrite/pull/132) 已合并,最终 22 项检查全部成功:[三系统回归](https://github.com/LiPu-jpg/Openwrite/actions/runs/40437762040)、[完整安装/客户端验收](https://github.com/LiPu-jpg/Openwrite/actions/runs/40437761963)、[插件检查](https://github.com/LiPu-jpg/Openwrite/actions/runs/40437762138)。三系统 Core 各 1541 passed / 32 skipped、HTTP 各 2 passed、真实 Electron 各 5 passed。8 份安装/源码、5 份客户端和 6 份原生报告下载后复核通过。
56
+
57
+ 本轮 tarball SHA-256 为 `4bcde6d6f535906a5a04490218a0d972e84329ff750af6803a4214fbf609024e`;CI 提交 `ecfb7c34c5b0a29d395136da775bb964c3c91d11` 与修复合并提交 `14dd3a5dbc7d1661adb9b684e0f137298bf2591f` 的源码 tree 同为 `67042838daf11f5c7fc27e0ffe158677a73c3196`。产物未发布;本轮未发起真实模型请求,不能把请求边界替身测试算作服务商实测。
58
+
59
+ ### 前轮候选证据(Core 5.8.17,未发布)
60
+
61
+ 按用户要求先修可修部分,保留未完成项并暂停发布。变更范围与限制见 [#121–#123 修复记录](ISSUES_121_123.md)。本节不是正式发布记录,npm/GitHub 公开版本仍为 0.2.27。
62
+
63
+ Core 5.8.17 来源 [PR #126](https://github.com/LiPu-jpg/Openwrite/pull/126),固定提交 `c655dc2106b07cf08324728e0b5babf1fcc12afb`;冻结提交全量 **1531 passed / 32 skipped**。wheel 从该提交的干净归档构建,498 个打包源文件逐字节一致,并核对 163 个应打包 Python 文件未遗漏;wheel SHA-256 为 `93507c54ee5fe3d22d4e858e9e1d8efe0cd2917f554ff5a13872dbb1fed06fab`。
64
+
65
+ 修复已通过 [Core PR #126](https://github.com/LiPu-jpg/Openwrite/pull/126) 和 [插件 PR #127](https://github.com/LiPu-jpg/Openwrite/pull/127) 合并。最终 **22 项检查全部成功**:[三系统回归](https://github.com/LiPu-jpg/Openwrite/actions/runs/40391934852)、[完整安装/客户端验收](https://github.com/LiPu-jpg/Openwrite/actions/runs/40391934711)、[插件检查](https://github.com/LiPu-jpg/Openwrite/actions/runs/40391935114)。原始 CI 报告下载后再次核对:
66
+
67
+ | 验收 | Linux | macOS | Windows |
68
+ | --- | --- | --- | --- |
69
+ | 固定 Core 全量 | 1531 passed / 32 skipped | 1531 passed / 32 skipped | 1531 passed / 32 skipped |
70
+ | 真实 HTTP dry-run / 归档历史 | 2 passed | 2 passed | 2 passed |
71
+ | 真实 Electron 44.7.0 脚本 | 5 passed / 0 skipped | 5 passed / 0 skipped | 5 passed / 0 skipped |
72
+ | wheel 源码字节 / 应打包 Python 文件 | 498 / 163 一致 | 498 / 163 一致 | 498 / 163 一致 |
73
+
74
+ 32 项跳过均来自仓库缺失的旧标准样例、演示作品或外部 checkout,新增问题回归未跳过。自动化没有复现报告者的原 Windows Electron 历史会话,也不等于 Android/Termux 真机验收。
75
+
76
+ 界面 310 项、本地 DoG 64 项和类型检查、managed 32 项及插件完整检查通过。8 份安装/源码、5 份精确宿主客户端和 6 份原生回归报告全部通过;原生报告覆盖持久预设、离线升级和受管理后端三组。安装包报告绑定同一 tarball SHA-256,源码安装固定插件提交。
77
+
78
+ 候选 tarball SHA-256:`2d0f1b6c34c1a48386fc08798c8fb7a09c2e964ef6d2d6a558f62e7ed469c7bb`。CI 来源提交 `a8babe9b9b3909bbfedbf3e26df41d022624abbb` 与主分支修复合并提交 `bc6af78a562725a02a0fff6133eb0e3f5e603d6f` 的 tree 均为 `240a99caea04ba8436c1bfaec306969db0c216ea`。Core 来源提交已保留在 native-core 的合并历史中。
79
+
80
+ 真实 OpenCode Go 单次流式取消验收确认保留部分正文、关闭 HTTP 响应,后续请求在调用提供方前拒绝,作品文件未变;它与不调用模型的 CI 分开记录。新增 [95 项工具参考](TOOLS.md) 和 [上下文槽位参考](CONTEXT_SLOTS.md) 已核对运行时注册、固定 Core 源码及候选包内字节,修复 #128。
81
+
82
+ **以上前轮候选包只作验收证据保存,没有发布。** 当时 #123 的四项待办均保留;后续回复补齐了其中两项,余下条件见本节开头。#121/#122 的报告条目已修复、验收并合并关闭;关闭报告不代表候选版本已发行。
83
+
84
+ ## 0.2.27
4
85
 
5
86
  捆绑 Core 5.8.16,来源 [PR #124](https://github.com/LiPu-jpg/Openwrite/pull/124),源码提交 `27ec8b3bea0a3f8754f5701a7b21c23a9328d6b7`。wheel 从该提交的干净归档构建,496 个打包源文件与提交逐字节一致,SHA-256 为 `8be4dc5e3feb2d0faf91a1e0763f05ff338c237912edd8c066aaad118ec41ec4`。
6
87
 
7
88
  本地 Core 全量 1478 passed / 32 skipped;HTTP 行中锚点的 LF/CRLF 预览、应用、撤销与不匹配保护通过。预设生命周期、停机升级与 managed runtime 组合 32 passed(含五项手动重试/取消回归),并加入六组原生安装矩阵。真实 OpenCode Go 流式安全评审 1 次成功,首次 max_tokens=24000、耗时 4.424 秒;此前工作台 Console 档案保存、连接测试及流式写作也成功。CI 本身不调用模型,真实模型记录与其独立,不能把 CI 的 modelCalls:0 解释成真实模型验收。
8
89
 
9
- 发布和各平台安装报告将在完整 CI 完成并下载核对后补充。[未完成验收与上游依赖](CLOSED_ISSUE_FOLLOWUPS.md) 继续由 [#123](https://github.com/LiPu-jpg/Openwrite/issues/123) 跟踪。
90
+ [GitHub Release v0.2.27](https://github.com/LiPu-jpg/Openwrite/releases/tag/v0.2.27) 与 [npm `dsh-openwrite@0.2.27`](https://www.npmjs.com/package/dsh-openwrite/v/0.2.27) 均已发布,官方 registry 的 `latest` 已更新到 0.2.27。GitHub 四份公开附件逐字节与 CI 原始文件一致;从官方 npm registry 无认证重新下载的 10,169,500 字节安装包也与 CI 包逐字节一致,SHA-256、npm 的 SHA-1 与 SHA-512 integrity 均已核对。发布通过本人双重验证后先返回 HTTP 202,等待服务端校验与公开同步完成,再以公开下载验证确认发布成功。
91
+
92
+ 使用 [完整发布 CI](https://github.com/LiPu-jpg/Openwrite/actions/runs/40358781683) 原始 validated-release 产物;[插件检查](https://github.com/LiPu-jpg/Openwrite/actions/runs/40358781965) 同样通过,共 16 项检查全部成功。验收包含 8 份安装/源码报告、5 份精确宿主客户端报告,以及 6 份绑定安装包哈希的原生回归报告,每组 32 项回归通过。tarball SHA-256 为 `94e9df25289b7053f12978f8fc4bb75f3f8da894f02312e82a88ca19efa095f2`。CI 来源提交 `e08679c47258bb1584e2920cf0245f24718bb9db` 与主分支合并提交 `cbab43b4e427ae1507d26e96e47a9abdbeb6414b` 的源码 tree 均为 `5bde0e856c7643d603bfe202704c4051860c43a0`;发布直接使用 CI 包,没有重新打包。
93
+
94
+ 合并后的[主分支发布 CI](https://github.com/LiPu-jpg/Openwrite/actions/runs/40360046529) 和[插件检查](https://github.com/LiPu-jpg/Openwrite/actions/runs/40360046553) 同样全部通过。
95
+
96
+ [未完成验收与上游依赖](CLOSED_ISSUE_FOLLOWUPS.md) 继续由 [#123](https://github.com/LiPu-jpg/Openwrite/issues/123) 跟踪;其后新增的 #121/#122 已由上方候选修复完成并关闭,尚未随新版本发行。
10
97
 
11
98
  ## CI 运行范围
12
99
 
@@ -146,7 +233,7 @@ Core 5.8.7 由 `native-core` 分支干净树 `pip wheel` 构建,manifest 的 `
146
233
 
147
234
  ## 0.2.12
148
235
 
149
- [GitHub Release](https://github.com/LiPu-jpg/Openwrite/releases/tag/v0.2.12) 已发布,直接使用[完整 CI](https://github.com/LiPu-jpg/Openwrite/actions/runs/37389772004)验收的同一份包。来源提交 a349ea964e43d75f9fc98d1f83354a237bc2ff51,SHA-256 为 2545031292d80689f80d4c0d8c99e007c18ff0c477d662e2813cf67bc876246c。六组原生平台/Node、源码安装、alpha 兼容及三代宿主客户端共 11 份报告全部通过;详见 Release 的 release-acceptance.json。npm `dsh-openwrite@0.2.12` 和 GitHub Release 均已发布,`latest` 已更新到 0.2.12;从公共 npm registry 无认证重新下载后,SHA-256 与上述 CI / Release 包一致。合并后的[主分支完整 CI](https://github.com/LiPu-jpg/Openwrite/actions/runs/37390503895)也已通过。
236
+ [GitHub Release](https://github.com/LiPu-jpg/Openwrite/releases/tag/v0.2.12) 已发布,直接使用[完整 CI](https://github.com/LiPu-jpg/Openwrite/actions/runs/37389772004)验收的同一份包。来源提交 a349ea964e43d75f9fc98d1f83364a237bc2ff51,SHA-256 为 2545031292d80689f80d4c0d8c99e007c18ff0c477d662e2813cf67bc876246c。六组原生平台/Node、源码安装、alpha 兼容及三代宿主客户端共 11 份报告全部通过;详见 Release 的 release-acceptance.json。npm `dsh-openwrite@0.2.12` 和 GitHub Release 均已发布,`latest` 已更新到 0.2.12;从公共 npm registry 无认证重新下载后,SHA-256 与上述 CI / Release 包一致。合并后的[主分支完整 CI](https://github.com/LiPu-jpg/Openwrite/actions/runs/37390503895)也已通过。
150
237
 
151
238
  本版修复 #50–#52 的 0.2 宿主兼容问题及 #54 阅读模式刷新闪烁,纳入 #53 的导航和会话作用域改动,并保留旧宿主的预设插件。
152
239
 
@@ -0,0 +1,67 @@
1
+ # 第二十二轮:插件侧并发与安装/升级路径审查
2
+
3
+ ## 结论:2 个真实缺陷(已修)
4
+
5
+ ## V-1:companion 升级后缓存不失效
6
+
7
+ `companions.mjs` 的缓存 fingerprint 只包含 profile 的 `package.json` mtime,**不含 companion 自身的 manifest**。而 companion 的 `package.json`(`peerDependencies['@deepseek-ai/dsh']`)正是判定宿主兼容性的依据。
8
+
9
+ 后果:升级 companion(放宽或收紧 peer range)后,缓存仍返回旧判定——正是 #150/#151/#142 那一类问题的复发路径,只是触发条件从"版本比较错"变成"缓存不失效"。
10
+
11
+ 修复:把每个候选 companion 的 manifest mtime 纳入 fingerprint。
12
+
13
+ **测试因此在断言错误行为**:原测试 `a cache hit serves the stored answer instead of recomputing` 删掉 companion 包后断言仍返回 `cached: true, usable: true`——即"包没了还说可用"。已改为正确语义(删除后必须失效、重新计算为不可用),并补了第三次调用验证纯重复仍命中缓存。
14
+
15
+ ## V-2:损坏的 ownership marker 被永久误判
16
+
17
+ `install.sh` 用裸 `cat >` 写 `.openwrite-managed.json`,崩溃会留下截断文件。`maintenance.mjs` 的 `inspectPresets` 对解析失败 `.catch(() => null)` → 判为 `author-owned` → **升级被永久拒绝,且没有任何诊断说明原因**。
18
+
19
+ fail-closed 方向是对的(不会误覆盖作者数据),但不可恢复、不可诊断。
20
+
21
+ 双管齐下:
22
+ - **消除根因**:marker 改为 `mktemp` + `mv` 原子写入,带 `trap` 清理临时文件
23
+ - **可诊断**:`inspectPresets` 区分 `marker-corrupt` 与 `author-owned`,并返回 marker 内容
24
+
25
+ ## V-2b 的测试三次才抓住
26
+
27
+ 内容断言无法区分原子写和非原子写(成功时字节相同)。前两次尝试:
28
+ 1. 断言 marker 内容完整 → 两种写法都通过
29
+ 2. 断言 `version` 非空 → 发现 fixture 的 package.json 没 version 字段(不是产品缺陷)
30
+
31
+ 最终用**结构性断言**:install.sh 必须匹配 `marker_tmp=$(mktemp ...)` + `mv "$marker_tmp" "$target/.openwrite-managed.json"`,且不得匹配 `cat > "$target/.openwrite-managed.json"`。
32
+
33
+ ## 审查过但未发现问题的部分
34
+
35
+ - **`safe-upgrade.mjs` 的 `acquireRecoveryLock`**:`mkdir` 原子创建 + `dev/ino/birthtime` 身份校验 + 每秒心跳续租 + 30 秒陈旧回收。实现相当严谨,未发现问题。
36
+ - **`install.sh` 的 move-aside + rsync**:`set -euo pipefail` 保证 `mv` 失败即中止(rsync 不会执行),`mktemp -d` 避免同秒冲突,NUL 分隔处理任意文件名。安全。
37
+ - **companion 缓存的并发写**:`writeFile` 非原子,但读侧有容错,损坏只导致缓存失效(重新计算),不会产生错误结果。低风险。
38
+
39
+ ## 验证
40
+
41
+ | 变异 | 结果 |
42
+ |---|---|
43
+ | V-1a fingerprint 不含 companion manifest | 3 failing ✓ |
44
+ | V-2a 损坏 marker 当作 author-owned | 3 failing ✓ |
45
+ | V-2b install.sh marker 裸写 | 3 failing ✓ |
46
+
47
+ ## 最终状态
48
+
49
+ | | |
50
+ |---|---|
51
+ | 插件 test:maintenance | **81 passed / 0 failed**(原 80) |
52
+ | studio-panel | **41 files / 358 passed / 0 failed** |
53
+ | docs:check / doctor | 全绿 |
54
+ | lifecycle | 10 passed |
55
+
56
+ 改动:插件 211 项,未提交。
57
+
58
+ ## 二十二轮总账
59
+
60
+ | 维度 | 轮次 | 结果 |
61
+ |---|---|---|
62
+ | 变异验证 | 13–14 | 15 个修复无防线 |
63
+ | 数据丢失 | 12–16 | 5 个模块 |
64
+ | 门禁 fail-open | 17 | 2 处 |
65
+ | except 方向 | 18–19 | 7 个错误码缺失 |
66
+ | 并发(Core) | 20–21 | 1 个无锁缺陷 |
67
+ | 并发(插件)+ 安装路径 | 22 | 2 个缺陷 |
@@ -0,0 +1,48 @@
1
+ # 第二十三轮:缓存/标记失效条件的系统性审计
2
+
3
+ ## 结论:未发现新缺陷(V-1/V-2 已在第二十二轮修复)
4
+
5
+ 本轮按第二十二轮识别出的模式(**缓存/标记与事实不同步**)做了两个系统化审计,都是零命中。
6
+
7
+ ## W-1:派生缓存的失效键(Core 侧全部完备)
8
+
9
+ 自动扫描噪音太大(正则匹配到 `us` 之类的碎片),改为按已知缓存逐个查:
10
+
11
+ | 缓存 | 失效键 | 判定 |
12
+ |---|---|---|
13
+ | `writing_assets` | `sha256(内容)` | 内容哈希,比 mtime 更可靠 |
14
+ | `context_manifest` | `sha256(rendered)` | 内容哈希 |
15
+ | `character_state_index` | `path + size + mtime_ns` 三元组 | 路径集变化也会改变 manifest(列表长度不同) |
16
+ | `chapter_memory` / `review_store` | `source_revision` 对比 | 三态 current/stale/corrupt |
17
+ | `companions.mjs` | **已在 V-1 修复** | 现含 companion manifest mtime |
18
+
19
+ `character_state_index._load_cache` 对损坏返回 `{}` → `cached` 为假 → 重新计算。**fail-open 到"重新算",是安全方向**。
20
+
21
+ 其余 `st_mtime` 用法(`arc_audit`、`narrative_forecast`、`research_service`、`review_store`)都是"取最新的 N 个"排序,不是缓存判定。
22
+
23
+ ## W-2:二值/三态判定的第三态
24
+
25
+ V-2 已修(`marker-corrupt`)。其余:
26
+
27
+ | 判定 | 第三态行为 | 判定 |
28
+ |---|---|---|
29
+ | `preset-definition.legacyPresetIds` | version 不可解析 → `[]` | fail-open 到"无兼容别名",但此时整个插件都该失败,不会静默 |
30
+ | `chapter_memory` acceptance head 检查 | `except Exception: pass` 保持原 freshness | **有意的权衡**:降到 `unknown` 会让所有摘要都不进 prompt(可用性骤降),而保持 current 的风险只是"摘要略旧" |
31
+ | `manuscript_editing.revision_matches` | 允许 16 位短哈希前缀 | 空串不匹配(`fullmatch` 拒绝),16^16 碰撞可忽略 |
32
+
33
+ ## 方法论:本轮为什么零命中
34
+
35
+ 不是因为没有问题了,而是:
36
+
37
+ 1. **W-1 的自动扫描失败了**——正则噪音让我无法相信它的输出,只好回到手工逐个查。这意味着"系统性"只覆盖了我已知列表里的缓存,可能漏掉我没列出的。
38
+ 2. **W-2 的判定大多是三态或 fail-open 到重新计算**——这是第二十二轮修复 + 前几轮修复的结果,模式已经被清理过一遍。
39
+
40
+ ## 状态
41
+
42
+ Core 缓存/新鲜度相关测试 **102 passed**,插件 81 passed,改动未提交(第二十二轮的 211 项 + 本轮无新改动)。
43
+
44
+ ## 剩余未覆盖面
45
+
46
+ - **W-1 的自动扫描能力缺失**:我没有可靠的方法枚举"所有派生缓存"。本轮靠手工列表,可能遗漏。一个可靠的扫描需要先定义"缓存"的语义(有失效键的持久化数据),这本身是个待建能力。
47
+ - `live_tests/`、三系统 CI、真实设备(始终未覆盖)。
48
+ - **性能/资源维度**:从未审查过(内存增长、文件句柄泄漏、无界增长)。