shieldcortex 4.13.0 → 4.14.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 (235) hide show
  1. package/dashboard/.next/standalone/dashboard/.next/BUILD_ID +1 -1
  2. package/dashboard/.next/standalone/dashboard/.next/build-manifest.json +2 -2
  3. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.html +2 -2
  4. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.rsc +1 -1
  5. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  6. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  7. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  8. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  9. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  10. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.html +1 -1
  11. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.rsc +1 -1
  12. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  13. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  14. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  15. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  16. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  17. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  18. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.html +1 -1
  19. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.rsc +1 -1
  20. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/!KGRhc2hib2FyZCk/admin/__PAGE__.segment.rsc +1 -1
  21. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/!KGRhc2hib2FyZCk/admin.segment.rsc +1 -1
  22. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  23. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_full.segment.rsc +1 -1
  24. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_head.segment.rsc +1 -1
  25. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_index.segment.rsc +1 -1
  26. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_tree.segment.rsc +1 -1
  27. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.html +1 -1
  28. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.rsc +1 -1
  29. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/!KGRhc2hib2FyZCk/cloud/__PAGE__.segment.rsc +1 -1
  30. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/!KGRhc2hib2FyZCk/cloud.segment.rsc +1 -1
  31. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  32. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_full.segment.rsc +1 -1
  33. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_head.segment.rsc +1 -1
  34. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_index.segment.rsc +1 -1
  35. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_tree.segment.rsc +1 -1
  36. package/dashboard/.next/standalone/dashboard/.next/server/app/index.html +1 -1
  37. package/dashboard/.next/standalone/dashboard/.next/server/app/index.rsc +1 -1
  38. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  39. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_full.segment.rsc +1 -1
  40. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_head.segment.rsc +1 -1
  41. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_index.segment.rsc +1 -1
  42. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  43. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.html +1 -1
  44. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.rsc +1 -1
  45. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk/memory/capture/__PAGE__.segment.rsc +1 -1
  46. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk/memory/capture.segment.rsc +1 -1
  47. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  48. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  49. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_full.segment.rsc +1 -1
  50. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_head.segment.rsc +1 -1
  51. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_index.segment.rsc +1 -1
  52. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_tree.segment.rsc +1 -1
  53. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.html +1 -1
  54. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.rsc +1 -1
  55. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk/memory/graph/__PAGE__.segment.rsc +1 -1
  56. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk/memory/graph.segment.rsc +1 -1
  57. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  58. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  59. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_full.segment.rsc +1 -1
  60. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_head.segment.rsc +1 -1
  61. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_index.segment.rsc +1 -1
  62. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_tree.segment.rsc +1 -1
  63. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.html +1 -1
  64. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.rsc +1 -1
  65. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk/memory/recall/__PAGE__.segment.rsc +1 -1
  66. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk/memory/recall.segment.rsc +1 -1
  67. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  68. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  69. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_full.segment.rsc +1 -1
  70. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_head.segment.rsc +1 -1
  71. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_index.segment.rsc +1 -1
  72. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_tree.segment.rsc +1 -1
  73. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.html +1 -1
  74. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.rsc +1 -1
  75. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk/memory/review/__PAGE__.segment.rsc +1 -1
  76. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk/memory/review.segment.rsc +1 -1
  77. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  78. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  79. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_full.segment.rsc +1 -1
  80. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_head.segment.rsc +1 -1
  81. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_index.segment.rsc +1 -1
  82. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_tree.segment.rsc +1 -1
  83. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.html +1 -1
  84. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.rsc +1 -1
  85. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk/memory/timeline/__PAGE__.segment.rsc +1 -1
  86. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk/memory/timeline.segment.rsc +1 -1
  87. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  88. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  89. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_full.segment.rsc +1 -1
  90. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_head.segment.rsc +1 -1
  91. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_index.segment.rsc +1 -1
  92. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_tree.segment.rsc +1 -1
  93. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.html +1 -1
  94. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.rsc +1 -1
  95. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/!KGRhc2hib2FyZCk/memory/__PAGE__.segment.rsc +1 -1
  96. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  97. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  98. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_full.segment.rsc +1 -1
  99. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_head.segment.rsc +1 -1
  100. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_index.segment.rsc +1 -1
  101. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_tree.segment.rsc +1 -1
  102. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.html +1 -1
  103. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.rsc +1 -1
  104. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/!KGRhc2hib2FyZCk/overview/__PAGE__.segment.rsc +1 -1
  105. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/!KGRhc2hib2FyZCk/overview.segment.rsc +1 -1
  106. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  107. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_full.segment.rsc +1 -1
  108. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_head.segment.rsc +1 -1
  109. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_index.segment.rsc +1 -1
  110. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_tree.segment.rsc +1 -1
  111. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.html +1 -1
  112. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.rsc +1 -1
  113. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk/protection/audit/__PAGE__.segment.rsc +1 -1
  114. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk/protection/audit.segment.rsc +1 -1
  115. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  116. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  117. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_full.segment.rsc +1 -1
  118. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_head.segment.rsc +1 -1
  119. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_index.segment.rsc +1 -1
  120. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_tree.segment.rsc +1 -1
  121. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.html +1 -1
  122. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.rsc +1 -1
  123. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk/protection/intercepts/__PAGE__.segment.rsc +1 -1
  124. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk/protection/intercepts.segment.rsc +1 -1
  125. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  126. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  127. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_full.segment.rsc +1 -1
  128. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_head.segment.rsc +1 -1
  129. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_index.segment.rsc +1 -1
  130. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_tree.segment.rsc +1 -1
  131. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.html +1 -1
  132. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.rsc +1 -1
  133. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk/protection/iron-dome/__PAGE__.segment.rsc +1 -1
  134. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk/protection/iron-dome.segment.rsc +1 -1
  135. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  136. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  137. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_full.segment.rsc +1 -1
  138. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_head.segment.rsc +1 -1
  139. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_index.segment.rsc +1 -1
  140. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_tree.segment.rsc +1 -1
  141. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.html +1 -1
  142. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.rsc +1 -1
  143. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk/protection/policies/__PAGE__.segment.rsc +1 -1
  144. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk/protection/policies.segment.rsc +1 -1
  145. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  146. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  147. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_full.segment.rsc +1 -1
  148. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_head.segment.rsc +1 -1
  149. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_index.segment.rsc +1 -1
  150. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_tree.segment.rsc +1 -1
  151. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.html +1 -1
  152. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.rsc +1 -1
  153. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk/protection/quarantine/__PAGE__.segment.rsc +1 -1
  154. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk/protection/quarantine.segment.rsc +1 -1
  155. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  156. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  157. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_full.segment.rsc +1 -1
  158. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_head.segment.rsc +1 -1
  159. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_index.segment.rsc +1 -1
  160. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_tree.segment.rsc +1 -1
  161. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.html +1 -1
  162. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.rsc +1 -1
  163. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/!KGRhc2hib2FyZCk/protection/__PAGE__.segment.rsc +1 -1
  164. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  165. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  166. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_full.segment.rsc +1 -1
  167. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_head.segment.rsc +1 -1
  168. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_index.segment.rsc +1 -1
  169. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_tree.segment.rsc +1 -1
  170. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.html +1 -1
  171. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.rsc +1 -1
  172. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/!KGRhc2hib2FyZCk/settings/__PAGE__.segment.rsc +1 -1
  173. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/!KGRhc2hib2FyZCk/settings.segment.rsc +1 -1
  174. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  175. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_full.segment.rsc +1 -1
  176. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  177. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_index.segment.rsc +1 -1
  178. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
  179. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.html +1 -1
  180. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.rsc +1 -1
  181. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk/supply-chain/xray/__PAGE__.segment.rsc +1 -1
  182. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk/supply-chain/xray.segment.rsc +1 -1
  183. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk/supply-chain.segment.rsc +1 -1
  184. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  185. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_full.segment.rsc +1 -1
  186. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_head.segment.rsc +1 -1
  187. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_index.segment.rsc +1 -1
  188. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_tree.segment.rsc +1 -1
  189. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.html +1 -1
  190. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.rsc +1 -1
  191. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/!KGRhc2hib2FyZCk/supply-chain/__PAGE__.segment.rsc +1 -1
  192. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/!KGRhc2hib2FyZCk/supply-chain.segment.rsc +1 -1
  193. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  194. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_full.segment.rsc +1 -1
  195. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_head.segment.rsc +1 -1
  196. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_index.segment.rsc +1 -1
  197. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_tree.segment.rsc +1 -1
  198. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.html +1 -1
  199. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.rsc +1 -1
  200. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/!KGRhc2hib2FyZCk/xray/__PAGE__.segment.rsc +1 -1
  201. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/!KGRhc2hib2FyZCk/xray.segment.rsc +1 -1
  202. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  203. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_full.segment.rsc +1 -1
  204. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_head.segment.rsc +1 -1
  205. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_index.segment.rsc +1 -1
  206. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_tree.segment.rsc +1 -1
  207. package/dashboard/.next/standalone/dashboard/.next/server/pages/404.html +1 -1
  208. package/dashboard/.next/standalone/dashboard/.next/server/pages/500.html +2 -2
  209. package/dist/cli/doctor.d.ts +16 -0
  210. package/dist/cli/doctor.js +329 -8
  211. package/dist/cli/migrate-legacy.d.ts +30 -0
  212. package/dist/cli/migrate-legacy.js +199 -0
  213. package/dist/cloud/config.d.ts +22 -0
  214. package/dist/cloud/config.js +38 -0
  215. package/dist/context/derive-project-key.d.ts +36 -0
  216. package/dist/context/derive-project-key.js +150 -0
  217. package/dist/context/project-context.d.ts +8 -5
  218. package/dist/context/project-context.js +16 -32
  219. package/dist/index.js +16 -1
  220. package/dist/setup/settings-hooks.d.ts +6 -0
  221. package/dist/setup/settings-hooks.js +37 -3
  222. package/dist/worker/brain-worker.d.ts +13 -5
  223. package/dist/worker/brain-worker.js +80 -40
  224. package/dist/worker/types.d.ts +19 -0
  225. package/dist/worker/types.js +7 -0
  226. package/package.json +1 -1
  227. package/plugins/openclaw/dist/openclaw.plugin.json +1 -1
  228. package/scripts/lib/auto-memory-config.mjs +22 -4
  229. package/scripts/lib/project-key.mjs +6 -0
  230. package/scripts/pre-compact-hook.mjs +2 -34
  231. package/scripts/session-end-hook.mjs +2 -24
  232. package/scripts/stop-hook.mjs +88 -44
  233. /package/dashboard/.next/standalone/dashboard/.next/static/{kiA_iEHG_1wWOEYFsD0Tj → wrB1TUcOfBtV94V2I9t9N}/_buildManifest.js +0 -0
  234. /package/dashboard/.next/standalone/dashboard/.next/static/{kiA_iEHG_1wWOEYFsD0Tj → wrB1TUcOfBtV94V2I9t9N}/_clientMiddlewareManifest.json +0 -0
  235. /package/dashboard/.next/standalone/dashboard/.next/static/{kiA_iEHG_1wWOEYFsD0Tj → wrB1TUcOfBtV94V2I9t9N}/_ssgManifest.js +0 -0
@@ -9,7 +9,7 @@
9
9
  *
10
10
  * This transforms the memory system from reactive to continuously organic.
11
11
  */
12
- import { DEFAULT_WORKER_CONFIG, } from './types.js';
12
+ import { DEFAULT_WORKER_CONFIG, MCP_LIGHT_TICK_INTERVAL_MS, } from './types.js';
13
13
  import { getDatabase } from '../database/init.js';
14
14
  import { pruneActivationCache } from '../memory/activation.js';
15
15
  import { getMemoryStats } from '../memory/store.js';
@@ -22,6 +22,21 @@ import { processRetryQueue, purgeOldEntries } from '../cloud/sync-queue.js';
22
22
  import { sendHeartbeat } from '../cloud/sync.js';
23
23
  import { refreshCloudIronDome, applyCachedCloudPatterns } from '../cloud/iron-dome-sync.js';
24
24
  import { isFeatureEnabled } from '../license/gate.js';
25
+ import { existsSync, mkdirSync, writeFileSync } from 'fs';
26
+ import { join } from 'path';
27
+ import { homedir } from 'os';
28
+ const WORKER_STATE_DIR = join(homedir(), '.shieldcortex', 'state');
29
+ const WORKER_STATE_FILE = join(WORKER_STATE_DIR, 'worker.json');
30
+ function persistWorkerState(profile, lastLightTick) {
31
+ try {
32
+ if (!existsSync(WORKER_STATE_DIR))
33
+ mkdirSync(WORKER_STATE_DIR, { recursive: true });
34
+ writeFileSync(WORKER_STATE_FILE, JSON.stringify({ pid: process.pid, profile, lastLightTick: lastLightTick.toISOString() }, null, 2), 'utf-8');
35
+ }
36
+ catch {
37
+ // Best-effort: doctor will warn if the file is stale or missing
38
+ }
39
+ }
25
40
  /**
26
41
  * Brain Worker Class
27
42
  *
@@ -47,10 +62,17 @@ export class BrainWorker {
47
62
  /**
48
63
  * Create a new BrainWorker
49
64
  *
50
- * @param config - Partial configuration to override defaults
65
+ * @param config - Partial configuration to override defaults. When `profile`
66
+ * is 'mcp' and no explicit `lightTickIntervalMs` is provided,
67
+ * the lite 15-minute cadence is applied so MCP-server-mode
68
+ * workers don't run as often as dashboard-mode ones.
51
69
  */
52
70
  constructor(config = {}) {
53
- this.config = { ...DEFAULT_WORKER_CONFIG, ...config };
71
+ const merged = { ...DEFAULT_WORKER_CONFIG, ...config };
72
+ if (merged.profile === 'mcp' && config.lightTickIntervalMs === undefined) {
73
+ merged.lightTickIntervalMs = MCP_LIGHT_TICK_INTERVAL_MS;
74
+ }
75
+ this.config = merged;
54
76
  }
55
77
  /**
56
78
  * Start the background worker
@@ -62,17 +84,26 @@ export class BrainWorker {
62
84
  return;
63
85
  }
64
86
  this.isRunning = true;
65
- console.log('[BrainWorker] Starting background worker');
87
+ console.log(`[BrainWorker] Starting background worker (profile=${this.config.profile} pid=${process.pid})`);
66
88
  console.log(`[BrainWorker] Light tick interval: ${this.config.lightTickIntervalMs / 1000}s`);
67
- console.log(`[BrainWorker] Medium tick interval: ${this.config.mediumTickIntervalMs / 1000}s`);
68
- // Light tick every 5 minutes (by default)
89
+ if (this.config.profile === 'full') {
90
+ console.log(`[BrainWorker] Medium tick interval: ${this.config.mediumTickIntervalMs / 1000}s`);
91
+ }
92
+ else {
93
+ console.log('[BrainWorker] MCP profile — medium tick + cloud sync disabled');
94
+ }
95
+ // Light tick — every 5 min (full) or every 15 min (mcp)
69
96
  this.lightTimer = setInterval(() => this.lightTick(), this.config.lightTickIntervalMs);
70
97
  this.lightTimer.unref();
71
- // Medium tick every 30 minutes (by default)
72
- this.mediumTimer = setInterval(() => this.mediumTick(), this.config.mediumTickIntervalMs);
73
- this.mediumTimer.unref();
74
- // Apply cached cloud Iron Dome patterns immediately on start (requires Pro+)
75
- if (isFeatureEnabled('custom_injection_patterns')) {
98
+ // Medium tick full profile only. mcp-mode skips link discovery,
99
+ // contradiction scans, graph maintenance, and sync-queue purging — those
100
+ // are dashboard concerns and shouldn't multiply across N MCP windows.
101
+ if (this.config.profile === 'full') {
102
+ this.mediumTimer = setInterval(() => this.mediumTick(), this.config.mediumTickIntervalMs);
103
+ this.mediumTimer.unref();
104
+ }
105
+ // Apply cached cloud Iron Dome patterns immediately on start (Pro+, full only)
106
+ if (this.config.profile === 'full' && isFeatureEnabled('custom_injection_patterns')) {
76
107
  try {
77
108
  applyCachedCloudPatterns();
78
109
  }
@@ -150,38 +181,42 @@ export class BrainWorker {
150
181
  result: result.predictiveConsolidation,
151
182
  });
152
183
  }
153
- // 3. Process cloud sync retry queue
154
- try {
155
- const retryResult = await processRetryQueue();
156
- if (retryResult.processed > 0) {
157
- console.log(`[BrainWorker] Sync retry queue: processed ${retryResult.processed} ` +
158
- `(${retryResult.succeeded} ok, ${retryResult.failed} retry, ${retryResult.permanentlyFailed} failed)`);
159
- }
160
- }
161
- catch (retryError) {
162
- console.error('[BrainWorker] Sync retry queue failed:', retryError);
163
- }
164
- // 4. Send cloud heartbeat (keeps device status "Online") — Team+ only
165
- if (isFeatureEnabled('cloud_sync')) {
184
+ // 3-5: cloud sync (retry queue, heartbeat, Iron Dome) — full profile only.
185
+ // Skipped under MCP profile so we don't fan out N concurrent network calls
186
+ // from N open Claude Code windows.
187
+ if (this.config.profile === 'full') {
166
188
  try {
167
- sendHeartbeat();
189
+ const retryResult = await processRetryQueue();
190
+ if (retryResult.processed > 0) {
191
+ console.log(`[BrainWorker] Sync retry queue: processed ${retryResult.processed} ` +
192
+ `(${retryResult.succeeded} ok, ${retryResult.failed} retry, ${retryResult.permanentlyFailed} failed)`);
193
+ }
168
194
  }
169
- catch {
170
- // Truly silent heartbeat is best-effort
195
+ catch (retryError) {
196
+ console.error('[BrainWorker] Sync retry queue failed:', retryError);
171
197
  }
172
- }
173
- // 5. Refresh Iron Dome cloud patterns + policy — Pro+ only
174
- if (isFeatureEnabled('custom_injection_patterns')) {
175
- try {
176
- await refreshCloudIronDome();
198
+ if (isFeatureEnabled('cloud_sync')) {
199
+ try {
200
+ sendHeartbeat();
201
+ }
202
+ catch {
203
+ // Truly silent — heartbeat is best-effort
204
+ }
177
205
  }
178
- catch {
179
- // Non-critical — cloud Iron Dome sync is best-effort
206
+ if (isFeatureEnabled('custom_injection_patterns')) {
207
+ try {
208
+ await refreshCloudIronDome();
209
+ }
210
+ catch {
211
+ // Non-critical — cloud Iron Dome sync is best-effort
212
+ }
180
213
  }
181
214
  }
182
215
  // Update stats
183
216
  this.lastLightTick = result.timestamp;
184
217
  this.stats.lightTicks++;
218
+ // Persist worker freshness for `shieldcortex doctor` to detect stalls.
219
+ persistWorkerState(this.config.profile, result.timestamp);
185
220
  // Emit light tick event
186
221
  emitWorkerLightTick(result);
187
222
  // Log summary
@@ -314,19 +349,24 @@ export class BrainWorker {
314
349
  // Default singleton instance (optional - server can create its own)
315
350
  let defaultWorker = null;
316
351
  /**
317
- * Get or create the default worker instance
352
+ * Get or create the default worker instance.
353
+ * The first call wins — subsequent calls return the existing singleton even
354
+ * if a different config is passed. That's intentional: it prevents accidental
355
+ * re-instantiation from creating two competing timer sets within one process.
318
356
  */
319
- export function getDefaultWorker() {
357
+ export function getDefaultWorker(config) {
320
358
  if (!defaultWorker) {
321
- defaultWorker = new BrainWorker();
359
+ defaultWorker = new BrainWorker(config);
322
360
  }
323
361
  return defaultWorker;
324
362
  }
325
363
  /**
326
- * Start the default worker if not already running
364
+ * Start the default worker if not already running. Forwards config to the
365
+ * underlying constructor on first call (used by MCP-server mode to start
366
+ * with `profile: 'mcp'`).
327
367
  */
328
- export function startDefaultWorker() {
329
- const worker = getDefaultWorker();
368
+ export function startDefaultWorker(config) {
369
+ const worker = getDefaultWorker(config);
330
370
  if (!worker.isActive()) {
331
371
  worker.start();
332
372
  }
@@ -7,6 +7,17 @@
7
7
  * for the background brain worker.
8
8
  */
9
9
  import { ConsolidationResult } from '../memory/types.js';
10
+ /**
11
+ * Worker profile.
12
+ * - 'full': dashboard / api / worker modes — runs medium tick, cloud sync,
13
+ * link discovery, the works.
14
+ * - 'mcp': default MCP-server mode (one process per Claude Code window) —
15
+ * keeps consolidation alive but skips heavy/networked work so we don't
16
+ * multiply background load by the number of open windows. Without this,
17
+ * hooks-only installs never run consolidation and STM never graduates
18
+ * to LTM (#45).
19
+ */
20
+ export type WorkerProfile = 'full' | 'mcp';
10
21
  /**
11
22
  * Configuration for the brain worker
12
23
  */
@@ -27,11 +38,19 @@ export interface WorkerConfig {
27
38
  contradictionScanLimit: number;
28
39
  /** High activity threshold - memories created in 30 min (default: 5) */
29
40
  highActivityThreshold: number;
41
+ /** Worker profile - 'full' (default) or 'mcp' (lite, see WorkerProfile docs) */
42
+ profile: WorkerProfile;
30
43
  }
31
44
  /**
32
45
  * Default worker configuration
33
46
  */
34
47
  export declare const DEFAULT_WORKER_CONFIG: WorkerConfig;
48
+ /**
49
+ * MCP-profile interval override. 15 min vs full's 5 min — one MCP server runs
50
+ * per Claude Code window, so we want lower per-window cadence to keep total
51
+ * background work in check across many windows.
52
+ */
53
+ export declare const MCP_LIGHT_TICK_INTERVAL_MS: number;
35
54
  /**
36
55
  * Result of a light tick operation
37
56
  */
@@ -18,4 +18,11 @@ export const DEFAULT_WORKER_CONFIG = {
18
18
  maxLinksPerCycle: 10,
19
19
  contradictionScanLimit: 50,
20
20
  highActivityThreshold: 5,
21
+ profile: 'full',
21
22
  };
23
+ /**
24
+ * MCP-profile interval override. 15 min vs full's 5 min — one MCP server runs
25
+ * per Claude Code window, so we want lower per-window cadence to keep total
26
+ * background work in check across many windows.
27
+ */
28
+ export const MCP_LIGHT_TICK_INTERVAL_MS = 15 * 60 * 1000;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shieldcortex",
3
- "version": "4.13.0",
3
+ "version": "4.14.0",
4
4
  "description": "Trustworthy memory and security for AI agents. Recall debugging, review queue, OpenClaw session capture, and memory poisoning defence for Claude Code, Codex, OpenClaw, LangChain, and MCP agents.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "shieldcortex-realtime",
3
- "version": "4.13.0",
3
+ "version": "4.14.0",
4
4
  "name": "ShieldCortex Real-time Scanner",
5
5
  "description": "Real-time defence scanning on LLM input, memory extraction on LLM output, and active tool call interception with approval gating.",
6
6
  "kind": null,
@@ -2,13 +2,27 @@ import { existsSync, readFileSync } from 'fs';
2
2
  import { join } from 'path';
3
3
  import { homedir } from 'os';
4
4
 
5
- const CONFIG_PATH = join(homedir(), '.shieldcortex', 'config.json');
5
+ function getConfigPath() {
6
+ // Honour the same SHIELDCORTEX_CONFIG_DIR override that src/cloud/config.ts
7
+ // uses, so the runtime gate and the rest of the system always resolve to the
8
+ // same config file (and so tests can isolate via a temp dir).
9
+ const override = process.env.SHIELDCORTEX_CONFIG_DIR?.trim();
10
+ const dir = override || join(homedir(), '.shieldcortex');
11
+ return join(dir, 'config.json');
12
+ }
6
13
 
7
14
  const DEFAULTS = Object.freeze({
8
15
  maxTranscriptBytes: 1024 * 1024,
9
16
  maxTranscriptLines: 5000,
10
17
  keepSlashCommandProse: true,
11
- stopHookSamplingTurns: 10,
18
+ // Lowered 10 → 5 in v4.14.0. At 1-in-10 the realistic capture rate over
19
+ // typical sessions was ~7%, which left LTM near-empty (#44). Salience
20
+ // bypass below catches high-signal turns at any cadence.
21
+ stopHookSamplingTurns: 5,
22
+ // Bypass the modulo gate when the last assistant turn carries a fenced
23
+ // code block or hits multiple keyword categories — those turns are
24
+ // disproportionately what we want to remember.
25
+ stopHookSalienceBypass: true,
12
26
  stopHookWindowBytes: 256 * 1024,
13
27
  enableSessionEnd: false,
14
28
  enableStop: false,
@@ -17,8 +31,9 @@ const DEFAULTS = Object.freeze({
17
31
  export function getAutoMemoryConfig() {
18
32
  let raw = {};
19
33
  try {
20
- if (existsSync(CONFIG_PATH)) {
21
- raw = JSON.parse(readFileSync(CONFIG_PATH, 'utf-8'));
34
+ const configPath = getConfigPath();
35
+ if (existsSync(configPath)) {
36
+ raw = JSON.parse(readFileSync(configPath, 'utf-8'));
22
37
  }
23
38
  } catch {
24
39
  // fall through to defaults
@@ -31,6 +46,9 @@ export function getAutoMemoryConfig() {
31
46
  ? overrides.keepSlashCommandProse
32
47
  : DEFAULTS.keepSlashCommandProse,
33
48
  stopHookSamplingTurns: pickPositiveInt(overrides.stopHookSamplingTurns, DEFAULTS.stopHookSamplingTurns),
49
+ stopHookSalienceBypass: typeof overrides.stopHookSalienceBypass === 'boolean'
50
+ ? overrides.stopHookSalienceBypass
51
+ : DEFAULTS.stopHookSalienceBypass,
34
52
  stopHookWindowBytes: pickPositiveInt(overrides.stopHookWindowBytes, DEFAULTS.stopHookWindowBytes),
35
53
  enableSessionEnd: overrides.enableSessionEnd === true,
36
54
  enableStop: overrides.enableStop === true,
@@ -143,6 +143,12 @@ export function deriveProjectKey(cwd) {
143
143
  }
144
144
  }
145
145
 
146
+ // Hot path post-#42 fix: this branch should only fire outside any git repo
147
+ // or when origin parsing fails. If users see this often after upgrading,
148
+ // the helper itself needs another look.
149
+ if (process.env.SHIELDCORTEX_DEBUG) {
150
+ process.stderr.write(`[shieldcortex deriveProjectKey] basename fallback for cwd=${cwd}\n`);
151
+ }
146
152
  return basename;
147
153
  }
148
154
 
@@ -20,6 +20,7 @@ import { saveAutoExtractedMemory } from './lib/save-memory.mjs';
20
20
  import { readTranscriptText } from './lib/transcript-reader.mjs';
21
21
  import { getAutoMemoryConfig } from './lib/auto-memory-config.mjs';
22
22
  import { recordHookInvocation } from './lib/telemetry.mjs';
23
+ import { deriveProjectKey } from './lib/project-key.mjs';
23
24
 
24
25
  // Database paths (with legacy fallback)
25
26
  const NEW_DB_DIR = join(homedir(), '.shieldcortex');
@@ -62,39 +63,6 @@ const CATEGORY_EXTRACTION_THRESHOLDS = {
62
63
  custom: 0.45,
63
64
  };
64
65
 
65
- // ==================== PROJECT DETECTION (Mirrors src/context/project-context.ts) ====================
66
-
67
- /** Directories to skip when extracting project name from path */
68
- const SKIP_DIRECTORIES = [
69
- 'src', 'lib', 'dist', 'build', 'out',
70
- 'node_modules', '.git', '.next', '.cache',
71
- 'test', 'tests', '__tests__', 'spec',
72
- 'bin', 'scripts', 'config', 'public', 'static',
73
- ];
74
-
75
- /**
76
- * Extract project name from a file path.
77
- * Skips common directory names that don't represent projects.
78
- */
79
- function extractProjectFromPath(path) {
80
- if (!path) return null;
81
-
82
- const segments = path.split(/[/\\]/).filter(Boolean);
83
- if (segments.length === 0) return null;
84
-
85
- // Start from the end and find first non-skipped segment
86
- for (let i = segments.length - 1; i >= 0; i--) {
87
- const segment = segments[i];
88
- if (!SKIP_DIRECTORIES.includes(segment.toLowerCase())) {
89
- // Skip hidden directories (starting with .)
90
- if (segment.startsWith('.')) continue;
91
- return segment;
92
- }
93
- }
94
-
95
- return null;
96
- }
97
-
98
66
  // Maximum memories to auto-create per compaction.
99
67
  // Dropped 5 → 2 in v4.11.0 for the same reason thresholds were raised.
100
68
  const MAX_AUTO_MEMORIES = 2;
@@ -520,7 +488,7 @@ process.stdin.on('end', () => {
520
488
  const hookData = JSON.parse(input || '{}');
521
489
 
522
490
  const trigger = hookData.trigger || 'unknown';
523
- const project = extractProjectFromPath(hookData.cwd);
491
+ const project = deriveProjectKey(hookData.cwd);
524
492
  const autoMemConfig = getAutoMemoryConfig();
525
493
 
526
494
  // Extract conversation text from hook data
@@ -29,6 +29,7 @@ import { saveAutoExtractedMemory } from './lib/save-memory.mjs';
29
29
  import { readTranscriptText } from './lib/transcript-reader.mjs';
30
30
  import { getAutoMemoryConfig } from './lib/auto-memory-config.mjs';
31
31
  import { recordHookInvocation } from './lib/telemetry.mjs';
32
+ import { deriveProjectKey } from './lib/project-key.mjs';
32
33
 
33
34
  // Database paths (with legacy fallback)
34
35
  const NEW_DB_DIR = join(homedir(), '.shieldcortex');
@@ -64,29 +65,6 @@ const CATEGORY_EXTRACTION_THRESHOLDS = {
64
65
  custom: 0.35,
65
66
  };
66
67
 
67
- // ==================== PROJECT DETECTION ====================
68
-
69
- const SKIP_DIRECTORIES = [
70
- 'src', 'lib', 'dist', 'build', 'out',
71
- 'node_modules', '.git', '.next', '.cache',
72
- 'test', 'tests', '__tests__', 'spec',
73
- 'bin', 'scripts', 'config', 'public', 'static',
74
- ];
75
-
76
- function extractProjectFromPath(path) {
77
- if (!path) return null;
78
- const segments = path.split(/[/\\]/).filter(Boolean);
79
- if (segments.length === 0) return null;
80
- for (let i = segments.length - 1; i >= 0; i--) {
81
- const segment = segments[i];
82
- if (!SKIP_DIRECTORIES.includes(segment.toLowerCase())) {
83
- if (segment.startsWith('.')) continue;
84
- return segment;
85
- }
86
- }
87
- return null;
88
- }
89
-
90
68
  // ==================== DYNAMIC THRESHOLD ====================
91
69
 
92
70
  function getMemoryStats(db) {
@@ -442,7 +420,7 @@ process.stdin.on('end', () => {
442
420
  const hookData = JSON.parse(input || '{}');
443
421
 
444
422
  const reason = hookData.reason || 'unknown';
445
- const project = extractProjectFromPath(hookData.cwd);
423
+ const project = deriveProjectKey(hookData.cwd);
446
424
  const autoMemConfig = getAutoMemoryConfig();
447
425
 
448
426
  // Config gate: opt-in (default off). Preserves the historical default
@@ -17,13 +17,43 @@
17
17
  */
18
18
 
19
19
  import Database from 'better-sqlite3';
20
- import { existsSync, mkdirSync, openSync, readSync, closeSync, statSync } from 'fs';
20
+ import { existsSync, mkdirSync, openSync, readSync, closeSync, statSync, writeFileSync } from 'fs';
21
21
  import { join } from 'path';
22
22
  import { homedir } from 'os';
23
23
  import { saveAutoExtractedMemory } from './lib/save-memory.mjs';
24
24
  import { readTranscriptText } from './lib/transcript-reader.mjs';
25
25
  import { getAutoMemoryConfig } from './lib/auto-memory-config.mjs';
26
26
  import { recordHookInvocation } from './lib/telemetry.mjs';
27
+ import { deriveProjectKey } from './lib/project-key.mjs';
28
+
29
+ // Sentinel directory for once-per-session "disabled" log lines. Without this
30
+ // the stop hook bails silently on every turn when autoMemory.enableStop is
31
+ // false — the user-visible symptom is "ShieldCortex never captured anything"
32
+ // with zero feedback (filed in #41 as silent-amnesia). One sentinel file
33
+ // per session keeps the log to a single line for the lifetime of the session.
34
+ const SC_LOG_DIR = join(homedir(), '.shieldcortex', 'logs');
35
+ const STOP_DISABLED_SENTINEL_DIR = join(SC_LOG_DIR, 'stop-hook-disabled-sessions');
36
+
37
+ function logDisabledOnceForSession(sessionId, reason) {
38
+ // Always print the line — stderr is the existing channel for hook diagnostics
39
+ // (mirrors session-end-hook). Then plant a sentinel so subsequent fires in
40
+ // the same session stay quiet.
41
+ if (!sessionId) {
42
+ console.error(`[shieldcortex stop-hook] ${reason}`);
43
+ return;
44
+ }
45
+ try {
46
+ mkdirSync(STOP_DISABLED_SENTINEL_DIR, { recursive: true });
47
+ const sentinel = join(STOP_DISABLED_SENTINEL_DIR, sessionId.replace(/[^a-zA-Z0-9_.-]/g, '_'));
48
+ if (existsSync(sentinel)) return;
49
+ writeFileSync(sentinel, new Date().toISOString(), { mode: 0o600 });
50
+ console.error(`[shieldcortex stop-hook] ${reason}`);
51
+ } catch {
52
+ // Sentinel write failed — fall back to printing once per fire rather than
53
+ // staying silent. Better noisy-but-discoverable than silent-amnesia.
54
+ console.error(`[shieldcortex stop-hook] ${reason}`);
55
+ }
56
+ }
27
57
 
28
58
  // ==================== DB ====================
29
59
 
@@ -60,28 +90,6 @@ const CATEGORY_EXTRACTION_THRESHOLDS = {
60
90
  custom: 0.45,
61
91
  };
62
92
 
63
- // ==================== PROJECT DETECTION ====================
64
-
65
- const SKIP_DIRECTORIES = [
66
- 'src', 'lib', 'dist', 'build', 'out',
67
- 'node_modules', '.git', '.next', '.cache',
68
- 'test', 'tests', '__tests__', 'spec',
69
- 'bin', 'scripts', 'config', 'public', 'static',
70
- ];
71
-
72
- function extractProjectFromPath(p) {
73
- if (!p) return null;
74
- const segments = p.split(/[/\\]/).filter(Boolean);
75
- for (let i = segments.length - 1; i >= 0; i--) {
76
- const segment = segments[i];
77
- if (!SKIP_DIRECTORIES.includes(segment.toLowerCase())) {
78
- if (segment.startsWith('.')) continue;
79
- return segment;
80
- }
81
- }
82
- return null;
83
- }
84
-
85
93
  // ==================== SALIENCE (mirrors pre-compact) ====================
86
94
 
87
95
  const ARCHITECTURE_KEYWORDS = ['architecture','design','pattern','structure','system','database','api','schema','model','framework','stack','microservice','monolith','serverless','infrastructure'];
@@ -244,18 +252,17 @@ function getDynamicThreshold(count, max) {
244
252
  return 0.25;
245
253
  }
246
254
 
247
- // ==================== TURN COUNT (cheap, partial-read) ====================
255
+ // ==================== TRANSCRIPT PEEK (cheap, partial-read) ====================
248
256
 
249
257
  /**
250
- * Count assistant turns in the last `windowBytes` of the transcript.
251
- * Doesn't parse just counts occurrences of the assistant role marker.
252
- * That's a very rough approximation but it's enough for sample-every-N
253
- * decisions and an order of magnitude cheaper than full JSON parse.
258
+ * Read the last `windowBytes` of the transcript as raw text and count
259
+ * assistant-role markers. Used for both the modulo sampling gate and the
260
+ * salience-bypass probe one disk read serves both decisions.
254
261
  */
255
- function countAssistantTurns(transcriptPath, windowBytes) {
256
- if (!transcriptPath) return 0;
262
+ function peekRecentTranscript(transcriptPath, windowBytes) {
263
+ if (!transcriptPath) return { turnCount: 0, raw: '' };
257
264
  const resolved = transcriptPath.replace(/^~/, homedir());
258
- if (!existsSync(resolved)) return 0;
265
+ if (!existsSync(resolved)) return { turnCount: 0, raw: '' };
259
266
  try {
260
267
  const stat = statSync(resolved);
261
268
  const bytes = Math.min(stat.size, windowBytes);
@@ -268,14 +275,33 @@ function countAssistantTurns(transcriptPath, windowBytes) {
268
275
  } finally {
269
276
  closeSync(fd);
270
277
  }
271
- // Each assistant message line carries `"role":"assistant"` (or `"type":"assistant"`).
272
- // Count occurrences of either marker — close enough for sampling decisions.
273
- return (raw.match(/"role":"assistant"|"type":"assistant"/g) || []).length;
278
+ const turnCount = (raw.match(/"role":"assistant"|"type":"assistant"/g) || []).length;
279
+ return { turnCount, raw };
274
280
  } catch {
275
- return 0;
281
+ return { turnCount: 0, raw: '' };
276
282
  }
277
283
  }
278
284
 
285
+ /**
286
+ * Cheap salience probe over the recent transcript window. A turn is "salient"
287
+ * (and worth bypassing the modulo gate for) when:
288
+ * - it carries a fenced code block — strong signal of code work / errors / diffs
289
+ * - or ≥2 keyword categories hit (architecture, error, decision, learning,
290
+ * pattern, code-reference)
291
+ */
292
+ function isSalientWindow(rawText) {
293
+ if (!rawText) return false;
294
+ if (/```/.test(rawText)) return true;
295
+ let hits = 0;
296
+ if (detectKeywords(rawText, ARCHITECTURE_KEYWORDS)) hits++;
297
+ if (detectKeywords(rawText, ERROR_KEYWORDS)) hits++;
298
+ if (detectKeywords(rawText, DECISION_KEYWORDS)) hits++;
299
+ if (detectKeywords(rawText, LEARNING_KEYWORDS)) hits++;
300
+ if (detectKeywords(rawText, PATTERN_KEYWORDS)) hits++;
301
+ if (detectCodeReferences(rawText)) hits++;
302
+ return hits >= 2;
303
+ }
304
+
279
305
  // ==================== MAIN ====================
280
306
 
281
307
  let input = '';
@@ -303,18 +329,35 @@ process.stdin.on('end', () => {
303
329
 
304
330
  const autoMemConfig = getAutoMemoryConfig();
305
331
  if (!autoMemConfig.enableStop) {
306
- // Opt-in by config (or by `--with-stop-hook` install flag, which only
307
- // wires the hook in settings.json config still gates execution).
332
+ // Opt-in by config. As of v4.13.1 the install flag (`--with-stop-hook`)
333
+ // flips this gate at install time so wiring the hook and enabling it are
334
+ // a single user action. If the gate is still false here, the user wired
335
+ // the hook by hand without setting autoMemory.enableStop=true. Log once
336
+ // per session so the failure is visible (was silent-amnesia in #41).
337
+ logDisabledOnceForSession(
338
+ hookData.session_id,
339
+ `disabled — set autoMemory.enableStop=true in ~/.shieldcortex/config.json (or re-run \`shieldcortex setup --with-stop-hook\`)`,
340
+ );
308
341
  process.exit(0);
309
342
  }
310
343
 
311
344
  const samplingTurns = autoMemConfig.stopHookSamplingTurns;
312
345
  const windowBytes = autoMemConfig.stopHookWindowBytes;
313
-
314
- const turnCount = countAssistantTurns(hookData.transcript_path, windowBytes);
315
- if (turnCount === 0 || turnCount % samplingTurns !== 0) {
316
- // Off-sample. Exit silently but record the firing so telemetry shows
317
- // the hook is actually wired and active.
346
+ const salienceBypassEnabled = autoMemConfig.stopHookSalienceBypass;
347
+
348
+ // Use a smaller window for the cheap peek so off-sample turns stay fast.
349
+ // The full extraction below still uses the configured windowBytes.
350
+ const peekBytes = Math.min(32 * 1024, windowBytes);
351
+ const peek = peekRecentTranscript(hookData.transcript_path, peekBytes);
352
+ const turnCount = peek.turnCount;
353
+ const onSample = turnCount > 0 && turnCount % samplingTurns === 0;
354
+ const salientBypass = salienceBypassEnabled && !onSample && isSalientWindow(peek.raw);
355
+
356
+ if (!onSample && !salientBypass) {
357
+ // Off-sample, no salience bypass. Surface the sampling decision to stderr
358
+ // so the "1-in-N turns" behaviour stops being invisible (#41), and still
359
+ // record telemetry so the dashboard shows the hook is wired and active.
360
+ console.error(`[shieldcortex stop-hook] telemetry-only turn=${turnCount}/${samplingTurns}`);
318
361
  if (existsSync(DB_PATH)) {
319
362
  try {
320
363
  const tdb = new Database(DB_PATH, { timeout: 1500 });
@@ -332,7 +375,7 @@ process.stdin.on('end', () => {
332
375
  process.exit(0);
333
376
  }
334
377
 
335
- const project = extractProjectFromPath(hookData.cwd);
378
+ const project = deriveProjectKey(hookData.cwd);
336
379
  const transcriptOut = readTranscriptText(hookData.transcript_path, {
337
380
  maxBytes: windowBytes,
338
381
  maxLines: autoMemConfig.maxTranscriptLines,
@@ -370,7 +413,8 @@ process.stdin.on('end', () => {
370
413
  console.error(`[stop] Failed to save "${memory.title}": ${err.message}`);
371
414
  }
372
415
  }
373
- console.error(`[stop] Sampled turn=${turnCount}: ${extractedCount} memories extracted`);
416
+ const sampleReason = salientBypass ? `bypass=salience turn=${turnCount}` : `turn=${turnCount}`;
417
+ console.error(`[stop] Sampled ${sampleReason}: ${extractedCount} memories extracted`);
374
418
  }
375
419
  }
376
420
  } catch (err) {