@zooique/memora 2.0.0 → 2.0.3

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 (212) hide show
  1. package/README.en.md +272 -0
  2. package/README.md +150 -38
  3. package/dist/agent/agent.d.ts +233 -58
  4. package/dist/agent/agent.d.ts.map +1 -1
  5. package/dist/agent/agent.js +651 -359
  6. package/dist/agent/agent.js.map +1 -1
  7. package/dist/agent/assembler.d.ts +29 -13
  8. package/dist/agent/assembler.d.ts.map +1 -1
  9. package/dist/agent/assembler.js +79 -44
  10. package/dist/agent/assembler.js.map +1 -1
  11. package/dist/agent/builtinToolHandlers.d.ts +26 -1
  12. package/dist/agent/builtinToolHandlers.d.ts.map +1 -1
  13. package/dist/agent/builtinToolHandlers.js +73 -1
  14. package/dist/agent/builtinToolHandlers.js.map +1 -1
  15. package/dist/agent/constants.d.ts +4 -0
  16. package/dist/agent/constants.d.ts.map +1 -1
  17. package/dist/agent/constants.js +4 -0
  18. package/dist/agent/constants.js.map +1 -1
  19. package/dist/agent/contextManager.d.ts +8 -0
  20. package/dist/agent/contextManager.d.ts.map +1 -1
  21. package/dist/agent/contextManager.js +7 -2
  22. package/dist/agent/contextManager.js.map +1 -1
  23. package/dist/agent/guardrail.d.ts +4 -2
  24. package/dist/agent/guardrail.d.ts.map +1 -1
  25. package/dist/agent/guardrail.js +13 -5
  26. package/dist/agent/guardrail.js.map +1 -1
  27. package/dist/agent/loop.d.ts +58 -14
  28. package/dist/agent/loop.d.ts.map +1 -1
  29. package/dist/agent/loop.js +184 -131
  30. package/dist/agent/loop.js.map +1 -1
  31. package/dist/agent/managers/archiveCoordinator.d.ts +126 -22
  32. package/dist/agent/managers/archiveCoordinator.d.ts.map +1 -1
  33. package/dist/agent/managers/archiveCoordinator.js +239 -44
  34. package/dist/agent/managers/archiveCoordinator.js.map +1 -1
  35. package/dist/agent/managers/autoConfigRefiner.d.ts.map +1 -1
  36. package/dist/agent/managers/autoConfigRefiner.js +4 -8
  37. package/dist/agent/managers/autoConfigRefiner.js.map +1 -1
  38. package/dist/agent/managers/configManager.d.ts +87 -3
  39. package/dist/agent/managers/configManager.d.ts.map +1 -1
  40. package/dist/agent/managers/configManager.js +139 -2
  41. package/dist/agent/managers/configManager.js.map +1 -1
  42. package/dist/agent/managers/dedupManager.d.ts +169 -0
  43. package/dist/agent/managers/dedupManager.d.ts.map +1 -0
  44. package/dist/agent/managers/dedupManager.js +336 -0
  45. package/dist/agent/managers/dedupManager.js.map +1 -0
  46. package/dist/agent/managers/insightExtractor.d.ts.map +1 -1
  47. package/dist/agent/managers/insightExtractor.js +11 -11
  48. package/dist/agent/managers/insightExtractor.js.map +1 -1
  49. package/dist/agent/managers/llmJudgeHelper.d.ts +38 -0
  50. package/dist/agent/managers/llmJudgeHelper.d.ts.map +1 -0
  51. package/dist/agent/managers/llmJudgeHelper.js +49 -0
  52. package/dist/agent/managers/llmJudgeHelper.js.map +1 -0
  53. package/dist/agent/managers/memoryAdvisor.d.ts +3 -3
  54. package/dist/agent/managers/memoryAdvisor.d.ts.map +1 -1
  55. package/dist/agent/managers/memoryAdvisor.js +53 -67
  56. package/dist/agent/managers/memoryAdvisor.js.map +1 -1
  57. package/dist/agent/managers/memoryDecayScheduler.d.ts +46 -5
  58. package/dist/agent/managers/memoryDecayScheduler.d.ts.map +1 -1
  59. package/dist/agent/managers/memoryDecayScheduler.js +127 -63
  60. package/dist/agent/managers/memoryDecayScheduler.js.map +1 -1
  61. package/dist/agent/managers/memoryGovernance.d.ts +56 -0
  62. package/dist/agent/managers/memoryGovernance.d.ts.map +1 -0
  63. package/dist/agent/managers/memoryGovernance.js +63 -0
  64. package/dist/agent/managers/memoryGovernance.js.map +1 -0
  65. package/dist/agent/managers/memoryInspector.d.ts +32 -157
  66. package/dist/agent/managers/memoryInspector.d.ts.map +1 -1
  67. package/dist/agent/managers/memoryInspector.js +70 -363
  68. package/dist/agent/managers/memoryInspector.js.map +1 -1
  69. package/dist/agent/managers/relationBuilder.js +2 -2
  70. package/dist/agent/managers/relationBuilder.js.map +1 -1
  71. package/dist/agent/managers/sessionArchiver.d.ts +6 -1
  72. package/dist/agent/managers/sessionArchiver.d.ts.map +1 -1
  73. package/dist/agent/managers/sessionArchiver.js +19 -22
  74. package/dist/agent/managers/sessionArchiver.js.map +1 -1
  75. package/dist/agent/managers/streamAccumulator.d.ts +45 -0
  76. package/dist/agent/managers/streamAccumulator.d.ts.map +1 -0
  77. package/dist/agent/managers/streamAccumulator.js +40 -0
  78. package/dist/agent/managers/streamAccumulator.js.map +1 -0
  79. package/dist/agent/managers/textPolishManager.d.ts.map +1 -1
  80. package/dist/agent/managers/textPolishManager.js +4 -7
  81. package/dist/agent/managers/textPolishManager.js.map +1 -1
  82. package/dist/agent/managers/workProjection.d.ts +16 -1
  83. package/dist/agent/managers/workProjection.d.ts.map +1 -1
  84. package/dist/agent/managers/workProjection.js +48 -24
  85. package/dist/agent/managers/workProjection.js.map +1 -1
  86. package/dist/agent/toolExecutor.d.ts +22 -2
  87. package/dist/agent/toolExecutor.d.ts.map +1 -1
  88. package/dist/agent/toolExecutor.js +28 -3
  89. package/dist/agent/toolExecutor.js.map +1 -1
  90. package/dist/agent/types.d.ts +10 -1
  91. package/dist/agent/types.d.ts.map +1 -1
  92. package/dist/agent/userFactExtractor.d.ts.map +1 -1
  93. package/dist/agent/userFactExtractor.js +7 -0
  94. package/dist/agent/userFactExtractor.js.map +1 -1
  95. package/dist/config/loader.d.ts +124 -236
  96. package/dist/config/loader.d.ts.map +1 -1
  97. package/dist/config/loader.js +273 -117
  98. package/dist/config/loader.js.map +1 -1
  99. package/dist/index.d.ts +7 -2
  100. package/dist/index.d.ts.map +1 -1
  101. package/dist/index.js +9 -0
  102. package/dist/index.js.map +1 -1
  103. package/dist/llm/embedding.d.ts +13 -1
  104. package/dist/llm/embedding.d.ts.map +1 -1
  105. package/dist/llm/embedding.js.map +1 -1
  106. package/dist/llm/factory.d.ts +19 -5
  107. package/dist/llm/factory.d.ts.map +1 -1
  108. package/dist/llm/factory.js +19 -37
  109. package/dist/llm/factory.js.map +1 -1
  110. package/dist/llm/openaiCompatible.d.ts.map +1 -1
  111. package/dist/llm/openaiCompatible.js +2 -9
  112. package/dist/llm/openaiCompatible.js.map +1 -1
  113. package/dist/logging/logger.d.ts +3 -1
  114. package/dist/logging/logger.d.ts.map +1 -1
  115. package/dist/logging/logger.js +47 -50
  116. package/dist/logging/logger.js.map +1 -1
  117. package/dist/memory/governance.d.ts +50 -0
  118. package/dist/memory/governance.d.ts.map +1 -0
  119. package/dist/memory/governance.js +70 -0
  120. package/dist/memory/governance.js.map +1 -0
  121. package/dist/memory/hybridMerge.d.ts +0 -4
  122. package/dist/memory/hybridMerge.d.ts.map +1 -1
  123. package/dist/memory/hybridMerge.js +19 -4
  124. package/dist/memory/hybridMerge.js.map +1 -1
  125. package/dist/memory/inMemoryRelationStore.d.ts +7 -0
  126. package/dist/memory/inMemoryRelationStore.d.ts.map +1 -1
  127. package/dist/memory/inMemoryRelationStore.js +15 -0
  128. package/dist/memory/inMemoryRelationStore.js.map +1 -1
  129. package/dist/memory/inMemoryStorage.d.ts +36 -1
  130. package/dist/memory/inMemoryStorage.d.ts.map +1 -1
  131. package/dist/memory/inMemoryStorage.js +66 -16
  132. package/dist/memory/inMemoryStorage.js.map +1 -1
  133. package/dist/memory/loader.d.ts +2 -0
  134. package/dist/memory/loader.d.ts.map +1 -1
  135. package/dist/memory/loader.js +8 -1
  136. package/dist/memory/loader.js.map +1 -1
  137. package/dist/memory/lockManager.d.ts +7 -2
  138. package/dist/memory/lockManager.d.ts.map +1 -1
  139. package/dist/memory/lockManager.js +31 -5
  140. package/dist/memory/lockManager.js.map +1 -1
  141. package/dist/memory/projectManager.d.ts +2 -1
  142. package/dist/memory/projectManager.d.ts.map +1 -1
  143. package/dist/memory/projectManager.js +21 -3
  144. package/dist/memory/projectManager.js.map +1 -1
  145. package/dist/memory/projectRegistry.d.ts +34 -1
  146. package/dist/memory/projectRegistry.d.ts.map +1 -1
  147. package/dist/memory/projectRegistry.js +99 -22
  148. package/dist/memory/projectRegistry.js.map +1 -1
  149. package/dist/memory/recall.d.ts +16 -0
  150. package/dist/memory/recall.d.ts.map +1 -1
  151. package/dist/memory/recall.js +33 -18
  152. package/dist/memory/recall.js.map +1 -1
  153. package/dist/memory/relationStore.d.ts +20 -3
  154. package/dist/memory/relationStore.d.ts.map +1 -1
  155. package/dist/memory/sourceValidation.d.ts +11 -0
  156. package/dist/memory/sourceValidation.d.ts.map +1 -1
  157. package/dist/memory/sourceValidation.js +24 -2
  158. package/dist/memory/sourceValidation.js.map +1 -1
  159. package/dist/memory/storageInterface.d.ts +26 -1
  160. package/dist/memory/storageInterface.d.ts.map +1 -1
  161. package/dist/memory/store.d.ts +22 -1
  162. package/dist/memory/store.d.ts.map +1 -1
  163. package/dist/memory/store.js +58 -20
  164. package/dist/memory/store.js.map +1 -1
  165. package/dist/memory/types.d.ts +44 -31
  166. package/dist/memory/types.d.ts.map +1 -1
  167. package/dist/memory/types.js +63 -24
  168. package/dist/memory/types.js.map +1 -1
  169. package/dist/memory/userProfile.d.ts +32 -8
  170. package/dist/memory/userProfile.d.ts.map +1 -1
  171. package/dist/memory/userProfile.js +105 -44
  172. package/dist/memory/userProfile.js.map +1 -1
  173. package/dist/memory/vectorStore.d.ts +16 -22
  174. package/dist/memory/vectorStore.d.ts.map +1 -1
  175. package/dist/memory/vectorStore.js +49 -22
  176. package/dist/memory/vectorStore.js.map +1 -1
  177. package/dist/persona/personaManager.d.ts +36 -87
  178. package/dist/persona/personaManager.d.ts.map +1 -1
  179. package/dist/persona/personaManager.js +131 -230
  180. package/dist/persona/personaManager.js.map +1 -1
  181. package/dist/skill/skillManager.d.ts +11 -57
  182. package/dist/skill/skillManager.d.ts.map +1 -1
  183. package/dist/skill/skillManager.js +46 -142
  184. package/dist/skill/skillManager.js.map +1 -1
  185. package/dist/skill/types.d.ts +2 -3
  186. package/dist/skill/types.d.ts.map +1 -1
  187. package/dist/utils/configResourceManager.d.ts +111 -0
  188. package/dist/utils/configResourceManager.d.ts.map +1 -0
  189. package/dist/utils/configResourceManager.js +148 -0
  190. package/dist/utils/configResourceManager.js.map +1 -0
  191. package/dist/utils/errors.d.ts +17 -0
  192. package/dist/utils/errors.d.ts.map +1 -1
  193. package/dist/utils/errors.js +19 -0
  194. package/dist/utils/errors.js.map +1 -1
  195. package/dist/utils/eventEmitter.d.ts +83 -6
  196. package/dist/utils/eventEmitter.d.ts.map +1 -1
  197. package/dist/utils/eventEmitter.js +23 -0
  198. package/dist/utils/eventEmitter.js.map +1 -1
  199. package/dist/utils/frontmatter.d.ts.map +1 -1
  200. package/dist/utils/frontmatter.js +4 -2
  201. package/dist/utils/frontmatter.js.map +1 -1
  202. package/dist/utils/math.d.ts +11 -0
  203. package/dist/utils/math.d.ts.map +1 -1
  204. package/dist/utils/math.js +17 -0
  205. package/dist/utils/math.js.map +1 -1
  206. package/dist/utils/segmenter.d.ts +0 -10
  207. package/dist/utils/segmenter.d.ts.map +1 -1
  208. package/dist/utils/segmenter.js +10 -1
  209. package/dist/utils/segmenter.js.map +1 -1
  210. package/docs/memora-api-reference.md +1235 -0
  211. package/docs/memora-/346/216/245/345/205/245/346/214/207/345/215/227.md +808 -0
  212. package/package.json +39 -22
@@ -1,3 +1,4 @@
1
+ import { MemoraError } from '../utils/errors.js';
1
2
  /**
2
3
  * 项目注册表条目
3
4
  */
@@ -9,6 +10,26 @@ export interface ProjectEntry {
9
10
  /** 最后打开时间 */
10
11
  lastOpened: string;
11
12
  }
13
+ /**
14
+ * 项目注册表损坏错误
15
+ *
16
+ * FIX-P0-3:当磁盘上的 projects.json 存在但内容无法解析(JSON 语法错误或结构
17
+ * 不符合 ProjectEntry[] 契约)时抛出。与"文件不存在"语义区分——后者是首次启动
18
+ * 的正常情况,前者意味着数据可能丢失,需要调用方决策(备份/重建/中止)。
19
+ *
20
+ * 设计意图:
21
+ * - register/unregister 路径必须让此错误向上传播,避免用空数据覆盖损坏文件
22
+ * - list getter 可捕获此错误降级返回空数组(只读操作,不破坏数据)
23
+ *
24
+ * 规则对齐(RULE-ALIGN-0729):继承 MemoraError 而非 Error,统一错误体系
25
+ * (project-rules.md §7.1 + coding-convention-rules.md §2)。保留 registryPath
26
+ * 扩展字段以支持调用方备份/排查流程。
27
+ */
28
+ export declare class ProjectRegistryCorruptError extends MemoraError {
29
+ /** 损坏文件的绝对路径,便于备份/排查 */
30
+ readonly registryPath: string;
31
+ constructor(registryPath: string, cause?: unknown);
32
+ }
12
33
  /**
13
34
  * 项目注册表
14
35
  *
@@ -23,6 +44,10 @@ export declare class ProjectRegistry {
23
44
  constructor(registryPath: string);
24
45
  /**
25
46
  * 列出已注册的项目(同步读取,契约要求 getter 风格)
47
+ *
48
+ * FIX-P0-3:list 是只读操作,损坏时降级返回空数组(UI 显示空列表)。
49
+ * 与 register/unregister 不同——只读不会用空数据覆盖原文件,降级是安全的。
50
+ * 损坏错误记录 warn 日志便于排查,但不向上抛出避免 UI 崩溃。
26
51
  */
27
52
  get list(): ProjectEntry[];
28
53
  /**
@@ -51,7 +76,15 @@ export declare class ProjectRegistry {
51
76
  * 读取项目注册表
52
77
  *
53
78
  * 同步读取:list getter 契约要求同步返回,注册表操作低频,同步 I/O 影响可控。
54
- * 损坏时返回空数组并记录警告日志,避免静默吞错掩盖磁盘故障。
79
+ *
80
+ * FIX-P0-3:语义区分——
81
+ * - 文件不存在:返回空数组(首次启动的正常情况)
82
+ * - 文件损坏(JSON 解析失败或顶层非数组):抛出 ProjectRegistryCorruptError
83
+ * 让调用方决策。register/unregister 不捕获此错误,避免用空数据覆盖原文件。
84
+ * - 数组内个别条目不合法:仅过滤保留合法条目(容错,不抛错)
85
+ *
86
+ * @returns 项目注册表条目数组
87
+ * @throws {ProjectRegistryCorruptError} 文件存在但内容损坏时抛出
55
88
  */
56
89
  private read;
57
90
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"projectRegistry.d.ts","sourceRoot":"","sources":["../../src/memory/projectRegistry.ts"],"names":[],"mappings":"AA4BA;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,sBAAsB;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAkCD;;;;;GAKG;AACH,qBAAa,eAAe;IAId,OAAO,CAAC,QAAQ,CAAC,YAAY;IAHzC;;OAEG;gBAC0B,YAAY,EAAE,MAAM;IAEjD;;OAEG;IACH,IAAI,IAAI,IAAI,YAAY,EAAE,CAEzB;IAED;;;;;;;OAOG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAsBjD;;;;OAIG;IACH,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IASrC;;;;;OAKG;IACH,MAAM,CAAC,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IAKpD;;;;;OAKG;IACH,OAAO,CAAC,IAAI;IA6BZ;;OAEG;IACH,OAAO,CAAC,KAAK;CAMd"}
1
+ {"version":3,"file":"projectRegistry.d.ts","sourceRoot":"","sources":["../../src/memory/projectRegistry.ts"],"names":[],"mappings":"AAwBA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAMhD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,sBAAsB;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,2BAA4B,SAAQ,WAAW;IAC1D,wBAAwB;IACxB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;gBAElB,YAAY,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAiBlD;AA6CD;;;;;GAKG;AACH,qBAAa,eAAe;IAId,OAAO,CAAC,QAAQ,CAAC,YAAY;IAHzC;;OAEG;gBAC0B,YAAY,EAAE,MAAM;IAEjD;;;;;;OAMG;IACH,IAAI,IAAI,IAAI,YAAY,EAAE,CAezB;IAED;;;;;;;OAOG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAsBjD;;;;OAIG;IACH,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IASrC;;;;;OAKG;IACH,MAAM,CAAC,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IAKpD;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,IAAI;IAoCZ;;OAEG;IACH,OAAO,CAAC,KAAK;CAMd"}
@@ -2,7 +2,7 @@
2
2
  * 项目注册表 — 多项目注册信息持久化
3
3
  *
4
4
  * 从 ProjectManager 拆分出来,专职管理 projects.json 注册表:
5
- * - 读写项目注册表(~/.memora/projects.json 或宿主指定 registryDir)
5
+ * - 读写项目注册表(registryDir 由宿主注入,默认位于宿主数据目录)
6
6
  * - 注册/注销项目条目(Windows 大小写不敏感去重)
7
7
  * - 从路径推断项目名称
8
8
  * - 不可信磁盘 JSON 的运行时类型校验(QC-24,替代 `as` 类型断言)
@@ -10,7 +10,9 @@
10
10
  * 设计原则:
11
11
  * - 纯文件系统操作,无锁机制(锁由 LockManager 负责)
12
12
  * - 同步 I/O(list getter 契约要求同步返回;注册表操作低频,影响可控)
13
- * - 损坏降级:解析失败返回空列表 + 警告日志,不抛异常
13
+ * - 损坏语义区分(FIX-P0-3):文件不存在 = 首次启动返回空列表;文件损坏 = 抛出
14
+ * ProjectRegistryCorruptError 让调用方决策。list getter 只读降级返回空,
15
+ * register/unregister 写入路径必须抛错传播,防止用空数据覆盖原文件导致数据丢失
14
16
  *
15
17
  * 与 ProjectManager 的分工(1.0 接口稳定化):
16
18
  * - ProjectRegistry:注册表读写 + 条目管理 + 名称推断
@@ -20,9 +22,45 @@
20
22
  */
21
23
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
22
24
  import { logger } from '../logging/logger.js';
23
- import { toError } from '../utils/toError.js';
25
+ import { MemoraError } from '../utils/errors.js';
24
26
  import { nowIso } from '../utils/time.js';
25
27
  import { isPlainObject } from '../utils/objects.js';
28
+ /**
29
+ * 项目注册表损坏错误
30
+ *
31
+ * FIX-P0-3:当磁盘上的 projects.json 存在但内容无法解析(JSON 语法错误或结构
32
+ * 不符合 ProjectEntry[] 契约)时抛出。与"文件不存在"语义区分——后者是首次启动
33
+ * 的正常情况,前者意味着数据可能丢失,需要调用方决策(备份/重建/中止)。
34
+ *
35
+ * 设计意图:
36
+ * - register/unregister 路径必须让此错误向上传播,避免用空数据覆盖损坏文件
37
+ * - list getter 可捕获此错误降级返回空数组(只读操作,不破坏数据)
38
+ *
39
+ * 规则对齐(RULE-ALIGN-0729):继承 MemoraError 而非 Error,统一错误体系
40
+ * (project-rules.md §7.1 + coding-convention-rules.md §2)。保留 registryPath
41
+ * 扩展字段以支持调用方备份/排查流程。
42
+ */
43
+ export class ProjectRegistryCorruptError extends MemoraError {
44
+ /** 损坏文件的绝对路径,便于备份/排查 */
45
+ registryPath;
46
+ constructor(registryPath, cause) {
47
+ // cause 归一化为 Error 类型,符合 MemoraError.cause 契约
48
+ const causeError = cause instanceof Error ? cause : cause !== undefined ? new Error(String(cause)) : undefined;
49
+ super({
50
+ title: `项目注册表损坏:${registryPath}`,
51
+ detail: causeError?.message,
52
+ suggestions: [
53
+ '检查文件是否被外部程序修改',
54
+ '从备份恢复 projects.json',
55
+ '或删除该文件让精灵重建(会丢失历史项目记录)',
56
+ ],
57
+ category: 'config',
58
+ cause: causeError,
59
+ });
60
+ this.name = 'ProjectRegistryCorruptError';
61
+ this.registryPath = registryPath;
62
+ }
63
+ }
26
64
  // ─── 类型守卫(QC-24,对不可信磁盘 JSON 运行时校验) ─────
27
65
  /**
28
66
  * 判断值是否为 ProjectEntry(项目注册表条目)
@@ -40,14 +78,21 @@ function isProjectEntry(value) {
40
78
  /**
41
79
  * 判断值是否为 ProjectEntry 数组
42
80
  *
43
- * 过滤掉不符合结构的条目,仅保留合法条目
81
+ * 顶层必须为数组,否则视为注册表结构损坏(抛错让调用方决策)。
82
+ * 数组内个别条目不合法时仅过滤保留合法条目(容错:单条损坏不毁全部)。
83
+ *
84
+ * FIX-P0-3:顶层非数组不再静默返回空,而是抛 ProjectRegistryCorruptError,
85
+ * 避免 register 用空数据覆盖原文件导致全部项目记录永久丢失。
44
86
  *
45
87
  * @param value 待校验的值
46
- * @returns 解析后的合法条目数组(损坏时返回空数组)
88
+ * @param registryPath 注册表路径(用于错误信息)
89
+ * @returns 解析后的合法条目数组
90
+ * @throws {ProjectRegistryCorruptError} 顶层非数组时抛出
47
91
  */
48
- function asProjectEntryArray(value) {
49
- if (!Array.isArray(value))
50
- return [];
92
+ function asProjectEntryArray(value, registryPath) {
93
+ if (!Array.isArray(value)) {
94
+ throw new ProjectRegistryCorruptError(registryPath, new Error(`注册表顶层应为数组,实际类型:${typeof value}`));
95
+ }
51
96
  return value.filter(isProjectEntry);
52
97
  }
53
98
  // ─── 类 ──────────────────────────────────────────────────
@@ -67,9 +112,24 @@ export class ProjectRegistry {
67
112
  }
68
113
  /**
69
114
  * 列出已注册的项目(同步读取,契约要求 getter 风格)
115
+ *
116
+ * FIX-P0-3:list 是只读操作,损坏时降级返回空数组(UI 显示空列表)。
117
+ * 与 register/unregister 不同——只读不会用空数据覆盖原文件,降级是安全的。
118
+ * 损坏错误记录 warn 日志便于排查,但不向上抛出避免 UI 崩溃。
70
119
  */
71
120
  get list() {
72
- return this.read();
121
+ try {
122
+ return this.read();
123
+ }
124
+ catch (err) {
125
+ // 只读降级:损坏时返回空列表,UI 显示"无项目",但不会破坏磁盘数据
126
+ if (err instanceof ProjectRegistryCorruptError) {
127
+ logger.warn({ path: err.registryPath, cause: err.cause }, '项目注册表损坏,list getter 降级返回空列表(只读,不破坏数据)');
128
+ return [];
129
+ }
130
+ // 非 ProjectRegistryCorruptError 的意外错误仍向上抛出
131
+ throw err;
132
+ }
73
133
  }
74
134
  /**
75
135
  * 注册项目到注册表
@@ -121,29 +181,46 @@ export class ProjectRegistry {
121
181
  * 读取项目注册表
122
182
  *
123
183
  * 同步读取:list getter 契约要求同步返回,注册表操作低频,同步 I/O 影响可控。
124
- * 损坏时返回空数组并记录警告日志,避免静默吞错掩盖磁盘故障。
184
+ *
185
+ * FIX-P0-3:语义区分——
186
+ * - 文件不存在:返回空数组(首次启动的正常情况)
187
+ * - 文件损坏(JSON 解析失败或顶层非数组):抛出 ProjectRegistryCorruptError
188
+ * 让调用方决策。register/unregister 不捕获此错误,避免用空数据覆盖原文件。
189
+ * - 数组内个别条目不合法:仅过滤保留合法条目(容错,不抛错)
190
+ *
191
+ * @returns 项目注册表条目数组
192
+ * @throws {ProjectRegistryCorruptError} 文件存在但内容损坏时抛出
125
193
  */
126
194
  read() {
195
+ // 文件不存在 = 首次启动,返回空数组(正常情况,不抛错)
127
196
  if (!existsSync(this.registryPath)) {
128
197
  return [];
129
198
  }
199
+ let raw;
200
+ try {
201
+ raw = readFileSync(this.registryPath, 'utf-8');
202
+ }
203
+ catch (err) {
204
+ // 文件存在但读取失败(权限/磁盘故障),视为损坏
205
+ throw new ProjectRegistryCorruptError(this.registryPath, err);
206
+ }
207
+ let parsed;
130
208
  try {
131
- const raw = readFileSync(this.registryPath, 'utf-8');
132
209
  // QC-24 使用类型守卫校验 JSON.parse 结果,替代 `as ProjectEntry[]` 类型断言
133
- // 过滤掉不符合结构的条目,仅保留合法条目
134
- const parsed = JSON.parse(raw);
135
- const entries = asProjectEntryArray(parsed);
136
- if (entries.length === 0 && Array.isArray(parsed) && parsed.length > 0) {
137
- // 数组存在但所有条目都不合法,记录警告
138
- logger.warn({ path: this.registryPath, totalEntries: parsed.length }, '项目注册表所有条目结构不合法,返回空列表');
139
- }
140
- return entries;
210
+ parsed = JSON.parse(raw);
141
211
  }
142
212
  catch (err) {
143
- // 注册表损坏:记录警告日志便于排查(不存在属正常首次启动,损坏需排查)
144
- logger.warn({ path: this.registryPath, err: toError(err).message }, '项目注册表解析失败,返回空列表');
145
- return [];
213
+ // JSON 语法错误 = 文件整体损坏,抛错让调用方决策(备份/重建/中止)
214
+ throw new ProjectRegistryCorruptError(this.registryPath, err);
215
+ }
216
+ // 顶层非数组也视为损坏(asProjectEntryArray 内部抛 ProjectRegistryCorruptError)
217
+ // 数组内个别条目不合法时仅过滤保留合法条目(容错:单条损坏不毁全部)
218
+ const entries = asProjectEntryArray(parsed, this.registryPath);
219
+ if (entries.length === 0 && Array.isArray(parsed) && parsed.length > 0) {
220
+ // 数组存在但所有条目都不合法,记录警告(仍返回空,因为是单条容错的极端情况)
221
+ logger.warn({ path: this.registryPath, totalEntries: parsed.length }, '项目注册表所有条目结构不合法,返回空列表');
146
222
  }
223
+ return entries;
147
224
  }
148
225
  /**
149
226
  * 写入项目注册表
@@ -1 +1 @@
1
- {"version":3,"file":"projectRegistry.js","sourceRoot":"","sources":["../../src/memory/projectRegistry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"projectRegistry.js","sourceRoot":"","sources":["../../src/memory/projectRegistry.ts"],"names":[],"mappings":"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"}
@@ -55,6 +55,22 @@ export interface RecallOptions {
55
55
  * @returns 匹配的记忆列表
56
56
  */
57
57
  export declare function recall(storage: IMemoryStorage, query: string, options?: RecallOptions): Promise<Memory[]>;
58
+ /**
59
+ * 批量持久化 boost 后的 score(FIX-P1-2:从 recall() 拆分出的显式写操作)
60
+ *
61
+ * 调用方在 recall() 后 fire-and-forget 调用本函数持久化 boost,不阻塞读路径。
62
+ * 失败仅 log 不抛错,避免读路径因 boost 写入失败而中断。
63
+ *
64
+ * 设计权衡:
65
+ * - 不在 recall() 内部 upsert:消除 IO 写耦合读路径(boost 是软指标,丢失影响小)
66
+ * - 不引入 dirty 标记 + 治理调度器批量持久化:避免新增状态队列和跨模块依赖
67
+ * - 立即持久化但 fire-and-forget:boost 数据不丢,读路径不阻塞
68
+ *
69
+ * @param storage 记忆存储实例
70
+ * @param ids 待 boost 的记忆 id 列表(从 recall() 返回结果的 id 字段提取)
71
+ * @param now 当前时间戳(可选,默认 nowIso())
72
+ */
73
+ export declare function boostScores(storage: IMemoryStorage, ids: string[], now?: string): Promise<void>;
58
74
  /**
59
75
  * 对单条记忆执行衰减计算
60
76
  *
@@ -1 +1 @@
1
- {"version":3,"file":"recall.d.ts","sourceRoot":"","sources":["../../src/memory/recall.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AA2B5D,eAAe;AACf,eAAO,MAAM,UAAU,QAAsB,CAAC;AAE9C;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAUvD;AAID;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,mBAAmB;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,8CAA8C;IAC9C,WAAW,CAAC,EAAE,YAAY,CAAC;IAC3B,wBAAwB;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,MAAM,CAC1B,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,MAAM,EAAE,CAAC,CAgEnB;AAkBD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,GAAG,OAAO,CAcrE"}
1
+ {"version":3,"file":"recall.d.ts","sourceRoot":"","sources":["../../src/memory/recall.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAe5D,eAAe;AACf,eAAO,MAAM,UAAU,QAAsB,CAAC;AAE9C;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAUvD;AAID;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,mBAAmB;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,8CAA8C;IAC9C,WAAW,CAAC,EAAE,YAAY,CAAC;IAC3B,wBAAwB;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,MAAM,CAC1B,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,MAAM,EAAE,CAAC,CA+DnB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,cAAc,EACvB,GAAG,EAAE,MAAM,EAAE,EACb,GAAG,GAAE,MAAiB,GACrB,OAAO,CAAC,IAAI,CAAC,CAOf;AAkBD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,GAAG,OAAO,CAcrE"}
@@ -3,19 +3,12 @@ import { SOURCE_LABELS } from '../memory/types.js';
3
3
  import { segmentLower, STOPWORDS } from '../utils/segmenter.js';
4
4
  import { nowIso } from '../utils/time.js';
5
5
  import { hybridMerge, RECALL_LIMIT_MULTIPLIER } from '../memory/hybridMerge.js';
6
- // ─── 召回与衰减常量 ─────────────────────────────────────
6
+ // 召回 score 提升量/上限/下限 + 衰减常量:使用治理共享常量(v2 REPEAT-2/REPEAT-3 闭环)
7
+ // 衰减常量与宿主 SqliteStorage.decayScores 共用同一真理源,消除跨层重复硬编码
8
+ import { BOOST_INCREMENT, SCORE_CEILING, DECAY_FLOOR, DECAY_AGE_DAYS, DECAY_AMOUNT } from '../memory/governance.js';
9
+ // ─── 召回常量 ─────────────────────────────────────
7
10
  /** 语义搜索默认相似度阈值 */
8
11
  const DEFAULT_MIN_SIMILARITY = 0.3;
9
- /** 每次召回时 score 提升量 */
10
- const BOOST_INCREMENT = 0.05;
11
- /** score 上限 */
12
- const SCORE_CEILING = 1.0;
13
- /** 衰减:未访问天数阈值 */
14
- const DECAY_AGE_DAYS = 7;
15
- /** 衰减:每过一个周期 score 降低量 */
16
- const DECAY_AMOUNT = 0.02;
17
- /** 衰减:score 下限 */
18
- const DECAY_FLOOR = 0.1;
19
12
  /** 一天对应的毫秒数 */
20
13
  export const ONE_DAY_MS = 24 * 60 * 60 * 1000;
21
14
  /**
@@ -93,18 +86,40 @@ export async function recall(storage, query, options = {}) {
93
86
  return [];
94
87
  // ── 综合排序:委托给 hybridMerge 纯函数 ──
95
88
  const sorted = hybridMerge(merged.values(), limit);
96
- // ── 召回时提升 score ──
97
- // 在副本上操作避免污染调用方持有的对象,boost 后写回存储
89
+ // ── FIX-P1-2:拆分读/写,recall 只读 + boostScores 显式写 ──
90
+ // 在副本上 boost,仅影响本轮上下文排序;持久化由调用方 fire-and-forget 调用 boostScores,
91
+ // 不阻塞读路径,boost 写入失败不影响 chat 流程。
98
92
  const now = nowIso();
99
- const result = [];
100
- for (const { memory } of sorted) {
93
+ const result = sorted.map(({ memory }) => {
101
94
  const copy = { ...memory };
102
95
  boostScore(copy, now);
103
- storage.upsert(copy); // 写回存储,持久化 score 提升
104
- result.push(copy);
105
- }
96
+ return copy;
97
+ });
106
98
  return result;
107
99
  }
100
+ /**
101
+ * 批量持久化 boost 后的 score(FIX-P1-2:从 recall() 拆分出的显式写操作)
102
+ *
103
+ * 调用方在 recall() 后 fire-and-forget 调用本函数持久化 boost,不阻塞读路径。
104
+ * 失败仅 log 不抛错,避免读路径因 boost 写入失败而中断。
105
+ *
106
+ * 设计权衡:
107
+ * - 不在 recall() 内部 upsert:消除 IO 写耦合读路径(boost 是软指标,丢失影响小)
108
+ * - 不引入 dirty 标记 + 治理调度器批量持久化:避免新增状态队列和跨模块依赖
109
+ * - 立即持久化但 fire-and-forget:boost 数据不丢,读路径不阻塞
110
+ *
111
+ * @param storage 记忆存储实例
112
+ * @param ids 待 boost 的记忆 id 列表(从 recall() 返回结果的 id 字段提取)
113
+ * @param now 当前时间戳(可选,默认 nowIso())
114
+ */
115
+ export async function boostScores(storage, ids, now = nowIso()) {
116
+ for (const id of ids) {
117
+ // MIND2-L3:改用 incrementScore 原子操作,消除 read-modify-write 并发冲突
118
+ // 原 getById → boostScore → upsert 三步合并为存储层一条原子更新,
119
+ // 与 decayScores 同模式(避免与衰减/去重并发写时基于旧值覆盖)
120
+ storage.incrementScore(id, BOOST_INCREMENT, now);
121
+ }
122
+ }
108
123
  // ─── Score 衰减机制 ─────────────────────────────────────
109
124
  /**
110
125
  * 召回时提升记忆的 score(上限 1.0)
@@ -1 +1 @@
1
- {"version":3,"file":"recall.js","sourceRoot":"","sources":["../../src/memory/recall.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"recall.js","sourceRoot":"","sources":["../../src/memory/recall.ts"],"names":[],"mappings":"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"}
@@ -10,9 +10,11 @@
10
10
  * - SqliteRelationStore:扩展 memory_relations 表,依赖 better-sqlite3
11
11
  * - InMemoryRelationStore:测试用实现,纯内存数组
12
12
  *
13
- * 关系构建时机(Sprite 层,不进内核):
14
- * - InsightExtractor.extract() 完成后 fire-and-forget
15
- * - 代码层召回 top-5 相关记忆 → LLM 判断关系类型 → 写入 IMemoryRelationStore
13
+ * 关系构建时机与层属(ADR-014 §5):
14
+ * - 机制层(候选召回 + prompt 构建 + 关系写入 + 冲突检测)在内核
15
+ * src/agent/managers/relationBuilder.ts,LLM 调用合并到 InsightExtractor
16
+ * 单次 extract() 中,不增加 LLM 调用次数
17
+ * - 宿主项目(Sprite 层)仅需注入 IMemoryRelationStore 实现
16
18
  * - 遵循降级优先(ADR-006):关系构建失败不阻塞对话,仅记录日志
17
19
  */
18
20
  import type { MemoryRelation, RelationDirection } from '../memory/types.js';
@@ -74,5 +76,20 @@ export interface IMemoryRelationStore {
74
76
  * @param type 关系类型
75
77
  */
76
78
  removeRelation(sourceId: string, targetId: string, type: string): void;
79
+ /**
80
+ * 删除某记忆的所有关系(不论方向)
81
+ *
82
+ * 删除 sourceId 或 targetId 等于 memoryId 的所有关系边。
83
+ * 用于记忆删除/物理清除场景,防止 memory_relations 表残留孤儿边。
84
+ *
85
+ * 实现约束:
86
+ * - 必须原子执行(单条 SQL DELETE WHERE sourceId=? OR targetId=?)
87
+ * - 返回被删除的关系数量,便于审计
88
+ * - 不存在的 memoryId 返回 0,不抛错
89
+ *
90
+ * @param memoryId 记忆 ID
91
+ * @returns 被删除的关系数量
92
+ */
93
+ removeRelationsByMemoryId(memoryId: string): number;
77
94
  }
78
95
  //# sourceMappingURL=relationStore.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"relationStore.d.ts","sourceRoot":"","sources":["../../src/memory/relationStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE3E;;;;;;;;GAQG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;;;OAMG;IACH,WAAW,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI,CAAC;IAE5C;;;;;;;;;OASG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,iBAAiB,GAAG,cAAc,EAAE,CAAC;IAEhF;;;;;;;OAOG;IACH,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,EAAE,CAAC;IAEnD;;;;;;;OAOG;IACH,eAAe,IAAI,cAAc,EAAE,CAAC;IAEpC;;;;;;;;;OASG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACxE"}
1
+ {"version":3,"file":"relationStore.d.ts","sourceRoot":"","sources":["../../src/memory/relationStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE3E;;;;;;;;GAQG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;;;OAMG;IACH,WAAW,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI,CAAC;IAE5C;;;;;;;;;OASG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,iBAAiB,GAAG,cAAc,EAAE,CAAC;IAEhF;;;;;;;OAOG;IACH,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,EAAE,CAAC;IAEnD;;;;;;;OAOG;IACH,eAAe,IAAI,cAAc,EAAE,CAAC;IAEpC;;;;;;;;;OASG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAEvE;;;;;;;;;;;;;OAaG;IACH,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;CACrD"}
@@ -21,6 +21,17 @@ export declare function inferSource(filePath: string, frontmatterSource?: string
21
21
  * @returns 转义后的字符串
22
22
  */
23
23
  export declare function escapeLike(str: string): string;
24
+ /**
25
+ * 截取字符串前 maxLen 字符后转义 LIKE 通配符
26
+ *
27
+ * 用于将用户输入 / insight 文本作为关键词搜索 SQLite LIKE 查询的输入。
28
+ * 截断避免超长输入导致 LIKE 解析性能问题,转义防止通配符注入。
29
+ *
30
+ * @param text - 原始文本(用户输入 / insight 内容)
31
+ * @param maxLen - 最大截取长度,默认 50
32
+ * @returns 截断 + 转义后的字符串
33
+ */
34
+ export declare function escapeLikeSnippet(text: string, maxLen?: number): string;
24
35
  /**
25
36
  * 校验 source 字段是否为已知标签
26
37
  *
@@ -1 +1 @@
1
- {"version":3,"file":"sourceValidation.d.ts","sourceRoot":"","sources":["../../src/memory/sourceValidation.ts"],"names":[],"mappings":"AAgBA;;;;;;GAMG;AACH,MAAM,MAAM,wBAAwB,GAAG,OAAO,GAAG,MAAM,CAAC;AAUxD;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,iBAAiB,CAAC,EAAE,MAAM,GAAG,MAAM,CAWhF;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG;IAC9C,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,wBAAwB,CAAC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAgDA;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CA2BxD"}
1
+ {"version":3,"file":"sourceValidation.d.ts","sourceRoot":"","sources":["../../src/memory/sourceValidation.ts"],"names":[],"mappings":"AAgBA;;;;;;GAMG;AACH,MAAM,MAAM,wBAAwB,GAAG,OAAO,GAAG,MAAM,CAAC;AAUxD;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,iBAAiB,CAAC,EAAE,MAAM,GAAG,MAAM,CAWhF;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,SAAK,GAAG,MAAM,CAEnE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG;IAC9C,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,wBAAwB,CAAC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CA0DA;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CA2BxD"}
@@ -38,8 +38,8 @@ export function inferSource(filePath, frontmatterSource) {
38
38
  return SOURCE_LABELS.RULE;
39
39
  if (/[\\/]skills[\\/]/.test(filePath))
40
40
  return SOURCE_LABELS.SKILL;
41
- // 默认
42
- return 'unknown';
41
+ // 默认:未知来源(SOURCE_LABELS.UNKNOWN 显式声明,避免字符串字面量分散)
42
+ return SOURCE_LABELS.UNKNOWN;
43
43
  }
44
44
  /**
45
45
  * 转义 LIKE 通配符,防止注入
@@ -50,6 +50,19 @@ export function inferSource(filePath, frontmatterSource) {
50
50
  export function escapeLike(str) {
51
51
  return str.replace(/[%_]/g, '\\$&');
52
52
  }
53
+ /**
54
+ * 截取字符串前 maxLen 字符后转义 LIKE 通配符
55
+ *
56
+ * 用于将用户输入 / insight 文本作为关键词搜索 SQLite LIKE 查询的输入。
57
+ * 截断避免超长输入导致 LIKE 解析性能问题,转义防止通配符注入。
58
+ *
59
+ * @param text - 原始文本(用户输入 / insight 内容)
60
+ * @param maxLen - 最大截取长度,默认 50
61
+ * @returns 截断 + 转义后的字符串
62
+ */
63
+ export function escapeLikeSnippet(text, maxLen = 50) {
64
+ return escapeLike(text.slice(0, maxLen));
65
+ }
53
66
  /**
54
67
  * 校验 source 字段是否为已知标签
55
68
  *
@@ -86,6 +99,15 @@ export function validateSource(source) {
86
99
  warning: `source 不能包含路径遍历序列:"${source}"`,
87
100
  };
88
101
  }
102
+ // 路径分隔符(/ 或 \)同样构成目录穿越:source="rules/secret" 可落入保留的
103
+ // rules/ 目录子树,污染命名空间。source 是扁平标签,必须拒绝分隔符。
104
+ if (source.includes('/') || source.includes('\\')) {
105
+ return {
106
+ valid: false,
107
+ severity: 'block',
108
+ warning: `source 不能包含路径分隔符(/ 或 \\):"${source}"`,
109
+ };
110
+ }
89
111
  if (source.includes('\0')) {
90
112
  return {
91
113
  valid: false,
@@ -1 +1 @@
1
- {"version":3,"file":"sourceValidation.js","sourceRoot":"","sources":["../../src/memory/sourceValidation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sourceValidation.js","sourceRoot":"","sources":["../../src/memory/sourceValidation.ts"],"names":[],"mappings":"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"}
@@ -73,7 +73,8 @@ export interface IMemoryStorage {
73
73
  *
74
74
  * 按 deletedAt 降序(最近删除的在前),便于回收站 UI 展示。
75
75
  *
76
- * @param limit - 返回数量上限(默认 50)
76
+ * @param limit - 返回数量上限。`limit <= 0` 或 `undefined` 表示不设上限(返回全部);
77
+ * 正整数 N 表示返回最近 N 条。默认 undefined(全部)。
77
78
  * @returns 软删除记忆列表(浅拷贝)
78
79
  */
79
80
  listDeleted(limit?: number): Memory[];
@@ -153,6 +154,30 @@ export interface IMemoryStorage {
153
154
  * @returns 受影响的记忆数量
154
155
  */
155
156
  decayScores(sources: string[], now: Date): number;
157
+ /**
158
+ * 原子增加记忆 score(MIND2-L3:消除 boost 路径 read-modify-write 并发冲突)
159
+ *
160
+ * score = clamp(score + delta, DECAY_FLOOR, SCORE_CEILING),同时更新 accessedAt 为 now。
161
+ * 与 decayScores 同模式:宿主实现用一条 SQL UPDATE 完成原子操作,避免读回内存。
162
+ *
163
+ * @param id 记忆 ID
164
+ * @param delta 增量(正数 boost,负数可降级)
165
+ * @param now 当前时间(ISO 8601,用于更新 accessedAt)
166
+ * @returns 记忆不存在/软删除时返回 false,成功返回 true
167
+ */
168
+ incrementScore(id: string, delta: number, now: string): boolean;
169
+ /**
170
+ * 原子设置记忆 score 绝对值(MIND2-L3:消除 demote 路径 spread 旧快照覆盖其他字段)
171
+ *
172
+ * 直接设置 score = newScore,不 clamp(调用方负责传合法值)。同时更新 accessedAt 为 now。
173
+ * 用于 demoteMemory / demoteOutdatedMemory 等设绝对值场景,避免 spread 旧快照覆盖 content 等字段。
174
+ *
175
+ * @param id 记忆 ID
176
+ * @param newScore 新 score 绝对值
177
+ * @param now 当前时间(ISO 8601,用于更新 accessedAt)
178
+ * @returns 记忆不存在/软删除时返回 false,成功返回 true
179
+ */
180
+ setScore(id: string, newScore: number, now: string): boolean;
156
181
  /**
157
182
  * 获取所有 source 标签及其活跃记忆数量(不含已软删除的)
158
183
  *
@@ -1 +1 @@
1
- {"version":3,"file":"storageInterface.d.ts","sourceRoot":"","sources":["../../src/memory/storageInterface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAE7B;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAEzB;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAE1B;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAExB;;;;;;;OAOG;IACH,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAEtC;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAE1C;;;;;;;;OAQG;IACH,YAAY,CAAC,MAAM,EAAE,IAAI,GAAG,MAAM,CAAC;IAEnC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAEnC;;;;;OAKG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAEtC;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAEhD;;;;;OAKG;IACH,KAAK,IAAI,MAAM,CAAC;IAEhB;;;;;OAKG;IACH,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IAEtC;;;;;;;;;;OAUG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,IAAI,GAAG,MAAM,CAAC;IAElD;;;;;;;;OAQG;IACH,aAAa,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAErC;;;;;OAKG;IACH,KAAK,CAAC,IAAI,IAAI,CAAC;CAChB"}
1
+ {"version":3,"file":"storageInterface.d.ts","sourceRoot":"","sources":["../../src/memory/storageInterface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAE7B;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAEzB;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAE1B;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAExB;;;;;;;;OAQG;IACH,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAEtC;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAE1C;;;;;;;;OAQG;IACH,YAAY,CAAC,MAAM,EAAE,IAAI,GAAG,MAAM,CAAC;IAEnC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAEnC;;;;;OAKG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAEtC;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAEhD;;;;;OAKG;IACH,KAAK,IAAI,MAAM,CAAC;IAEhB;;;;;OAKG;IACH,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IAEtC;;;;;;;;;;OAUG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,IAAI,GAAG,MAAM,CAAC;IAElD;;;;;;;;;;OAUG;IACH,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAEhE;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAE7D;;;;;;;;OAQG;IACH,aAAa,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAErC;;;;;OAKG;IACH,KAAK,CAAC,IAAI,IAAI,CAAC;CAChB"}
@@ -17,6 +17,9 @@ export declare class FileStore {
17
17
  read(source: string, name: string): Promise<Memory | null>;
18
18
  /**
19
19
  * 写入记忆文件
20
+ *
21
+ * frontmatter 包含标准字段(id/source/score/createdAt/accessedAt)
22
+ * 和 memory.metadata 中的额外元数据(如 keywords/description)。
20
23
  */
21
24
  write(memory: Memory): Promise<void>;
22
25
  /**
@@ -33,9 +36,27 @@ export declare class FileStore {
33
36
  /**
34
37
  * source 到目录名的映射
35
38
  *
36
- * 已知 source 使用预定义目录,未知 source 直接用 source 字符串作目录名
39
+ * 已知 source 使用预定义目录,未知 source 直接用 source 字符串作目录名。
40
+ * 安全校验:调用 validateSource 拒绝路径遍历(`..`)、null 字节等危险字符,
41
+ * 防止未知 source 被构造为恶意路径绕过 SOURCE_TO_DIR 白名单。
37
42
  */
38
43
  private sourceToDir;
44
+ /**
45
+ * 文件系统错误统一处理
46
+ *
47
+ * 区分两类错误:
48
+ * - ENOENT(文件/目录不存在):正常情况,静默返回
49
+ * - 其他错误(EACCES/EISDIR 等):真实故障,抛出异常让调用方感知
50
+ *
51
+ * 之前所有错误统一返回 null/[],导致磁盘故障伪装成"无数据",
52
+ * 用户感知不到数据丢失。现区分:ENOENT 静默,其他抛错。
53
+ *
54
+ * @param err 捕获的异常
55
+ * @param path 文件/目录路径(用于日志上下文)
56
+ * @param label 日志标签(中文,如 "记忆文件读取失败")
57
+ * @throws {NodeJS.ErrnoException} 非 ENOENT 错误时重新抛出
58
+ */
59
+ private handleFsError;
39
60
  /**
40
61
  * 解析记忆文件为 Memory 对象
41
62
  *
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/memory/store.ts"],"names":[],"mappings":"AAQA,OAAO,EAAiB,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAqB/D;;;;;GAKG;AACH,qBAAa,SAAS;IACR,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,MAAM;IAE5C;;;;;OAKG;IACG,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAqBhE;;OAEG;IACG,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAe1C;;;;;OAKG;IACG,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAiB7C;;OAEG;IACH,OAAO,CAAC,WAAW;IAInB;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAInB;;;;;;;;OAQG;IACH,OAAO,CAAC,WAAW;CA4CpB"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/memory/store.ts"],"names":[],"mappings":"AAQA,OAAO,EAAuC,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAmBrF;;;;;GAKG;AACH,qBAAa,SAAS;IACR,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,MAAM;IAE5C;;;;;OAKG;IACG,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAkBhE;;;;;OAKG;IACG,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwB1C;;;;;OAKG;IACG,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAc7C;;OAEG;IACH,OAAO,CAAC,WAAW;IAInB;;;;;;OAMG;IACH,OAAO,CAAC,WAAW;IAanB;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,aAAa;IAWrB;;;;;;;;OAQG;IACH,OAAO,CAAC,WAAW;CA4CpB"}