shieldcortex 4.28.1 → 4.29.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 (249) hide show
  1. package/dashboard/.next/standalone/dashboard/.next/BUILD_ID +1 -1
  2. package/dashboard/.next/standalone/dashboard/.next/build-manifest.json +2 -2
  3. package/dashboard/.next/standalone/dashboard/.next/prerender-manifest.json +3 -3
  4. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.html +2 -2
  5. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.rsc +1 -1
  6. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  7. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  8. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  9. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  10. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  11. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.html +2 -2
  12. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.rsc +1 -1
  13. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  14. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  15. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  16. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  17. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  18. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  19. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.html +1 -1
  20. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.rsc +1 -1
  21. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/!KGRhc2hib2FyZCk/admin/__PAGE__.segment.rsc +1 -1
  22. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/!KGRhc2hib2FyZCk/admin.segment.rsc +1 -1
  23. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  24. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_full.segment.rsc +1 -1
  25. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_head.segment.rsc +1 -1
  26. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_index.segment.rsc +1 -1
  27. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_tree.segment.rsc +1 -1
  28. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.html +1 -1
  29. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.rsc +1 -1
  30. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/!KGRhc2hib2FyZCk/cloud/__PAGE__.segment.rsc +1 -1
  31. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/!KGRhc2hib2FyZCk/cloud.segment.rsc +1 -1
  32. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  33. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_full.segment.rsc +1 -1
  34. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_head.segment.rsc +1 -1
  35. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_index.segment.rsc +1 -1
  36. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_tree.segment.rsc +1 -1
  37. package/dashboard/.next/standalone/dashboard/.next/server/app/index.html +1 -1
  38. package/dashboard/.next/standalone/dashboard/.next/server/app/index.rsc +1 -1
  39. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  40. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_full.segment.rsc +1 -1
  41. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_head.segment.rsc +1 -1
  42. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_index.segment.rsc +1 -1
  43. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  44. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.html +1 -1
  45. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.rsc +1 -1
  46. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk/memory/capture/__PAGE__.segment.rsc +1 -1
  47. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk/memory/capture.segment.rsc +1 -1
  48. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  49. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  50. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_full.segment.rsc +1 -1
  51. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_head.segment.rsc +1 -1
  52. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_index.segment.rsc +1 -1
  53. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_tree.segment.rsc +1 -1
  54. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.html +1 -1
  55. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.rsc +1 -1
  56. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk/memory/graph/__PAGE__.segment.rsc +1 -1
  57. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk/memory/graph.segment.rsc +1 -1
  58. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  59. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  60. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_full.segment.rsc +1 -1
  61. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_head.segment.rsc +1 -1
  62. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_index.segment.rsc +1 -1
  63. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_tree.segment.rsc +1 -1
  64. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.html +1 -1
  65. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.rsc +1 -1
  66. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk/memory/recall/__PAGE__.segment.rsc +1 -1
  67. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk/memory/recall.segment.rsc +1 -1
  68. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  69. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  70. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_full.segment.rsc +1 -1
  71. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_head.segment.rsc +1 -1
  72. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_index.segment.rsc +1 -1
  73. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_tree.segment.rsc +1 -1
  74. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.html +2 -2
  75. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.rsc +1 -1
  76. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/!KGRhc2hib2FyZCk/memory/replay/__PAGE__.segment.rsc +1 -1
  77. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/!KGRhc2hib2FyZCk/memory/replay.segment.rsc +1 -1
  78. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  79. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  80. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/_full.segment.rsc +1 -1
  81. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/_head.segment.rsc +1 -1
  82. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/_index.segment.rsc +1 -1
  83. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/_tree.segment.rsc +1 -1
  84. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.html +1 -1
  85. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.rsc +1 -1
  86. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk/memory/review/__PAGE__.segment.rsc +1 -1
  87. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk/memory/review.segment.rsc +1 -1
  88. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  89. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  90. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_full.segment.rsc +1 -1
  91. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_head.segment.rsc +1 -1
  92. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_index.segment.rsc +1 -1
  93. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_tree.segment.rsc +1 -1
  94. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.html +1 -1
  95. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.rsc +1 -1
  96. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk/memory/timeline/__PAGE__.segment.rsc +1 -1
  97. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk/memory/timeline.segment.rsc +1 -1
  98. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  99. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  100. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_full.segment.rsc +1 -1
  101. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_head.segment.rsc +1 -1
  102. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_index.segment.rsc +1 -1
  103. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_tree.segment.rsc +1 -1
  104. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.html +2 -2
  105. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.rsc +1 -1
  106. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/!KGRhc2hib2FyZCk/memory/__PAGE__.segment.rsc +1 -1
  107. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  108. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  109. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_full.segment.rsc +1 -1
  110. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_head.segment.rsc +1 -1
  111. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_index.segment.rsc +1 -1
  112. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_tree.segment.rsc +1 -1
  113. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.html +2 -2
  114. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.rsc +1 -1
  115. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/!KGRhc2hib2FyZCk/overview/__PAGE__.segment.rsc +1 -1
  116. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/!KGRhc2hib2FyZCk/overview.segment.rsc +1 -1
  117. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  118. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_full.segment.rsc +1 -1
  119. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_head.segment.rsc +1 -1
  120. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_index.segment.rsc +1 -1
  121. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_tree.segment.rsc +1 -1
  122. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.html +1 -1
  123. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.rsc +1 -1
  124. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk/protection/audit/__PAGE__.segment.rsc +1 -1
  125. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk/protection/audit.segment.rsc +1 -1
  126. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  127. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  128. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_full.segment.rsc +1 -1
  129. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_head.segment.rsc +1 -1
  130. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_index.segment.rsc +1 -1
  131. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_tree.segment.rsc +1 -1
  132. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.html +1 -1
  133. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.rsc +1 -1
  134. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk/protection/intercepts/__PAGE__.segment.rsc +1 -1
  135. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk/protection/intercepts.segment.rsc +1 -1
  136. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  137. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  138. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_full.segment.rsc +1 -1
  139. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_head.segment.rsc +1 -1
  140. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_index.segment.rsc +1 -1
  141. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_tree.segment.rsc +1 -1
  142. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.html +1 -1
  143. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.rsc +1 -1
  144. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk/protection/iron-dome/__PAGE__.segment.rsc +1 -1
  145. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk/protection/iron-dome.segment.rsc +1 -1
  146. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  147. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  148. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_full.segment.rsc +1 -1
  149. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_head.segment.rsc +1 -1
  150. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_index.segment.rsc +1 -1
  151. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_tree.segment.rsc +1 -1
  152. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.html +1 -1
  153. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.rsc +1 -1
  154. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk/protection/policies/__PAGE__.segment.rsc +1 -1
  155. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk/protection/policies.segment.rsc +1 -1
  156. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  157. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  158. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_full.segment.rsc +1 -1
  159. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_head.segment.rsc +1 -1
  160. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_index.segment.rsc +1 -1
  161. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_tree.segment.rsc +1 -1
  162. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.html +1 -1
  163. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.rsc +1 -1
  164. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk/protection/quarantine/__PAGE__.segment.rsc +1 -1
  165. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk/protection/quarantine.segment.rsc +1 -1
  166. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  167. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  168. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_full.segment.rsc +1 -1
  169. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_head.segment.rsc +1 -1
  170. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_index.segment.rsc +1 -1
  171. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_tree.segment.rsc +1 -1
  172. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.html +2 -2
  173. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.rsc +1 -1
  174. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/!KGRhc2hib2FyZCk/protection/__PAGE__.segment.rsc +1 -1
  175. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  176. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  177. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_full.segment.rsc +1 -1
  178. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_head.segment.rsc +1 -1
  179. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_index.segment.rsc +1 -1
  180. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_tree.segment.rsc +1 -1
  181. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.html +2 -2
  182. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.rsc +1 -1
  183. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/!KGRhc2hib2FyZCk/settings/__PAGE__.segment.rsc +1 -1
  184. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/!KGRhc2hib2FyZCk/settings.segment.rsc +1 -1
  185. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  186. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_full.segment.rsc +1 -1
  187. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  188. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_index.segment.rsc +1 -1
  189. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
  190. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.html +1 -1
  191. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.rsc +1 -1
  192. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk/supply-chain/xray/__PAGE__.segment.rsc +1 -1
  193. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk/supply-chain/xray.segment.rsc +1 -1
  194. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk/supply-chain.segment.rsc +1 -1
  195. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  196. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_full.segment.rsc +1 -1
  197. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_head.segment.rsc +1 -1
  198. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_index.segment.rsc +1 -1
  199. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_tree.segment.rsc +1 -1
  200. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.html +1 -1
  201. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.rsc +1 -1
  202. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/!KGRhc2hib2FyZCk/supply-chain/__PAGE__.segment.rsc +1 -1
  203. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/!KGRhc2hib2FyZCk/supply-chain.segment.rsc +1 -1
  204. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  205. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_full.segment.rsc +1 -1
  206. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_head.segment.rsc +1 -1
  207. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_index.segment.rsc +1 -1
  208. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_tree.segment.rsc +1 -1
  209. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.html +2 -2
  210. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.rsc +1 -1
  211. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/!KGRhc2hib2FyZCk/xray/__PAGE__.segment.rsc +1 -1
  212. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/!KGRhc2hib2FyZCk/xray.segment.rsc +1 -1
  213. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  214. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_full.segment.rsc +1 -1
  215. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_head.segment.rsc +1 -1
  216. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_index.segment.rsc +1 -1
  217. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_tree.segment.rsc +1 -1
  218. package/dashboard/.next/standalone/dashboard/.next/server/pages/404.html +2 -2
  219. package/dashboard/.next/standalone/dashboard/.next/server/pages/500.html +2 -2
  220. package/dashboard/.next/standalone/dashboard/.next/server/server-reference-manifest.js +1 -1
  221. package/dashboard/.next/standalone/dashboard/.next/server/server-reference-manifest.json +1 -1
  222. package/dist/cli/doctor.d.ts +17 -0
  223. package/dist/cli/doctor.js +44 -0
  224. package/dist/cli/memory.d.ts +23 -0
  225. package/dist/cli/memory.js +101 -0
  226. package/dist/database/init.d.ts +9 -0
  227. package/dist/database/init.js +32 -4
  228. package/dist/database/migrations.js +126 -0
  229. package/dist/memory/consolidate.d.ts +82 -6
  230. package/dist/memory/consolidate.js +287 -117
  231. package/dist/setup/openclaw.d.ts +26 -0
  232. package/dist/setup/openclaw.js +61 -0
  233. package/dist/tools/remember.js +24 -3
  234. package/hooks/openclaw/cortex-memory/handler.ts +223 -171
  235. package/hooks/openclaw/cortex-memory/runtime.mjs +64 -0
  236. package/package.json +1 -1
  237. package/scripts/lib/dedup.mjs +99 -0
  238. package/scripts/lib/openclaw-extract.mjs +129 -0
  239. package/scripts/lib/recall-log.mjs +16 -1
  240. package/scripts/lib/recall-relevance.mjs +191 -0
  241. package/scripts/lib/salience.mjs +8 -3
  242. package/scripts/lib/save-memory.mjs +62 -6
  243. package/scripts/lib/session-context.mjs +30 -0
  244. package/scripts/postinstall.mjs +29 -10
  245. package/scripts/prompt-recall-hook.mjs +118 -15
  246. package/scripts/session-start-hook.mjs +17 -6
  247. /package/dashboard/.next/standalone/dashboard/.next/static/{N9XiRuuRX4eTtiJFa43tY → 0HpUm8SRvm9fnWVO0OBB2}/_buildManifest.js +0 -0
  248. /package/dashboard/.next/standalone/dashboard/.next/static/{N9XiRuuRX4eTtiJFa43tY → 0HpUm8SRvm9fnWVO0OBB2}/_clientMiddlewareManifest.json +0 -0
  249. /package/dashboard/.next/standalone/dashboard/.next/static/{N9XiRuuRX4eTtiJFa43tY → 0HpUm8SRvm9fnWVO0OBB2}/_ssgManifest.js +0 -0
@@ -27,8 +27,42 @@ export declare function findDuplicateMemoryPairs(options?: {
27
27
  limit?: number;
28
28
  }): DuplicateMemoryPair[];
29
29
  /**
30
- * Find memories with very similar titles/content and merge them.
31
- * Keeps the newer one, appends unique content from the older one.
30
+ * De-duplicate long-term memories found as duplicate PAIRS by
31
+ * findDuplicateMemoryPairs (same project|category, similar title + >0.5 content
32
+ * overlap). Runs every ~4h on the auto path: server.ts setInterval → fullCleanup
33
+ * → consolidate → deduplicateMemories.
34
+ *
35
+ * B11 (memory-quality fix): the previous implementation built
36
+ * `kept.content + "\n\nMerged from duplicate:\n" + uniqueSentences` and wrote it
37
+ * back with `UPDATE memories SET content = ?`. That was the SECOND lossy-append
38
+ * site (mergeSimilarMemories was the first) and kept generating ever-growing
39
+ * "frankenmemories" on this path even after the first site was fixed. The kept
40
+ * memory's `content` is now NEVER modified.
41
+ *
42
+ * New policy (identical to mergeSimilarMemories — one source of truth):
43
+ * - KEEP the higher-EFFECTIVE-salience member of the pair (computeEffectiveSalience
44
+ * via the shared salience.mjs — recency/access/pin/downvote, same ranking as
45
+ * recall and the downvote CLI). NOTE: this can differ from the pair's raw
46
+ * `recommendedKeepId`, which only considered raw salience + recency.
47
+ * - Dispose the loser via the shared disposeLoser: combined similarity
48
+ * (re-measured vs the kept row) ≥ 0.85 → DELETE; below → DOWNVOTE (reversible).
49
+ * - Tags are unioned onto the kept row (metadata only, non-lossy). The kept
50
+ * content and salience are untouched.
51
+ *
52
+ * Defence re-scan removed (B11): the old re-scan existed ONLY to validate the
53
+ * SYNTHESIZED concatenated merged body before persisting it (two individually-
54
+ * clean rows could straddle a credential pattern across the join). Now that no
55
+ * concatenation happens here, there is no synthesized content to scan — the kept
56
+ * row's bytes are written verbatim and unchanged, exactly as they already exist
57
+ * in `memories`. So this pass introduces no new bytes to validate. (This is a
58
+ * narrow claim about THIS path: it does not assume every row was scanned at write
59
+ * time — e.g. importMemories inserts rows with no scan — only that the dedup no
60
+ * longer fabricates a new body that would need scanning.) Dropping the re-scan
61
+ * also avoids re-auditing unchanged content on every 4h pass.
62
+ *
63
+ * Only rows clustered in THIS pass are acted on; historical merged rows are not
64
+ * rewritten (effective salience demotes them over time). STM→LTM promotion is
65
+ * handled separately by processDecay/promoteMemory in consolidate().
32
66
  */
33
67
  export declare function deduplicateMemories(options?: {
34
68
  dryRun?: boolean;
@@ -55,10 +89,32 @@ export declare function clusterAndSummarise(options?: {
55
89
  */
56
90
  export declare function enforceMemoryLimits(config?: MemoryConfig): number;
57
91
  /**
58
- * Find and merge similar short-term memories into coherent long-term entries.
59
- * Groups memories by project|category, then clusters by Jaccard similarity
60
- * on content (0.6 weight) + title (0.4 weight).
61
- * Returns count of deleted (merged) memories.
92
+ * Find clusters of similar short-term memories within each project|category,
93
+ * KEEP the single highest-effective-salience member, and demote the rest
94
+ * WITHOUT destroying or concatenating their content.
95
+ *
96
+ * B11 (memory-quality fix): the previous implementation appended every loser's
97
+ * body into the kept memory ("Consolidated context:" bullets) and deleted the
98
+ * losers. Over ~417 live rows this produced 188 ever-growing "frankenmemories"
99
+ * — exactly the garbled content users complained about. The kept memory's
100
+ * `content` is now NEVER modified.
101
+ *
102
+ * Disposition per loser (see NEAR_IDENTICAL_DELETE_THRESHOLD):
103
+ * - combined ≥ 0.85 → DELETE (near-identical; content already in the kept row)
104
+ * - combined < 0.85 → DOWNVOTE (reversible; sinks via effective salience)
105
+ *
106
+ * Why the split exists at all: NO reaping path (decay.ts shouldDelete,
107
+ * prune.ts, expiry.ts, enforceMemoryLimits) reads `downvote_count` or effective
108
+ * salience — they all order by raw `salience`. So downvote-ONLY would leave the
109
+ * store unbounded (the dups sink in recall but never get pruned). Deleting the
110
+ * near-identical losers keeps the store bounded with zero information loss; the
111
+ * moderate near-dups are preserved and merely demoted.
112
+ *
113
+ * Tags are unioned onto the kept row and access counts summed (metadata only,
114
+ * non-lossy). STM→LTM promotion is handled separately by processDecay/
115
+ * promoteMemory in consolidate(); this function only de-duplicates.
116
+ *
117
+ * Returns the count of deleted (near-identical) losers.
62
118
  */
63
119
  export declare function mergeSimilarMemories(project?: string, similarityThreshold?: number): number;
64
120
  /**
@@ -144,5 +200,25 @@ export interface DreamModeResult {
144
200
  * 1. Find near-duplicates by embedding similarity >0.9, merge them
145
201
  * 2. Flag memories >30 days old with no access as archival candidates
146
202
  * 3. Detect and flag contradictions
203
+ *
204
+ * DISPOSAL POLICY — deliberately DIVERGES from the auto path:
205
+ * This is the EXPLICIT, user-invoked `shieldcortex consolidate` command (and the
206
+ * public `consolidateMemories` export). Because the user has actively asked for a
207
+ * consolidation, aggressive cleanup is the intended behaviour: the loser of every
208
+ * duplicate pair is HARD-DELETED. This is on purpose and must NOT be replaced with
209
+ * the gentle `disposeLoser` policy.
210
+ *
211
+ * Contrast with the 4-hourly AUTO path (deduplicateMemories / mergeSimilarMemories),
212
+ * which runs UNATTENDED and therefore uses the conservative `disposeLoser`: it only
213
+ * deletes near-identical losers (combined ≥ 0.85, content already contained in the
214
+ * kept row) and merely DOWNVOTES (reversible) the moderate near-dups. That caution
215
+ * is right for an unsupervised background job, but wrong for a deliberate manual
216
+ * cleanup the user explicitly triggered.
217
+ *
218
+ * The two paths DO share keep-selection: both pick the kept row by EFFECTIVE
219
+ * salience (effectiveSalienceOfRow — recency/access/pin/downvote), so the row that
220
+ * survives is consistent across all three dedup sites. Effective salience also
221
+ * discriminates where the pair's raw `recommendedKeepId` (raw salience + recency)
222
+ * ties at 1.0.
147
223
  */
148
224
  export declare function consolidateMemories(): DreamModeResult;
@@ -10,11 +10,21 @@
10
10
  import { getDatabase, withTransaction } from '../database/init.js';
11
11
  import { DEFAULT_CONFIG, } from './types.js';
12
12
  import { getMemoriesByType, getRecentMemories, promoteMemory, deleteMemory, searchMemories, getMemoryStats, updateDecayScores, addMemory, rowToMemory, } from './store.js';
13
- import { runDefencePipeline } from '../defence/index.js';
14
13
  import { processDecay, } from './decay.js';
15
14
  import { detectContradictions, linkContradictions, } from './contradiction.js';
16
15
  import { jaccardSimilarity } from './similarity.js';
17
16
  import { pruneActivationCache } from './activation.js';
17
+ // Static import of the shared effective-salience helper. Every other src/ file
18
+ // (cli/memory.ts, the recall hook) reaches salience.mjs via a relative path
19
+ // because `scripts/` lives outside tsconfig's rootDir; a static top-level
20
+ // import compiles clean (tsc keeps the dist layout intact and emits the same
21
+ // '../../scripts/lib/salience.mjs' specifier the dynamic import did) and lets
22
+ // these consolidation functions stay SYNCHRONOUS — better-sqlite3 transactions
23
+ // cannot await, and consolidate()/deduplicateMemories() have several sync
24
+ // callers. One source of truth: this is the same computeEffectiveSalience the
25
+ // recall hook and `shieldcortex memory downvote` use.
26
+ // @ts-expect-error — importing a .mjs hook util that has no .d.ts
27
+ import { computeEffectiveSalience } from '../../scripts/lib/salience.mjs';
18
28
  /**
19
29
  * Run full consolidation process
20
30
  * This is like the brain's sleep consolidation - should be run periodically
@@ -254,49 +264,80 @@ export function findDuplicateMemoryPairs(options) {
254
264
  return pairs;
255
265
  }
256
266
  /**
257
- * Find memories with very similar titles/content and merge them.
258
- * Keeps the newer one, appends unique content from the older one.
267
+ * De-duplicate long-term memories found as duplicate PAIRS by
268
+ * findDuplicateMemoryPairs (same project|category, similar title + >0.5 content
269
+ * overlap). Runs every ~4h on the auto path: server.ts setInterval → fullCleanup
270
+ * → consolidate → deduplicateMemories.
271
+ *
272
+ * B11 (memory-quality fix): the previous implementation built
273
+ * `kept.content + "\n\nMerged from duplicate:\n" + uniqueSentences` and wrote it
274
+ * back with `UPDATE memories SET content = ?`. That was the SECOND lossy-append
275
+ * site (mergeSimilarMemories was the first) and kept generating ever-growing
276
+ * "frankenmemories" on this path even after the first site was fixed. The kept
277
+ * memory's `content` is now NEVER modified.
278
+ *
279
+ * New policy (identical to mergeSimilarMemories — one source of truth):
280
+ * - KEEP the higher-EFFECTIVE-salience member of the pair (computeEffectiveSalience
281
+ * via the shared salience.mjs — recency/access/pin/downvote, same ranking as
282
+ * recall and the downvote CLI). NOTE: this can differ from the pair's raw
283
+ * `recommendedKeepId`, which only considered raw salience + recency.
284
+ * - Dispose the loser via the shared disposeLoser: combined similarity
285
+ * (re-measured vs the kept row) ≥ 0.85 → DELETE; below → DOWNVOTE (reversible).
286
+ * - Tags are unioned onto the kept row (metadata only, non-lossy). The kept
287
+ * content and salience are untouched.
288
+ *
289
+ * Defence re-scan removed (B11): the old re-scan existed ONLY to validate the
290
+ * SYNTHESIZED concatenated merged body before persisting it (two individually-
291
+ * clean rows could straddle a credential pattern across the join). Now that no
292
+ * concatenation happens here, there is no synthesized content to scan — the kept
293
+ * row's bytes are written verbatim and unchanged, exactly as they already exist
294
+ * in `memories`. So this pass introduces no new bytes to validate. (This is a
295
+ * narrow claim about THIS path: it does not assume every row was scanned at write
296
+ * time — e.g. importMemories inserts rows with no scan — only that the dedup no
297
+ * longer fabricates a new body that would need scanning.) Dropping the re-scan
298
+ * also avoids re-auditing unchanged content on every 4h pass.
299
+ *
300
+ * Only rows clustered in THIS pass are acted on; historical merged rows are not
301
+ * rewritten (effective salience demotes them over time). STM→LTM promotion is
302
+ * handled separately by processDecay/promoteMemory in consolidate().
259
303
  */
260
304
  export function deduplicateMemories(options) {
261
305
  const dryRun = options?.dryRun ?? false;
262
306
  return withTransaction(() => {
263
307
  const db = getDatabase();
264
308
  const pairs = [];
265
- const removed = new Set();
309
+ const disposed = new Set();
310
+ const nowIso = new Date().toISOString();
311
+ const downvoteStmt = db.prepare(DOWNVOTE_SQL);
312
+ // findDuplicateMemoryPairs returns rowToMemory-converted objects, which omit
313
+ // downvote_count. Fetch raw rows on demand so effective-salience ranking and
314
+ // the loser disposal see the full signal.
315
+ const rawRowStmt = db.prepare('SELECT * FROM memories WHERE id = ?');
316
+ const rawRow = (id) => rawRowStmt.get(id);
266
317
  for (const pair of findDuplicateMemoryPairs()) {
267
- if (removed.has(pair.memoryA.id) || removed.has(pair.memoryB.id))
318
+ if (disposed.has(pair.memoryA.id) || disposed.has(pair.memoryB.id))
268
319
  continue;
269
- const removedId = pair.recommendedKeepId === pair.memoryA.id ? pair.memoryB.id : pair.memoryA.id;
320
+ const rowA = rawRow(pair.memoryA.id);
321
+ const rowB = rawRow(pair.memoryB.id);
322
+ if (!rowA || !rowB)
323
+ continue; // already gone (e.g. deleted earlier this pass)
324
+ // KEEP the higher-effective-salience member (tie → keep A, the older row
325
+ // by findDuplicateMemoryPairs' created_at ASC ordering).
326
+ const keepA = effectiveSalienceOfRow(rowA) >= effectiveSalienceOfRow(rowB);
327
+ const kept = keepA ? pair.memoryA : pair.memoryB;
328
+ const loser = keepA ? pair.memoryB : pair.memoryA;
270
329
  if (!dryRun) {
271
- const kept = pair.recommendedKeepId === pair.memoryA.id ? pair.memoryA : pair.memoryB;
272
- const discarded = pair.recommendedKeepId === pair.memoryA.id ? pair.memoryB : pair.memoryA;
273
- const keptSentences = new Set(kept.content.split(/[.!?\n]+/).map(s => s.trim().toLowerCase()).filter(s => s.length > 0));
274
- const uniqueSentences = discarded.content
275
- .split(/[.!?\n]+/)
276
- .map(s => s.trim())
277
- .filter(s => s.length > 0 && !keptSentences.has(s.toLowerCase()));
278
- if (uniqueSentences.length > 0) {
279
- const mergedContent = kept.content + '\n\nMerged from duplicate:\n' + uniqueSentences.join('. ') + '.';
280
- // DEFENCE PIPELINE: re-scan the merged content. Two individually-clean
281
- // memories can produce content that straddles a credential pattern
282
- // across the join. Without this re-scan the "every byte in `memories`
283
- // has been scanned" invariant is broken. If the merge is blocked, skip
284
- // both the content update AND the delete so the source rows survive.
285
- const dedupSource = { type: 'hook', identifier: 'hook:consolidation' };
286
- const defenceResult = runDefencePipeline(mergedContent, kept.title, dedupSource, undefined, kept.project ?? discarded.project ?? undefined);
287
- if (defenceResult.firewall.result !== 'ALLOW') {
288
- // Surface in audit (already written by the pipeline) and skip this pair.
289
- console.warn(`[shieldcortex] Dedup merge blocked for memory ${kept.id} + ${removedId}: ${defenceResult.firewall.reason}`);
290
- continue;
291
- }
292
- db.prepare('UPDATE memories SET content = ? WHERE id = ?').run(mergedContent, kept.id);
293
- }
294
- deleteMemory(removedId);
330
+ // Union the loser's tags onto the kept row (metadata only, non-lossy).
331
+ const mergedTags = [...new Set([...kept.tags, ...loser.tags])];
332
+ db.prepare('UPDATE memories SET tags = ? WHERE id = ?')
333
+ .run(JSON.stringify(mergedTags), kept.id);
334
+ // Shared disposal policy — identical to mergeSimilarMemories.
335
+ disposeLoser({ content: kept.content, title: kept.title }, { id: loser.id, content: loser.content, title: loser.title }, downvoteStmt, nowIso);
295
336
  }
296
- removed.add(removedId);
337
+ disposed.add(loser.id);
297
338
  pairs.push({
298
- kept: pair.recommendedKeepId,
299
- removed: removedId,
339
+ kept: kept.id,
340
+ removed: loser.id,
300
341
  similarity: pair.similarity,
301
342
  });
302
343
  }
@@ -422,10 +463,79 @@ export function enforceMemoryLimits(config = DEFAULT_CONFIG) {
422
463
  return deleted;
423
464
  }
424
465
  /**
425
- * Find and merge similar short-term memories into coherent long-term entries.
426
- * Groups memories by project|category, then clusters by Jaccard similarity
427
- * on content (0.6 weight) + title (0.4 weight).
428
- * Returns count of deleted (merged) memories.
466
+ * Combined-similarity bar at/above which a clustered loser is considered a
467
+ * NEAR-IDENTICAL duplicate of the kept memory. Such a loser's content is, by
468
+ * construction, almost entirely contained in the kept memory, so deleting it
469
+ * loses no real information this is the non-lossy successor to the old
470
+ * concatenate-then-delete behaviour, minus the concatenation. Moderate
471
+ * near-dups (similarityThreshold ≤ combined < this) keep some distinct content,
472
+ * so we DOWNVOTE rather than delete them (reversible, non-lossy).
473
+ */
474
+ const NEAR_IDENTICAL_DELETE_THRESHOLD = 0.85;
475
+ /**
476
+ * Effective salience of a raw `memories` row, via the shared
477
+ * scripts/lib/salience.mjs helper (recency × access × pin × downvote_penalty).
478
+ * One source of truth with recall ranking and the `shieldcortex memory
479
+ * downvote` CLI, so "highest-salience to keep" and "downvoted to demote" agree.
480
+ */
481
+ function effectiveSalienceOfRow(m) {
482
+ return computeEffectiveSalience({
483
+ salience: m.salience ?? 0,
484
+ last_accessed: m.last_accessed ?? null,
485
+ access_count: m.access_count ?? 0,
486
+ pinned: m.pinned ?? 0,
487
+ downvote_count: m.downvote_count ?? 0,
488
+ });
489
+ }
490
+ function disposeLoser(kept, loser, downvoteStmt, nowIso) {
491
+ const cSim = jaccardSimilarity(kept.content, loser.content);
492
+ const tSim = jaccardSimilarity(kept.title, loser.title);
493
+ const combinedToKept = cSim * 0.6 + tSim * 0.4;
494
+ if (combinedToKept >= NEAR_IDENTICAL_DELETE_THRESHOLD) {
495
+ deleteMemory(loser.id);
496
+ return 'deleted';
497
+ }
498
+ downvoteStmt.run(nowIso, loser.id);
499
+ return 'downvoted';
500
+ }
501
+ /**
502
+ * The shared downvote SQL — prepared once per pass by each caller and handed to
503
+ * disposeLoser. Reversible soft demotion: bumps downvote_count (effective
504
+ * salience reads it) and stamps last_downvoted_at.
505
+ */
506
+ const DOWNVOTE_SQL = `
507
+ UPDATE memories
508
+ SET downvote_count = COALESCE(downvote_count, 0) + 1,
509
+ last_downvoted_at = ?
510
+ WHERE id = ?
511
+ `;
512
+ /**
513
+ * Find clusters of similar short-term memories within each project|category,
514
+ * KEEP the single highest-effective-salience member, and demote the rest
515
+ * WITHOUT destroying or concatenating their content.
516
+ *
517
+ * B11 (memory-quality fix): the previous implementation appended every loser's
518
+ * body into the kept memory ("Consolidated context:" bullets) and deleted the
519
+ * losers. Over ~417 live rows this produced 188 ever-growing "frankenmemories"
520
+ * — exactly the garbled content users complained about. The kept memory's
521
+ * `content` is now NEVER modified.
522
+ *
523
+ * Disposition per loser (see NEAR_IDENTICAL_DELETE_THRESHOLD):
524
+ * - combined ≥ 0.85 → DELETE (near-identical; content already in the kept row)
525
+ * - combined < 0.85 → DOWNVOTE (reversible; sinks via effective salience)
526
+ *
527
+ * Why the split exists at all: NO reaping path (decay.ts shouldDelete,
528
+ * prune.ts, expiry.ts, enforceMemoryLimits) reads `downvote_count` or effective
529
+ * salience — they all order by raw `salience`. So downvote-ONLY would leave the
530
+ * store unbounded (the dups sink in recall but never get pruned). Deleting the
531
+ * near-identical losers keeps the store bounded with zero information loss; the
532
+ * moderate near-dups are preserved and merely demoted.
533
+ *
534
+ * Tags are unioned onto the kept row and access counts summed (metadata only,
535
+ * non-lossy). STM→LTM promotion is handled separately by processDecay/
536
+ * promoteMemory in consolidate(); this function only de-duplicates.
537
+ *
538
+ * Returns the count of deleted (near-identical) losers.
429
539
  */
430
540
  export function mergeSimilarMemories(project, similarityThreshold = 0.25) {
431
541
  return withTransaction(() => {
@@ -466,6 +576,21 @@ export function mergeSimilarMemories(project, similarityThreshold = 0.25) {
466
576
  const contentSim = jaccardSimilarity(memA.content, memB.content);
467
577
  const titleSim = jaccardSimilarity(memA.title, memB.title);
468
578
  const combinedSim = contentSim * 0.6 + titleSim * 0.4;
579
+ // THRESHOLD RECONCILIATION (B11, reconciled with Task 8's write-path
580
+ // dedup):
581
+ // - Task 8's write-path SKIP fires at combined ≥ 0.5 and is STRICT
582
+ // because skipping a write is IRREVERSIBLE data loss — the memory
583
+ // is never stored.
584
+ // - Consolidate stays AGGRESSIVE at 0.25 because its action is now
585
+ // REVERSIBLE: moderate near-dups are DOWNVOTED — a soft demotion
586
+ // that leaves the row + its content intact (clearing
587
+ // downvote_count restores the prior ranking), not the old
588
+ // concatenate-into-kept + delete, which destroyed data.
589
+ // The two thresholds no longer conflict: a pair at combined ~0.3
590
+ // (below the 0.5 write-skip, above this 0.25 bar) survives the
591
+ // write but is demoted here via reversible downvote. Only
592
+ // near-IDENTICAL losers (≥ 0.85, content already in the kept row)
593
+ // are deleted — see NEAR_IDENTICAL_DELETE_THRESHOLD.
469
594
  if (combinedSim >= similarityThreshold) {
470
595
  cluster.push(j);
471
596
  }
@@ -475,18 +600,17 @@ export function mergeSimilarMemories(project, similarityThreshold = 0.25) {
475
600
  // Mark all as clustered
476
601
  for (const idx of cluster)
477
602
  clustered.add(idx);
478
- // Step 4: Merge cluster
479
- // Sort by salience desc, pick highest as base
603
+ // Step 4: Resolve the cluster WITHOUT lossy concatenation.
604
+ // KEEP the single highest-EFFECTIVE-salience member (downvotes,
605
+ // recency, pins and access all factor in — same ranking the recall
606
+ // hook uses). The kept row's `content` is NEVER touched.
480
607
  const clusterMems = cluster.map(idx => group[idx]);
481
- clusterMems.sort((a, b) => b.salience - a.salience);
482
- const base = clusterMems[0];
483
- const others = clusterMems.slice(1);
484
- // Merge content
485
- const bulletPoints = others
486
- .map(m => `- ${m.title}: ${m.content}`)
487
- .join('\n');
488
- const mergedContent = `${base.content}\n\nConsolidated context:\n${bulletPoints}`;
489
- // Merge tags (union)
608
+ clusterMems.sort((a, b) => effectiveSalienceOfRow(b) - effectiveSalienceOfRow(a));
609
+ const kept = clusterMems[0];
610
+ const losers = clusterMems.slice(1);
611
+ // Merge tags onto the kept row (union — metadata only, non-lossy) and
612
+ // accumulate the losers' access counts so reinforcement history isn't
613
+ // lost. The kept content and salience stay exactly as they were.
490
614
  const allTags = new Set();
491
615
  for (const m of clusterMems) {
492
616
  try {
@@ -498,24 +622,31 @@ export function mergeSimilarMemories(project, similarityThreshold = 0.25) {
498
622
  // skip invalid tags
499
623
  }
500
624
  }
501
- // Sum access counts
502
625
  const totalAccessCount = clusterMems.reduce((sum, m) => sum + (m.access_count || 0), 0);
503
- // New salience: base + 0.1, capped at 1.0
504
- const newSalience = Math.min(1.0, base.salience + 0.1);
505
- // Update base memory
626
+ // Promote the kept memory to long-term and absorb the union'd tags +
627
+ // summed access count. NOTE: content is deliberately omitted from this
628
+ // UPDATE no frankenmerge.
506
629
  db.prepare(`
507
630
  UPDATE memories
508
631
  SET type = 'long_term',
509
- content = ?,
510
632
  tags = ?,
511
- salience = ?,
512
633
  access_count = ?
513
634
  WHERE id = ?
514
- `).run(mergedContent, JSON.stringify([...allTags]), newSalience, totalAccessCount, base.id);
515
- // Delete others
516
- for (const other of others) {
517
- deleteMemory(other.id);
518
- deleted++;
635
+ `).run(JSON.stringify([...allTags]), totalAccessCount, kept.id);
636
+ // Dispose of each loser via the SHARED disposal policy (disposeLoser):
637
+ // near-identical ( 0.85 vs the kept row) → DELETE; moderate → DOWNVOTE.
638
+ // Identical policy to deduplicateMemories — one source of truth.
639
+ const nowIso = new Date().toISOString();
640
+ const downvoteStmt = db.prepare(DOWNVOTE_SQL);
641
+ const keptText = { content: kept.content, title: kept.title };
642
+ for (const loser of losers) {
643
+ const disposition = disposeLoser(keptText, {
644
+ id: loser.id,
645
+ content: loser.content,
646
+ title: loser.title,
647
+ }, downvoteStmt, nowIso);
648
+ if (disposition === 'deleted')
649
+ deleted++;
519
650
  }
520
651
  }
521
652
  }
@@ -782,70 +913,109 @@ export function fullCleanup(config = DEFAULT_CONFIG) {
782
913
  * 1. Find near-duplicates by embedding similarity >0.9, merge them
783
914
  * 2. Flag memories >30 days old with no access as archival candidates
784
915
  * 3. Detect and flag contradictions
916
+ *
917
+ * DISPOSAL POLICY — deliberately DIVERGES from the auto path:
918
+ * This is the EXPLICIT, user-invoked `shieldcortex consolidate` command (and the
919
+ * public `consolidateMemories` export). Because the user has actively asked for a
920
+ * consolidation, aggressive cleanup is the intended behaviour: the loser of every
921
+ * duplicate pair is HARD-DELETED. This is on purpose and must NOT be replaced with
922
+ * the gentle `disposeLoser` policy.
923
+ *
924
+ * Contrast with the 4-hourly AUTO path (deduplicateMemories / mergeSimilarMemories),
925
+ * which runs UNATTENDED and therefore uses the conservative `disposeLoser`: it only
926
+ * deletes near-identical losers (combined ≥ 0.85, content already contained in the
927
+ * kept row) and merely DOWNVOTES (reversible) the moderate near-dups. That caution
928
+ * is right for an unsupervised background job, but wrong for a deliberate manual
929
+ * cleanup the user explicitly triggered.
930
+ *
931
+ * The two paths DO share keep-selection: both pick the kept row by EFFECTIVE
932
+ * salience (effectiveSalienceOfRow — recency/access/pin/downvote), so the row that
933
+ * survives is consistent across all three dedup sites. Effective salience also
934
+ * discriminates where the pair's raw `recommendedKeepId` (raw salience + recency)
935
+ * ties at 1.0.
785
936
  */
786
937
  export function consolidateMemories() {
787
- const db = getDatabase();
788
- let nearDuplicatesMerged = 0;
789
- let archivalCandidates = 0;
790
- let contradictionsDetected = 0;
791
- // Step 1: Find and merge near-duplicates
792
- const duplicatePairs = findDuplicateMemoryPairs({ limit: 100 });
793
- for (const pair of duplicatePairs) {
794
- try {
795
- const memA = pair.memoryA;
796
- const memB = pair.memoryB;
797
- if (!memA || !memB)
798
- continue;
799
- // Keep the recommended one, delete the other
800
- const removedId = pair.recommendedKeepId === memA.id ? memB.id : memA.id;
801
- const keptId = pair.recommendedKeepId;
802
- // Merge tags from both
803
- const kept = keptId === memA.id ? memA : memB;
804
- const removed = keptId === memA.id ? memB : memA;
805
- const mergedTags = [...new Set([...kept.tags, ...removed.tags])];
806
- db.prepare('UPDATE memories SET tags = ? WHERE id = ?')
807
- .run(JSON.stringify(mergedTags), keptId);
808
- deleteMemory(removedId);
809
- nearDuplicatesMerged++;
938
+ // Wrap the dedup delete loop in a transaction for atomicity: previously each
939
+ // pair was deleted on a bare getDatabase() with no transaction, so a mid-loop
940
+ // failure left partial deletes (some losers gone, tag-merges half-applied).
941
+ return withTransaction(() => {
942
+ const db = getDatabase();
943
+ let nearDuplicatesMerged = 0;
944
+ let archivalCandidates = 0;
945
+ let contradictionsDetected = 0;
946
+ // findDuplicateMemoryPairs returns rowToMemory-converted objects, which omit
947
+ // downvote_count. Fetch raw rows on demand so effective-salience keep-selection
948
+ // sees the full signal (same pattern as deduplicateMemories).
949
+ const rawRowStmt = db.prepare('SELECT * FROM memories WHERE id = ?');
950
+ const rawRow = (id) => rawRowStmt.get(id);
951
+ // Step 1: Find and merge near-duplicates
952
+ const duplicatePairs = findDuplicateMemoryPairs({ limit: 100 });
953
+ for (const pair of duplicatePairs) {
954
+ try {
955
+ const memA = pair.memoryA;
956
+ const memB = pair.memoryB;
957
+ if (!memA || !memB)
958
+ continue;
959
+ // KEEP the higher-EFFECTIVE-salience member (recency/access/pin/downvote),
960
+ // consistent with deduplicateMemories and mergeSimilarMemories — one source
961
+ // of truth via effectiveSalienceOfRow. This can differ from the pair's raw
962
+ // `recommendedKeepId` (raw salience + recency), which can't break a 1.0 tie.
963
+ const rowA = rawRow(memA.id);
964
+ const rowB = rawRow(memB.id);
965
+ if (!rowA || !rowB)
966
+ continue; // already gone (deleted earlier this pass)
967
+ // Tie → keep A (the older row by findDuplicateMemoryPairs' created_at ASC).
968
+ const keepA = effectiveSalienceOfRow(rowA) >= effectiveSalienceOfRow(rowB);
969
+ const kept = keepA ? memA : memB;
970
+ const removed = keepA ? memB : memA;
971
+ // Merge tags from both onto the kept row (metadata only, non-lossy).
972
+ const mergedTags = [...new Set([...kept.tags, ...removed.tags])];
973
+ db.prepare('UPDATE memories SET tags = ? WHERE id = ?')
974
+ .run(JSON.stringify(mergedTags), kept.id);
975
+ // Aggressive hard-DELETE of the loser — intended for this manual command
976
+ // (see the disposal-policy note in the function header).
977
+ deleteMemory(removed.id);
978
+ nearDuplicatesMerged++;
979
+ }
980
+ catch {
981
+ // Skip problematic pairs
982
+ }
810
983
  }
811
- catch {
812
- // Skip problematic pairs
984
+ // Step 2: Flag stale memories for archival (>30 days, no access)
985
+ const thirtyDaysAgo = new Date(Date.now() - 30 * 86_400_000).toISOString();
986
+ const staleRows = db.prepare(`
987
+ SELECT id FROM memories
988
+ WHERE status = 'active'
989
+ AND last_accessed < ?
990
+ AND access_count <= 1
991
+ AND pinned = 0
992
+ `).all(thirtyDaysAgo);
993
+ for (const row of staleRows) {
994
+ try {
995
+ db.prepare("UPDATE memories SET status = 'archived', updated_at = CURRENT_TIMESTAMP WHERE id = ?")
996
+ .run(row.id);
997
+ archivalCandidates++;
998
+ }
999
+ catch {
1000
+ // Skip
1001
+ }
813
1002
  }
814
- }
815
- // Step 2: Flag stale memories for archival (>30 days, no access)
816
- const thirtyDaysAgo = new Date(Date.now() - 30 * 86_400_000).toISOString();
817
- const staleRows = db.prepare(`
818
- SELECT id FROM memories
819
- WHERE status = 'active'
820
- AND last_accessed < ?
821
- AND access_count <= 1
822
- AND pinned = 0
823
- `).all(thirtyDaysAgo);
824
- for (const row of staleRows) {
1003
+ // Step 3: Detect contradictions
825
1004
  try {
826
- db.prepare("UPDATE memories SET status = 'archived', updated_at = CURRENT_TIMESTAMP WHERE id = ?")
827
- .run(row.id);
828
- archivalCandidates++;
1005
+ const contradictions = detectContradictions();
1006
+ if (contradictions.length > 0) {
1007
+ contradictionsDetected = linkContradictions(contradictions);
1008
+ }
829
1009
  }
830
1010
  catch {
831
- // Skip
1011
+ // Contradiction detection may fail on empty/small DBs
832
1012
  }
833
- }
834
- // Step 3: Detect contradictions
835
- try {
836
- const contradictions = detectContradictions();
837
- if (contradictions.length > 0) {
838
- contradictionsDetected = linkContradictions(contradictions);
839
- }
840
- }
841
- catch {
842
- // Contradiction detection may fail on empty/small DBs
843
- }
844
- const totalProcessed = duplicatePairs.length + staleRows.length;
845
- return {
846
- nearDuplicatesMerged,
847
- archivalCandidates,
848
- contradictionsDetected,
849
- totalProcessed,
850
- };
1013
+ const totalProcessed = duplicatePairs.length + staleRows.length;
1014
+ return {
1015
+ nearDuplicatesMerged,
1016
+ archivalCandidates,
1017
+ contradictionsDetected,
1018
+ totalProcessed,
1019
+ };
1020
+ });
851
1021
  }
@@ -20,6 +20,32 @@ export declare function isDockerEnvironment(): boolean;
20
20
  * Creates the hooks/ subdirectory if the parent config dir exists.
21
21
  */
22
22
  export declare function findAllHooksDirs(): string[];
23
+ /**
24
+ * The standard installed-hook destination: `~/.openclaw/hooks/cortex-memory`.
25
+ * Resolves the real user's home (sudo-aware) so doctor/postinstall agree with
26
+ * the install path.
27
+ */
28
+ export declare function defaultHookDestDir(): string;
29
+ /**
30
+ * Single source of truth for "the installed hook copy is out of date".
31
+ *
32
+ * The cortex-memory hook is installed by FILE COPY (see `copyHookFiles`) into
33
+ * `~/.openclaw/hooks/cortex-memory/`. A package update does NOT automatically
34
+ * re-copy it, so the installed `handler.ts` / `runtime.mjs` can drift behind
35
+ * the package's `HOOK_SOURCE` version. This compares every HOOK_FILE in
36
+ * `destDir` against the packaged source by content.
37
+ *
38
+ * Pure + synchronous (fs reads only, no writes, no side effects). Returns
39
+ * `true` if any required file is missing from `destDir` OR differs byte-for-byte
40
+ * from the packaged source. Returns `false` only when every file is present and
41
+ * identical. On any unexpected read error it returns `true` (fail toward
42
+ * "refresh needed") so a half-readable install is never reported as current.
43
+ *
44
+ * If the package's own `HOOK_SOURCE` is missing (corrupt/partial package), the
45
+ * comparison is impossible, so this returns `false` — we can't claim the
46
+ * install is stale relative to a source we can't read.
47
+ */
48
+ export declare function hookFilesStale(destDir?: string): boolean;
23
49
  /**
24
50
  * Pure idempotency check for the openclaw.json plugin registration.
25
51
  *