shieldcortex 4.24.3 → 4.25.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) 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/server/app/_global-error.html +2 -2
  4. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.rsc +1 -1
  5. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  6. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  7. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  8. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  9. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  10. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.html +2 -2
  11. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.rsc +1 -1
  12. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  13. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  14. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  15. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  16. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  17. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  18. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.html +1 -1
  19. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.rsc +1 -1
  20. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/!KGRhc2hib2FyZCk/admin/__PAGE__.segment.rsc +1 -1
  21. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/!KGRhc2hib2FyZCk/admin.segment.rsc +1 -1
  22. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  23. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_full.segment.rsc +1 -1
  24. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_head.segment.rsc +1 -1
  25. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_index.segment.rsc +1 -1
  26. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_tree.segment.rsc +1 -1
  27. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.html +1 -1
  28. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.rsc +1 -1
  29. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/!KGRhc2hib2FyZCk/cloud/__PAGE__.segment.rsc +1 -1
  30. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/!KGRhc2hib2FyZCk/cloud.segment.rsc +1 -1
  31. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  32. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_full.segment.rsc +1 -1
  33. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_head.segment.rsc +1 -1
  34. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_index.segment.rsc +1 -1
  35. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_tree.segment.rsc +1 -1
  36. package/dashboard/.next/standalone/dashboard/.next/server/app/index.html +1 -1
  37. package/dashboard/.next/standalone/dashboard/.next/server/app/index.rsc +1 -1
  38. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  39. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_full.segment.rsc +1 -1
  40. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_head.segment.rsc +1 -1
  41. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_index.segment.rsc +1 -1
  42. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  43. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.html +1 -1
  44. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.rsc +1 -1
  45. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk/memory/capture/__PAGE__.segment.rsc +1 -1
  46. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk/memory/capture.segment.rsc +1 -1
  47. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  48. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  49. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_full.segment.rsc +1 -1
  50. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_head.segment.rsc +1 -1
  51. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_index.segment.rsc +1 -1
  52. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_tree.segment.rsc +1 -1
  53. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.html +1 -1
  54. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.rsc +1 -1
  55. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk/memory/graph/__PAGE__.segment.rsc +1 -1
  56. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk/memory/graph.segment.rsc +1 -1
  57. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  58. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  59. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_full.segment.rsc +1 -1
  60. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_head.segment.rsc +1 -1
  61. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_index.segment.rsc +1 -1
  62. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_tree.segment.rsc +1 -1
  63. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.html +1 -1
  64. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.rsc +1 -1
  65. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk/memory/recall/__PAGE__.segment.rsc +1 -1
  66. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk/memory/recall.segment.rsc +1 -1
  67. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  68. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  69. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_full.segment.rsc +1 -1
  70. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_head.segment.rsc +1 -1
  71. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_index.segment.rsc +1 -1
  72. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_tree.segment.rsc +1 -1
  73. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.html +2 -2
  74. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.rsc +1 -1
  75. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/!KGRhc2hib2FyZCk/memory/replay/__PAGE__.segment.rsc +1 -1
  76. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/!KGRhc2hib2FyZCk/memory/replay.segment.rsc +1 -1
  77. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  78. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  79. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/_full.segment.rsc +1 -1
  80. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/_head.segment.rsc +1 -1
  81. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/_index.segment.rsc +1 -1
  82. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/_tree.segment.rsc +1 -1
  83. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.html +1 -1
  84. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.rsc +1 -1
  85. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk/memory/review/__PAGE__.segment.rsc +1 -1
  86. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk/memory/review.segment.rsc +1 -1
  87. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  88. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  89. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_full.segment.rsc +1 -1
  90. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_head.segment.rsc +1 -1
  91. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_index.segment.rsc +1 -1
  92. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_tree.segment.rsc +1 -1
  93. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.html +1 -1
  94. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.rsc +1 -1
  95. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk/memory/timeline/__PAGE__.segment.rsc +1 -1
  96. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk/memory/timeline.segment.rsc +1 -1
  97. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  98. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  99. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_full.segment.rsc +1 -1
  100. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_head.segment.rsc +1 -1
  101. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_index.segment.rsc +1 -1
  102. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_tree.segment.rsc +1 -1
  103. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.html +2 -2
  104. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.rsc +1 -1
  105. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/!KGRhc2hib2FyZCk/memory/__PAGE__.segment.rsc +1 -1
  106. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  107. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  108. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_full.segment.rsc +1 -1
  109. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_head.segment.rsc +1 -1
  110. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_index.segment.rsc +1 -1
  111. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_tree.segment.rsc +1 -1
  112. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.html +2 -2
  113. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.rsc +1 -1
  114. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/!KGRhc2hib2FyZCk/overview/__PAGE__.segment.rsc +1 -1
  115. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/!KGRhc2hib2FyZCk/overview.segment.rsc +1 -1
  116. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  117. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_full.segment.rsc +1 -1
  118. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_head.segment.rsc +1 -1
  119. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_index.segment.rsc +1 -1
  120. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_tree.segment.rsc +1 -1
  121. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.html +1 -1
  122. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.rsc +1 -1
  123. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk/protection/audit/__PAGE__.segment.rsc +1 -1
  124. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk/protection/audit.segment.rsc +1 -1
  125. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  126. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  127. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_full.segment.rsc +1 -1
  128. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_head.segment.rsc +1 -1
  129. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_index.segment.rsc +1 -1
  130. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_tree.segment.rsc +1 -1
  131. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.html +1 -1
  132. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.rsc +1 -1
  133. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk/protection/intercepts/__PAGE__.segment.rsc +1 -1
  134. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk/protection/intercepts.segment.rsc +1 -1
  135. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  136. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  137. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_full.segment.rsc +1 -1
  138. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_head.segment.rsc +1 -1
  139. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_index.segment.rsc +1 -1
  140. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_tree.segment.rsc +1 -1
  141. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.html +1 -1
  142. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.rsc +1 -1
  143. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk/protection/iron-dome/__PAGE__.segment.rsc +1 -1
  144. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk/protection/iron-dome.segment.rsc +1 -1
  145. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  146. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  147. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_full.segment.rsc +1 -1
  148. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_head.segment.rsc +1 -1
  149. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_index.segment.rsc +1 -1
  150. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_tree.segment.rsc +1 -1
  151. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.html +1 -1
  152. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.rsc +1 -1
  153. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk/protection/policies/__PAGE__.segment.rsc +1 -1
  154. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk/protection/policies.segment.rsc +1 -1
  155. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  156. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  157. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_full.segment.rsc +1 -1
  158. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_head.segment.rsc +1 -1
  159. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_index.segment.rsc +1 -1
  160. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_tree.segment.rsc +1 -1
  161. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.html +1 -1
  162. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.rsc +1 -1
  163. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk/protection/quarantine/__PAGE__.segment.rsc +1 -1
  164. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk/protection/quarantine.segment.rsc +1 -1
  165. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  166. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  167. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_full.segment.rsc +1 -1
  168. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_head.segment.rsc +1 -1
  169. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_index.segment.rsc +1 -1
  170. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_tree.segment.rsc +1 -1
  171. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.html +2 -2
  172. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.rsc +1 -1
  173. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/!KGRhc2hib2FyZCk/protection/__PAGE__.segment.rsc +1 -1
  174. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  175. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  176. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_full.segment.rsc +1 -1
  177. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_head.segment.rsc +1 -1
  178. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_index.segment.rsc +1 -1
  179. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_tree.segment.rsc +1 -1
  180. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.html +2 -2
  181. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.rsc +1 -1
  182. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/!KGRhc2hib2FyZCk/settings/__PAGE__.segment.rsc +1 -1
  183. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/!KGRhc2hib2FyZCk/settings.segment.rsc +1 -1
  184. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  185. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_full.segment.rsc +1 -1
  186. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  187. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_index.segment.rsc +1 -1
  188. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
  189. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.html +1 -1
  190. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.rsc +1 -1
  191. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk/supply-chain/xray/__PAGE__.segment.rsc +1 -1
  192. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk/supply-chain/xray.segment.rsc +1 -1
  193. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk/supply-chain.segment.rsc +1 -1
  194. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  195. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_full.segment.rsc +1 -1
  196. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_head.segment.rsc +1 -1
  197. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_index.segment.rsc +1 -1
  198. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_tree.segment.rsc +1 -1
  199. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.html +1 -1
  200. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.rsc +1 -1
  201. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/!KGRhc2hib2FyZCk/supply-chain/__PAGE__.segment.rsc +1 -1
  202. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/!KGRhc2hib2FyZCk/supply-chain.segment.rsc +1 -1
  203. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  204. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_full.segment.rsc +1 -1
  205. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_head.segment.rsc +1 -1
  206. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_index.segment.rsc +1 -1
  207. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_tree.segment.rsc +1 -1
  208. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.html +2 -2
  209. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.rsc +1 -1
  210. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/!KGRhc2hib2FyZCk/xray/__PAGE__.segment.rsc +1 -1
  211. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/!KGRhc2hib2FyZCk/xray.segment.rsc +1 -1
  212. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  213. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_full.segment.rsc +1 -1
  214. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_head.segment.rsc +1 -1
  215. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_index.segment.rsc +1 -1
  216. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_tree.segment.rsc +1 -1
  217. package/dashboard/.next/standalone/dashboard/.next/server/pages/404.html +2 -2
  218. package/dashboard/.next/standalone/dashboard/.next/server/pages/500.html +2 -2
  219. package/dist/cli/inspect.d.ts +12 -0
  220. package/dist/cli/inspect.js +223 -0
  221. package/dist/cli/memory.d.ts +16 -0
  222. package/dist/cli/memory.js +228 -0
  223. package/dist/database/init.js +17 -1
  224. package/dist/database/schema.sql +2 -0
  225. package/dist/index.js +14 -0
  226. package/dist/setup/claude-md.d.ts +1 -0
  227. package/dist/setup/claude-md.js +1 -1
  228. package/package.json +1 -1
  229. package/plugins/openclaw/dist/openclaw.plugin.json +1 -1
  230. package/scripts/lib/extract-memorable-segments.mjs +40 -3
  231. package/scripts/lib/precompact-log.mjs +142 -0
  232. package/scripts/lib/recall-log.mjs +163 -0
  233. package/scripts/lib/recall-rank.mjs +29 -12
  234. package/scripts/lib/salience.mjs +83 -0
  235. package/scripts/lib/save-memory.mjs +17 -5
  236. package/scripts/pre-compact-hook.mjs +32 -0
  237. package/scripts/prompt-recall-hook.mjs +133 -6
  238. /package/dashboard/.next/standalone/dashboard/.next/static/{aT0chq-1AeBvu1T_c6RCy → EItbSW_ccG_F0ufC_s7dD}/_buildManifest.js +0 -0
  239. /package/dashboard/.next/standalone/dashboard/.next/static/{aT0chq-1AeBvu1T_c6RCy → EItbSW_ccG_F0ufC_s7dD}/_clientMiddlewareManifest.json +0 -0
  240. /package/dashboard/.next/standalone/dashboard/.next/static/{aT0chq-1AeBvu1T_c6RCy → EItbSW_ccG_F0ufC_s7dD}/_ssgManifest.js +0 -0
package/dist/index.js CHANGED
@@ -699,6 +699,20 @@ ${bold}DOCS${reset}
699
699
  await handleAuditCommand(process.argv.slice(3));
700
700
  return;
701
701
  }
702
+ // Handle "memory" subcommand (v4.25.0) — show / downvote / list a single
703
+ // memory. Distinct from the existing "memories" (plural) command which
704
+ // routes to migrate-legacy.
705
+ if (process.argv[2] === 'memory') {
706
+ const { handleMemoryCommand } = await import('./cli/memory.js');
707
+ await handleMemoryCommand(process.argv.slice(3));
708
+ return;
709
+ }
710
+ // Handle "inspect" subcommand (v4.25.0) — read the precompact ring buffer.
711
+ if (process.argv[2] === 'inspect') {
712
+ const { handleInspectCommand } = await import('./cli/inspect.js');
713
+ await handleInspectCommand(process.argv.slice(3));
714
+ return;
715
+ }
702
716
  // Handle "iron-dome" subcommand — behaviour protection layer
703
717
  if (process.argv[2] === 'iron-dome') {
704
718
  const { handleIronDomeCommand } = await import('./cli/iron-dome.js');
@@ -8,6 +8,7 @@
8
8
  *
9
9
  * Both steps are idempotent.
10
10
  */
11
+ export declare function setupGlobalMcp(): void;
11
12
  export declare function setupClaudeMd(options?: {
12
13
  stopHook?: boolean;
13
14
  sessionEnd?: boolean;
@@ -122,7 +122,7 @@ function isIdealMcpEntry(entry, ideal) {
122
122
  return false;
123
123
  return e.args.every((v, i) => v === ideal.args[i]);
124
124
  }
125
- function setupGlobalMcp() {
125
+ export function setupGlobalMcp() {
126
126
  // Claude Code reads user-scope MCP servers from ~/.claude.json
127
127
  const mcpPath = path.join(os.homedir(), '.claude.json');
128
128
  const ideal = resolveMcpCommand();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shieldcortex",
3
- "version": "4.24.3",
3
+ "version": "4.25.1",
4
4
  "description": "Trustworthy memory and security for AI agents. Recall debugging, review queue, OpenClaw session capture, and memory poisoning defence for Claude Code, Codex, OpenClaw, LangChain, and MCP agents.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "shieldcortex-realtime",
3
- "version": "4.24.3",
3
+ "version": "4.25.1",
4
4
  "name": "ShieldCortex Real-time Scanner",
5
5
  "description": "Real-time defence scanning on LLM input, memory extraction on LLM output, and active tool call interception with approval gating.",
6
6
  "kind": null,
@@ -23,6 +23,37 @@ export const BASE_THRESHOLD = 0.35;
23
23
  // trust band (0.5–0.7) used elsewhere in the pipeline.
24
24
  export const AUTO_EXTRACT_SALIENCE_CAP = 0.6;
25
25
 
26
+ // v4.25.0: deterministic taxonomy. The extractor already knows *why* a
27
+ // segment matched (extractorType) — derive memory_purpose and category
28
+ // from that signal instead of re-scanning the captured text. Keyword-
29
+ // based suggestCategory() stays as a fallback for any extractorType not
30
+ // in the map (defensive, not currently used by any in-tree extractor).
31
+ //
32
+ // memory_purpose follows the global taxonomy (src/memory/types.ts):
33
+ // user — who the human is
34
+ // feedback — corrections / instructions the human gave the agent
35
+ // project — facts about the project (decisions, architecture, fixes)
36
+ // reference — reusable knowledge (learnings, external references)
37
+ export const EXTRACTOR_TO_PURPOSE = {
38
+ preference: 'feedback',
39
+ decision: 'project',
40
+ architecture: 'project',
41
+ 'error-fix': 'project',
42
+ learning: 'reference',
43
+ 'important-note': 'project',
44
+ };
45
+
46
+ // Pinning category by extractorType eliminates the "important-note tagged
47
+ // as 'error' because the text mentioned a bug" failure mode.
48
+ export const EXTRACTOR_TO_CATEGORY = {
49
+ preference: 'preference',
50
+ decision: 'context',
51
+ architecture: 'architecture',
52
+ 'error-fix': 'error',
53
+ learning: 'learning',
54
+ 'important-note': 'note',
55
+ };
56
+
26
57
  // Default category thresholds (session-end / lighter hooks).
27
58
  // Pre-compact hook uses tighter thresholds (raised +0.10 in v4.11.0) and
28
59
  // passes them via processSegments({ categoryThresholds: ... }).
@@ -232,7 +263,7 @@ export function getExtractionThreshold(category, dynamicThreshold, categoryThres
232
263
  // newline, capping at 200 chars for safety, and optionally consumes the
233
264
  // terminator so the captured group ends cleanly. v4.24.3.
234
265
 
235
- const FULL_EXTRACTORS = [
266
+ export const FULL_EXTRACTORS = [
236
267
  {
237
268
  name: 'decision',
238
269
  titlePrefix: 'Decision: ',
@@ -306,7 +337,7 @@ const FULL_EXTRACTORS = [
306
337
  // no important-note, fewer learning + preference patterns). Preserve the
307
338
  // pre-refactor surface so its behaviour does not change with this move.
308
339
  // Same sentence-bounded capture form as FULL_EXTRACTORS (v4.24.3).
309
- const STOP_HOOK_EXTRACTORS = [
340
+ export const STOP_HOOK_EXTRACTORS = [
310
341
  FULL_EXTRACTORS[0], // decision
311
342
  {
312
343
  name: 'error-fix',
@@ -598,11 +629,17 @@ export function processSegments(segments, dynamicThreshold = BASE_THRESHOLD, opt
598
629
  if (!isDupe) {
599
630
  const text = seg.title + ' ' + seg.content;
600
631
  const baseSalience = calculateSalience(text);
601
- const category = suggestCategory(text);
632
+ // v4.25.0: extractorType drives category and memory_purpose. Fall
633
+ // back to keyword-based suggestCategory only when extractorType is
634
+ // unknown (defensive; no in-tree extractor produces a name outside
635
+ // EXTRACTOR_TO_CATEGORY).
636
+ const category = EXTRACTOR_TO_CATEGORY[seg.extractorType] ?? suggestCategory(text);
637
+ const memoryPurpose = EXTRACTOR_TO_PURPOSE[seg.extractorType] ?? 'project';
602
638
  unique.push({
603
639
  ...seg,
604
640
  baseSalience,
605
641
  category,
642
+ memoryPurpose,
606
643
  tags: extractTags(text, hookTag, seg.extractorType),
607
644
  });
608
645
  }
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Precompact ring buffer (v4.25.0).
3
+ *
4
+ * Each precompact hook run writes a debug log of "what did the extractor
5
+ * propose this time, and which proposals actually landed in `memories`?"
6
+ * Operators can read it via `shieldcortex inspect last-precompact` when
7
+ * tuning thresholds or chasing weird auto-extract behaviour.
8
+ *
9
+ * Ring buffer at `~/.shieldcortex/precompact-log/{0..9}.json` — index 0 is
10
+ * the most recent. On every write we rotate (delete 9, rename 8→9, ..., 0→1)
11
+ * and atomically write the new run to index 0 via a temp-file + rename so a
12
+ * crash mid-rotation never leaves a torn JSON file.
13
+ *
14
+ * Size cap: 10 files × ~5KB each = ~50KB. Negligible disk impact.
15
+ *
16
+ * Designed to be best-effort — never throws into the caller. The hook
17
+ * absolutely must not block compaction on a missing ~/.shieldcortex
18
+ * directory or a transient EBUSY.
19
+ */
20
+
21
+ import { existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from 'fs';
22
+ import { homedir } from 'os';
23
+ import { join } from 'path';
24
+
25
+ const RING_SIZE = 10;
26
+
27
+ // Resolved per-call so tests can swap HOME between cases. Read
28
+ // `process.env.HOME` directly rather than going through `os.homedir()`
29
+ // because jest's ESM VM loader doesn't reliably reflect HOME mutations
30
+ // through homedir(), causing test-suite cross-contamination.
31
+ function logDir() {
32
+ return join(process.env.HOME || homedir(), '.shieldcortex', 'precompact-log');
33
+ }
34
+
35
+ function logPath(index) {
36
+ return join(logDir(), `${index}.json`);
37
+ }
38
+
39
+ function ensureDir() {
40
+ const dir = logDir();
41
+ if (!existsSync(dir)) {
42
+ mkdirSync(dir, { recursive: true });
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Rotate the ring buffer one slot. Oldest entry (index 9) is unlinked,
48
+ * remaining entries shift up by one. Safe to call when slots are missing.
49
+ */
50
+ function rotate() {
51
+ try {
52
+ unlinkSync(logPath(RING_SIZE - 1));
53
+ } catch {
54
+ // No file at the oldest slot — fine.
55
+ }
56
+ for (let i = RING_SIZE - 2; i >= 0; i--) {
57
+ const from = logPath(i);
58
+ const to = logPath(i + 1);
59
+ if (existsSync(from)) {
60
+ try {
61
+ renameSync(from, to);
62
+ } catch {
63
+ // Best-effort — skip if EBUSY/EACCES.
64
+ }
65
+ }
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Atomically write a precompact run entry to slot 0 (the newest slot).
71
+ * Rotates the ring beforehand.
72
+ *
73
+ * @param {{
74
+ * ranAt?: string,
75
+ * thresholdUsed?: number,
76
+ * contextFullnessPct?: number,
77
+ * totalMemories?: number,
78
+ * candidates: Array<{
79
+ * extractorType?: string,
80
+ * category?: string,
81
+ * memoryPurpose?: string,
82
+ * title?: string,
83
+ * salience?: number,
84
+ * saved?: boolean,
85
+ * memoryId?: number | null,
86
+ * dropReason?: string | null,
87
+ * }>,
88
+ * }} entry
89
+ */
90
+ export function writePrecompactLog(entry) {
91
+ try {
92
+ ensureDir();
93
+ rotate();
94
+ const payload = {
95
+ ranAt: entry.ranAt ?? new Date().toISOString(),
96
+ thresholdUsed: entry.thresholdUsed ?? null,
97
+ contextFullnessPct: entry.contextFullnessPct ?? null,
98
+ totalMemories: entry.totalMemories ?? null,
99
+ candidates: Array.isArray(entry.candidates) ? entry.candidates : [],
100
+ };
101
+ const target = logPath(0);
102
+ const tmp = `${target}.tmp`;
103
+ writeFileSync(tmp, JSON.stringify(payload, null, 2), 'utf8');
104
+ renameSync(tmp, target);
105
+ } catch {
106
+ // Best-effort. The hook continues without a log entry rather than
107
+ // blocking compaction on a disk error.
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Read a precompact log entry by ring index.
113
+ *
114
+ * @param {number} index — 0 = newest, RING_SIZE-1 = oldest
115
+ * @returns {object | null} parsed entry, or null if missing/corrupt
116
+ */
117
+ export function readPrecompactLog(index = 0) {
118
+ try {
119
+ const raw = readFileSync(logPath(index), 'utf8');
120
+ return JSON.parse(raw);
121
+ } catch {
122
+ return null;
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Read all present precompact log entries, newest first. Missing slots are
128
+ * skipped (no nulls in the returned array).
129
+ *
130
+ * @returns {Array<{ index: number, entry: object }>}
131
+ */
132
+ export function listPrecompactLogs() {
133
+ const out = [];
134
+ for (let i = 0; i < RING_SIZE; i++) {
135
+ const entry = readPrecompactLog(i);
136
+ if (entry) out.push({ index: i, entry });
137
+ }
138
+ return out;
139
+ }
140
+
141
+ export const PRECOMPACT_RING_SIZE = RING_SIZE;
142
+ export { logDir as getPrecompactLogDir };
@@ -0,0 +1,163 @@
1
+ /**
2
+ * Recall ring buffer (v4.25.1).
3
+ *
4
+ * Each prompt-recall hook run logs "what prompt fired, what candidates did
5
+ * we consider, which were injected, which were dropped, and why?" Operators
6
+ * read it via `shieldcortex inspect last-recall` when diagnosing why a
7
+ * particular memory surfaced (or didn't) for a particular prompt.
8
+ *
9
+ * Designed to gather the data needed to scope v4.26.x recall-quality fixes
10
+ * from real fleet usage instead of one-anecdote guesses. See the v4.25.1
11
+ * plan for the diagnostic context (Jarvis's "Google Slides memory for a
12
+ * ShieldCortex-versions prompt" report, 2026-05-27).
13
+ *
14
+ * Ring buffer at `~/.shieldcortex/recall-log/{0..9}.json` — index 0 is the
15
+ * most recent. On every write we rotate (delete 9, rename 8→9, …, 0→1) and
16
+ * atomically write the new run to index 0 via a temp-file + rename so a
17
+ * crash mid-rotation never leaves a torn JSON file.
18
+ *
19
+ * Size cap: 10 files × ~15KB each (~150KB max). Each entry is slightly
20
+ * larger than precompact because it carries the prompt + per-candidate
21
+ * FTS rank / effective salience metadata.
22
+ *
23
+ * Best-effort — never throws into the caller. The hook must not block recall
24
+ * on a missing ~/.shieldcortex directory or a transient EBUSY.
25
+ *
26
+ * Trust boundary: identical to ~/.shieldcortex/memories.db (already stores
27
+ * raw memory content). Prompts are capped at 200 chars and the upstream
28
+ * sanitiser (scripts/lib/prompt-sanitiser.mjs) has already stripped
29
+ * framework metadata + fenced JSON before we see the prompt.
30
+ */
31
+
32
+ import { existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from 'fs';
33
+ import { homedir } from 'os';
34
+ import { join } from 'path';
35
+
36
+ const RING_SIZE = 10;
37
+
38
+ // Resolved per-call so tests can swap HOME between cases. Read
39
+ // `process.env.HOME` directly rather than going through `os.homedir()`
40
+ // because jest's ESM VM loader doesn't reliably reflect HOME mutations
41
+ // through homedir() (same gotcha as precompact-log.mjs).
42
+ function logDir() {
43
+ return join(process.env.HOME || homedir(), '.shieldcortex', 'recall-log');
44
+ }
45
+
46
+ function logPath(index) {
47
+ return join(logDir(), `${index}.json`);
48
+ }
49
+
50
+ function ensureDir() {
51
+ const dir = logDir();
52
+ if (!existsSync(dir)) {
53
+ mkdirSync(dir, { recursive: true });
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Rotate the ring buffer one slot. Oldest entry (index 9) is unlinked,
59
+ * remaining entries shift up by one. Safe to call when slots are missing.
60
+ */
61
+ function rotate() {
62
+ try {
63
+ unlinkSync(logPath(RING_SIZE - 1));
64
+ } catch {
65
+ // No file at the oldest slot — fine.
66
+ }
67
+ for (let i = RING_SIZE - 2; i >= 0; i--) {
68
+ const from = logPath(i);
69
+ const to = logPath(i + 1);
70
+ if (existsSync(from)) {
71
+ try {
72
+ renameSync(from, to);
73
+ } catch {
74
+ // Best-effort — skip if EBUSY/EACCES.
75
+ }
76
+ }
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Atomically write a recall run entry to slot 0 (the newest slot).
82
+ * Rotates the ring beforehand.
83
+ *
84
+ * @param {{
85
+ * ranAt?: string,
86
+ * prompt?: string,
87
+ * promptHash?: string,
88
+ * sessionId?: string,
89
+ * project?: string,
90
+ * minSalience?: number,
91
+ * candidates: Array<{
92
+ * id?: number,
93
+ * title?: string,
94
+ * category?: string,
95
+ * memoryPurpose?: string,
96
+ * salience?: number,
97
+ * ftsRank?: number | null,
98
+ * source?: 'fts' | 'category-boost',
99
+ * effectiveSalience?: number,
100
+ * injected?: boolean,
101
+ * dropReason?: string | null,
102
+ * }>,
103
+ * injectedCount?: number,
104
+ * finalContextChars?: number,
105
+ * }} entry
106
+ */
107
+ export function writeRecallLog(entry) {
108
+ try {
109
+ ensureDir();
110
+ rotate();
111
+ const payload = {
112
+ ranAt: entry.ranAt ?? new Date().toISOString(),
113
+ prompt: entry.prompt ?? null,
114
+ promptHash: entry.promptHash ?? null,
115
+ sessionId: entry.sessionId ?? null,
116
+ project: entry.project ?? null,
117
+ minSalience: entry.minSalience ?? null,
118
+ candidates: Array.isArray(entry.candidates) ? entry.candidates : [],
119
+ injectedCount: entry.injectedCount ?? null,
120
+ finalContextChars: entry.finalContextChars ?? null,
121
+ };
122
+ const target = logPath(0);
123
+ const tmp = `${target}.tmp`;
124
+ writeFileSync(tmp, JSON.stringify(payload, null, 2), 'utf8');
125
+ renameSync(tmp, target);
126
+ } catch {
127
+ // Best-effort. The hook continues without a log entry rather than
128
+ // blocking recall on a disk error.
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Read a recall log entry by ring index.
134
+ *
135
+ * @param {number} index — 0 = newest, RING_SIZE-1 = oldest
136
+ * @returns {object | null} parsed entry, or null if missing/corrupt
137
+ */
138
+ export function readRecallLog(index = 0) {
139
+ try {
140
+ const raw = readFileSync(logPath(index), 'utf8');
141
+ return JSON.parse(raw);
142
+ } catch {
143
+ return null;
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Read all present recall log entries, newest first. Missing slots are
149
+ * skipped (no nulls in the returned array).
150
+ *
151
+ * @returns {Array<{ index: number, entry: object }>}
152
+ */
153
+ export function listRecallLogs() {
154
+ const out = [];
155
+ for (let i = 0; i < RING_SIZE; i++) {
156
+ const entry = readRecallLog(i);
157
+ if (entry) out.push({ index: i, entry });
158
+ }
159
+ return out;
160
+ }
161
+
162
+ export const RECALL_RING_SIZE = RING_SIZE;
163
+ export { logDir as getRecallLogDir };
@@ -1,14 +1,12 @@
1
1
  /**
2
- * Recall result ranking helpers (v4.23.0).
2
+ * Recall result ranking helpers.
3
3
  *
4
- * Field context (edith, jarvis 2026-05-24): the UserPromptSubmit recall hook
5
- * was filtering candidates by FTS5 keyword match but then doing a final sort
6
- * by RAW salience, discarding the relevance signal. Result: high-salience-
7
- * but-off-topic memories bubbled to the top of the per-prompt recall preamble
8
- * ("Decision: that path for the rest of this conversation"-style fragments).
4
+ * v4.23.0 FTS rank primary, raw salience tiebreaker (fixed: high-salience-
5
+ * but-off-topic memories bubbling to the top of the per-prompt recall preamble).
9
6
  *
10
- * v4.23.0 picks the simplest of the three candidate approaches (A in the
11
- * v4.22.0 plan): **FTS rank is primary, raw salience is the tiebreaker**.
7
+ * v4.25.0 tiebreaker now uses *effective* salience instead of raw:
8
+ * recency × access × pin × downvote_penalty. See scripts/lib/salience.mjs.
9
+ * The DB column stays untouched — this is a read-time computation only.
12
10
  *
13
11
  * SQLite FTS5 BM25 ranks are negative numbers — more negative = more
14
12
  * relevant. So `a.rank - b.rank` (ascending) puts the most-relevant result
@@ -16,21 +14,36 @@
16
14
  * field; they sort below all FTS results.
17
15
  */
18
16
 
17
+ import { computeEffectiveSalience } from './salience.mjs';
18
+
19
19
  /**
20
20
  * Sort comparator for memory recall results.
21
21
  *
22
22
  * Behaviour:
23
23
  * - Both rows have `rank` (FTS results): lower rank wins (more relevant)
24
24
  * - Only one has `rank`: that one wins (FTS beats category-only fallback)
25
- * - Neither has `rank` (or tied): higher salience wins
25
+ * - Neither has `rank` (or tied): higher *effective* salience wins
26
26
  *
27
27
  * Stable behaviour for equal-rank-equal-salience: original order preserved
28
28
  * (Array.prototype.sort in modern engines is stable).
29
29
  *
30
- * @param {{ rank?: number, salience?: number }} a
31
- * @param {{ rank?: number, salience?: number }} b
30
+ * @param {{ rank?: number, salience?: number, last_accessed?: string, access_count?: number, pinned?: number, downvote_count?: number }} a
31
+ * @param {{ rank?: number, salience?: number, last_accessed?: string, access_count?: number, pinned?: number, downvote_count?: number }} b
32
32
  * @returns {number} negative if a comes first, positive if b comes first
33
33
  */
34
+ // A row carries the v4.25 salience-formula inputs only when the SELECT
35
+ // projected pinned/access_count/last_accessed/downvote_count. Older call
36
+ // sites and recall-rank tests pass rows with just {id, rank, salience} —
37
+ // for those, fall back to raw salience comparison (v4.23 behaviour).
38
+ function hasSalienceFormulaInputs(row) {
39
+ return (
40
+ row.access_count !== undefined ||
41
+ row.last_accessed !== undefined ||
42
+ row.pinned !== undefined ||
43
+ row.downvote_count !== undefined
44
+ );
45
+ }
46
+
34
47
  export function compareRecallResults(a, b) {
35
48
  const aHasRank = typeof a.rank === 'number' && Number.isFinite(a.rank);
36
49
  const bHasRank = typeof b.rank === 'number' && Number.isFinite(b.rank);
@@ -41,6 +54,10 @@ export function compareRecallResults(a, b) {
41
54
  } else if (aHasRank !== bHasRank) {
42
55
  return aHasRank ? -1 : 1;
43
56
  }
44
- // Neither has rank (both from category fallback), or tied rank → salience
57
+ // v4.25.0: effective salience if both rows carry the formula inputs.
58
+ // Otherwise (legacy or test rows) preserve v4.23 raw-salience behaviour.
59
+ if (hasSalienceFormulaInputs(a) && hasSalienceFormulaInputs(b)) {
60
+ return computeEffectiveSalience(b) - computeEffectiveSalience(a);
61
+ }
45
62
  return (b.salience ?? 0) - (a.salience ?? 0);
46
63
  }
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Effective salience computation (v4.25.0).
3
+ *
4
+ * Pre-4.25 the recall hook ranked tied FTS results by raw `salience` only.
5
+ * That ignored real signal: a memory that was last accessed 3 months ago
6
+ * carries less weight than a memory accessed yesterday; a pinned memory
7
+ * deserves more weight than an identical unpinned one; a memory the user
8
+ * downvoted via `shieldcortex memory downvote <id>` should be demoted.
9
+ *
10
+ * Formula:
11
+ * effective = base × recency × access × pin × downvote_penalty
12
+ *
13
+ * recency = exp(-Δt_days / halfLifeDays) // decay
14
+ * access = log(1 + access_count) / log(1 + accessNorm)
15
+ * pin = pinned ? pinBoost : 1
16
+ * downvote_penalty = max(0.1, 1 - downvoteDecay × downvote_count)
17
+ *
18
+ * All constants are env-var-tunable (no recompile needed for field tuning).
19
+ *
20
+ * The function returns the *multiplier-adjusted* salience. The base salience
21
+ * column in SQLite stays untouched — this is a read-time computation.
22
+ *
23
+ * @param {{
24
+ * salience?: number,
25
+ * last_accessed?: string | null,
26
+ * access_count?: number | null,
27
+ * pinned?: number | boolean | null,
28
+ * downvote_count?: number | null
29
+ * }} memory
30
+ * @param {{
31
+ * halfLifeDays?: number,
32
+ * accessNorm?: number,
33
+ * pinBoost?: number,
34
+ * downvoteDecay?: number,
35
+ * now?: number,
36
+ * }} [opts]
37
+ * @returns {number}
38
+ */
39
+ // Resolve a numeric tuning constant from opts (explicit override), then
40
+ // SHIELDCORTEX_* env var, then the documented default. Returns the default
41
+ // if either of the first two is NaN — we never want a typo'd env var to
42
+ // silently zero out a multiplier.
43
+ function pickNumber(override, envName, fallback) {
44
+ if (typeof override === 'number' && Number.isFinite(override)) return override;
45
+ const fromEnv = Number(process.env[envName]);
46
+ if (Number.isFinite(fromEnv) && fromEnv !== 0) return fromEnv;
47
+ return fallback;
48
+ }
49
+
50
+ export function computeEffectiveSalience(memory, opts = {}) {
51
+ const halfLifeDays = pickNumber(opts.halfLifeDays, 'SHIELDCORTEX_SALIENCE_HALF_LIFE_DAYS', 14);
52
+ const accessNorm = pickNumber(opts.accessNorm, 'SHIELDCORTEX_SALIENCE_ACCESS_NORM', 10);
53
+ const pinBoost = pickNumber(opts.pinBoost, 'SHIELDCORTEX_SALIENCE_PIN_BOOST', 1.5);
54
+ const downvoteDecay = pickNumber(opts.downvoteDecay, 'SHIELDCORTEX_SALIENCE_DOWNVOTE_DECAY', 0.3);
55
+ const now = opts.now ?? Date.now();
56
+
57
+ const base = typeof memory.salience === 'number' ? memory.salience : 0;
58
+
59
+ // Recency: exp(-Δt_days / halfLife). last_accessed missing → assume "now"
60
+ // (a brand-new memory should not be penalised for never having been read).
61
+ let recency = 1;
62
+ if (memory.last_accessed) {
63
+ const lastMs = Date.parse(memory.last_accessed);
64
+ if (Number.isFinite(lastMs)) {
65
+ const deltaDays = Math.max(0, (now - lastMs) / 86_400_000);
66
+ recency = Math.exp(-deltaDays / halfLifeDays);
67
+ }
68
+ }
69
+
70
+ // Access: log-scaled, normalised so access_count=accessNorm produces ~1.0.
71
+ const accessCount = Math.max(0, Number(memory.access_count) || 0);
72
+ const access = Math.log1p(accessCount) / Math.log1p(accessNorm);
73
+
74
+ // Pin: SQLite stores boolean as 0/1.
75
+ const pin = memory.pinned ? pinBoost : 1;
76
+
77
+ // Downvote: each downvote lops downvoteDecay off the multiplier, floored
78
+ // at 0.1 so a 4×-downvoted memory can still surface when truly relevant.
79
+ const downvotes = Math.max(0, Number(memory.downvote_count) || 0);
80
+ const downvotePenalty = Math.max(0.1, 1 - downvoteDecay * downvotes);
81
+
82
+ return base * recency * access * pin * downvotePenalty;
83
+ }
@@ -20,7 +20,7 @@ import { fileURLToPath, pathToFileURL } from 'url';
20
20
  * Async: the pipeline lives in dist/ as ESM and is loaded via dynamic import.
21
21
  *
22
22
  * @param {import('better-sqlite3').Database} db
23
- * @param {{ title: string, content: string, category: string, salience: number, tags: string[] }} memory
23
+ * @param {{ title: string, content: string, category: string, salience: number, tags: string[], memoryPurpose?: string }} memory
24
24
  * @param {string|null} [project]
25
25
  * @param {{ source?: string }} [opts] — `source` identifies the calling hook
26
26
  * ('session-end-hook' | 'pre-compact-hook' | 'stop-hook' | 'hook').
@@ -50,7 +50,7 @@ export async function saveAutoExtractedMemory(db, memory, project, opts = {}) {
50
50
  const decision = result.firewall.result;
51
51
 
52
52
  if (decision === 'ALLOW') {
53
- insertMemoryRow(db, memory, project);
53
+ insertMemoryRow(db, memory, project, sourceIdentifier);
54
54
  return;
55
55
  }
56
56
 
@@ -73,11 +73,21 @@ export async function saveAutoExtractedMemory(db, memory, project, opts = {}) {
73
73
 
74
74
  // ==================== Internal: writes ====================
75
75
 
76
- function insertMemoryRow(db, memory, project) {
76
+ function insertMemoryRow(db, memory, project, sourceIdentifier) {
77
77
  const timestamp = new Date().toISOString();
78
+ // v4.25.0: pre-4.25 the INSERT omitted memory_purpose / source / source_kind
79
+ // / capture_method, so every hook write looked identical to a user-typed
80
+ // memory at the SQL level. The hook already knows which hook is calling
81
+ // (sourceIdentifier) and the extractor already computed memoryPurpose —
82
+ // thread both through so `shieldcortex inspect last-precompact` and any
83
+ // memory-source SQL query can distinguish hook writes from user writes.
78
84
  db.prepare(`
79
- INSERT INTO memories (uuid, title, content, type, category, salience, tags, project, created_at, last_accessed)
80
- VALUES (?, ?, ?, 'short_term', ?, ?, ?, ?, ?, ?)
85
+ INSERT INTO memories (
86
+ uuid, title, content, type, category, salience, tags, project,
87
+ memory_purpose, source, source_kind, capture_method,
88
+ created_at, last_accessed
89
+ )
90
+ VALUES (?, ?, ?, 'short_term', ?, ?, ?, ?, ?, ?, 'hook', 'auto', ?, ?)
81
91
  `).run(
82
92
  randomUUID(),
83
93
  memory.title,
@@ -86,6 +96,8 @@ function insertMemoryRow(db, memory, project) {
86
96
  memory.salience,
87
97
  JSON.stringify(memory.tags),
88
98
  project || null,
99
+ memory.memoryPurpose ?? 'project',
100
+ `hook:${sourceIdentifier}`,
89
101
  timestamp,
90
102
  timestamp,
91
103
  );