shieldcortex 4.31.1 → 4.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (346) 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/mcp.d.ts +13 -0
  239. package/dist/cli/mcp.js +0 -0
  240. package/dist/cli/remember.d.ts +75 -0
  241. package/dist/cli/remember.js +195 -0
  242. package/dist/cloud/config.d.ts +23 -1
  243. package/dist/cloud/config.js +453 -193
  244. package/dist/cloud/quarantine-sync.d.ts +12 -2
  245. package/dist/cloud/quarantine-sync.js +28 -6
  246. package/dist/cloud/sync-queue.d.ts +21 -2
  247. package/dist/cloud/sync-queue.js +124 -29
  248. package/dist/database/better-sqlite3-guard.d.ts +27 -2
  249. package/dist/database/better-sqlite3-guard.js +58 -5
  250. package/dist/database/init.js +85 -17
  251. package/dist/database/inline-schema.js +35 -1
  252. package/dist/database/migrations.js +104 -8
  253. package/dist/database/schema.sql +39 -1
  254. package/dist/defence/audit/queries.d.ts +10 -2
  255. package/dist/defence/audit/queries.js +30 -4
  256. package/dist/defence/audit/retention.d.ts +50 -0
  257. package/dist/defence/audit/retention.js +161 -0
  258. package/dist/defence/credential-leak/entropy.d.ts +11 -0
  259. package/dist/defence/credential-leak/entropy.js +27 -0
  260. package/dist/defence/credential-leak/index.js +27 -1
  261. package/dist/defence/credential-leak/patterns.d.ts +9 -0
  262. package/dist/defence/credential-leak/patterns.js +21 -0
  263. package/dist/defence/custom-patterns/store.js +8 -1
  264. package/dist/defence/custom-rules/store.d.ts +18 -0
  265. package/dist/defence/custom-rules/store.js +63 -0
  266. package/dist/defence/firewall/confusables.d.ts +30 -0
  267. package/dist/defence/firewall/confusables.js +87 -0
  268. package/dist/defence/firewall/encoding-detector.js +23 -9
  269. package/dist/defence/firewall/index.d.ts +11 -1
  270. package/dist/defence/firewall/index.js +34 -1
  271. package/dist/defence/firewall/instruction-detector.js +18 -7
  272. package/dist/defence/firewall/markdown-image-detector.d.ts +34 -0
  273. package/dist/defence/firewall/markdown-image-detector.js +83 -0
  274. package/dist/defence/fragmentation/entity-extractor.js +17 -6
  275. package/dist/defence/index.d.ts +5 -0
  276. package/dist/defence/index.js +8 -0
  277. package/dist/defence/iron-dome/index.js +7 -1
  278. package/dist/defence/pipeline.js +62 -10
  279. package/dist/defence/scan-windows.d.ts +41 -0
  280. package/dist/defence/scan-windows.js +61 -0
  281. package/dist/defence/semantic/attack-corpus.d.ts +22 -0
  282. package/dist/defence/semantic/attack-corpus.js +75 -0
  283. package/dist/defence/semantic/index.d.ts +67 -0
  284. package/dist/defence/semantic/index.js +138 -0
  285. package/dist/defence/skill-scanner/deep-scan.js +35 -15
  286. package/dist/defence/skill-scanner/patterns.d.ts +1 -1
  287. package/dist/defence/skill-scanner/patterns.js +8 -7
  288. package/dist/defence/tool-response-scanner.d.ts +21 -5
  289. package/dist/defence/tool-response-scanner.js +111 -22
  290. package/dist/defence/types.d.ts +11 -1
  291. package/dist/index.d.ts +29 -0
  292. package/dist/index.js +104 -20
  293. package/dist/memory/consolidate.js +1 -1
  294. package/dist/memory/decay.js +3 -1
  295. package/dist/memory/embedding.d.ts +18 -2
  296. package/dist/memory/embedding.js +32 -11
  297. package/dist/memory/expiry.js +1 -1
  298. package/dist/memory/search-recall.js +107 -49
  299. package/dist/memory/search.d.ts +19 -3
  300. package/dist/memory/search.js +25 -10
  301. package/dist/memory/store.d.ts +13 -2
  302. package/dist/memory/store.js +115 -11
  303. package/dist/scan-only.d.ts +64 -0
  304. package/dist/scan-only.js +173 -0
  305. package/dist/server.d.ts +5 -0
  306. package/dist/server.js +6 -4
  307. package/dist/setup/claude-md.js +39 -34
  308. package/dist/setup/codex.js +9 -2
  309. package/dist/setup/copilot.js +160 -47
  310. package/dist/setup/json-config.d.ts +99 -0
  311. package/dist/setup/json-config.js +167 -0
  312. package/dist/setup/migrate.js +1 -1
  313. package/dist/setup/settings-hooks.js +8 -13
  314. package/dist/setup/uninstall.js +1 -21
  315. package/dist/tools/context.d.ts +8 -8
  316. package/dist/tools/forget.d.ts +9 -8
  317. package/dist/tools/forget.js +17 -4
  318. package/dist/tools/recall.d.ts +13 -13
  319. package/dist/tools/remember.d.ts +16 -16
  320. package/dist/tools/remember.js +19 -8
  321. package/dist/worker/brain-worker.d.ts +1 -0
  322. package/dist/worker/brain-worker.js +79 -16
  323. package/dist/worker/types.d.ts +8 -0
  324. package/dist/worker/types.js +8 -0
  325. package/dist/xray/dir-scanner.d.ts +18 -0
  326. package/dist/xray/dir-scanner.js +23 -1
  327. package/dist/xray/file-scanner.js +16 -1
  328. package/dist/xray/findings-store.js +9 -1
  329. package/dist/xray/index.d.ts +2 -0
  330. package/dist/xray/index.js +10 -1
  331. package/dist/xray/npm-inspector.d.ts +31 -0
  332. package/dist/xray/npm-inspector.js +135 -29
  333. package/dist/xray/patterns.d.ts +1 -1
  334. package/dist/xray/patterns.js +20 -23
  335. package/dist/xray/sarif.d.ts +78 -0
  336. package/dist/xray/sarif.js +166 -0
  337. package/dist/xray/watch.d.ts +1 -0
  338. package/dist/xray/watch.js +10 -1
  339. package/hooks/openclaw/cortex-memory/handler.ts +122 -18
  340. package/hooks/openclaw/cortex-memory/runtime.mjs +10 -4
  341. package/package.json +10 -3
  342. package/dist/memory/embedding-cache.d.ts +0 -20
  343. package/dist/memory/embedding-cache.js +0 -91
  344. /package/dashboard/.next/standalone/dashboard/.next/static/{T0hqc-Le01c8QVY0VrHnu → Ox9scglBehbbCk7DD8-Vn}/_buildManifest.js +0 -0
  345. /package/dashboard/.next/standalone/dashboard/.next/static/{T0hqc-Le01c8QVY0VrHnu → Ox9scglBehbbCk7DD8-Vn}/_clientMiddlewareManifest.json +0 -0
  346. /package/dashboard/.next/standalone/dashboard/.next/static/{T0hqc-Le01c8QVY0VrHnu → Ox9scglBehbbCk7DD8-Vn}/_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,15 +6,40 @@
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.
16
35
  */
17
36
  export declare function formatNativeLoadError(err: unknown, nodeVersion: string, abi: string): string;
37
+ /**
38
+ * True when an error from opening the database is a better-sqlite3 native-module
39
+ * load failure (environmental), as opposed to genuine file corruption. Pure +
40
+ * exported so the init path can route it away from destructive recovery.
41
+ */
42
+ export declare function isNativeModuleLoadError(error: unknown): boolean;
18
43
  declare const BetterSqlite3: typeof DatabaseConstructor;
19
44
  export type { DatabaseConstructor };
20
45
  export default BetterSqlite3;
@@ -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.
@@ -32,15 +55,45 @@ export function formatNativeLoadError(err, nodeVersion, abi) {
32
55
  `Underlying error: ${detail}`,
33
56
  ].join('\n');
34
57
  }
58
+ /**
59
+ * Signatures of a NATIVE-MODULE load failure (missing / ABI-mismatched / wrong-
60
+ * arch better-sqlite3 binding, or the module not being installed). These throw
61
+ * from `new Database()` — better-sqlite3 resolves its binding lazily at
62
+ * construction, not at require() — and must be distinguished from genuine SQLite
63
+ * FILE corruption: a load failure is an install problem, and treating it as
64
+ * corruption (renaming the live DB to .corrupt.*) is data loss.
65
+ */
66
+ const NATIVE_LOAD_SIGNATURES = [
67
+ /could not locate the bindings file/i,
68
+ /better_sqlite3\.node/i,
69
+ /NODE_MODULE_VERSION/i,
70
+ /compiled against a different node/i,
71
+ /invalid ELF header/i,
72
+ /wrong ELF class/i,
73
+ /dlopen\(/i,
74
+ /symbol not found/i,
75
+ /specified module could not be found/i,
76
+ /cannot find module ['"]better-sqlite3/i,
77
+ ];
78
+ /**
79
+ * True when an error from opening the database is a better-sqlite3 native-module
80
+ * load failure (environmental), as opposed to genuine file corruption. Pure +
81
+ * exported so the init path can route it away from destructive recovery.
82
+ */
83
+ export function isNativeModuleLoadError(error) {
84
+ const msg = error instanceof Error ? error.message : String(error ?? '');
85
+ return NATIVE_LOAD_SIGNATURES.some((re) => re.test(msg));
86
+ }
35
87
  function loadBetterSqlite3() {
36
88
  try {
37
89
  return require('better-sqlite3');
38
90
  }
39
91
  catch (err) {
40
92
  const message = formatNativeLoadError(err, process.version, String(process.versions.modules));
41
- // Clean, single-message fatal exit never the bare libc++abi crash-loop.
42
- console.error(`\n${message}\n`);
43
- 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);
44
97
  }
45
98
  }
46
99
  const BetterSqlite3 = loadBetterSqlite3();
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Database initialization and connection management
3
3
  */
4
- import BetterSqlite3 from './better-sqlite3-guard.js';
4
+ import BetterSqlite3, { isNativeModuleLoadError } from './better-sqlite3-guard.js';
5
5
  import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync, unlinkSync, renameSync, copyFileSync, readdirSync, openSync, closeSync, realpathSync } from 'fs';
6
6
  import { basename, dirname, join } from 'path';
7
7
  import { homedir } from 'os';
@@ -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,16 +428,45 @@ 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 {
434
448
  database = new BetterSqlite3(expandedPath);
435
449
  }
436
450
  catch (openError) {
451
+ // A NATIVE-MODULE load failure (missing / ABI-mismatched better-sqlite3
452
+ // binding) throws here too — better-sqlite3 resolves its binding lazily in
453
+ // the constructor, so it surfaces at open time, NOT at require(). That is an
454
+ // INSTALL problem, not file corruption: renaming a healthy DB to .corrupt.*
455
+ // here is data loss (observed 2026-06-09 on an arm64 box after a Node/native
456
+ // mismatch — a live memories.db was moved aside). Never touch the DB file on
457
+ // a binding error; surface an actionable message and let the caller stop.
458
+ if (isNativeModuleLoadError(openError)) {
459
+ const detail = openError instanceof Error ? openError.message : String(openError);
460
+ throw new Error('ShieldCortex could not load its database engine (the better-sqlite3 native module). ' +
461
+ `This is an install / Node-version issue, NOT database corruption — your data at ${expandedPath} is untouched. ` +
462
+ 'Rebuild the native module and retry:\n' +
463
+ ' cd "$(npm root -g)/shieldcortex" && npm rebuild better-sqlite3\n' +
464
+ '(install a C/C++ toolchain first if it fails to compile)\n' +
465
+ `Underlying error: ${detail}`);
466
+ }
437
467
  // Database file is corrupt or not a valid SQLite database
438
468
  console.error(`❌ Database open failed for ${expandedPath}: ${openError}`);
439
- const latestHealthyBackup = healthyBackups[0];
469
+ const latestHealthyBackup = getHealthyBackups()[0];
440
470
  if (latestHealthyBackup) {
441
471
  console.error(`[database] Restoring latest healthy backup with ${latestHealthyBackup.count} memories: ${latestHealthyBackup.path}`);
442
472
  restoreBackupAsLive(expandedPath, latestHealthyBackup.path, 'failed-open');
@@ -449,13 +479,21 @@ export function initDatabase(dbPath) {
449
479
  database = new BetterSqlite3(expandedPath);
450
480
  }
451
481
  }
452
- // 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;
453
489
  if (existsSync(expandedPath) && statSync(expandedPath).size > 0) {
454
490
  const integrityResult = runIntegrityCheck(database);
491
+ liveIntegrityOk = integrityResult === 'ok';
455
492
  if (integrityResult !== 'ok') {
456
493
  console.warn(`[database] WARNING: Database integrity check failed: ${integrityResult}`);
457
494
  if (isLikelyFtsIntegrityIssue(integrityResult) && attemptFtsRecovery(database)) {
458
495
  console.warn('[database] Preserved memory rows by repairing the FTS index in place.');
496
+ liveIntegrityOk = true; // FTS rebuild re-verified integrity == 'ok'.
459
497
  }
460
498
  else {
461
499
  const freshIntegrityResult = verifyOnDiskIntegrity(expandedPath);
@@ -463,6 +501,7 @@ export function initDatabase(dbPath) {
463
501
  console.warn('[database] Integrity failure was transient. Reopening the on-disk database without destructive recovery.');
464
502
  database.close();
465
503
  database = new BetterSqlite3(expandedPath);
504
+ liveIntegrityOk = true; // On-disk re-check was clean.
466
505
  }
467
506
  else {
468
507
  console.warn(`[database] Fresh integrity check also failed: ${freshIntegrityResult}`);
@@ -474,7 +513,7 @@ export function initDatabase(dbPath) {
474
513
  database = recovered;
475
514
  }
476
515
  else {
477
- const latestHealthyBackup = healthyBackups[0];
516
+ const latestHealthyBackup = getHealthyBackups()[0];
478
517
  if (latestHealthyBackup) {
479
518
  console.error(`[database] Recovery failed. Restoring latest healthy backup with ${latestHealthyBackup.count} memories: ${latestHealthyBackup.path}`);
480
519
  restoreBackupAsLive(expandedPath, latestHealthyBackup.path, 'recovery-failed');
@@ -490,23 +529,40 @@ export function initDatabase(dbPath) {
490
529
  database = new BetterSqlite3(expandedPath);
491
530
  }
492
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;
493
535
  }
494
536
  }
495
537
  }
496
538
  }
497
- const currentInspection = inspectDatabaseFile(expandedPath);
498
- 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
+ }
499
554
  const liveStats = existsSync(expandedPath) ? statSync(expandedPath) : null;
500
- if (currentInspection.integrity === 'ok'
501
- && currentInspection.count === 0
502
- && latestHealthyBackup
503
- && latestHealthyBackup.count >= 100
504
- && liveStats
505
- && (liveStats.mtimeMs - latestHealthyBackup.mtimeMs) < (24 * 60 * 60 * 1000)) {
506
- console.error(`[database] Empty live database detected alongside a recent healthy backup (${latestHealthyBackup.count} memories). Restoring ${latestHealthyBackup.path}`);
507
- database.close();
508
- restoreBackupAsLive(expandedPath, latestHealthyBackup.path, 'empty-live');
509
- 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
+ }
510
566
  }
511
567
  db = database;
512
568
  // Record file identity so getDatabase() can detect if the file was replaced
@@ -561,6 +617,18 @@ export function initDatabase(dbPath) {
561
617
  // Inline schema if file not found (for bundled deployment)
562
618
  db.exec(getInlineSchema());
563
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
+ }
564
632
  return db;
565
633
  }
566
634
  /**