shieldcortex 4.31.2 → 4.32.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 (353) hide show
  1. package/README.md +78 -2
  2. package/dashboard/.next/standalone/dashboard/.next/BUILD_ID +1 -1
  3. package/dashboard/.next/standalone/dashboard/.next/build-manifest.json +2 -2
  4. package/dashboard/.next/standalone/dashboard/.next/prerender-manifest.json +3 -3
  5. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.html +2 -2
  6. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.rsc +1 -1
  7. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  8. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  9. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  10. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  11. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  12. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.html +2 -2
  13. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.rsc +1 -1
  14. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  15. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  16. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  17. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  18. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  19. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  20. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.html +1 -1
  21. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.rsc +1 -1
  22. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/!KGRhc2hib2FyZCk/admin/__PAGE__.segment.rsc +1 -1
  23. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/!KGRhc2hib2FyZCk/admin.segment.rsc +1 -1
  24. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  25. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_full.segment.rsc +1 -1
  26. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_head.segment.rsc +1 -1
  27. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_index.segment.rsc +1 -1
  28. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_tree.segment.rsc +1 -1
  29. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.html +1 -1
  30. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.rsc +1 -1
  31. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/!KGRhc2hib2FyZCk/cloud/__PAGE__.segment.rsc +1 -1
  32. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/!KGRhc2hib2FyZCk/cloud.segment.rsc +1 -1
  33. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  34. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_full.segment.rsc +1 -1
  35. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_head.segment.rsc +1 -1
  36. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_index.segment.rsc +1 -1
  37. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_tree.segment.rsc +1 -1
  38. package/dashboard/.next/standalone/dashboard/.next/server/app/index.html +1 -1
  39. package/dashboard/.next/standalone/dashboard/.next/server/app/index.rsc +1 -1
  40. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  41. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_full.segment.rsc +1 -1
  42. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_head.segment.rsc +1 -1
  43. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_index.segment.rsc +1 -1
  44. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  45. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.html +1 -1
  46. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.rsc +1 -1
  47. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk/memory/capture/__PAGE__.segment.rsc +1 -1
  48. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk/memory/capture.segment.rsc +1 -1
  49. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  50. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  51. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_full.segment.rsc +1 -1
  52. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_head.segment.rsc +1 -1
  53. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_index.segment.rsc +1 -1
  54. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_tree.segment.rsc +1 -1
  55. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.html +1 -1
  56. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.rsc +1 -1
  57. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk/memory/graph/__PAGE__.segment.rsc +1 -1
  58. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk/memory/graph.segment.rsc +1 -1
  59. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  60. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  61. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_full.segment.rsc +1 -1
  62. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_head.segment.rsc +1 -1
  63. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_index.segment.rsc +1 -1
  64. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_tree.segment.rsc +1 -1
  65. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.html +1 -1
  66. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.rsc +1 -1
  67. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk/memory/recall/__PAGE__.segment.rsc +1 -1
  68. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk/memory/recall.segment.rsc +1 -1
  69. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  70. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  71. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_full.segment.rsc +1 -1
  72. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_head.segment.rsc +1 -1
  73. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_index.segment.rsc +1 -1
  74. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_tree.segment.rsc +1 -1
  75. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.html +2 -2
  76. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.rsc +1 -1
  77. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/!KGRhc2hib2FyZCk/memory/replay/__PAGE__.segment.rsc +1 -1
  78. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/!KGRhc2hib2FyZCk/memory/replay.segment.rsc +1 -1
  79. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  80. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  81. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/_full.segment.rsc +1 -1
  82. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/_head.segment.rsc +1 -1
  83. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/_index.segment.rsc +1 -1
  84. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/_tree.segment.rsc +1 -1
  85. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.html +1 -1
  86. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.rsc +1 -1
  87. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk/memory/review/__PAGE__.segment.rsc +1 -1
  88. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk/memory/review.segment.rsc +1 -1
  89. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  90. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  91. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_full.segment.rsc +1 -1
  92. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_head.segment.rsc +1 -1
  93. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_index.segment.rsc +1 -1
  94. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_tree.segment.rsc +1 -1
  95. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.html +1 -1
  96. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.rsc +1 -1
  97. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk/memory/timeline/__PAGE__.segment.rsc +1 -1
  98. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk/memory/timeline.segment.rsc +1 -1
  99. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  100. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  101. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_full.segment.rsc +1 -1
  102. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_head.segment.rsc +1 -1
  103. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_index.segment.rsc +1 -1
  104. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_tree.segment.rsc +1 -1
  105. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.html +2 -2
  106. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.rsc +1 -1
  107. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/!KGRhc2hib2FyZCk/memory/__PAGE__.segment.rsc +1 -1
  108. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  109. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  110. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_full.segment.rsc +1 -1
  111. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_head.segment.rsc +1 -1
  112. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_index.segment.rsc +1 -1
  113. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_tree.segment.rsc +1 -1
  114. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.html +2 -2
  115. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.rsc +1 -1
  116. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/!KGRhc2hib2FyZCk/overview/__PAGE__.segment.rsc +1 -1
  117. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/!KGRhc2hib2FyZCk/overview.segment.rsc +1 -1
  118. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  119. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_full.segment.rsc +1 -1
  120. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_head.segment.rsc +1 -1
  121. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_index.segment.rsc +1 -1
  122. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_tree.segment.rsc +1 -1
  123. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.html +1 -1
  124. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.rsc +1 -1
  125. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk/protection/audit/__PAGE__.segment.rsc +1 -1
  126. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk/protection/audit.segment.rsc +1 -1
  127. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  128. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  129. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_full.segment.rsc +1 -1
  130. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_head.segment.rsc +1 -1
  131. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_index.segment.rsc +1 -1
  132. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_tree.segment.rsc +1 -1
  133. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.html +1 -1
  134. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.rsc +1 -1
  135. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk/protection/intercepts/__PAGE__.segment.rsc +1 -1
  136. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk/protection/intercepts.segment.rsc +1 -1
  137. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  138. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  139. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_full.segment.rsc +1 -1
  140. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_head.segment.rsc +1 -1
  141. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_index.segment.rsc +1 -1
  142. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_tree.segment.rsc +1 -1
  143. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.html +1 -1
  144. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.rsc +1 -1
  145. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk/protection/iron-dome/__PAGE__.segment.rsc +1 -1
  146. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk/protection/iron-dome.segment.rsc +1 -1
  147. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  148. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  149. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_full.segment.rsc +1 -1
  150. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_head.segment.rsc +1 -1
  151. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_index.segment.rsc +1 -1
  152. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_tree.segment.rsc +1 -1
  153. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.html +1 -1
  154. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.rsc +1 -1
  155. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk/protection/policies/__PAGE__.segment.rsc +1 -1
  156. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk/protection/policies.segment.rsc +1 -1
  157. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  158. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  159. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_full.segment.rsc +1 -1
  160. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_head.segment.rsc +1 -1
  161. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_index.segment.rsc +1 -1
  162. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_tree.segment.rsc +1 -1
  163. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.html +1 -1
  164. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.rsc +1 -1
  165. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk/protection/quarantine/__PAGE__.segment.rsc +1 -1
  166. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk/protection/quarantine.segment.rsc +1 -1
  167. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  168. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  169. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_full.segment.rsc +1 -1
  170. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_head.segment.rsc +1 -1
  171. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_index.segment.rsc +1 -1
  172. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_tree.segment.rsc +1 -1
  173. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.html +2 -2
  174. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.rsc +1 -1
  175. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/!KGRhc2hib2FyZCk/protection/__PAGE__.segment.rsc +1 -1
  176. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  177. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  178. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_full.segment.rsc +1 -1
  179. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_head.segment.rsc +1 -1
  180. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_index.segment.rsc +1 -1
  181. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_tree.segment.rsc +1 -1
  182. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.html +2 -2
  183. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.rsc +1 -1
  184. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/!KGRhc2hib2FyZCk/settings/__PAGE__.segment.rsc +1 -1
  185. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/!KGRhc2hib2FyZCk/settings.segment.rsc +1 -1
  186. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  187. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_full.segment.rsc +1 -1
  188. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  189. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_index.segment.rsc +1 -1
  190. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
  191. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.html +1 -1
  192. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.rsc +1 -1
  193. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk/supply-chain/xray/__PAGE__.segment.rsc +1 -1
  194. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk/supply-chain/xray.segment.rsc +1 -1
  195. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk/supply-chain.segment.rsc +1 -1
  196. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  197. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_full.segment.rsc +1 -1
  198. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_head.segment.rsc +1 -1
  199. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_index.segment.rsc +1 -1
  200. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_tree.segment.rsc +1 -1
  201. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.html +1 -1
  202. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.rsc +1 -1
  203. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/!KGRhc2hib2FyZCk/supply-chain/__PAGE__.segment.rsc +1 -1
  204. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/!KGRhc2hib2FyZCk/supply-chain.segment.rsc +1 -1
  205. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  206. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_full.segment.rsc +1 -1
  207. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_head.segment.rsc +1 -1
  208. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_index.segment.rsc +1 -1
  209. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_tree.segment.rsc +1 -1
  210. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.html +2 -2
  211. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.rsc +1 -1
  212. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/!KGRhc2hib2FyZCk/xray/__PAGE__.segment.rsc +1 -1
  213. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/!KGRhc2hib2FyZCk/xray.segment.rsc +1 -1
  214. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  215. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_full.segment.rsc +1 -1
  216. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_head.segment.rsc +1 -1
  217. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_index.segment.rsc +1 -1
  218. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_tree.segment.rsc +1 -1
  219. package/dashboard/.next/standalone/dashboard/.next/server/pages/404.html +2 -2
  220. package/dashboard/.next/standalone/dashboard/.next/server/pages/500.html +2 -2
  221. package/dashboard/.next/standalone/dashboard/.next/server/server-reference-manifest.js +1 -1
  222. package/dashboard/.next/standalone/dashboard/.next/server/server-reference-manifest.json +1 -1
  223. package/dist/api/control.d.ts +2 -0
  224. package/dist/api/control.js +119 -2
  225. package/dist/api/routes/memories.js +19 -14
  226. package/dist/api/routes/system.js +2 -3
  227. package/dist/api/visualization-server.d.ts +13 -1
  228. package/dist/api/visualization-server.js +57 -1
  229. package/dist/audit/env-scanner.js +5 -2
  230. package/dist/audit/index.d.ts +4 -1
  231. package/dist/audit/index.js +2 -1
  232. package/dist/audit/mcp-config-scanner.d.ts +23 -0
  233. package/dist/audit/mcp-config-scanner.js +110 -0
  234. package/dist/audit/mcp-tools-scanner.d.ts +112 -0
  235. package/dist/audit/mcp-tools-scanner.js +299 -0
  236. package/dist/cli/audit.d.ts +1 -0
  237. package/dist/cli/audit.js +12 -1
  238. package/dist/cli/doctor.js +4 -1
  239. package/dist/cli/mcp.d.ts +13 -0
  240. package/dist/cli/mcp.js +0 -0
  241. package/dist/cli/remember.d.ts +75 -0
  242. package/dist/cli/remember.js +195 -0
  243. package/dist/cli/repair.d.ts +8 -0
  244. package/dist/cli/repair.js +34 -0
  245. package/dist/cli/update.js +34 -0
  246. package/dist/cloud/config.d.ts +23 -1
  247. package/dist/cloud/config.js +453 -193
  248. package/dist/cloud/quarantine-sync.d.ts +12 -2
  249. package/dist/cloud/quarantine-sync.js +28 -6
  250. package/dist/cloud/sync-queue.d.ts +21 -2
  251. package/dist/cloud/sync-queue.js +124 -29
  252. package/dist/database/better-sqlite3-guard.d.ts +21 -2
  253. package/dist/database/better-sqlite3-guard.js +29 -5
  254. package/dist/database/init.js +68 -16
  255. package/dist/database/inline-schema.js +35 -1
  256. package/dist/database/migrations.js +104 -8
  257. package/dist/database/schema.sql +39 -1
  258. package/dist/defence/audit/queries.d.ts +10 -2
  259. package/dist/defence/audit/queries.js +30 -4
  260. package/dist/defence/audit/retention.d.ts +50 -0
  261. package/dist/defence/audit/retention.js +161 -0
  262. package/dist/defence/credential-leak/entropy.d.ts +11 -0
  263. package/dist/defence/credential-leak/entropy.js +27 -0
  264. package/dist/defence/credential-leak/index.js +27 -1
  265. package/dist/defence/credential-leak/patterns.d.ts +9 -0
  266. package/dist/defence/credential-leak/patterns.js +21 -0
  267. package/dist/defence/custom-patterns/store.js +8 -1
  268. package/dist/defence/custom-rules/store.d.ts +18 -0
  269. package/dist/defence/custom-rules/store.js +63 -0
  270. package/dist/defence/firewall/confusables.d.ts +30 -0
  271. package/dist/defence/firewall/confusables.js +87 -0
  272. package/dist/defence/firewall/encoding-detector.js +23 -9
  273. package/dist/defence/firewall/index.d.ts +11 -1
  274. package/dist/defence/firewall/index.js +34 -1
  275. package/dist/defence/firewall/instruction-detector.js +18 -7
  276. package/dist/defence/firewall/markdown-image-detector.d.ts +34 -0
  277. package/dist/defence/firewall/markdown-image-detector.js +83 -0
  278. package/dist/defence/fragmentation/entity-extractor.js +17 -6
  279. package/dist/defence/index.d.ts +5 -0
  280. package/dist/defence/index.js +8 -0
  281. package/dist/defence/iron-dome/index.js +7 -1
  282. package/dist/defence/pipeline.js +62 -10
  283. package/dist/defence/scan-windows.d.ts +41 -0
  284. package/dist/defence/scan-windows.js +61 -0
  285. package/dist/defence/semantic/attack-corpus.d.ts +22 -0
  286. package/dist/defence/semantic/attack-corpus.js +75 -0
  287. package/dist/defence/semantic/index.d.ts +67 -0
  288. package/dist/defence/semantic/index.js +138 -0
  289. package/dist/defence/skill-scanner/deep-scan.js +35 -15
  290. package/dist/defence/skill-scanner/patterns.d.ts +1 -1
  291. package/dist/defence/skill-scanner/patterns.js +8 -7
  292. package/dist/defence/tool-response-scanner.d.ts +21 -5
  293. package/dist/defence/tool-response-scanner.js +111 -22
  294. package/dist/defence/types.d.ts +11 -1
  295. package/dist/index.d.ts +29 -0
  296. package/dist/index.js +112 -21
  297. package/dist/memory/consolidate.js +1 -1
  298. package/dist/memory/decay.js +3 -1
  299. package/dist/memory/embedding.d.ts +18 -2
  300. package/dist/memory/embedding.js +32 -11
  301. package/dist/memory/expiry.js +1 -1
  302. package/dist/memory/search-recall.js +107 -49
  303. package/dist/memory/search.d.ts +19 -3
  304. package/dist/memory/search.js +25 -10
  305. package/dist/memory/store.d.ts +13 -2
  306. package/dist/memory/store.js +115 -11
  307. package/dist/scan-only.d.ts +64 -0
  308. package/dist/scan-only.js +173 -0
  309. package/dist/server.d.ts +5 -0
  310. package/dist/server.js +6 -4
  311. package/dist/setup/claude-md.js +39 -34
  312. package/dist/setup/codex.js +9 -2
  313. package/dist/setup/copilot.js +160 -47
  314. package/dist/setup/json-config.d.ts +99 -0
  315. package/dist/setup/json-config.js +167 -0
  316. package/dist/setup/migrate.js +1 -1
  317. package/dist/setup/native-binding.d.ts +75 -0
  318. package/dist/setup/native-binding.js +146 -0
  319. package/dist/setup/settings-hooks.js +8 -13
  320. package/dist/setup/uninstall.js +1 -21
  321. package/dist/tools/context.d.ts +8 -8
  322. package/dist/tools/forget.d.ts +9 -8
  323. package/dist/tools/forget.js +17 -4
  324. package/dist/tools/recall.d.ts +13 -13
  325. package/dist/tools/remember.d.ts +16 -16
  326. package/dist/tools/remember.js +19 -8
  327. package/dist/worker/brain-worker.d.ts +1 -0
  328. package/dist/worker/brain-worker.js +79 -16
  329. package/dist/worker/types.d.ts +8 -0
  330. package/dist/worker/types.js +8 -0
  331. package/dist/xray/dir-scanner.d.ts +18 -0
  332. package/dist/xray/dir-scanner.js +23 -1
  333. package/dist/xray/file-scanner.js +16 -1
  334. package/dist/xray/findings-store.js +9 -1
  335. package/dist/xray/index.d.ts +2 -0
  336. package/dist/xray/index.js +10 -1
  337. package/dist/xray/npm-inspector.d.ts +31 -0
  338. package/dist/xray/npm-inspector.js +135 -29
  339. package/dist/xray/patterns.d.ts +1 -1
  340. package/dist/xray/patterns.js +20 -23
  341. package/dist/xray/sarif.d.ts +78 -0
  342. package/dist/xray/sarif.js +166 -0
  343. package/dist/xray/watch.d.ts +1 -0
  344. package/dist/xray/watch.js +10 -1
  345. package/hooks/openclaw/cortex-memory/handler.ts +122 -18
  346. package/hooks/openclaw/cortex-memory/runtime.mjs +10 -4
  347. package/package.json +10 -3
  348. package/scripts/postinstall.mjs +8 -3
  349. package/dist/memory/embedding-cache.d.ts +0 -20
  350. package/dist/memory/embedding-cache.js +0 -91
  351. /package/dashboard/.next/standalone/dashboard/.next/static/{_j4TeMpss-w79QtNNWqZw → tjJ3X8xQ-2_WQTPGF3zCA}/_buildManifest.js +0 -0
  352. /package/dashboard/.next/standalone/dashboard/.next/static/{_j4TeMpss-w79QtNNWqZw → tjJ3X8xQ-2_WQTPGF3zCA}/_clientMiddlewareManifest.json +0 -0
  353. /package/dashboard/.next/standalone/dashboard/.next/static/{_j4TeMpss-w79QtNNWqZw → tjJ3X8xQ-2_WQTPGF3zCA}/_ssgManifest.js +0 -0
@@ -2,8 +2,14 @@
2
2
  * Fire-and-forget: sends quarantined content to ShieldCortex cloud.
3
3
  * Never blocks, never throws. Failed requests are logged and queued for retry.
4
4
  *
5
- * IMPORTANT: Content is redacted before transmission credentials and secrets
6
- * are replaced with [REDACTED-{type}] placeholders to prevent PII/secret leakage.
5
+ * IMPORTANT: Quarantine holds the most sensitive payloads, so it applies the
6
+ * SAME CloudSyncControls gating as memory-sync (see shouldSyncRecord /
7
+ * applyContentMode in memory-sync.ts) BEFORE any content leaves the device:
8
+ * - project filter (`shouldSyncProject`) — excluded projects never sync
9
+ * - `excludeSensitive` — CONFIDENTIAL+ items are dropped entirely
10
+ * - `contentMode: 'metadata'` — content/title are redacted to a placeholder
11
+ * On top of that, credentials/secrets are always redacted with
12
+ * [REDACTED-{type}] placeholders to prevent secret leakage.
7
13
  */
8
14
  export declare function syncQuarantineToCloud(entry: {
9
15
  original_content: string;
@@ -14,4 +20,8 @@ export declare function syncQuarantineToCloud(entry: {
14
20
  threat_indicators: string[];
15
21
  anomaly_score: number;
16
22
  firewall_result: string;
23
+ /** Project the quarantined write belongs to (for the project filter). */
24
+ project?: string | null;
25
+ /** Sensitivity classification of the content (for `excludeSensitive`). */
26
+ sensitivity_level?: string | null;
17
27
  }): void;
@@ -1,22 +1,44 @@
1
- import { getCloudConfig, getDeviceId, getDeviceName } from './config.js';
1
+ import { getCloudConfig, getCloudSyncControls, getDeviceId, getDeviceName, isSensitiveLevel, shouldSyncProject, } from './config.js';
2
2
  import { enqueueFailedQuarantineSync } from './sync-queue.js';
3
3
  import { redactCredentials } from '../defence/credential-leak/index.js';
4
4
  /**
5
5
  * Fire-and-forget: sends quarantined content to ShieldCortex cloud.
6
6
  * Never blocks, never throws. Failed requests are logged and queued for retry.
7
7
  *
8
- * IMPORTANT: Content is redacted before transmission credentials and secrets
9
- * are replaced with [REDACTED-{type}] placeholders to prevent PII/secret leakage.
8
+ * IMPORTANT: Quarantine holds the most sensitive payloads, so it applies the
9
+ * SAME CloudSyncControls gating as memory-sync (see shouldSyncRecord /
10
+ * applyContentMode in memory-sync.ts) BEFORE any content leaves the device:
11
+ * - project filter (`shouldSyncProject`) — excluded projects never sync
12
+ * - `excludeSensitive` — CONFIDENTIAL+ items are dropped entirely
13
+ * - `contentMode: 'metadata'` — content/title are redacted to a placeholder
14
+ * On top of that, credentials/secrets are always redacted with
15
+ * [REDACTED-{type}] placeholders to prevent secret leakage.
10
16
  */
11
17
  export function syncQuarantineToCloud(entry) {
12
18
  const config = getCloudConfig();
13
19
  if (!config.cloudEnabled || !config.cloudApiKey)
14
20
  return;
21
+ // Apply the user's CloudSyncControls (parity with memory-sync).
22
+ const controls = getCloudSyncControls();
23
+ if (!shouldSyncProject(entry.project ?? null, controls))
24
+ return;
25
+ if (controls.excludeSensitive && isSensitiveLevel(entry.sensitivity_level ?? null))
26
+ return;
27
+ const metadataOnly = controls.contentMode === 'metadata';
28
+ // Always redact credentials; metadata-only mode replaces content entirely.
29
+ const safeContent = metadataOnly
30
+ ? '[ShieldCortex] Quarantine content redacted by local sync policy.'
31
+ : redactCredentials(entry.original_content);
32
+ const safeTitle = metadataOnly
33
+ ? '[Metadata only]'
34
+ : entry.original_title
35
+ ? redactCredentials(entry.original_title)
36
+ : entry.original_title;
15
37
  const payload = {
16
38
  ...entry,
17
- // Redact credentials/secrets before sending to cloud
18
- original_content: redactCredentials(entry.original_content),
19
- original_title: entry.original_title ? redactCredentials(entry.original_title) : entry.original_title,
39
+ original_content: safeContent,
40
+ original_title: safeTitle,
41
+ content_redacted: metadataOnly,
20
42
  device_id: getDeviceId(),
21
43
  device_name: getDeviceName(),
22
44
  timestamp: new Date().toISOString(),
@@ -31,6 +31,9 @@ export interface QuarantineSyncEntry {
31
31
  threat_indicators: string[];
32
32
  anomaly_score: number;
33
33
  firewall_result: string;
34
+ project?: string | null;
35
+ sensitivity_level?: string | null;
36
+ content_redacted?: boolean;
34
37
  device_id: string;
35
38
  device_name: string;
36
39
  timestamp: string;
@@ -79,12 +82,28 @@ export declare function enqueueFailedGraphSync(entry: GraphSyncEnvelope): void;
79
82
  * number of rows dropped. Best-effort and never throws.
80
83
  */
81
84
  export declare function enforceQueueCap(maxRows?: number): number;
85
+ export interface ProcessRetryOptions {
86
+ /**
87
+ * Maximum number of pending rows to attempt in one call. Bounds the network
88
+ * work an MCP-profile worker does per light tick (it passes a small budget,
89
+ * e.g. 25); the full dashboard profile uses the default. Resurrection is
90
+ * unaffected — only the pending-row SELECT is limited.
91
+ */
92
+ maxRows?: number;
93
+ }
82
94
  /**
83
95
  * Process pending items in the retry queue.
84
- * SELECT pending WHERE next_retry_at <= now, retry each (up to 10 per tick).
96
+ *
97
+ * Runs a resurrection pass first (revive transiently-failed rows within TTL),
98
+ * then SELECTs pending rows due for retry (up to `maxRows`) and attempts each.
85
99
  * Awaits each fetch so results are accurate and no double-processing occurs.
100
+ *
101
+ * Failure handling:
102
+ * - HTTP 4xx (≠429) → permanent: mark failed, no further retries.
103
+ * - network/timeout/5xx/429 → transient: keep pending with capped (≤1h)
104
+ * backoff, retrying until the 7-day TTL purge — survives long outages.
86
105
  */
87
- export declare function processRetryQueue(): Promise<SyncQueueResult>;
106
+ export declare function processRetryQueue(options?: ProcessRetryOptions): Promise<SyncQueueResult>;
88
107
  /**
89
108
  * Get queue statistics by status.
90
109
  */
@@ -159,26 +159,102 @@ function buildRetryRequest(payloadText) {
159
159
  }
160
160
  throw new Error('Unsupported sync queue payload');
161
161
  }
162
+ /** Cap on transient backoff. A single offline laptop shouldn't wait more than
163
+ * an hour between retry attempts, but we don't want 2^attempts*30s to grow
164
+ * unbounded after a long outage (it hits days within ~14 attempts). */
165
+ const MAX_BACKOFF_MS = 60 * 60 * 1000; // 1h
166
+ const BASE_BACKOFF_MS = 30_000;
162
167
  /**
163
- * Mark a queue row as retrying (schedule next attempt) or permanently failed.
164
- * Exponential backoff: 2^attempts * 30s (30s, 60s, 120s).
168
+ * Classify a sync failure to decide retry policy.
169
+ *
170
+ * - 'permanent': HTTP 4xx. The request is malformed, unauthorised, or points
171
+ * at something that doesn't exist — retrying is pointless, so fail fast.
172
+ * - 'transient': network errors, timeouts/AbortError, HTTP 5xx, HTTP 429.
173
+ * The server or link is temporarily unavailable; retrying always makes
174
+ * sense, so we keep the row pending (capped backoff) until the 7-day TTL
175
+ * purge removes it.
176
+ *
177
+ * 429 (rate limited) is deliberately transient — backing off and retrying is
178
+ * exactly the right response to a rate limit.
179
+ */
180
+ function classifyHttpStatus(status) {
181
+ // 4xx (except 429) is a client error → permanent. 429 + 5xx → transient.
182
+ if (status === 429)
183
+ return 'transient';
184
+ if (status >= 400 && status < 500)
185
+ return 'permanent';
186
+ return 'transient';
187
+ }
188
+ /**
189
+ * Heuristic for whether a stored `last_error` describes a transient failure,
190
+ * used by the resurrection pass to revive rows that the OLD 3-attempt logic
191
+ * wrongly marked terminal. We can't store the classification (no schema
192
+ * change), so we infer from the message:
193
+ * - `HTTP 4xx` (but not `HTTP 429`) → permanent → leave failed.
194
+ * - everything else (timeouts, network messages, `HTTP 5xx`, `HTTP 429`)
195
+ * → transient → resurrect.
196
+ * Conservative by design: an unrecognised message is treated as transient so
197
+ * we err on the side of retrying rather than silently dropping a sync.
165
198
  */
166
- function markRetryOrFailed(rowId, currentAttempts, newAttempts, maxAttempts, errorMsg) {
199
+ function isTransientErrorMessage(lastError) {
200
+ if (!lastError)
201
+ return true;
202
+ const m = /^HTTP (\d{3})/.exec(lastError);
203
+ if (m)
204
+ return classifyHttpStatus(Number(m[1])) === 'transient';
205
+ return true; // network/timeout/unknown → transient
206
+ }
207
+ /**
208
+ * Schedule a transient-failure retry. Keeps the row `pending` with a future
209
+ * `next_retry_at` using capped exponential backoff (min(2^attempts*30s, 1h)).
210
+ * Crucially this does NOT honour max_attempts — transient errors retry until
211
+ * the 7-day TTL purge, so an overnight outage recovers instead of being
212
+ * permanently lost after 3 strikes. `attempts` still increments for observability.
213
+ */
214
+ function scheduleRetry(rowId, currentAttempts, newAttempts, errorMsg) {
167
215
  const db = getDatabase();
168
- if (newAttempts >= maxAttempts) {
169
- db.prepare(`
170
- UPDATE sync_queue SET status = 'failed', attempts = ?, last_error = ?
171
- WHERE id = ?
172
- `).run(newAttempts, errorMsg, rowId);
173
- return true; // permanently failed
174
- }
175
- const backoffMs = Math.pow(2, currentAttempts) * 30_000;
216
+ const backoffMs = Math.min(Math.pow(2, currentAttempts) * BASE_BACKOFF_MS, MAX_BACKOFF_MS);
176
217
  const nextRetry = new Date(Date.now() + backoffMs).toISOString();
177
218
  db.prepare(`
178
- UPDATE sync_queue SET attempts = ?, next_retry_at = ?, last_error = ?
219
+ UPDATE sync_queue SET status = 'pending', attempts = ?, next_retry_at = ?, last_error = ?
179
220
  WHERE id = ?
180
221
  `).run(newAttempts, nextRetry, errorMsg, rowId);
181
- return false;
222
+ }
223
+ /**
224
+ * Mark a queue row permanently failed (HTTP 4xx). No further retries.
225
+ */
226
+ function markPermanentlyFailed(rowId, newAttempts, errorMsg) {
227
+ const db = getDatabase();
228
+ db.prepare(`
229
+ UPDATE sync_queue SET status = 'failed', attempts = ?, last_error = ?
230
+ WHERE id = ?
231
+ `).run(newAttempts, errorMsg, rowId);
232
+ }
233
+ /**
234
+ * Revive `failed` rows that were really transient failures (old 3-attempt
235
+ * logic, or pre-upgrade rows). Only rows still within the 7-day TTL window
236
+ * and whose `last_error` looks transient are reset to `pending` + due now.
237
+ * Genuine 4xx failures stay failed. Returns the number of rows resurrected.
238
+ */
239
+ function resurrectTransientFailures() {
240
+ const db = getDatabase();
241
+ const now = new Date().toISOString();
242
+ const cutoff = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString();
243
+ // Resurrect failed rows within TTL whose last_error is NOT a 4xx (4xx except
244
+ // 429 are permanent). `HTTP 429` and `HTTP 5xx` and network/timeout messages
245
+ // all fall through to transient. NULL last_error → transient (be generous).
246
+ const result = db.prepare(`
247
+ UPDATE sync_queue
248
+ SET status = 'pending', next_retry_at = ?
249
+ WHERE status = 'failed'
250
+ AND created_at > ?
251
+ AND (
252
+ last_error IS NULL
253
+ OR last_error NOT GLOB 'HTTP 4[0-9][0-9]*'
254
+ OR last_error GLOB 'HTTP 429*'
255
+ )
256
+ `).run(now, cutoff);
257
+ return Number(result.changes ?? 0);
182
258
  }
183
259
  function formatQueueError(err) {
184
260
  const name = err instanceof Error ? err.name : '';
@@ -191,14 +267,25 @@ function formatQueueError(err) {
191
267
  }
192
268
  return message;
193
269
  }
270
+ // Default per-tick budget for the full profile. Kept at the historical value
271
+ // so dashboard behaviour is unchanged; mcp callers pass a smaller budget.
272
+ const DEFAULT_RETRY_BUDGET = 10;
194
273
  /**
195
274
  * Process pending items in the retry queue.
196
- * SELECT pending WHERE next_retry_at <= now, retry each (up to 10 per tick).
275
+ *
276
+ * Runs a resurrection pass first (revive transiently-failed rows within TTL),
277
+ * then SELECTs pending rows due for retry (up to `maxRows`) and attempts each.
197
278
  * Awaits each fetch so results are accurate and no double-processing occurs.
279
+ *
280
+ * Failure handling:
281
+ * - HTTP 4xx (≠429) → permanent: mark failed, no further retries.
282
+ * - network/timeout/5xx/429 → transient: keep pending with capped (≤1h)
283
+ * backoff, retrying until the 7-day TTL purge — survives long outages.
198
284
  */
199
- export async function processRetryQueue() {
285
+ export async function processRetryQueue(options = {}) {
200
286
  const db = getDatabase();
201
287
  const config = getCloudConfig();
288
+ const limit = options.maxRows && options.maxRows > 0 ? options.maxRows : DEFAULT_RETRY_BUDGET;
202
289
  const result = {
203
290
  processed: 0,
204
291
  succeeded: 0,
@@ -209,15 +296,23 @@ export async function processRetryQueue() {
209
296
  if (!config.cloudEnabled || !config.cloudApiKey) {
210
297
  return result;
211
298
  }
299
+ // Revive any transiently-failed rows (old 3-attempt logic / pre-upgrade)
300
+ // before selecting the pending batch, so they get a chance this tick.
301
+ try {
302
+ resurrectTransientFailures();
303
+ }
304
+ catch {
305
+ /* best-effort — resurrection failure must not block live retries */
306
+ }
212
307
  const now = new Date().toISOString();
213
- // Fetch up to 10 pending items ready for retry
308
+ // Fetch pending items ready for retry, bounded by the budget.
214
309
  const rows = db.prepare(`
215
- SELECT id, payload, attempts, max_attempts
310
+ SELECT id, payload, attempts
216
311
  FROM sync_queue
217
312
  WHERE status = 'pending' AND next_retry_at <= ?
218
313
  ORDER BY next_retry_at ASC
219
- LIMIT 10
220
- `).all(now);
314
+ LIMIT ?
315
+ `).all(now, limit);
221
316
  if (rows.length === 0) {
222
317
  return result;
223
318
  }
@@ -250,21 +345,21 @@ export async function processRetryQueue() {
250
345
  }
251
346
  catch { /* non-critical */ }
252
347
  }
348
+ else if (classifyHttpStatus(res.status) === 'permanent') {
349
+ markPermanentlyFailed(row.id, newAttempts, `HTTP ${res.status}`);
350
+ result.permanentlyFailed++;
351
+ }
253
352
  else {
254
- const permanent = markRetryOrFailed(row.id, row.attempts, newAttempts, row.max_attempts, `HTTP ${res.status}`);
255
- if (permanent)
256
- result.permanentlyFailed++;
257
- else
258
- result.failed++;
353
+ // 5xx / 429 transient, keep retrying with capped backoff.
354
+ scheduleRetry(row.id, row.attempts, newAttempts, `HTTP ${res.status}`);
355
+ result.failed++;
259
356
  }
260
357
  }
261
358
  catch (err) {
359
+ // Network errors, timeouts (AbortError) — all transient.
262
360
  const errorMsg = formatQueueError(err);
263
- const permanent = markRetryOrFailed(row.id, row.attempts, newAttempts, row.max_attempts, errorMsg);
264
- if (permanent)
265
- result.permanentlyFailed++;
266
- else
267
- result.failed++;
361
+ scheduleRetry(row.id, row.attempts, newAttempts, errorMsg);
362
+ result.failed++;
268
363
  }
269
364
  }
270
365
  return result;
@@ -6,10 +6,29 @@
6
6
  * toolchain to compile from source), the native load fails — historically
7
7
  * with a bare `libc++abi: terminating ... Napi::Error` crash-loop and zero
8
8
  * guidance. This module is the single place better-sqlite3 is loaded at
9
- * runtime: it turns that failure into one actionable message and a clean
10
- * exit instead of an opaque abort.
9
+ * runtime: it turns that failure into one actionable, catchable error
10
+ * instead of an opaque abort.
11
+ *
12
+ * It must NEVER call `process.exit()`: this module is reachable from the
13
+ * library entry (`shieldcortex` → `initDatabase`), so a host app that merely
14
+ * imports the package must not be terminated. The load failure is thrown as a
15
+ * typed `NativeModuleLoadError`; a CLI/server entry point can catch it and
16
+ * decide to exit, but the module itself stays a well-behaved library.
11
17
  */
12
18
  import type DatabaseConstructor from 'better-sqlite3';
19
+ /**
20
+ * Thrown when the better-sqlite3 native binding cannot be loaded (missing /
21
+ * ABI-mismatched / wrong-arch prebuild, or the module is not installed).
22
+ *
23
+ * Carries the actionable, formatted guidance in `.message` so a caller can
24
+ * print it verbatim. Typed so entry points can distinguish an environmental
25
+ * install problem from a genuine runtime error and exit cleanly if they choose.
26
+ */
27
+ export declare class NativeModuleLoadError extends Error {
28
+ /** The original error raised by `require('better-sqlite3')`. */
29
+ readonly cause: unknown;
30
+ constructor(message: string, cause: unknown);
31
+ }
13
32
  /**
14
33
  * Build the user-facing message for a native-load failure. Pure and
15
34
  * side-effect free so it can be unit-tested without breaking the binding.
@@ -6,11 +6,34 @@
6
6
  * toolchain to compile from source), the native load fails — historically
7
7
  * with a bare `libc++abi: terminating ... Napi::Error` crash-loop and zero
8
8
  * guidance. This module is the single place better-sqlite3 is loaded at
9
- * runtime: it turns that failure into one actionable message and a clean
10
- * exit instead of an opaque abort.
9
+ * runtime: it turns that failure into one actionable, catchable error
10
+ * instead of an opaque abort.
11
+ *
12
+ * It must NEVER call `process.exit()`: this module is reachable from the
13
+ * library entry (`shieldcortex` → `initDatabase`), so a host app that merely
14
+ * imports the package must not be terminated. The load failure is thrown as a
15
+ * typed `NativeModuleLoadError`; a CLI/server entry point can catch it and
16
+ * decide to exit, but the module itself stays a well-behaved library.
11
17
  */
12
18
  import { createRequire } from 'module';
13
19
  const require = createRequire(import.meta.url);
20
+ /**
21
+ * Thrown when the better-sqlite3 native binding cannot be loaded (missing /
22
+ * ABI-mismatched / wrong-arch prebuild, or the module is not installed).
23
+ *
24
+ * Carries the actionable, formatted guidance in `.message` so a caller can
25
+ * print it verbatim. Typed so entry points can distinguish an environmental
26
+ * install problem from a genuine runtime error and exit cleanly if they choose.
27
+ */
28
+ export class NativeModuleLoadError extends Error {
29
+ /** The original error raised by `require('better-sqlite3')`. */
30
+ cause;
31
+ constructor(message, cause) {
32
+ super(message);
33
+ this.name = 'NativeModuleLoadError';
34
+ this.cause = cause;
35
+ }
36
+ }
14
37
  /**
15
38
  * Build the user-facing message for a native-load failure. Pure and
16
39
  * side-effect free so it can be unit-tested without breaking the binding.
@@ -67,9 +90,10 @@ function loadBetterSqlite3() {
67
90
  }
68
91
  catch (err) {
69
92
  const message = formatNativeLoadError(err, process.version, String(process.versions.modules));
70
- // Clean, single-message fatal exit never the bare libc++abi crash-loop.
71
- console.error(`\n${message}\n`);
72
- process.exit(1);
93
+ // THROW, never exit: this module is imported by the library entry, so it
94
+ // must not kill a host app. The message carries the rebuild guidance; an
95
+ // entry point (CLI/server) may catch this and exit if it wants to.
96
+ throw new NativeModuleLoadError(message, err);
73
97
  }
74
98
  }
75
99
  const BetterSqlite3 = loadBetterSqlite3();
@@ -9,6 +9,7 @@ import { fileURLToPath } from 'url';
9
9
  import { execSync } from 'child_process';
10
10
  import { runMigrations } from './migrations.js';
11
11
  import { getInlineSchema } from './inline-schema.js';
12
+ import { seedDefaultFirewallRules } from './seed-firewall-rules.js';
12
13
  const _currentFile = fileURLToPath(import.meta.url);
13
14
  const _currentDir = dirname(_currentFile);
14
15
  let db = null;
@@ -427,7 +428,20 @@ export function initDatabase(dbPath) {
427
428
  currentDbPath = expandedPath;
428
429
  acquireStartupLock(expandedPath);
429
430
  console.error(`[database] Startup runtime=${resolveRuntimeInfo().kind} db=${expandedPath} wal=${existsSync(expandedPath + '-wal')} shm=${existsSync(expandedPath + '-shm')}`);
430
- const healthyBackups = listHealthyBackups(expandedPath);
431
+ // Lazily inspect `.corrupt.*` backups (Phase 17 B4). Each backup inspection
432
+ // opens the file read-only and runs a FULL integrity check, so doing it
433
+ // unconditionally on every startup paid a per-backup scan even when the live
434
+ // DB opened cleanly. Defer it: the only consumers are the corruption /
435
+ // empty-live recovery branches below, so the scan now happens ONLY when
436
+ // recovery is actually invoked. Memoised so a branch that consults it twice
437
+ // still inspects each backup once.
438
+ let _healthyBackups = null;
439
+ const getHealthyBackups = () => {
440
+ if (_healthyBackups === null) {
441
+ _healthyBackups = listHealthyBackups(expandedPath);
442
+ }
443
+ return _healthyBackups;
444
+ };
431
445
  // Wrap the initial open in try/catch to handle corrupt files gracefully
432
446
  let database;
433
447
  try {
@@ -452,7 +466,7 @@ export function initDatabase(dbPath) {
452
466
  }
453
467
  // Database file is corrupt or not a valid SQLite database
454
468
  console.error(`❌ Database open failed for ${expandedPath}: ${openError}`);
455
- const latestHealthyBackup = healthyBackups[0];
469
+ const latestHealthyBackup = getHealthyBackups()[0];
456
470
  if (latestHealthyBackup) {
457
471
  console.error(`[database] Restoring latest healthy backup with ${latestHealthyBackup.count} memories: ${latestHealthyBackup.path}`);
458
472
  restoreBackupAsLive(expandedPath, latestHealthyBackup.path, 'failed-open');
@@ -465,13 +479,21 @@ export function initDatabase(dbPath) {
465
479
  database = new BetterSqlite3(expandedPath);
466
480
  }
467
481
  }
468
- // Integrity check on existing databases (skip for newly created files)
482
+ // Integrity check on existing databases (skip for newly created files).
483
+ // This is the SINGLE live-DB integrity scan on the startup path (Phase 17
484
+ // B4). `liveIntegrityOk` records its outcome so the empty-live heuristic
485
+ // below can reuse it instead of re-opening the file and scanning a second
486
+ // time. It stays true for freshly-created files (size 0, check skipped) and
487
+ // for connections rebuilt by a recovery branch — both are known-good.
488
+ let liveIntegrityOk = true;
469
489
  if (existsSync(expandedPath) && statSync(expandedPath).size > 0) {
470
490
  const integrityResult = runIntegrityCheck(database);
491
+ liveIntegrityOk = integrityResult === 'ok';
471
492
  if (integrityResult !== 'ok') {
472
493
  console.warn(`[database] WARNING: Database integrity check failed: ${integrityResult}`);
473
494
  if (isLikelyFtsIntegrityIssue(integrityResult) && attemptFtsRecovery(database)) {
474
495
  console.warn('[database] Preserved memory rows by repairing the FTS index in place.');
496
+ liveIntegrityOk = true; // FTS rebuild re-verified integrity == 'ok'.
475
497
  }
476
498
  else {
477
499
  const freshIntegrityResult = verifyOnDiskIntegrity(expandedPath);
@@ -479,6 +501,7 @@ export function initDatabase(dbPath) {
479
501
  console.warn('[database] Integrity failure was transient. Reopening the on-disk database without destructive recovery.');
480
502
  database.close();
481
503
  database = new BetterSqlite3(expandedPath);
504
+ liveIntegrityOk = true; // On-disk re-check was clean.
482
505
  }
483
506
  else {
484
507
  console.warn(`[database] Fresh integrity check also failed: ${freshIntegrityResult}`);
@@ -490,7 +513,7 @@ export function initDatabase(dbPath) {
490
513
  database = recovered;
491
514
  }
492
515
  else {
493
- const latestHealthyBackup = healthyBackups[0];
516
+ const latestHealthyBackup = getHealthyBackups()[0];
494
517
  if (latestHealthyBackup) {
495
518
  console.error(`[database] Recovery failed. Restoring latest healthy backup with ${latestHealthyBackup.count} memories: ${latestHealthyBackup.path}`);
496
519
  restoreBackupAsLive(expandedPath, latestHealthyBackup.path, 'recovery-failed');
@@ -506,23 +529,40 @@ export function initDatabase(dbPath) {
506
529
  database = new BetterSqlite3(expandedPath);
507
530
  }
508
531
  }
532
+ // Dump-recovery, backup-restore and fresh-create all yield a
533
+ // known-good DB — the empty-live heuristic can trust it.
534
+ liveIntegrityOk = true;
509
535
  }
510
536
  }
511
537
  }
512
538
  }
513
- const currentInspection = inspectDatabaseFile(expandedPath);
514
- const latestHealthyBackup = healthyBackups[0];
539
+ // Empty-live recovery heuristic (Phase 17 B4): this used to call
540
+ // `inspectDatabaseFile(expandedPath)`, which RE-OPENED the live file
541
+ // read-only and ran a SECOND full integrity check purely to obtain the row
542
+ // count — duplicating the scan already performed above. Now the count comes
543
+ // from the open connection and integrity is reused from `liveIntegrityOk`.
544
+ // `getHealthyBackups()` (the eager per-backup scan) is consulted ONLY when
545
+ // the live DB is actually healthy-but-empty, so a normal startup never
546
+ // inspects a backup at all.
547
+ let liveCount = null;
548
+ try {
549
+ liveCount = database.prepare('SELECT COUNT(*) AS count FROM memories').get().count;
550
+ }
551
+ catch {
552
+ liveCount = null;
553
+ }
515
554
  const liveStats = existsSync(expandedPath) ? statSync(expandedPath) : null;
516
- if (currentInspection.integrity === 'ok'
517
- && currentInspection.count === 0
518
- && latestHealthyBackup
519
- && latestHealthyBackup.count >= 100
520
- && liveStats
521
- && (liveStats.mtimeMs - latestHealthyBackup.mtimeMs) < (24 * 60 * 60 * 1000)) {
522
- console.error(`[database] Empty live database detected alongside a recent healthy backup (${latestHealthyBackup.count} memories). Restoring ${latestHealthyBackup.path}`);
523
- database.close();
524
- restoreBackupAsLive(expandedPath, latestHealthyBackup.path, 'empty-live');
525
- database = new BetterSqlite3(expandedPath);
555
+ if (liveIntegrityOk && liveCount === 0) {
556
+ const latestHealthyBackup = getHealthyBackups()[0];
557
+ if (latestHealthyBackup
558
+ && latestHealthyBackup.count >= 100
559
+ && liveStats
560
+ && (liveStats.mtimeMs - latestHealthyBackup.mtimeMs) < (24 * 60 * 60 * 1000)) {
561
+ console.error(`[database] Empty live database detected alongside a recent healthy backup (${latestHealthyBackup.count} memories). Restoring ${latestHealthyBackup.path}`);
562
+ database.close();
563
+ restoreBackupAsLive(expandedPath, latestHealthyBackup.path, 'empty-live');
564
+ database = new BetterSqlite3(expandedPath);
565
+ }
526
566
  }
527
567
  db = database;
528
568
  // Record file identity so getDatabase() can detect if the file was replaced
@@ -577,6 +617,18 @@ export function initDatabase(dbPath) {
577
617
  // Inline schema if file not found (for bundled deployment)
578
618
  db.exec(getInlineSchema());
579
619
  }
620
+ // Seed built-in firewall rules. This runs AFTER the schema so the
621
+ // firewall_rules table is guaranteed to exist — `runMigrations()` returns
622
+ // early on a fresh DB (no `memories` table), so seeding cannot live there or
623
+ // it never fires for new installs (the case the README's "seeded on first
624
+ // run" promise covers). Idempotent: the seeder no-ops when built_in rows are
625
+ // already present, so re-running on every startup is safe and cheap.
626
+ try {
627
+ seedDefaultFirewallRules(db);
628
+ }
629
+ catch {
630
+ // Seeder is best-effort; a failure here must never block startup.
631
+ }
580
632
  return db;
581
633
  }
582
634
  /**
@@ -69,7 +69,7 @@ export function getInlineSchema() {
69
69
  VALUES('delete', old.id, old.title, old.content, old.tags);
70
70
  END;
71
71
 
72
- CREATE TRIGGER IF NOT EXISTS memories_au AFTER UPDATE ON memories BEGIN
72
+ CREATE TRIGGER IF NOT EXISTS memories_au AFTER UPDATE OF title, content, tags ON memories BEGIN
73
73
  INSERT INTO memories_fts(memories_fts, rowid, title, content, tags)
74
74
  VALUES('delete', old.id, old.title, old.content, old.tags);
75
75
  INSERT INTO memories_fts(rowid, title, content, tags)
@@ -183,6 +183,18 @@ export function getInlineSchema() {
183
183
  CREATE INDEX IF NOT EXISTS idx_audit_source ON defence_audit(source_type);
184
184
  CREATE INDEX IF NOT EXISTS idx_audit_project ON defence_audit(project);
185
185
 
186
+ -- Cumulative audit aggregate (single row, id=1) — retention rollup target.
187
+ -- See schema.sql for the rationale.
188
+ CREATE TABLE IF NOT EXISTS audit_aggregates (
189
+ id INTEGER PRIMARY KEY CHECK (id = 1),
190
+ total_scans INTEGER NOT NULL DEFAULT 0,
191
+ threats_blocked INTEGER NOT NULL DEFAULT 0,
192
+ quarantined INTEGER NOT NULL DEFAULT 0,
193
+ memories_protected INTEGER NOT NULL DEFAULT 0,
194
+ credential_leaks INTEGER NOT NULL DEFAULT 0,
195
+ updated_at TEXT
196
+ );
197
+
186
198
  CREATE TABLE IF NOT EXISTS quarantine (
187
199
  id INTEGER PRIMARY KEY AUTOINCREMENT,
188
200
  original_content TEXT NOT NULL,
@@ -283,10 +295,12 @@ export function getInlineSchema() {
283
295
  condition_value TEXT NOT NULL,
284
296
  action TEXT NOT NULL CHECK(action IN ('block', 'allow', 'quarantine')),
285
297
  enabled INTEGER NOT NULL DEFAULT 1,
298
+ built_in INTEGER NOT NULL DEFAULT 0,
286
299
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
287
300
  );
288
301
  CREATE INDEX IF NOT EXISTS idx_firewall_rules_priority ON firewall_rules(priority);
289
302
  CREATE INDEX IF NOT EXISTS idx_firewall_rules_enabled ON firewall_rules(enabled);
303
+ CREATE INDEX IF NOT EXISTS idx_firewall_rules_built_in ON firewall_rules(built_in);
290
304
 
291
305
  CREATE TABLE IF NOT EXISTS rate_limits (
292
306
  source_key TEXT PRIMARY KEY,
@@ -294,6 +308,14 @@ export function getInlineSchema() {
294
308
  window_start_ms INTEGER NOT NULL
295
309
  );
296
310
 
311
+ -- Control state (single row, cross-process kill-switch / pause)
312
+ CREATE TABLE IF NOT EXISTS control_state (
313
+ id INTEGER PRIMARY KEY CHECK (id = 1),
314
+ mode TEXT NOT NULL DEFAULT 'active' CHECK (mode IN ('active','paused','kill_switch')),
315
+ meta_json TEXT,
316
+ updated_at TEXT NOT NULL
317
+ );
318
+
297
319
  -- v4.17 Session capture (mirrors schema.sql; bundled fallback only).
298
320
  -- v4.28 (Fix #10): + sensitivity_level for prompt-redaction tagging.
299
321
  CREATE TABLE IF NOT EXISTS session_events (
@@ -318,5 +340,17 @@ export function getInlineSchema() {
318
340
  CREATE INDEX IF NOT EXISTS idx_session_events_sensitivity ON session_events(sensitivity_level);
319
341
  CREATE UNIQUE INDEX IF NOT EXISTS idx_session_events_dedupe
320
342
  ON session_events(session_id, ts, kind, content_hash);
343
+
344
+ -- Phase 14: MCP tool-description hashes (drift / rug-pull detection).
345
+ -- Mirrors schema.sql.
346
+ CREATE TABLE IF NOT EXISTS mcp_tool_hashes (
347
+ server_name TEXT NOT NULL,
348
+ tool_name TEXT NOT NULL,
349
+ content_hash TEXT NOT NULL,
350
+ first_seen TEXT,
351
+ last_seen TEXT,
352
+ last_changed TEXT,
353
+ PRIMARY KEY (server_name, tool_name)
354
+ );
321
355
  `;
322
356
  }