@zooique/memora 5.0.0 → 5.2.0

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 (102) hide show
  1. package/CHANGELOG.md +142 -7
  2. package/README.en.md +7 -3
  3. package/README.md +7 -3
  4. package/dist/agent/agent.d.ts +5 -2
  5. package/dist/agent/agent.d.ts.map +1 -1
  6. package/dist/agent/agent.js +8 -3
  7. package/dist/agent/agent.js.map +1 -1
  8. package/dist/agent/assembler.d.ts.map +1 -1
  9. package/dist/agent/assembler.js +37 -19
  10. package/dist/agent/assembler.js.map +1 -1
  11. package/dist/agent/builtinToolHandlers.d.ts +23 -2
  12. package/dist/agent/builtinToolHandlers.d.ts.map +1 -1
  13. package/dist/agent/builtinToolHandlers.js +22 -11
  14. package/dist/agent/builtinToolHandlers.js.map +1 -1
  15. package/dist/agent/builtinTools.d.ts +16 -0
  16. package/dist/agent/builtinTools.d.ts.map +1 -1
  17. package/dist/agent/builtinTools.js +11 -1
  18. package/dist/agent/builtinTools.js.map +1 -1
  19. package/dist/agent/constants.d.ts +27 -0
  20. package/dist/agent/constants.d.ts.map +1 -1
  21. package/dist/agent/constants.js +27 -0
  22. package/dist/agent/constants.js.map +1 -1
  23. package/dist/agent/contextManager.d.ts +31 -3
  24. package/dist/agent/contextManager.d.ts.map +1 -1
  25. package/dist/agent/contextManager.js +39 -2
  26. package/dist/agent/contextManager.js.map +1 -1
  27. package/dist/agent/guardRail.d.ts +24 -9
  28. package/dist/agent/guardRail.d.ts.map +1 -1
  29. package/dist/agent/guardRail.js +153 -45
  30. package/dist/agent/guardRail.js.map +1 -1
  31. package/dist/agent/loop.d.ts +3 -3
  32. package/dist/agent/loop.d.ts.map +1 -1
  33. package/dist/agent/loop.js +23 -12
  34. package/dist/agent/loop.js.map +1 -1
  35. package/dist/agent/managers/llmCaller.d.ts.map +1 -1
  36. package/dist/agent/managers/llmCaller.js +14 -1
  37. package/dist/agent/managers/llmCaller.js.map +1 -1
  38. package/dist/agent/managers/sessionManager.d.ts.map +1 -1
  39. package/dist/agent/managers/sessionManager.js +1 -0
  40. package/dist/agent/managers/sessionManager.js.map +1 -1
  41. package/dist/agent/messageHistory.d.ts +3 -0
  42. package/dist/agent/messageHistory.d.ts.map +1 -1
  43. package/dist/agent/messageHistory.js +14 -0
  44. package/dist/agent/messageHistory.js.map +1 -1
  45. package/dist/agent/seed/orchestrator.d.ts +2 -1
  46. package/dist/agent/seed/orchestrator.d.ts.map +1 -1
  47. package/dist/agent/seed/orchestrator.js +3 -3
  48. package/dist/agent/seed/orchestrator.js.map +1 -1
  49. package/dist/agent/seed/prepare.d.ts +3 -1
  50. package/dist/agent/seed/prepare.d.ts.map +1 -1
  51. package/dist/agent/seed/prepare.js +10 -2
  52. package/dist/agent/seed/prepare.js.map +1 -1
  53. package/dist/agent/sessionStateMachine.d.ts +3 -0
  54. package/dist/agent/sessionStateMachine.d.ts.map +1 -1
  55. package/dist/agent/sessionStateMachine.js.map +1 -1
  56. package/dist/agent/textSanitize.d.ts +1 -1
  57. package/dist/agent/textSanitize.js +1 -1
  58. package/dist/agent/toolExecutor.d.ts +18 -12
  59. package/dist/agent/toolExecutor.d.ts.map +1 -1
  60. package/dist/agent/toolExecutor.js +114 -19
  61. package/dist/agent/toolExecutor.js.map +1 -1
  62. package/dist/index.d.ts +2 -0
  63. package/dist/index.d.ts.map +1 -1
  64. package/dist/index.js +5 -0
  65. package/dist/index.js.map +1 -1
  66. package/dist/llm/factory.d.ts +21 -0
  67. package/dist/llm/factory.d.ts.map +1 -1
  68. package/dist/llm/factory.js +4 -1
  69. package/dist/llm/factory.js.map +1 -1
  70. package/dist/llm/openaiCompatible.d.ts +8 -1
  71. package/dist/llm/openaiCompatible.d.ts.map +1 -1
  72. package/dist/llm/openaiCompatible.js +26 -0
  73. package/dist/llm/openaiCompatible.js.map +1 -1
  74. package/dist/llm/provider.d.ts +65 -0
  75. package/dist/llm/provider.d.ts.map +1 -1
  76. package/dist/llm/provider.js +10 -0
  77. package/dist/llm/provider.js.map +1 -1
  78. package/dist/memory/inMemorySessionStore.d.ts.map +1 -1
  79. package/dist/memory/inMemorySessionStore.js +11 -0
  80. package/dist/memory/inMemorySessionStore.js.map +1 -1
  81. package/dist/memory/roundStore.d.ts +7 -0
  82. package/dist/memory/roundStore.d.ts.map +1 -1
  83. package/dist/memory/roundStore.js.map +1 -1
  84. package/dist/memory/sessionStore.d.ts +8 -0
  85. package/dist/memory/sessionStore.d.ts.map +1 -1
  86. package/dist/memory/sessionStore.js.map +1 -1
  87. package/dist/security/confirmEntries.d.ts +21 -6
  88. package/dist/security/confirmEntries.d.ts.map +1 -1
  89. package/dist/security/confirmEntries.js +21 -6
  90. package/dist/security/confirmEntries.js.map +1 -1
  91. package/dist/security/pathGuard.d.ts +43 -9
  92. package/dist/security/pathGuard.d.ts.map +1 -1
  93. package/dist/security/pathGuard.js +69 -9
  94. package/dist/security/pathGuard.js.map +1 -1
  95. package/docs/architecture/role-pack-authoring-guide.md +4 -0
  96. package/docs/architecture/role-pack-spec.md +9 -5
  97. package/docs/memora-api-reference.md +21 -7
  98. package/docs/memora-/346/216/245/345/205/245/346/214/207/345/215/227.md +47 -17
  99. package/package.json +7 -1
  100. package/role-packs/memora/345/212/251/346/211/213/rules.md +1 -0
  101. package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/rules.md +1 -0
  102. package/role-packs//347/231/275/350/257/235/346/226/271/346/241/210/350/256/276/350/256/241/345/270/210/rules.md +2 -1
package/CHANGELOG.md CHANGED
@@ -1,14 +1,94 @@
1
1
  # Changelog
2
2
 
3
- 本文件记录 **@zooique/memora(内核 npm 包)**的版本变更。**宿主**(`hosts/memora-vscode`)不在发布包 `files` 白名单内(见 `package.json`),不占内核版本号:内核变更定档独立版本号(当前 **[5.0.0]** 开发中),宿主变更在 `[Unreleased] · 宿主`(随做随用,攒批随 `vsce package` 定版,ADR-033)。
3
+ 本文件记录 **@zooique/memora(内核 npm 包)**的版本变更。**宿主**(`hosts/memora-vscode`)不在发布包 `files` 白名单内(见 `package.json`),不占内核版本号:内核与宿主各按自己的版本号成区(ADR-033),**已发布与否以 npm registry 为准**(内核 `npm view @zooique/memora dist-tags.latest`;宿主见 Marketplace / Open VSX)——本文件不复述该状态,只记各版本改了什么。
4
4
 
5
5
  格式遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),版本号遵循 [Semantic Versioning](https://semver.org/lang/zh-CN/)。
6
6
 
7
- > **版本定位(v5.0.0)**:**Node.js 专属 · 零第三方运行时依赖的 Agent 内核**(依赖 `node:*` 内置模块,不引第三方运行时依赖 / native / 宿主 API)。**4.0.0**:导出面收敛(−54)+ `agent.memory.search()` 退役(唯一入口 `searchByKeyword()`)。**5.0.0(当前)**:公开面大收面(删 23 导出 + 32 成员 + 3 事件)+ 多项目形态定案(一个 Agent = 一个项目)+ 三套空转机制退役 + SQLite 存储——逐项改法见[升级指南](docs/memora-升级指南-4.x-到-5.0.0.md)。**4.0.0 及更早版本全文**:`docs/CHANGELOG-归档.md`(仓库内归档,npm 包不含)。内核不内置 agent 级行为评估(eval)/ 独立验证——由宿主基于内核可观测性(ITracer / 事件 / 指纹)自行承担;内核对接口契约与全量单测负责,不对"agent 整体行为稳定"作承诺。
7
+ > **版本定位(v5.x)**:**Node.js 专属 · 零第三方运行时依赖的 Agent 内核**(依赖 `node:*` 内置模块,不引第三方运行时依赖 / native / 宿主 API)。**4.0.0**:导出面收敛(−54)+ `agent.memory.search()` 退役(唯一入口 `searchByKeyword()`)。**5.0.0**:公开面大收面(删 23 导出 + 32 成员 + 3 事件)+ 多项目形态定案(一个 Agent = 一个项目)+ 三套空转机制退役 + SQLite 存储——逐项改法见[升级指南](docs/memora-升级指南-4.x-到-5.0.0.md)。**5.1.0**:MCP 工具接入的内核接口(`ToolDefinition.confirmPolicy` + `SecurityGuard` 单一确认入口)+ 脚本族执行面四面按正文裁决(`CMD-1-BYPASS` / `CMD-1-CONTENT`)——零删除、零既有签名变更。**4.0.0 及更早版本全文**:`docs/CHANGELOG-归档.md`(仓库内归档,npm 包不含)。内核不内置 agent 级行为评估(eval)/ 独立验证——由宿主基于内核可观测性(ITracer / 事件 / 指纹)自行承担;内核对接口契约与全量单测负责,不对"agent 整体行为稳定"作承诺。
8
8
  >
9
9
  > 本文件 2026-10-19 起按 `CHLOG-TRIM-1` 精简:只记「改了什么 + 为什么 + 对消费者的影响」;逐批拍板过程、变异验证收据、台账叙事的 SSOT 在仓库台账 `tasks/待完成任务.md` 对应 ID 条目(npm 包不含),此处只留 ID 锚保交叉引用。
10
10
 
11
- ## [5.0.0] · 未发布
11
+ ## [5.2.0] · 2026-10-29
12
+
13
+ > **本区归属**:仅**内核**变更;SemVer 定档**随本区收口复核**——本区现有三批:①**文档 + 测试守卫**(**运行时代码零变更、公开面零变更**),含**三件契约守卫增量**(公开面 diff 快照 / 可达成员面冻结表 / 随包接入指南一致性,封住三处「消费者可感知的契约变更会静默通过」的真实漏洞)与**一件文本卫生守卫**(全仓 U+FFFD 乱码扫描);②**一处运行时行为修复**(`ISessionStore.loadMessages` 的附件契约补齐,见 Fixed 小节,**公开面零变更、零签名变更**);③**一处运行时功能项**(图片输入内核面,见 Added 小节——`ImageRef` / `ImageResolver` / `imageTokens` 三导出与三个 `attachments?` 字段在 5.1.0 中均不存在,**公开面纯新增、零删除、零既有签名变更**)。③ 使本区按 SemVer 定档 **minor(5.2.0)**——与 2026-10-27 拍板的版本号自洽;①②单看是 patch,被③吸收。
14
+ > **收据与拍板过程**:见仓库台账(npm 包不含)ID 锚 `RUNTIME-TIER-1`(运行时门槛)/ `PUB-SNAPSHOT-1`(公开面快照守卫)/ `PUB-REACHABLE-1`(可达成员面守卫)/ `GUIDE-AUDIT-1`(接入指南核查)/ `GUIDE-GUARD-1`(接入指南守卫)/ `ONBOARD-MIN-1`(最小接入面叙事)/ `FFFD-GUARD-1`(全仓乱码清零与扫描守卫)/ `IMG-1`(图片内核面)/ `IMG-3`(能力位透传链)。
15
+ > **发版纪律**:本区标题日期须在打 tag 前改为实际发布日(`scripts/verify-changelog-version.mjs` 挂 `release.yml` 校验;已发布 tarball 不可变,见 `RELEASE-CHLOG-DATE-1`)。
16
+
17
+ ### Added(内核)
18
+
19
+ - **公开面 diff 守卫「向 E」**(`PUB-SNAPSHOT-1`):`publicApiSurfaceGuard.test.ts` 新增公开面 ↔ **冻结快照**(2026-10-27 冻结,计数以快照数组自身为准)逐位对账——删除或改名任一 `src/index.ts` 导出即红。**为什么**:原向 A/B/C/D 全部从「现存集合」出发迭代,符号一旦被删就不再被任何闸门检查——**任何被删除的导出都会全库静默**(实测:删 `isRoundSettled`,它**宿主真实消费**但不挂文档承诺面 ⇒ 仅向 E 变红、其余全绿)。**对消费者**:零运行时行为变化;此后删除公开导出必走「清算 README / 手册承诺与全部消费方 → major」的显式流程。新增导出仍先过向 A,同批补进快照(快照注释写明二选一更新纪律,不存在「改断言让它绿」的第三选项)。
20
+ - **可达成员面守卫**(`PUB-REACHABLE-1`):`publicMemberSurfaceGuard.test.ts` 新增「可达成员面」层——冻结**经已登记符号的公开 getter 返回、但未挂 `src/index.ts` 导出面**的类的公开成员清单(实测 **7 类型 / 133 成员** = `AgentLoop` / `ToolExecutor` / `MessageHistory` / `SkillManager` / `SecurityGuard` / `WorkProjectionManager` / `TextPolishManager`),增删即红。**为什么**:该守卫原只遍历**导出符号** ⇒ 不挂导出面的类完全不在射程——`SecurityGuard` 虽未从包入口导出,但 `Agent.get security` 返回它,消费者(宿主设置面板 / 装配层)**真实在调** `agent.security.setConfirmWrites(...)` 等方法,而 5.1.0 新增的 `requestToolCallConfirmation` 也在该面上 ⇒ **删改这些方法此前任何闸门都不红**(消费侧仅 TS 编译期拦截)。**对消费者**:零运行时行为变化;此后这类「经公开 getter 可达」的方法增删同样必走审查(新增 = 真能力还是谎报?删除 = 纠谎还是误删?),不再静默。冻结范围经三轮收紧(排除 TS 内置类型 / 内部协作对象 / 零消费类型),避免「为完整性而完整性」给内部实现上枷锁。
21
+ - **随包接入指南一致性守卫**(`GUIDE-GUARD-1`):`integrationGuideGuard.test.ts` 把 `docs/memora-接入指南.md`(**随包发布**、22 个可照抄的 TS 代码块)纳入机检——① 代码块 `import` 的符号必须存在于 `src/index.ts` 导出面;② 代码块与行内 `agent.X` 必须是 `Agent` 公开成员(**解析 `extends` 链**,故 `agent.on` 不假红);③ 文档**自称「接口全集」**时示例类必须实现接口全部必需成员;④ 扫描面归零即红(防路径漂移导致恒绿)。**为什么**:该文档此前**不在任何文档守卫射程**(既有守卫只对账 README 与 API 手册),两处真伤因此长期存活——示例里的 `appendMessage` **内核全仓不存在**(`ISessionStore` 有 11 个必需方法,示例只写 3 个 ⇒ 消费者照抄必编译失败)、`agent.projects` 僵尸引用(该 getter 已于 5.0.0 随项目层退役)。**对消费者**:零运行时行为变化;此后该指南的 API 引用与「照抄可编译」承诺随内核一起被机检。判据全部**实时读源码**(不建冻结表 ⇒ 无第二份真源);**历史留痕**(明写「已移除 / 已退役」的表述)与**合法节选**示例均豁免,不误伤正确写法。
22
+ - **全仓 U+FFFD 乱码清零 + 替换字符扫描守卫**(`FFFD-GUARD-1`):新增 `src/__tests__/replacementCharGuard.test.ts`——对全仓十二种文本后缀(含 `.trae` / `.github` 等隐藏目录)扫 U+FFFD 替换字符,判据为「零违例 + 扫描面下限断言(防空集假绿)+ 判据探针自检 + 与 `scan:phrase` 排除集的逐元素同源契约(防双写漂移)」;同批清零 **4 处存量乱码**(内核 `textSanitize.ts` 生产注释、宿主 `chatView.ts` 注释、仓库台账与方案文档各 1 处——生产注释**随编译进 dist .js 出货**,见 `package.json` 构建无 `removeComments`)。**为什么**:乱码是「没有任何测试会红」的伤(读者肉眼可见、机器不报错,与措辞折叠同族),4 处经 git 溯源均 **born corrupt**(入仓即带、原文不可从 VCS 恢复,只能语义重构),此前无任何闸门扫描此类损坏。**对消费者**:dist 注释里一处乱码的文本修复(零运行时行为变化);此后文本文件混入替换字符在测试闸门即红。
23
+ - **图片输入(多模态用户输入)内核面**(`IMG-1` / `IMG-3`):公开面**纯新增**——① `ImageRef`(宿主采集侧构造的图片引用:`sha256` / `mime` / `width` / `height` / `bytes` / 必填 `name`);② `ImageResolver`(宿主持有的**运行时回调**,把 `ImageRef` 物化为 `{url}` 或 `{text}` 占位文案——内核零外部 IO,回调不可持久化、不进任何配置 DTO);③ `imageTokens`(单图 token 估算**单点公式**,入参只要宽高子集,宿主入口限额直接复用,不各写一份数学);④ `Message` / `RoundMessage` / `SessionMessage` 各增可选 `attachments` 字段(随 `loadMessages` 恢复链带回,见 Fixed 小节);⑤ `ProviderConfig` 增 `supportsVision`(缺省 `false`——「声称看得见图却看不懂」比「坦承不支持」危害更大)与 `imageResolver`;⑥ `Agent.chat` / `AgentLoop.processUserInput` 增可选 `attachments` 参(仅流式入口承载)。带图请求发往未声明 `supportsVision` 的模型时**一级门禁 fail-closed 明确拒绝**(读**路由后** provider,非配置快照);resolver 未命中的图推**可见占位文本块**,绝不静默丢。**为什么**:多模态输入的内核契约与执行面——OpenAI `image_url` 形态序列化、token 计量与占用环复用同一公式、无附件请求体**字节级不变**(快照守门)。**对消费者**:不用图片的既有代码零影响(`attachments` 不带即字段不存在);要用图须三件齐备——模型声明 `supportsVision` + 注入 `imageResolver` + 调 `chat()` 时传 `attachments`。
24
+
25
+ ### Fixed(内核)
26
+
27
+ - **`ISessionStore.loadMessages` 的附件契约补齐:历史图片随轮恢复,并按窗口衰减**(`IMG-2` 断点B):`ISessionStore.loadMessages` 的 JSDoc 新增契约句——user 消息**必须**带 `attachments`,且经 `LOOP_CONSTANTS.RETAIN_IMAGE_ROUNDS` 窗口衰减;内核 `InMemorySessionStore.loadMessages` 与宿主 `WorkspaceSessionStore.loadMessages` 同批落地,两实现与 `messageHistory.loadRoundBasedMessages` **同判据同构**(`当前索引 − 消息索引 < 4`,索引一律 `roundIds.indexOf(round.id)` 取位——`getByIds` 会跳过缺失轮,用返回数组下标必错位)。**为什么**:本方法是内核 `restoreHistory` 的**唯一上游**,此前只透传 `role / content / timestamp / roundId`,漏掉了 5.0.0 起就存在于 `RoundMessage` 的 `attachments` ⇒ **重启宿主后历史图片全灭**(模型只见纯文本,连 D7 占位都没有;真机验收实锤)。**对消费者**:`loadMessages` 返回的 user 消息此后**会带** `attachments`(仅窗口内轮次)——自行实现 `ISessionStore` 的消费者不补该字段不会有任何报错,但历史图对其模型不可见;不需要该行为者可忽略该字段。**零签名变更、零公开面变更**;`RETAIN_IMAGE_ROUNDS` 仍是单点常量(其注释已同步登记**四个消费点**:三处窗口衰减 + 一处预读量)。
28
+
29
+ ### Changed(内核 · 文档)
30
+
31
+ - **运行时门槛双档口径**(`RUNTIME-TIER-1`):README 中英各三处对齐(「运行时要求」声明块 / 技术栈表行 / IMemoryStorage 表行)——包门槛 Node.js ≥ 22.0.0(与 `package.json#engines` 同源,**engines 刻意不收紧**,2026-10-16 A1 拍板);SQLite 落盘工厂 `createNodeSqliteStorage`(`node:sqlite`)需 **Node ≥ 22.13**(22.13 起免 `--experimental-sqlite` 标志)。低于 22.13 时包可正常加载、内存存储照常可用,仅调用该工厂抛「需 Node ≥22.13」的 `NOT_AVAILABLE` 明确错误,**不会静默失败**。**对消费者**:npm 安装面此前只见 22.0.0 门槛、不知第二档能力线,现补齐双档事实。
32
+ - **最小接入面叙事**(`ONBOARD-MIN-1`):README 中英边界声明后各增一段——构造 `Agent` 必填仅 **`projectPath` / `provider` / `dataDir` 三项**(`dataDir` 无缺省值,与 API 手册 §〇.5 同口径);`storage` 缺省为内置内存实现(对话与记忆闭环照常,仅不持久化),`sessionStore` / `roundStore` / `tracer` 与五个外部工具 provider(`web_search` / `web_fetch` / `run_code` / `search_project` / 环境上报)均可选,不配只是不启用对应能力、不阻塞启动。**对消费者**:纠正「接入需自实现一整套存储/会话接口」的错觉——要落盘直接用内置 `createNodeSqliteStorage` 工厂,无需自实现存储接口。
33
+
34
+ ## [5.1.0] · 2026-10-25
35
+
36
+ > **本区归属**:仅**内核**变更;SemVer = **minor**(零删除 / 零既有签名变更;**行为变化共三处、均为修复方向、不构成破坏性**:① 脚本族执行面按正文裁决,命中黑名单/恒弹清单的执行行为收紧;② 写侧护栏判据改为「无进展」(`write_loop` 只计整文件覆盖与连续失败写,增量写不再计数);③ `task_table_update` 不再被跨轮幂等跳过(防回喂旧任务表)。三者均见 Fixed 区)。公开面**分两层**:① **包入口符号面**增量 = **仅** `ToolDefinition` 加可选字段 `confirmPolicy`(类型面)——`SecurityGuard` 类与 `SCRIPT_READ_MAX_LEN` 均**未**从包入口 `src/index.ts` 导出;② **公开成员面**零新增(`publicMemberSurfaceGuard` 成员表未增元素),但 `agent.security` 本就是公开成员,其新增方法 `requestToolCallConfirmation(toolName, summary, needConfirm)` 对消费者**可达**(文档见 `docs/memora-api-reference.md` §2.6)。宿主侧 MCP 消费面(连接 / 设置页 / 审批卡)随宿主下一版独立成区、不占内核版本号(ADR-033)。逐条拍板与变异验证收据见仓库台账(npm 包不含),**按条目 ID 检索**(`tasks/待完成任务.md` 与 `tasks/archive/5.1.0-kernel.md`,不按区名——已发行版本区已于 2026-10-26 归元折叠):`D1-MCP`(顶层条目仍留主台账 `tasks/待完成任务.md`);`CMD-1-BYPASS` 的实现收据见主台账 `㉔` 条、最后一面见 `tasks/archive/5.1.0-kernel.md` 的 `CMD-1-CONTENT` 条目;`CMD-1-CONTENT` / `GUARD-WRITE-PROGRESS-1` / `IDEM-TASK-TABLE-1` 均在 `tasks/archive/5.1.0-kernel.md`。
37
+ > **发版纪律**:本区标题日期即**实际发布日**——`scripts/verify-changelog-version.mjs`(挂 `release.yml`,不进 pre-push)校验「合法日历日期 + 与发布日相差 ≤1 天」;已发布版本的 npm tarball 不可变、改不回来(`RELEASE-CHLOG-DATE-1` 血训),故日期须在打 tag 前定稿。
38
+ > **日期口径(2026-10-27 澄清)**:本区标题日期 = **打 tag 的那个日历日(本地时区)**;台账「版本索引」的发布日期列 = **npm 上架日(北京时间)**。二者可能差一天(5.1.0 = 本区 10-25 / 上架 10-26,跨午夜)⇒ **两者都正确,非笔误**。
39
+
40
+ ### Added(内核)
41
+
42
+ **MCP 工具接入的内核接口(`D1-MCP` 切片 0 · 2026-10-23)**——MCP SDK 与传输全在宿主依赖,内核仍不认识 MCP、零第三方运行时依赖不变
43
+
44
+ - `ToolDefinition.confirmPolicy?: 'always' | 'audit'`:自定义/外部工具(如宿主接入的 MCP 工具)声明审批意图的**唯一字段**。**缺省 = 字段不存在 = 不过闸 = 现状**;刻意不设 `'never'`——宿主只需「关弹窗」,不需「关审计」。
45
+ - `SecurityGuard.requestToolCallConfirmation(toolName, summary, needConfirm)`:复用私有 `confirmGate` 的**单一确认入口**(一次入口、两种模式),`ToolExecutor.execute()` 的 custom 分支按上述字段过闸——`'always'` 弹确认、`'audit'` 自动放行但仍落审计,拒绝则不调 handler(`[ERR:TOOL_DECLINE]` + blocked outcome)。**为什么重要**:此前 custom 分支完全不过闸 = 动态工具源(MCP)零审批;补后**全仓仍只有一条审批路径**,不存在第二条。
46
+ - 审计**零新增类型**:确认统一走后恒落既有三值(`write-auto` / `write-confirm` / `write-decline`),工具调用补 `source: 'custom'` + `tool` + `path`(= 调用摘要,与 `run_command` 把命令塞 `path` 同构);`confirmGate` 加可选 `source` 末参并透传**全部四个**审计出口(写入类不传 = `undefined`,零行为变化)⇒ 宿主既有「denied 计数」自动覆盖 MCP,宿主审计面零改动。
47
+ - `ToolExecutor.removeTool()` 的 JSDoc 由「供测试场景使用」扩为「运行时可注销」(`K2`,零代码改动)——宿主据此实现 MCP server 停用与工具集整换。
48
+ - **对消费者**:纯增量。不声明 `confirmPolicy` 的既有自定义工具行为完全不变;要接入动态工具源的宿主声明字段即得审批 + 审计。
49
+ - ⚠️ **本期刻意不做**(`K3`,有判据的拒绝):不放宽 `ToolDefinition.parameters` 的 schema 类型(不支持嵌套 object / enum / anyOf)——`loop.ts` 的 prompt 渲染器只读顶层 `type`/`description`,放宽须连带改模型可见文案并回归全部内置工具,收益不抵风险;宿主侧以「结构映射 + 约束搬 description」适配。
50
+
51
+ **内置角色包 L1 增「编辑纪律基线」(`GUARD-WRITE-PROGRESS-1` 配套 · 2026-10-25)**
52
+
53
+ - 三个内置包(`memora助手` / `共鸣小说家` / `白话方案设计师`)的 `rules.md` 增一条**领域无关的编辑纪律**:增量写入优先(`replace` / `insert` / `append`)、同一文件多处修订在**同一回复内连续发出**、整文件覆盖仅用于确需重建且不反复覆盖、复核只读改动片段。`role-packs/` 在 `package.json#files` 内,**消费者可见**。
54
+ - 作者指南 §2.4 同步该基线,并明示 **L1(`rules.md` / `persona.md`)不得写运行时拒绝令牌**(`[WRITE_LOOP_STOP]` / `[WRITE_FAIL_STOP]`)——L1 常驻 system prompt,令牌会干扰「按令牌定位运行时拒绝消息」的消费方(纪律真源 `src/agent/guardRail.ts` GUIDELINES)。
55
+ - **为什么**:写侧护栏只拦「无进展」,**不拦「慢」**——真正决定模型行为的纪律必须写在 L1;真机 `round-1792904123909`(7 次被拦、5 处修订拖到下轮、27 分钟 / 116 万输入 token)即缺该条所致。
56
+
57
+ ### Fixed(内核)
58
+
59
+ **脚本面内容裁决(`CMD-1-BYPASS` · 2026-10-25)**
60
+
61
+ - `SecurityGuard.confirmScriptRun` 接受可选第 4 参 `content`(= 将被执行的脚本/代码正文),内部喂给**同一个** `classifyCommand`:`deny` 恒拦(任何档位/权限,不进确认流程)/`always-ask` 恒弹(`owner` + `confirmScripts=false` 也弹)/`normal` 回落原档位判据。**为什么**:此前 `classifyCommand` 的唯一调用点是 `confirmCommandRun`,脚本面只看档位不看内容 ⇒「把 `git push` / `rm -rf` 写进脚本」零护栏,恒弹清单成了纸墙(一次工具调用即可绕过)。
62
+ - 已接入两面:`run_code`(内联代码传正文)、`run_project_script`(确认前读脚本文本);正文 > `SCRIPT_READ_MAX_LEN`(20 万字符)**拒绝执行**(fail-closed,不给「读不动就放行」的口子)。
63
+ - `ALWAYS_ASK` 清单补 `git clean`(此前落 normal 档 = 默认档直接执行,真洞)。
64
+ - `BuiltinToolHandlers.readScriptFile` 加可选 `label`(默认 `run_code script_path`):复用读正文时审计归属不再写死 `run_code`(原会把项目脚本的路径审计记到 `run_code` 头上 = 归属说谎)。
65
+ - 三处 decline 文案改中性措辞(「未获执行许可(命中恒拦 / 用户拒绝 / fail-closed)」)——原写「未获确认(用户拒绝…)」会把命中黑名单说成用户拒绝。
66
+
67
+ **技能脚本内容裁决(`CMD-1-CONTENT` · 2026-10-25)**
68
+
69
+ - `run_skill_script` 是脚本族最后一面(此前只判档位)。现确认点经装配期新注入字段 `ToolExecutor.resolveSkillScript`(与执行回调**共用** assembler 的 `resolveSkillScriptTarget`:角色包 → 全局池,解析顺序天然单点)定位脚本文件读正文,喂同一个 `classifyCommand`。
70
+ - 长度上限复用 `SCRIPT_READ_MAX_LEN`(本轮改为导出常量,三消费面共用,**不造第二上限**);**不走项目根白名单**——技能目录 = 可信根(脚本经作者审阅),路径防逃逸由解析器自身保证(角色包 layer3 白名单 + `resolveSafePath` 边界 / 全局 `resolveLayer3ScriptPath` + 存在性校验)。
71
+ - fail-closed 分级:解析不到 = 不传正文(维持 `[ERR:SCRIPT_NOT_FOUND]`,执行点同一解析必返 null);读失败 / 超长 = `[ERR:SCRIPT_DECLINE]` 拒绝执行。
72
+ - **对消费者**:`runSkillScript`(执行回调)契约与行为不变;不注入 `resolveSkillScript` 的装配(含既有单测)行为与补齐前完全一致。**至此四个执行面(`run_command` / `run_code` / `run_project_script` / `run_skill_script`)全部按正文裁决。**
73
+
74
+ > **不声称的内容(防误读)**:`classifyCommand` 是**字符串判据**——拦「模型手滑 / 幻觉 / 提示注入直接写出危险命令」,不是「危险执行总闸」;正文之外的间接载体(变量展开、编码混淆、执行期才决定的路径)拦不住。语义防护由**用户审批 + 审计溯源**承担,不由 denylist 承担。
75
+
76
+ **写侧护栏判据改为「无进展」(`GUARD-WRITE-PROGRESS-1` · 2026-10-25)**
77
+
78
+ - `write_loop` 原判据 = 「同路径连续写 N 次」,把 `mode=replace` 的逐处修订与整文件覆盖混算:第 5 次写入即硬拦,且被拦后 `read_file` **不复位**计数(`notifyExec` 原先只按 `matches` 分发,读事件根本喂不到该护栏)⇒ 该路径在**本 turn 内永久封死**。真机 `round-1792904123909` 实证:7 次被拦、5 处修订拖到下轮、27 分钟 / 116 万输入 token。
79
+ - 现判据 = **无进展信号**:① 仅整文件覆盖(`mode=overwrite`,缺省)计入连写(阈值 `writeLoop` 不变 = 5);② 增量写(`replace` / `insert` / `append`)每次改不同片段,**永不计数**;③ 同路径连续**失败写**达新增静态阈值 `writeFail`(= 3)即拦,读成功 / 写成功即清;④ `failed` 不再被当作一次写(原实现会推进 streak)。
80
+ - `notifyExec` 改为**全量分发**(各护栏在 `onExec` 内按工具自过滤)——原「借 `matches` 路由」让一个字段担两份职责,护栏文案承诺的「先读再写」出口从未生效。
81
+ - 新增**放行钩子** `onAllow` / `notifyAllow`(同批洞补丁,真机 `round-1792919558093`):同批工具调用先集中判定、后统一执行,判定阶段看不到结果 ⇒ 只靠执行后回喂的连写计数会被「一条回复内连发 N 次整文件覆盖」整批绕过(实测 6 次全部放行)。现于派发时**预登记整文件覆盖意图**,第 5 次同批覆盖即拦;执行回喂消费预登记(一次写只计一次),被拦未执行则撤销。增量写不登记(批量逐处修订仍零计数)。`write_fail` 刻意不预登记——批内看不到失败结果,预拦会误伤同批中本可成功的写。
82
+ - 文案:`[WRITE_LOOP_STOP]` 的出口改为**可执行**的「改用 replace/insert/append 增量写入」;新增 `[WRITE_FAIL_STOP]`(先读最新原文再写)。
83
+ - **对消费者**:`BlockedReason` 未新增/未改名(仍是 `write_loop`)、零公开签名变更、零新增 metrics 字段(拦截事实已在 round 事件的 `tool_result.blocked` 中,另立计数即第二真理源)。行为向修复:同一 turn 内对同一文件的增量修订不再被封顶。
84
+
85
+ **任务表更新不再被跨轮幂等跳过(`IDEM-TASK-TABLE-1` · 2026-10-25)**
86
+
87
+ - `BUILTIN_TOOL_IDEMPOTENCY.task_table_update`:`idempotent` → `non-idempotent`。**为什么**:幂等键只有 `name + 完整 args`,而 `task_table_update` 的 `plan_item_id` 是**位置序号**——跨轮 `task_table_write` 重写任务表后,同序号可能指向另一个任务项;此时同 args 重发会被「仅一次语义」跳过并回喂上一轮的旧任务表摘要 = **向模型谎报「已更新」而实际未更新**(真机观测:回显旧任务项)。重跑本身无害(状态确定),故与 `delete_file` 同判据——归入「禁止跳过」而非「重跑有害」。
88
+ - **对消费者**:`IdempotencyLevel` 枚举未变、零签名变更;仅该工具不再被跳过。内置映射现**无** `idempotent` 级工具(级别本身保留,供宿主自定义工具声明)。
89
+ - 同族**未改**(登记观察,不随本版动):`write_file`(`idempotent-key`)跨轮「同 path + 同 content」仍会跳过——若文件在两次调用间被外部删除/改动,同内容重写不会落盘。无真机实证,且该跳过是核心重试去重通道,改动面大。
90
+
91
+ ## [5.0.0] · 2026-10-23
12
92
 
13
93
  > **📖 升级必读**:[`docs/memora-升级指南-4.x-到-5.0.0.md`](docs/memora-升级指南-4.x-到-5.0.0.md) —— 本区所有 Breaking 项的**改法**逐项在那篇,本区不重复**怎么改**。
14
94
  > 本区归属:仅**内核**变更;SemVer = **major**(编译期破坏:删 23 个导出符号 + 32 个公开成员 + 3 个事件)。
@@ -43,7 +123,7 @@
43
123
 
44
124
  - Agent:`canContinueWithoutInput()`(软暂停模型下暂停恒安全,可续跑性由 waiting 原因位表达,方法本身是采样时机不可靠的带陷阱死面)/ `getRecentToolExecutions()`(订阅 `tool_start`/`tool_result` 事件自聚合)/ `getBackgroundTaskStats()` / `forceReleaseChatLock()`(承诺的超时兜底从未接线)/ `heartbeat()`(私有 `touchCheckpoint` 的机制外漏)。
45
125
  - SessionManager:`flushNow()` / `flushOnShutdown()`(检查点不落盘,二者是 no-op 清脏,方法名谎报持久化)/ `loadSessionMessages()`(改锚点不 restore 工作记忆的陷阱出口)/ `restoreSession(date, session)` / `restoreMostRecentSession()`(恢复双入口并入 `switchToSession('YYYY-MM-DD-session')` 复合 ID,最近会话从自己的 store `listSessionMetas()[0]` 取)/ `isPauseLimitReached()` / `getConsecutivePauseCount()` / `resetConsecutivePauseCount()`(连续暂停计数链从未通电,生产恒传 `lowRisk=true`)/ `compensateTool()` / `compensateAllNonIdempotent()`(只生成文案、零状态变更)/ `isPaused()` / `isRunning()`(三态 `'running'|'paused'|'error'` 被两布尔吞掉 error 态——看 `status`)。
46
- - ⚠️ 上述多项随 4.0.0 已发布,直删失去 deprecation 预警期,由本 Breaking 明示;`loadSessionMessages` 原走 `DEPRECATE-1` 周期,用户拍板提前直删。决策依据 = 三面零消费 + 5.0.0 未发布(npm 最新 4.0.0)零外部破坏窗口。
126
+ - ⚠️ 上述多项随 4.0.0 已发布,直删失去 deprecation 预警期,由本 Breaking 明示;`loadSessionMessages` 原走 `DEPRECATE-1` 周期,用户拍板提前直删。决策依据 = 三面零消费 + 5.0.0 定档时点未发布(npm 最新 4.0.0)零外部破坏窗口。
47
127
 
48
128
  **选项与常量**
49
129
 
@@ -72,13 +152,68 @@
72
152
 
73
153
  - **后台任务槽位按 Agent 实例隔离**(`MULTI-AGENT-1`,2026-10-18):模块级槽位 → `class BackgroundTaskScheduler` 实例级,同进程多 Agent 不再交叉等待/挤占(形态定案后多实例是必然)。非公开 API 变更。
74
154
 
75
- ## [Unreleased] · 宿主(随做随用 · 不占内核版本号)
155
+ ## [0.3.0] · 2026-10-26 · 宿主
156
+
157
+ > **本区归属**:仅**宿主**(`hosts/memora-vscode`)变更,随 `vsce package` 定版,不进内核 npm 包(ADR-033)。**开区原因**:`vscode@0.2.0` tag 早于宿主 MCP 接入 ⇒ 已发布版没有任何 MCP 能力。**主体条目(MCP 接入)已于 2026-10-26 按 `git log vscode@0.2.0..vscode@0.3.0 -- hosts/` 补齐**(该区间实测 63 笔宿主提交,其中 33 笔属 MCP 接入);切片叙事不复述,逐笔变更以该 tag 区间为准。**对外文档不引用内部台账坐标**(区名会随台账重组失效,tag 区间不会)。
158
+ > **随包内核代次 = `5.1.0`**(esbuild 内联 dist,内核自身变更见内核区)。
159
+
160
+ ### Added(宿主)
161
+
162
+ - **MCP 工具接入(本地 stdio):对话里可以直接调用外部工具服务器**(2026-10-23 ~ 10-25 落地,2026-10-26 补记):Memora 现在是一个 **MCP 客户端**——你告诉它有哪些工具服务器,它把这些服务器暴露的工具注册进 Agent,模型在对话里能像调内置工具一样调用,工具名形如 `mcp__<服务器名>__<工具名>`。配置在**设置面板 → MCP** 页(每台服务器一张卡片 + 表单增删改),写用户级 `memora.mcpServers`;工作区级配置**不读**(可被他人提交进仓库 = 让任意仓库拉起任意命令,2026-10-25 定案不开放)。启动前做一次**静态预检**(命令是否存在 / 是否把脚本当命令 / 工作目录是否存在),不通过就不拉起并把原因写在卡片上。卡片给的是**真实状态**而非「我以为连上了」:已连接 / 启动失败(附原因)/ **待接入**(配置在、运行态还没追平——不是故障)/ 已停用 / 配置不完整。配置**改完即时生效**:新增立即拉起、改参数先停后起、停用与删除立即注销工具、改白名单只重算档位不重连;配置没变但连接已坏(子进程被外部杀掉)时热更不触发,用卡片「重启」按名字重建。也支持**粘贴 JSON 片段批量导入**(Claude Desktop / Cursor / VS Code `mcp.json` 均可),同名与字段不合法的条目逐条跳过、不覆盖已有配置。**为什么**:`vscode@0.2.0` tag 早于本接入,已发布版**没有任何 MCP 能力**,这 33 笔提交(占 0.2.0 之后宿主提交的六成)此前在本区一条未记。**对消费者**:这是 0.3.0 唯一的功能级新增;调用面如实登记四条边界——单次转发 60s 超时(超时不断连接,其余工具照常可调)、单条结果超 20,000 字符截断、图片/音频等非文本内容丢弃并注明类型、合计工具数 > 64 时在输出面板告警(工具过多会降低模型选对工具的概率,可停用部分服务器收敛)。**排障入口**:输出面板 → Memora(server 的 stderr 与宿主接入告警都在此处);完整用法见 `hosts/memora-vscode/docs/mcp-setup.md`。
163
+
164
+ - **MCP 免确认白名单(工具级 / 整台级)**(2026-10-23 ~ 10-25 落地,2026-10-26 补记):默认**每次调用都弹确认**(MCP 工具来源不可信,宁多弹窗不静默放行);写进 `memora.mcpToolAllowlist` 后免弹窗但**仍写审计**(`write-auto`,可在审计记录里回查)。两种键都按**原始名**寻址:`mcp__<服务器名>__<工具名>` 只放行一个工具,`mcp__<服务器名>__*` 放行整台。最省事的做法是在 MCP 页的工具行勾「免确认」,写的就是这个键。**为什么**:只给「全问」或「全不问」两端,用户会在第三次弹窗时去关掉整个功能;放行必须逐台/逐工具显式表达才既能用又不失控。**对消费者**:① 没有「一次放行所有服务器」的写法(`mcp__*` 不是合法键,防「自动化默认」);② 键若写成**显示名**(如 `my-tool` 被清洗成 `mcp__fs__my_tool`)**不命中**、回落为每次确认——写错的表现是「还在问」,不是「悄悄放行」(fail-closed);③ 删除服务器**不联动**清白名单(那是逐条授予的信任记录),重新添加同名服务器时档位自动恢复;④ **整台级键是服务器级授权,不是工具名快照**——该台之后新增的工具(server 升级后多出工具、或同名换了另一台)**自动**落进免确认范围,不会重新问你,批准时也不存在「我当初批了哪几个工具」的记录可回查;工具名无法预知 ⇒ 想让新工具仍需确认的只能用工具级键逐个放行。
165
+
166
+ - **MCP 远程服务器接入(Streamable HTTP,无 OAuth)**(2026-10-25 落地,2026-10-26 补记):配置项新增 `transport: 'http'` + `url`;**stdio 仍是缺省**,既有配置零迁移(写盘只在 http 时落 `transport`)。从外部格式导入时 `type: "http"` 映射到本仓 `transport`(别名只在写入点映射一次,读面零第二字段名)。**为什么**:远程 MCP 是社区主流形态,只支持本地子进程等于把一半生态排除在外。**对消费者**:① 远程服务器**没有表单编辑**(本期未做)——用页脚「粘贴 JSON」导入或手写 settings.json,面板只读标注 `http · <url>`,卡片上的「编辑」按钮对远程**置灰**(表单里没有 `url` / `headers` 字段,打开也只能填 command,而 command 与 http 互斥 ⇒ 那会是个点了必然失败的假动作);② **SSE 已定案不支持**(只接 Streamable HTTP);③ 本期**不含 OAuth**,需要鉴权的远程服务器会在 401 时落到「启动失败」(归因见下方 Fixed 条);④ **`headers` 一律明文落盘**——作用域 `machine` 只表示不随 Settings Sync 同步到别的设备,**不是**加密存储,本机任何能读 `settings.json` 的程序都能看到里面的令牌;当前版本**没有** SecretStorage 托管入口,别把长期有效的高权限令牌放进去。
167
+
168
+ - **设置面板入口:侧栏「对话」视图标题栏齿轮**(2026-10-26):`menus.view/title` 挂 `memora.openSettings`(`when: view == memora.chat`,icon `$(settings-gear)`),点开即 editor tab 形态的设置面板(默认落「记忆」页,单例复用已开面板)。**为什么**:设置整体迁 editor tab 后侧栏不再有设置入口,只剩命令面板——真机反馈「输入框没有直接打开设置页的按钮」,可发现性不足。**取舍**:走 VS Code 原生 view 标题栏而非 webview 内自建按钮 ⇒ **零协议改动、零 webview 改动**;刻意不给「当前角色徽章」挂齿轮(图标承诺全局设置、行为却落角色页 = 视觉谎报),也未给徽章加常驻描边(齿轮方案落地后即取代该思路,两处都做 = 同一问题双补丁)。角色徽章维持原职(点开落角色页),与齿轮职责不同、不构成双入口。
169
+
170
+ ### Changed(宿主)
171
+
172
+ - **设置六页从侧栏 view 迁到 editor tab(L3 设置分家)**(2026-10-26):`MemoraSettingsViewProvider`(`registerWebviewViewProvider`)→ `MemoraSettingsPanel`(`createWebviewPanel`);package.json 侧栏 `memora.settings` 视图贡献项删除,对话 view 独占侧栏。导航仍走既有 `switchTab` + `_pendingTab` + ready 握手单点(`memora.configureModel` / `memora.openRoles` 落点不变);panel 单例 reveal-or-create,**设 `retainContextWhenHidden: true` 保上下文**(切走 tab 是 editor tab 的常态用法,不设则每次失焦销毁上下文 ⇒ 六页表单草稿全丢;隐藏态投递语义官方注释两说,故导航在隐藏期只记 pending、转可见时补发,数据面同一时机补刷兜底,见下方条目),关 tab 仍走 dispose 后重开 + ready 握手重建;协议**零新增消息**、内核 `src/` 零改动、设置样式 / HTML 零逻辑改动(九条判据全过,收据见台账「L3 设置分家方案」条)。**为什么**:真机 UI 评审实测设置六页挤占对话空间、对话→设置→返回三层级导航、危险按钮贴脸、回执离视线远。**对消费者**:活动栏不再有设置入口,改用 `memora.openSettings` 命令或侧栏标题栏齿轮(见 Added)。
173
+
174
+ - **设置面板:上下文保留 + 打开入口收 tab 参数 + 挂载链数据驱动**(2026-10-26,L3 落地后审查修复):
175
+ **① 假前提订正(先认错再改)**:L3 落地时记「panel 无 `retainContextWhenHidden` 选项(API 本就不存在)」,据此判定「与侧栏隐藏销毁语义等价」——**该前提是假的**。`createWebviewPanel` 的 options 类型是 `WebviewPanelOptions & WebviewOptions`,后者明载 `retainContextWhenHidden?: boolean`,且默认行为是「面板不可见即销毁 html context」。后果真实存在:editor tab 切走是常态用法(改一半配置去看代码),而 webview 侧零 `setState` 兜底 ⇒ 六页表单草稿每次切换全丢。现设 `retainContextWhenHidden: true`。**代价不是「消息全丢」,而是官方文档在此自相矛盾**:`retainContextWhenHidden` 的注释写「You cannot send messages to a hidden webview, even with retainContextWhenHidden enabled」,同一份 `index.d.ts` 里 `Webview.postMessage` 的注释却把「hidden webviews that set retainContextWhenHidden」算作 live(可投递)——两句不可能同时为真。处理方式是不赌任何一侧:隐藏期导航只记 pending、转可见时补发(见下方条目),重新可见时另全量补刷一次作为**收敛网**(覆盖那些没有推送路径的宿主侧变更)。**对消费者**:切走再切回的设置页保状态,回来看到的是当前态。
176
+ **② 打开入口收 `tab` 参数**:`memora.openSettings` 接受可选 `SettingsTab`,`memora.configureModel` / `memora.openRoles` 变为它的薄包装(命令名保留,既有 keybinding 不断)。`chatPanel` 的「tab → 命令名」映射表删除,`open_settings_tab` 的 tab 由 `Extract<…,'config'|'roles'>` 放宽回全集——收窄的前提(其余页无导航入口)已不成立。**对消费者**:无行为变化;**对后续加页**:不必新增命令或映射表,`executeCommand('memora.openSettings', '<tab>')` 直达。
177
+ **③ 挂载链数据驱动**:`settingsView.ts` 六段手抄 try/catch → 一张 `mounts` 表,异常隔离语义不变(每项独立 try/catch,不截断末尾 ready 握手)。**为什么**:手抄版漏一段不会让任何测试红(该页有按钮无内容,只有真机能发现);`settingsTabs.ts` 旧注释承诺「加 tab = 一行数组 + 两张 Record」与实际改动面差 5 处,已按实测订正为完整清单。
178
+ **守卫**:`settingsPanelRoles.test.ts` 新增两例(创建参数含 `retainContextWhenHidden` / 仅由隐藏转可见才补刷),`settingsTabs.test.ts` 新增一例类型级(tab 收窄即 TS2322)。变异实测三条全红:`expected false to be true` / `expected "refreshAll" to not be called at all` / `TS2322: Type '"skills"' is not assignable to type '"config" | "roles"'`。
179
+
180
+ - **设置面板:导航落点可靠性 + 遗留四项收口**(2026-10-26,`L3-AUDIT-FIX-2`):
181
+ **① 导航判据从「panel 存在」改为「可投递」**:`_panel` 有值只说明 tab 存在,不说明脚本已注册监听器——`postMessage` 契约原文「A response of `true` does not mean that the message was actually received … no message listeners may have been hooked up」,而隐藏态又两说(见上条)。旧实现「投出即清 `_pendingTab`」在这两类时机(open→ready 之间 / 面板在后台)会把导航指令丢掉且宿主侧无痕,用户落在默认「记忆」页。现单点:`isDeliverable()`(`_panel` ∧ `_webviewReady` ∧ `visible`)+ `flushPendingTab()`(唯一投递点与唯一清空点,`switchTab` / `ready` / 由隐藏转可见三个时机共用);不可投递时只记 pending。**对消费者**:设置已开但还在加载、或设置 tab 在后台时点角色徽章,仍会落在「角色」页。
182
+ **② `settingsPanelHostDiag` 补接线自证**:`expect(posted).toHaveLength(0)` 是负向断言,`post → postMessage` 通道断线时照样绿(只证明「没发」,证明不了「发得出」)。现每例先投一条已知消息断言被捕获,再清空验零下行。
183
+ **③ `memora.settings.focus` 消失记入 Removed**(见下)。
184
+ **④ 闸门数字与注释对齐**:eslint 的 `settingsPanel.ts` 注「一 class 扛 5 个 tab」改为六页;三条 `max-lines` 按「闸门自报」口径下调(chatView 6716→6715 / chatPanel 4516→4515 / settingsPanel 2041→2037,只降不升)。
185
+ **守卫**:`settingsPanelRoles.test.ts` 新增两例(未 ready 不投递且 pending 保留 / 已 ready 但后台不投递、转可见补发),`settingsPanelHostDiag.test.ts` 加接线自证。变异实测三条全红:判据退回 `_panel !== undefined` ⇒ 两例 `expected [ { …(2) } ] to deeply equal []`;去掉 `visible` ⇒ 后台例同上;`post()` 断线 ⇒ `接线自证失败:post → webview.postMessage 捕获链断了: expected [] to have a length of 1 but got +0`。
186
+
187
+ - **设置面板:切走再切回不再丢列表态(重推非破坏化)**(2026-10-26,`L3-CTX-KEEP-1` + `L3-CTX-KEEP-2`):
188
+ **现象**:`retainContextWhenHidden` 只保住了「输入框里还没提交的草稿」,保不住「列表正在看哪一页」——面板由隐藏转可见时宿主会重推一次数据(`refreshAll` 收敛网,覆盖那些没有推送路径的宿主侧变更),而 webview 侧把每次重推都当「新数据」处理:技能页 `pager.show(1, …)` + `contentMap.clear()` ⇒ 翻到第 N 页被打回第 1 页、已展开的技能正文收起并需要重新向宿主取;记忆页回第 1 页,且**搜索框里的词没清、列表却回全量**(界面自相矛盾)。**即:草稿保住了,列表态被反向洗掉 = 只保一半。**
189
+ **修法(留触发、消代价)**:不删重推触发——「隐藏期消息是否可达」VS Code 自己的两份注释互相矛盾(`retainContextWhenHidden` 注说不可投递,`Webview.postMessage` 注把设了该选项的隐藏 webview 算作 live),两边各赌一半是最坏组合。改为让重推**非破坏**:① 技能页把展开态收进 `expanded` 集合(唯一真源,DOM 只做投影),`skills_loaded` 改为「留在原页(页数变少时向前夹取)+ 按名字逐出已消失技能」,不再整体清缓存;「整体清空」只保留给用户显式点刷新(显式意图与被动重推判据不同源,刻意不合并)。② 记忆页三条分支:搜索框有词 ⇒ 按原词重放 `memory_search`(检索只走一条路,不在 webview 本地过滤数组);当前页 > 1 ⇒ 走既有 `memory_page` 增量通道取该页(首屏载荷只含第 1 页,直接铺会把第 1 页数据贴上第 N 页页码);其余直接填充。③ 角色页同样漏扫(`roles_loaded` 无条件回第 1 页),本批一并收口,并把「保持当前页 + 越界夹取」的判据下沉到 `PagerController.showKeepingPage` 单点——调用方不得再各写一份 `Math.min(getPage(), pageCount)`。
190
+ **对消费者**:切去别的 tab 再切回设置页,页面停在你离开时的那一页,展开的技能正文仍展开,搜索词与结果仍在同一上下文。**代价**:重推数据变了(例如角色包被删除)时按新页数向前夹取,落到最后一个有内容的页而不是空页。
191
+ **守卫**:`settingsView.test.ts` 3 例(留在当前页 / 已展开正文保持展开 / 页数变少向前夹取)、`memoryView.test.ts` 2 例(第 2 页不被第 1 页数据顶替 / 搜索词重放且输入框与列表同上下文)、`pager.test.ts` 3 例(保持当前页 / 变少夹取 / 空数据集收敛)、`rolesView.test.ts` 2 例(重推保页 / 重推变少夹取),全部变异验证。
192
+
193
+ - **设置面板:子视图挂载表可被测试钉住**(2026-10-26,`L3-CTX-KEEP-2`):`settingsView.ts` 的六页挂载表原在 `createSettingsView` 函数作用域内 ⇒ `settingsTabs.ts` 承诺的「加一页 = 挂载表一行」**没有任何测试能守住**,而漏一行的表现是「该页有按钮、无内容」:tsc 不报错、其余测试全绿,只有真机能发现。现提到模块级导出 `SETTINGS_VIEW_MOUNTS`,由 `settingsView.test.ts` 断言「表内 name 集合 == `SETTINGS_TABS`」+ 无重复 + 每项工厂为函数(断言集合相等而非顺序相等:UI 顺序与初始化时序刻意不同源)。**对消费者**:无行为变化;**对后续加页**:漏挂载从「真机才发现」变成「测试红」。
194
+
195
+ - **MCP 两键作用域 `application` → `machine`**(`H0-2`,2026-10-25):`memora.mcpServers` / `memora.mcpToolAllowlist` 不再随 VS Code Settings Sync 同步。**为什么**:`application` 会把 `headers` 里的明文令牌与免确认批准带到同账号的其他设备——批准的语义是「本机用户同意本机进程」,跨机继承等于替另一台机器点同意。**对消费者**:① 只写用户设置、工作区 / 文件夹写入仍被忽略(`.mcp.json` 不读的红线不变);② **升级后每台机器需各配一次**,原先靠设置同步带过来的 MCP 配置不会再自动出现;③ 本机已有配置不受影响。断言钉在 `mcpConfig.test.ts`(结构机制不在代码里,改 scope 只有这条测试能拦住)。
196
+
197
+ ### Removed(宿主)
198
+
199
+ - **`memora.settings.focus` 命令**(2026-10-26,L3 设置分家的连带影响):该命令**不是本扩展显式贡献的**——VS Code 为每个 `contributes.views` 视图自动提供 `<viewId>.focus`(本仓全历史 grep 无一处置,键位设置里却能搜到),`memora.settings` 视图贡献项删除后它随之消失。**对消费者**:若曾绑过该命令的快捷键,绑定会**静默失效**(按 id 调用不抛错,只是不再发生);聚焦设置请改用 `memora.openSettings`。
200
+
201
+ ### Fixed(宿主)
202
+
203
+ - **安装包夹带本地文件(出包前复核发现,2026-10-26)**:0.3.0 首版 `memora-vscode.vsix`(183 条目)里实际混进了 `mcp-acceptance-server.mjs`(手工验收脚本)、`.workbuddy/*.log` ×3(本地调试日志)、`.tmp-vsce.log`(vsce 自身临时日志)、`dist/.bundle-smoke/vscode-stub.mjs`(打包前门禁探针)。**成因**:`.gitignore` 与 `.vscodeignore` 是**两套判据**——前三个前缀都已在 `.gitignore` 里,`git status` 干净,但 `vsce` **不读 `.gitignore`** ⇒ 「仓库干净」被当成了「包内干净」。**修法**:`.vscodeignore` 补 `.workbuddy/**` / `*.log` / `.tmp-vsce.log` / `mcp-acceptance-server.mjs` / `dist/.bundle-smoke/**`,本地日志与临时产物同批删除。**对消费者**:安装包不再包含验收脚本与本地日志(183 → 177 条目,1,852,326 → 1,809,088 字节),运行时行为零变化。**守卫缺口如实登记**:无自动闸门——`vsce ls` 断言只查「该有的在」(`dist/extension/host/mcp/*.js`),不查「不该有的不在」,本次靠人工按条目清单逐条核对,登记于台账 F 段。
204
+
205
+ - **MCP 连接失败归因订正**(`H0-1`,2026-10-25):没有 `tools` 能力的 server 此前被判成「server 未声明 tools 能力」并置 `failed`——但纯 `resources` / `prompts` 的 server 是**合法形态**,这是本宿主只接 tools 的**覆盖面边界**,不是对方故障。现文案改为「本宿主当前只接 tools 能力;该 server 只提供 X / Y,暂不支持(不是 server 故障)」,并对连上后被忽略的非 tools 能力打一次 info 日志(不静默)。**为什么**:谎报成因与谎报能力同族——原文案会让用户去查一台没坏的 server。**对消费者**:仅失败原因文案变化;无 tools 的 server 仍不注册空工具清单(不静默成功)。**登记**:方案-MCP工具接入 §10 新增「`resources` / `prompts` 零接入(能力边界 · 非功能缺口)」行。
206
+
207
+ - **角色页:角色包被清空后不再留着幽灵分页条**(2026-10-26,`L3-ROLES-SLIM-1`):`roles_loaded` 收到空列表时,列表正确地换成了「暂无角色包」空态,但**分页条没被收掉**——它保留着上一轮的页码与条数(实测:17 个角色翻到第 2 页后角色包被清空 ⇒ 条上仍写「第 2 / 2 页(共 16 条)」且上下页都能点)。于是页面上同时存在「一个声称有 16 条内容、可双向翻页的条」和「一个永远空着的列表」,点翻页也翻不出任何东西。**成因**:空态分支渲染完空态引导就 `return`,跳过了分页态的收敛(`othersAll` 因早退没被清、`pager` 也没被重置 ⇒ 翻页切的是上一轮的旧数组)。现空态分支同批收敛两件事:`othersAll` 随 `lastData` 一并清空(派生数据必须随源更新),`pager.showKeepingPage([])` 让分页条隐藏、页码回到 1/1、上下页均禁用。**对消费者**:角色包全删光 / 切到没有角色包的工作区时,看到的是干净的空态,不会再有翻不出内容的条。**守卫**:`rolesView.test.ts` 新增一例(先翻到第 2 页,再投空载荷,断言分页条 `hidden`、双向 `disabled`、卡片数 0),变异实测:删掉收敛 ⇒ `expected false to be true`。
208
+
209
+ ## [0.2.0] · 2026-10-23 · 宿主
76
210
 
77
- > 仅**宿主**(`hosts/memora-vscode`)变更,攒批随下次 `vsce package` 定版。逐条拍板与变异验证收据见台账对应 ID。
211
+ > 仅**宿主**(`hosts/memora-vscode`)变更,随 `vsce package` 定版。**随包内核代次 = `5.0.0`**(esbuild 内联 dist,内核自身变更见内核区)。逐条拍板与变异验证收据见台账对应 ID。
78
212
 
79
213
  ### Added(宿主)
80
214
 
81
- - **`@problems`:把工作区错误 / 警告挂进对话(有界注入第一笔)**(`HOST-CTX-4`,2026-10-21):对话框原本只能挂「文件 / 目录 / 当前文件」——它们都只给**指针**,内容由模型自己读。但 VS Code 的诊断是**瞬态派生数据**,内核工具箱里没有 diagnostics(也没有 git / 终端读取),「提示模型去看」这条路根本不通 ⇒ 定案(`HOST-CTX-0`)为这类数据开了**唯一一处例外**:允许有界注入。本笔只落 `@problems` 一源(`@git-changes` 语义仍待拍板、终端输出仍待 spike,**一行未写**)。用法:输入框打 `@` → 列表置顶多一项「诊断(问题面板)」→ 选中挂一枚**与引用 chip 明显不同长相**的 chip(圆角矩形 + warn 色 + ⚠,形状/颜色/图标三通道可辨;**无锁**)→ 发送。**体验要点**:① 选中那一刻**不取数**,按下发送那刻才去问题面板拉最新(按严重度取前 20 条,每条带 `文件:行:列` + 错误文案 + 该行源码,超限明说「已截断」);② chip **发完即消**——注入的是那一刻的快照,钉住就是下轮拿过期数据糊弄模型,要新鲜的下轮重点;③ 圆环 hover 卡片底部出「本轮注入 N」回执(分项明细同屏:当前文件正文 / 工作区诊断),下一轮发送覆盖;④ 历史里你的消息仍只显示你打的字(注入块回放时剥掉),但模型确实收到了。**同一笔的类型级重构**:`ActiveFileProjection.injectedTokens` 迁出为 `injection_summary.segments` 的 `active-file` 分项(三个源各挂一个字段 = 并列腐化 + 违反「与 CTX-6 同一处呈现」),本轮注入量自此**按源分项**回推、「渲染两处、数据一次」。协议 +2 条(消息计数 126 → **128**,治理阈值 130,**余 2**)。逐条拍板过程与 14 次变异验证签名见台账 `HOST-CTX-4`。**真机验收第一项通过**(2026-10-21 用户实测功能通过;反馈「徽记突然出现在状态行有点奇怪」⇒ 已按 `.injection-badge` 样式注释里预登记的回退方向,把回执从状态行徽记整模迁入圆环 hover 卡片底部、分项明细同屏可见,**待复验新形态**;浅色主题对比度仍未实测)。
215
+ - **`@problems`:把工作区错误 / 警告挂进对话(有界注入第一笔)**(`HOST-CTX-4`,2026-10-21):对话框原本只能挂「文件 / 目录 / 当前文件」——它们都只给**指针**,内容由模型自己读。但 VS Code 的诊断是**瞬态派生数据**,内核工具箱里没有 diagnostics(也没有 git / 终端读取),「提示模型去看」这条路根本不通 ⇒ 定案(`HOST-CTX-0`)为这类数据开了**唯一一处例外**:允许有界注入。本笔只落 `@problems` 一源(同版另有 `@git-changes` 有界注入二笔,见下条;terminal 源 spike 结论 = 不做、维持触发登记)。用法:输入框打 `@` → 列表置顶多一项「诊断(问题面板)」→ 选中挂一枚**与引用 chip 明显不同长相**的 chip(圆角矩形 + warn 色 + ⚠,形状/颜色/图标三通道可辨;**无锁**)→ 发送。**体验要点**:① 选中那一刻**不取数**,按下发送那刻才去问题面板拉最新(按严重度取前 20 条,每条带 `文件:行:列` + 错误文案 + 该行源码,超限明说「已截断」);② chip **发完即消**——注入的是那一刻的快照,钉住就是下轮拿过期数据糊弄模型,要新鲜的下轮重点;③ 圆环 hover 卡片底部出「本轮注入 N」回执(分项明细同屏:当前文件正文 / 工作区诊断),下一轮发送覆盖;④ 历史里你的消息仍只显示你打的字(注入块回放时剥掉),但模型确实收到了。**同一笔的类型级重构**:`ActiveFileProjection.injectedTokens` 迁出为 `injection_summary.segments` 的 `active-file` 分项(三个源各挂一个字段 = 并列腐化 + 违反「与 CTX-6 同一处呈现」),本轮注入量自此**按源分项**回推、「渲染两处、数据一次」。协议 +2 条(消息计数 126 → **128**,治理阈值 130,**余 2**)。逐条拍板过程与 14 次变异验证签名见台账 `HOST-CTX-4`。**真机验收第一项通过**(2026-10-21 用户实测功能通过;反馈「徽记突然出现在状态行有点奇怪」⇒ 已按 `.injection-badge` 样式注释里预登记的回退方向,把回执从状态行徽记整模迁入圆环 hover 卡片底部、分项明细同屏可见,新形态与浅色主题 chip 对比度均于 2026-10-23 真机复验通过,`HOST-CTX-4` 关账)。
216
+ - **`@git-changes`:把 git 未提交改动挂进对话(有界注入二笔)**(`HOST-CTX-4`,2026-10-21 落地 · 10-22 三轮硬化):@ 提及置顶项「未提交改动(git)」→ **发送时刻**宿主只读采集(`git status --porcelain -z` + `git diff` + `git diff --cached`;固定开关防中文路径八进制转义、防 ANSI 污染、防仓库配置借 diff 执行外部程序;子目录工作区按工作区根换算坐标),有界三道闸(≤20 文件 / 单文件 ≤200 行 / 合计 ≤12K 字符,超出明示截断),非 git 仓库 / git 缺失 / 执行失败一律给**事实行**、不给空。语义给的是真 `git diff`(未提交),不是「本会话助手改动快照」——「帮我的改动写提交信息」场景下模型看到的即 git 所见;未跟踪文件只给 `?? 路径`(git 不对未跟踪文件做 diff,如实为限)。注入形态与 `@problems` 同款(chip 无锁 · 发送即取即清 · 回执按源归因)。
82
217
  - **输入框 @ 提及挂引用**(`HOST-CTX-1`,2026-10-20):主输入框键入 `@` 弹出工作区文件 QuickPick(多选、模糊过滤),选中即挂引用 chip——想加文件不再必须去资源管理器右键。引用模式红线守住:@ 只是「挂引用的快捷入口」,宿主侧零内容注入。触发时 `@` 先留在正文(Esc 取消文本零扰动),mention 通道挂载成功后按触发点精准撤除该字符(判据不猜,其余入口不带信源不撤——防误删正文里邮箱等合法 `@` 字样);文件列表逐项过首根归属判据(`relativeUnderPrimaryRoot`,第二根 / 根外连列表都不进,与 addToChat 拒挂同一契约两半)。协议最小改动:W→E `mention_open`(只报意图不传过滤词)+ E→W `addRef.source?: 'mention'`。守卫 webview 3 例 + 宿主 2 例,变异验证摘撤除调用即红。
83
218
  - **@ 提及落地补强:判据守卫 + 截断明示 + 防重入**(`HOST-CTX-11`,2026-10-20,CTX-1 落地次日对抗式审查后当日修):① 撤除 `@` 的判据中真正带语义的只有「落点恰为 `@`」一条(另两条 null / 越界删掉行为等价),而它此前**零测试**——实测删掉该行 chatView 448 例全绿;现补 2 例守卫(触发后文本被编辑 / @ 已被删,均不撤不猜),并订正「判据三重」的夸大措辞。② `findFiles` 上限命中即**静默截断**(大仓里搜不到目标文件还以为仓库里没有)——现上限提为导出常量 `MENTION_FILE_LIMIT`,命中时 placeholder 明示「已截断,请输入关键词缩小范围」(不用「提示项」进列表:QuickPickItem 无 disabled,选中即变伪引用)。③ 连按 `@` 会各开一个 QuickPick、后开的静默覆盖先开的且只撤一个 `@`——现加 in-flight 守卫(try/finally 保证异常路径也归位)。④ 订正退化分支注释的**描述性撒谎**:该分支唯一可达场景是「QuickPick 打开期间视图被销毁」,不是注释原写的「webview 未就绪」;代价如实改写为「多出一个延迟注入的引用」。守卫 chatView 450 / chatPanelMention 4,变异三次均红后还原。
84
219
  - **修复输入 `@` 无反应:未知消息不再静默丢弃 + 消息链获得可测入口**(`HOST-CTX-12`,2026-10-20,真机验收发现当日修):真机输入 `@` 字符正常落入输入框但 QuickPick 毫无反应。根因不是 `@` 分支写错,而是 **webview 脚本与扩展宿主不是同一版本**——webview 脚本是外部文件(`dist/webview/scripts/chatView.js`,从磁盘读 ⇒ 重编译后是新的),而宿主的消息分发活在进程内存里(旧的)⇒ 新 webview 朝旧宿主发 `mention_open`,旧宿主**没有任何分支匹配、静默丢弃**。修法第一动作是 Reload Window 重启扩展宿主,但真正的伤是「静默丢弃」本身:消息链**没有 else 兜底**,123 个类型里任何一个因版本错位不到达都表现为功能凭空消失、零反馈(「静默失败」族第三次踩)。① 加 else 兜底,未知类型落 `console.warn`(含类型名与「最可能原因:扩展宿主未重启」),不驱动 UI 不弹提示;② 🔴 把整条 120+ 分支的消息链从匿名回调**摘为 `private handleWebviewMessage`**——它原先零可测入口(加上兜底后立刻发现「有守卫却验证不了」),摘出后与 `handleInput` 等同构、测试可直接驱动。守卫 +1 例,变异(摘 `console.warn`)红后还原。
package/README.en.md CHANGED
@@ -54,6 +54,8 @@ await agent.close();
54
54
  ```
55
55
 
56
56
  > **Boundary**: Memora is a **non-standalone pure logic kernel** — persistence, sandbox, observability, CLI/UI are all injected by the host. The kernel guarantees **interface contracts + unit-tested logic correctness**; agent-level behavior evaluation is the host's responsibility.
57
+ >
58
+ > **Minimal integration surface**: constructing an `Agent` requires only `projectPath`, `provider`, `dataDir`. Without an injected store, the built-in in-memory implementation is used (chat and memory loop work as usual, just not persisted); for persistence, use the built-in `createNodeSqliteStorage` factory directly — **no need to implement a storage interface yourself**. `sessionStore` / `roundStore` / `tracer` and the external tool providers (`web_search` / `web_fetch` / `run_code` / `search_project` / environment reporting) are all optional: omitting them only disables the corresponding capability, it never blocks startup.
57
59
 
58
60
  ---
59
61
 
@@ -80,7 +82,7 @@ await agent.close();
80
82
 
81
83
  Memora is a **brain kernel that cannot run standalone** — it has interfaces but no "form." A CLI, WebUI, desktop sprite, or novel generator can be its "host." The host gives it a body (UI), blood vessels (Provider), and neural circuits (event loops).
82
84
 
83
- > **Version positioning (v5.0.0)**: **Node.js-only · Zero third-party runtime deps Agent kernel**. **v5.0.0 (current)**: major public surface pruning (23 exports + 32 public members + 3 events removed) + multi-project shape finalized (one Agent = one project) + three never-live chains retired (goal-drift detection / memory governance facade / checkpoint fake-flushing) + a `node:*` built-in SQLite storage implementation added (`createNodeSqliteStorage`) — see the [upgrade guide](docs/memora-升级指南-4.x-到-5.0.0.md) for per-item migration. **v4.0.0**: public export surface collapsed (54 exports removed; full list in the `[4.0.0]` section of [CHANGELOG](./CHANGELOG.md)) + `agent.memory.search()` removed (`searchByKeyword()` is the sole entry).
85
+ > **Version positioning (v5.x)**: **Node.js-only · Zero third-party runtime deps Agent kernel**. **The released version and per-version changes are authoritative in the npm registry and [CHANGELOG](./CHANGELOG.md); this section does not restate release state** (any static "which version is current" claim inside a package rots over time). **Since 5.0.0**: major public surface pruning (23 exports + 32 public members + 3 events removed) + multi-project shape finalized (one Agent = one project) + three never-live chains retired (goal-drift detection / memory governance facade / checkpoint fake-flushing) + a `node:*` built-in SQLite storage implementation added (`createNodeSqliteStorage`) — see the [upgrade guide](docs/memora-升级指南-4.x-到-5.0.0.md) for per-item migration. **v4.0.0**: public export surface collapsed (54 exports removed; full list in the `[4.0.0]` section of [CHANGELOG](./CHANGELOG.md)) + `agent.memory.search()` removed (`searchByKeyword()` is the sole entry).
84
86
 
85
87
  ---
86
88
 
@@ -106,6 +108,8 @@ Memora is a **brain kernel that cannot run standalone** — it has interfaces bu
106
108
  npm install @zooique/memora
107
109
  ```
108
110
 
111
+ > **Runtime requirement**: Node.js ≥ 22.0.0 (same wording as `package.json#engines`). The SQLite persistence factory `createNodeSqliteStorage` (`node:sqlite`) additionally requires **Node ≥ 22.13** — that's when `node:sqlite` stopped needing the `--experimental-sqlite` flag. Below 22.13 the package still loads and the in-memory store works; only calling that factory throws an explicit "Node ≥22.13 required" error (`ToolErrorCode.NOT_AVAILABLE`), never a silent failure.
112
+
109
113
  ### Create an Agent
110
114
 
111
115
  ```typescript
@@ -198,7 +202,7 @@ The kernel interacts with the outside world through interfaces. Hosts inject imp
198
202
 
199
203
  | Interface | Responsibility | Built-in Implementation |
200
204
  |-----------|---------------|------------------------|
201
- | `IMemoryStorage` | Memory CRUD + search + query by source | Built-in in-memory default (placeholder, non-persistent; internal class, not on the public surface — PUB-API-PRUNE-2) + optional persistent impl `createNodeSqliteStorage(dbPath)` (built-in `node:sqlite`, zero third-party deps) | Host picks the backend: create SQLite via the kernel factory, or implement its own (JSON / own SQLite) |
205
+ | `IMemoryStorage` | Memory CRUD + search + query by source | Built-in in-memory default (placeholder, non-persistent; internal class, not on the public surface — PUB-API-PRUNE-2) + optional persistent impl `createNodeSqliteStorage(dbPath)` (built-in `node:sqlite`, zero third-party deps; requires Node ≥22.13) | Host picks the backend: create SQLite via the kernel factory, or implement its own (JSON / own SQLite) |
202
206
  | `ISessionStore` | Session history persistence | None (host implements) |
203
207
  | `ILogger` | Logging output | console fallback |
204
208
  | `ITracer` | Observability spans | Internal noop (not on the public surface; omit `tracer` for zero overhead) |
@@ -247,7 +251,7 @@ src/
247
251
 
248
252
  | Category | Choice | Rationale |
249
253
  |----------|--------|-----------|
250
- | Runtime | Node.js ≥ 22 LTS + TypeScript 5 strict + ESM | ADR-001 |
254
+ | Runtime | Node.js ≥ 22.0.0 (SQLite persistence factory needs ≥ 22.13, see Quick Start) + TypeScript 5 strict + ESM | ADR-001 |
251
255
  | Data Layer | IMemoryStorage interface (host injects persistence) | ADR-002 |
252
256
  | LLM Protocol | OpenAI Chat Completions compatible (streaming SSE + Tool Calling) | ADR-003 |
253
257
  | Memory Model | Memory-as-summary: round-summary single track, traceable to source; source open-string primitive | ADR-004 · memory-as-summary.md |
package/README.md CHANGED
@@ -54,6 +54,8 @@ await agent.close();
54
54
  ```
55
55
 
56
56
  > **边界声明**:memora 是**不可独立运行的纯逻辑内核**——持久化 / 沙箱 / 可观测 / CLI·UI 均由宿主注入。内核保证**接口契约 + 单测验证的逻辑正确性**,agent 级行为评估由宿主自行承担。
57
+ >
58
+ > **最小接入面**:构造 `Agent` 只需 `projectPath`、`provider`、`dataDir`。存储未注入时用内置内存实现(对话与记忆闭环照常,仅不持久化);要落盘可直接用内置 `createNodeSqliteStorage` 工厂,**无需自实现存储接口**。`sessionStore` / `roundStore` / `tracer` 与外部工具 provider(`web_search` / `web_fetch` / `run_code` / `search_project` / 环境上报)均为可选——不配只是不启用对应能力,不阻塞启动。
57
59
 
58
60
  > **零依赖如何成立(2026-09-21 审计)**:「零依赖」特指**零第三方运行时依赖**。内核仅使用 Node 内置模块(`node:fs` / `node:path` / `node:crypto` / `node:os` / `node:child_process`),6 类共见于 18 个生产文件,全部必要、无冗余。文件落盘(记忆 / 角色包 / 原子写 / 技能脚本执行)走**接口 + 内存默认实现**(如 `ISessionStore` → `InMemorySessionStore`),持久化 sink 交由宿主注入 `WorkspaceSessionStore` 等实现替换——这既支撑「本地、私有、零依赖」卖点,也遵守「持久化由宿主注入」边界。
59
61
 
@@ -86,7 +88,7 @@ await agent.close();
86
88
 
87
89
  Memora 是一个**无法独立运行**的智能大脑内核——它只有接口,没有"形态"。CLI、WebUI、桌面精灵、小说生成器都是它的"宿主",宿主负责给它身体(UI)、血管(Provider)、神经网络(事件回路)。
88
90
 
89
- > **版本定位(v5.0.0)**:**Node.js 专属 · 零第三方运行时依赖的 Agent 内核**。**5.0.0(当前)**:公开面大收面(删 23 个导出符号 + 32 个公开成员 + 3 个事件)+ 多项目形态定案(一个 Agent = 一个项目)+ 三套空转机制退役(目标漂移检测 / 记忆治理门面 / 检查点假落盘)+ SQLite 存储实现(`createNodeSqliteStorage`)——破坏性变更逐条改法见 [升级指南](docs/memora-升级指南-4.x-到-5.0.0.md)。**4.0.0**:导出面收敛(移除 54 个公共导出,逐条清单见 [CHANGELOG](./CHANGELOG.md) 的 `[4.0.0]` 区)+ `agent.memory.search()` 退役(唯一入口 `searchByKeyword()`)。
91
+ > **版本定位(v5.x 系列)**:**Node.js 专属 · 零第三方运行时依赖的 Agent 内核**。**已发布版本与各版变更以 npm registry 与 [CHANGELOG](./CHANGELOG.md) 为准,此处不复述发布态**(包内静态文本写「哪个版本是当前」必随时间腐化)。**5.0.0 起的形态**:公开面大收面(删 23 个导出符号 + 32 个公开成员 + 3 个事件)+ 多项目形态定案(一个 Agent = 一个项目)+ 三套空转机制退役(目标漂移检测 / 记忆治理门面 / 检查点假落盘)+ SQLite 存储实现(`createNodeSqliteStorage`)——破坏性变更逐条改法见 [升级指南](docs/memora-升级指南-4.x-到-5.0.0.md)。**4.0.0**:导出面收敛(移除 54 个公共导出,逐条清单见 [CHANGELOG](./CHANGELOG.md) 的 `[4.0.0]` 区)+ `agent.memory.search()` 退役(唯一入口 `searchByKeyword()`)。
90
92
 
91
93
  ---
92
94
 
@@ -112,6 +114,8 @@ Memora 是一个**无法独立运行**的智能大脑内核——它只有接口
112
114
  npm install @zooique/memora
113
115
  ```
114
116
 
117
+ > **运行时要求**:Node.js ≥ 22.0.0(与 `package.json#engines` 同口径)。其中 SQLite 落盘工厂 `createNodeSqliteStorage`(`node:sqlite`)需 **Node ≥ 22.13**——22.13 起 `node:sqlite` 才免 `--experimental-sqlite` 标志。低于 22.13 时包可正常加载、内存存储照常可用,仅调用该工厂会抛出明确的「需 Node ≥22.13」专属错误(`ToolErrorCode.NOT_AVAILABLE`),不会静默失败。
118
+
115
119
  ### 创建 Agent
116
120
 
117
121
  ```typescript
@@ -200,7 +204,7 @@ await agent.close();
200
204
 
201
205
  | 接口 | 职责 | 内置实现 | 宿主注意 |
202
206
  |------|------|----------|----------|
203
- | `IMemoryStorage` | 记忆 CRUD + 搜索 + 按 source 查询 | 内置内存默认实现(**仅内存占位,不持久化**;内部类,不挂公共面——PUB-API-PRUNE-2 收面)+ **可选落盘实现** `createNodeSqliteStorage(dbPath)`(基于 `node:*` 内建模块,零第三方依赖) | 持久化后端由宿主选:经内核工厂建 SQLite,或自实现(JSON / 自有 SQLite);重启后数据依赖所选实现 |
207
+ | `IMemoryStorage` | 记忆 CRUD + 搜索 + 按 source 查询 | 内置内存默认实现(**仅内存占位,不持久化**;内部类,不挂公共面——PUB-API-PRUNE-2 收面)+ **可选落盘实现** `createNodeSqliteStorage(dbPath)`(基于 `node:*` 内建模块,零第三方依赖;需 Node ≥22.13) | 持久化后端由宿主选:经内核工厂建 SQLite,或自实现(JSON / 自有 SQLite);重启后数据依赖所选实现 |
204
208
  | `ISessionStore` | 会话历史 + 标题元数据持久化 | 无(宿主实现) | **不含检查点持久化**(2026-09-10 减法:跨重启恢复链整体退役)——中止/断电一律把未完成 turn 补全为完整 turn 身份、下次会话按历史加载;运行时暂停是同 turn 内续跑(内存态),无需跨进程载体 |
205
209
  | `ILogger` | 日志输出 | console fallback | 无 |
206
210
  | `ITracer` | 可观测性 span | 内核内部 Noop 实现(不挂公共面;不传 `tracer` 即零开销) | 无 |
@@ -249,7 +253,7 @@ src/
249
253
 
250
254
  | 类别 | 选型 | 决策依据 |
251
255
  |------|------|----------|
252
- | 运行时 | Node.js ≥ 22 LTS + TypeScript 5 strict + ESM | ADR-001 |
256
+ | 运行时 | Node.js ≥ 22.0.0(SQLite 落盘工厂需 ≥ 22.13,见「快速开始」)+ TypeScript 5 strict + ESM | ADR-001 |
253
257
  | 数据层 | IMemoryStorage 接口(宿主注入持久化实现) | ADR-002 |
254
258
  | LLM 协议 | OpenAI Chat Completions 兼容(流式 SSE + Tool Calling) | ADR-003 |
255
259
  | 记忆模型 | 摘要即记忆(round-summary 单轨,可溯源回原始对话);source 开放字符串基元 | ADR-004 · memory-as-summary.md |
@@ -17,7 +17,7 @@ import { type GCResult } from '../memory/gcService.js';
17
17
  import type { SessionManager, AgentForkResult } from '../agent/managers/sessionManager.js';
18
18
  import { type ArchiveTriggerOptions } from '../agent/managers/archiveCoordinator.js';
19
19
  import { TypedEventEmitter, type AgentEventMap } from '../utils/eventEmitter.js';
20
- import type { LlmProvider, Message } from '../llm/provider.js';
20
+ import type { LlmProvider, Message, ImageRef } from '../llm/provider.js';
21
21
  import type { AgentMetrics } from '../agent/tracer.js';
22
22
  /**
23
23
  * Memora Agent 门面类
@@ -132,8 +132,11 @@ export declare class Agent extends TypedEventEmitter<AgentEventMap> {
132
132
  private createSeedOrchestrator;
133
133
  /**
134
134
  * 流式对话(核心 API)
135
+ *
136
+ * @param attachments 图片附件(可选,多模态输入);透传到种子编排器 → 装配两跳 → 持久化(方案 §7 P0)。
137
+ * 不传 = 纯文本输入,行为与历史完全一致(零兼容回归)。
135
138
  */
136
- chat(input: string, signal?: AbortSignal): AsyncGenerator<AgentChunk, void, unknown>;
139
+ chat(input: string, signal?: AbortSignal, attachments?: readonly ImageRef[]): AsyncGenerator<AgentChunk, void, unknown>;
137
140
  /**
138
141
  * 校验 chat 输入
139
142
  */
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/agent/agent.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/agent/agent.ts"],"names":[],"mappings":"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"}
@@ -368,8 +368,11 @@ export class Agent extends TypedEventEmitter {
368
368
  }
369
369
  /**
370
370
  * 流式对话(核心 API)
371
+ *
372
+ * @param attachments 图片附件(可选,多模态输入);透传到种子编排器 → 装配两跳 → 持久化(方案 §7 P0)。
373
+ * 不传 = 纯文本输入,行为与历史完全一致(零兼容回归)。
371
374
  */
372
- async *chat(input, signal) {
375
+ async *chat(input, signal, attachments) {
373
376
  this.assertInitialized('chat');
374
377
  this.validateChatInput(input);
375
378
  const lockCtx = this.acquireChatLock(signal);
@@ -389,7 +392,7 @@ export class Agent extends TypedEventEmitter {
389
392
  }
390
393
  this._lastInteractionAt = new Date();
391
394
  // 委托种子编排器:对话路径完整闭环(prepare → act → reflect)
392
- yield* this.internals.seedOrchestrator.runChat(input, combinedSignal);
395
+ yield* this.internals.seedOrchestrator.runChat(input, combinedSignal, attachments);
393
396
  }
394
397
  finally {
395
398
  // 流已退出:清除活跃标志(与置位对称;无论正常/异常退出都复位)
@@ -499,7 +502,9 @@ export class Agent extends TypedEventEmitter {
499
502
  async *resumeExecution(input, signal, kind = 'supplement') {
500
503
  const resumeStatus = this._sessionManager?.status;
501
504
  // 错误态续跑须明确失败而非静默吞没:error 态由检查点恢复回填进入,运行时异常走
502
- // yield { type: 'error' } 不翻状态机,生产链路不会自然离开,必须显式提示重新开始
505
+ // yield { type: 'error' } 不翻状态机,生产链路不会自然离开,必须显式提示重新开始。
506
+ // 2026-10-27 拍板:维持不接线、宿主不建恢复入口(宿主策略 = error 视作终态;
507
+ // 内核 recover() 仍为库级公开 API)——详见状态机头注释与台账 HOST-ERR-1
503
508
  if (resumeStatus === 'error') {
504
509
  this.emit(AGENT_EVENTS.sessionResumeFailed, {
505
510
  sessionId: this._sessionManager?.getCheckpoint()?.sessionId,