shieldcortex 4.31.2 → 4.32.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -2
- package/dashboard/.next/standalone/dashboard/.next/BUILD_ID +1 -1
- package/dashboard/.next/standalone/dashboard/.next/build-manifest.json +2 -2
- package/dashboard/.next/standalone/dashboard/.next/prerender-manifest.json +3 -3
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/admin.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/admin.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/!KGRhc2hib2FyZCk/admin/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/!KGRhc2hib2FyZCk/admin.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/!KGRhc2hib2FyZCk/cloud/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/!KGRhc2hib2FyZCk/cloud.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk/memory/capture/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk/memory/capture.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk/memory/graph/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk/memory/graph.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk/memory/recall/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk/memory/recall.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/!KGRhc2hib2FyZCk/memory/replay/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/!KGRhc2hib2FyZCk/memory/replay.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk/memory/review/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk/memory/review.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk/memory/timeline/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk/memory/timeline.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/!KGRhc2hib2FyZCk/memory/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/overview.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/overview.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/!KGRhc2hib2FyZCk/overview/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/!KGRhc2hib2FyZCk/overview.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk/protection/audit/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk/protection/audit.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk/protection/intercepts/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk/protection/intercepts.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk/protection/iron-dome/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk/protection/iron-dome.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk/protection/policies/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk/protection/policies.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk/protection/quarantine/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk/protection/quarantine.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/!KGRhc2hib2FyZCk/protection/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/settings.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/settings.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/!KGRhc2hib2FyZCk/settings/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/!KGRhc2hib2FyZCk/settings.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk/supply-chain/xray/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk/supply-chain/xray.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk/supply-chain.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/!KGRhc2hib2FyZCk/supply-chain/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/!KGRhc2hib2FyZCk/supply-chain.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/xray.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/xray.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/!KGRhc2hib2FyZCk/xray/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/!KGRhc2hib2FyZCk/xray.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/pages/404.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/pages/500.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/server-reference-manifest.js +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/server-reference-manifest.json +1 -1
- package/dist/api/control.d.ts +2 -0
- package/dist/api/control.js +119 -2
- package/dist/api/routes/memories.js +19 -14
- package/dist/api/routes/system.js +2 -3
- package/dist/api/visualization-server.d.ts +13 -1
- package/dist/api/visualization-server.js +57 -1
- package/dist/audit/env-scanner.js +5 -2
- package/dist/audit/index.d.ts +4 -1
- package/dist/audit/index.js +2 -1
- package/dist/audit/mcp-config-scanner.d.ts +23 -0
- package/dist/audit/mcp-config-scanner.js +110 -0
- package/dist/audit/mcp-tools-scanner.d.ts +112 -0
- package/dist/audit/mcp-tools-scanner.js +299 -0
- package/dist/cli/audit.d.ts +1 -0
- package/dist/cli/audit.js +12 -1
- package/dist/cli/doctor.js +4 -1
- package/dist/cli/mcp.d.ts +13 -0
- package/dist/cli/mcp.js +0 -0
- package/dist/cli/remember.d.ts +75 -0
- package/dist/cli/remember.js +195 -0
- package/dist/cli/repair.d.ts +8 -0
- package/dist/cli/repair.js +34 -0
- package/dist/cli/update.js +34 -0
- package/dist/cloud/config.d.ts +23 -1
- package/dist/cloud/config.js +453 -193
- package/dist/cloud/quarantine-sync.d.ts +12 -2
- package/dist/cloud/quarantine-sync.js +28 -6
- package/dist/cloud/sync-queue.d.ts +21 -2
- package/dist/cloud/sync-queue.js +124 -29
- package/dist/database/better-sqlite3-guard.d.ts +21 -2
- package/dist/database/better-sqlite3-guard.js +29 -5
- package/dist/database/init.js +68 -16
- package/dist/database/inline-schema.js +35 -1
- package/dist/database/migrations.js +104 -8
- package/dist/database/schema.sql +39 -1
- package/dist/defence/audit/queries.d.ts +10 -2
- package/dist/defence/audit/queries.js +30 -4
- package/dist/defence/audit/retention.d.ts +50 -0
- package/dist/defence/audit/retention.js +161 -0
- package/dist/defence/credential-leak/entropy.d.ts +11 -0
- package/dist/defence/credential-leak/entropy.js +27 -0
- package/dist/defence/credential-leak/index.js +27 -1
- package/dist/defence/credential-leak/patterns.d.ts +9 -0
- package/dist/defence/credential-leak/patterns.js +21 -0
- package/dist/defence/custom-patterns/store.js +8 -1
- package/dist/defence/custom-rules/store.d.ts +18 -0
- package/dist/defence/custom-rules/store.js +63 -0
- package/dist/defence/firewall/confusables.d.ts +30 -0
- package/dist/defence/firewall/confusables.js +87 -0
- package/dist/defence/firewall/encoding-detector.js +23 -9
- package/dist/defence/firewall/index.d.ts +11 -1
- package/dist/defence/firewall/index.js +34 -1
- package/dist/defence/firewall/instruction-detector.js +18 -7
- package/dist/defence/firewall/markdown-image-detector.d.ts +34 -0
- package/dist/defence/firewall/markdown-image-detector.js +83 -0
- package/dist/defence/fragmentation/entity-extractor.js +17 -6
- package/dist/defence/index.d.ts +5 -0
- package/dist/defence/index.js +8 -0
- package/dist/defence/iron-dome/index.js +7 -1
- package/dist/defence/pipeline.js +62 -10
- package/dist/defence/scan-windows.d.ts +41 -0
- package/dist/defence/scan-windows.js +61 -0
- package/dist/defence/semantic/attack-corpus.d.ts +22 -0
- package/dist/defence/semantic/attack-corpus.js +75 -0
- package/dist/defence/semantic/index.d.ts +67 -0
- package/dist/defence/semantic/index.js +138 -0
- package/dist/defence/skill-scanner/deep-scan.js +35 -15
- package/dist/defence/skill-scanner/patterns.d.ts +1 -1
- package/dist/defence/skill-scanner/patterns.js +8 -7
- package/dist/defence/tool-response-scanner.d.ts +21 -5
- package/dist/defence/tool-response-scanner.js +111 -22
- package/dist/defence/types.d.ts +11 -1
- package/dist/index.d.ts +29 -0
- package/dist/index.js +112 -21
- package/dist/memory/consolidate.js +1 -1
- package/dist/memory/decay.js +3 -1
- package/dist/memory/embedding.d.ts +18 -2
- package/dist/memory/embedding.js +32 -11
- package/dist/memory/expiry.js +1 -1
- package/dist/memory/search-recall.js +107 -49
- package/dist/memory/search.d.ts +19 -3
- package/dist/memory/search.js +25 -10
- package/dist/memory/store.d.ts +13 -2
- package/dist/memory/store.js +115 -11
- package/dist/scan-only.d.ts +64 -0
- package/dist/scan-only.js +173 -0
- package/dist/server.d.ts +5 -0
- package/dist/server.js +6 -4
- package/dist/setup/claude-md.js +39 -34
- package/dist/setup/codex.js +9 -2
- package/dist/setup/copilot.js +160 -47
- package/dist/setup/json-config.d.ts +99 -0
- package/dist/setup/json-config.js +167 -0
- package/dist/setup/migrate.js +1 -1
- package/dist/setup/native-binding.d.ts +75 -0
- package/dist/setup/native-binding.js +146 -0
- package/dist/setup/settings-hooks.js +8 -13
- package/dist/setup/uninstall.js +1 -21
- package/dist/tools/context.d.ts +8 -8
- package/dist/tools/forget.d.ts +9 -8
- package/dist/tools/forget.js +17 -4
- package/dist/tools/recall.d.ts +13 -13
- package/dist/tools/remember.d.ts +16 -16
- package/dist/tools/remember.js +19 -8
- package/dist/worker/brain-worker.d.ts +1 -0
- package/dist/worker/brain-worker.js +79 -16
- package/dist/worker/types.d.ts +8 -0
- package/dist/worker/types.js +8 -0
- package/dist/xray/dir-scanner.d.ts +18 -0
- package/dist/xray/dir-scanner.js +23 -1
- package/dist/xray/file-scanner.js +16 -1
- package/dist/xray/findings-store.js +9 -1
- package/dist/xray/index.d.ts +2 -0
- package/dist/xray/index.js +10 -1
- package/dist/xray/npm-inspector.d.ts +31 -0
- package/dist/xray/npm-inspector.js +135 -29
- package/dist/xray/patterns.d.ts +1 -1
- package/dist/xray/patterns.js +20 -23
- package/dist/xray/sarif.d.ts +78 -0
- package/dist/xray/sarif.js +166 -0
- package/dist/xray/watch.d.ts +1 -0
- package/dist/xray/watch.js +10 -1
- package/hooks/openclaw/cortex-memory/handler.ts +122 -18
- package/hooks/openclaw/cortex-memory/runtime.mjs +10 -4
- package/package.json +10 -3
- package/scripts/postinstall.mjs +8 -3
- package/dist/memory/embedding-cache.d.ts +0 -20
- package/dist/memory/embedding-cache.js +0 -91
- /package/dashboard/.next/standalone/dashboard/.next/static/{_j4TeMpss-w79QtNNWqZw → tjJ3X8xQ-2_WQTPGF3zCA}/_buildManifest.js +0 -0
- /package/dashboard/.next/standalone/dashboard/.next/static/{_j4TeMpss-w79QtNNWqZw → tjJ3X8xQ-2_WQTPGF3zCA}/_clientMiddlewareManifest.json +0 -0
- /package/dashboard/.next/standalone/dashboard/.next/static/{_j4TeMpss-w79QtNNWqZw → tjJ3X8xQ-2_WQTPGF3zCA}/_ssgManifest.js +0 -0
package/dist/memory/embedding.js
CHANGED
|
@@ -115,8 +115,24 @@ export function clearQueryEmbeddingCache() {
|
|
|
115
115
|
queryEmbeddingCache.clear();
|
|
116
116
|
}
|
|
117
117
|
/**
|
|
118
|
-
* Embed the query, compute similarity against
|
|
119
|
-
* return top K (default 10) sorted by score desc.
|
|
118
|
+
* Embed the query, compute similarity against the candidate memories' PERSISTED
|
|
119
|
+
* embeddings, return top K (default 10) sorted by score desc.
|
|
120
|
+
*
|
|
121
|
+
* Candidate embeddings are read from the canonical `memories.embedding` column —
|
|
122
|
+
* the same vector addMemory persists on write and vectorSearch scores against —
|
|
123
|
+
* in ONE batched `WHERE id IN (...)` query, decoded with the shared
|
|
124
|
+
* `decodeEmbeddingBlob`. This is a reuse, not a recompute: previously every
|
|
125
|
+
* candidate was routed through `getOrComputeEmbedding`, which checked a SEPARATE,
|
|
126
|
+
* perpetually-cold `memory_embeddings` cache and re-embedded each candidate's text
|
|
127
|
+
* through the worker on the (near-universal) miss — up to 200 sequential worker
|
|
128
|
+
* round-trips per cold recall, all redundant.
|
|
129
|
+
*
|
|
130
|
+
* Candidates that genuinely lack a persisted embedding (rare — writes populate it;
|
|
131
|
+
* only possible when the model was unavailable at write time, or for legacy rows)
|
|
132
|
+
* are skipped, not re-embedded: re-embedding here would reintroduce exactly the
|
|
133
|
+
* per-candidate worker storm this change removed, and `addMemory` already
|
|
134
|
+
* (re)populates the column out of band. They simply don't contribute to the
|
|
135
|
+
* vector-similarity fallback this turn; FTS and the next write still cover them.
|
|
120
136
|
*
|
|
121
137
|
* Non-throwing: returns empty array on failure.
|
|
122
138
|
*/
|
|
@@ -125,17 +141,22 @@ export async function findSimilarMemories(query, memories, topK = 10, queryEmbed
|
|
|
125
141
|
const activeQueryEmbedding = queryEmbedding ?? await getCachedQueryEmbedding(query);
|
|
126
142
|
if (!activeQueryEmbedding)
|
|
127
143
|
return [];
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const {
|
|
144
|
+
if (memories.length === 0)
|
|
145
|
+
return [];
|
|
146
|
+
const { getDatabase } = await import('../database/init.js');
|
|
147
|
+
const { decodeEmbeddingBlob } = await import('./search.js');
|
|
148
|
+
const db = getDatabase();
|
|
149
|
+
// ONE batched read of the persisted embeddings for the candidate set.
|
|
150
|
+
const ids = memories.map((m) => m.id);
|
|
151
|
+
const placeholders = ids.map(() => '?').join(',');
|
|
152
|
+
const rows = db.prepare(`SELECT id, embedding FROM memories WHERE id IN (${placeholders}) AND embedding IS NOT NULL`).all(...ids);
|
|
132
153
|
const scored = [];
|
|
133
|
-
for (const
|
|
134
|
-
const memEmbedding =
|
|
135
|
-
|
|
136
|
-
|
|
154
|
+
for (const row of rows) {
|
|
155
|
+
const memEmbedding = decodeEmbeddingBlob(row.embedding);
|
|
156
|
+
// Dimension guard: a vector from a different model version won't match the
|
|
157
|
+
// query's dimensionality. cosineSimilarity returns 0 on length mismatch.
|
|
137
158
|
const score = cosineSimilarity(activeQueryEmbedding, memEmbedding);
|
|
138
|
-
scored.push({ id:
|
|
159
|
+
scored.push({ id: row.id, score });
|
|
139
160
|
}
|
|
140
161
|
scored.sort((a, b) => b.score - a.score);
|
|
141
162
|
return scored.slice(0, topK);
|
package/dist/memory/expiry.js
CHANGED
|
@@ -38,7 +38,7 @@ export function applyExpiryRules() {
|
|
|
38
38
|
for (const rule of expiryRules) {
|
|
39
39
|
const cutoffDate = new Date(Date.now() - rule.maxAgeDays * 24 * 60 * 60 * 1000).toISOString();
|
|
40
40
|
// Build WHERE clause for this rule
|
|
41
|
-
let where = 'WHERE
|
|
41
|
+
let where = 'WHERE created_at < ?';
|
|
42
42
|
const params = [cutoffDate];
|
|
43
43
|
if (rule.category) {
|
|
44
44
|
where += ' AND category = ?';
|
|
@@ -55,9 +55,9 @@ async function searchMemoriesInternal(options, config, source, execution) {
|
|
|
55
55
|
if (!queryEmbedding) {
|
|
56
56
|
throw new Error('query embedding unavailable');
|
|
57
57
|
}
|
|
58
|
-
const vectorHits = vectorSearch(db,
|
|
58
|
+
const vectorHits = vectorSearch(db, queryEmbedding, limit * 2, options.project, includeGlobal);
|
|
59
59
|
for (const hit of vectorHits) {
|
|
60
|
-
vectorResults.set(hit.
|
|
60
|
+
vectorResults.set(hit.id, hit.similarity);
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
catch {
|
|
@@ -116,7 +116,13 @@ async function searchMemoriesInternal(options, config, source, execution) {
|
|
|
116
116
|
)`;
|
|
117
117
|
params.push(...options.tags);
|
|
118
118
|
}
|
|
119
|
-
|
|
119
|
+
// Prefilter on the persisted decayed-score index (CLAUDE.md: "Persisted decay
|
|
120
|
+
// scores for efficient sorting", idx_memories_decayed_score). decayed_score is
|
|
121
|
+
// NULL until updateDecayScores() persists it (addMemory leaves it unset), so
|
|
122
|
+
// COALESCE back to raw salience for un-scored rows — identical to rowToMemory's
|
|
123
|
+
// `decayed_score ?? salience`. Without the COALESCE, NULL sorts last under DESC
|
|
124
|
+
// and would bury freshly-written high-salience memories out of the prefilter.
|
|
125
|
+
sql += ' ORDER BY COALESCE(m.decayed_score, m.salience) DESC, m.last_accessed DESC LIMIT ?';
|
|
120
126
|
params.push(limit);
|
|
121
127
|
const rows = db.prepare(sql).all(...params);
|
|
122
128
|
const scoringContext = {
|
|
@@ -171,29 +177,15 @@ async function searchMemoriesInternal(options, config, source, execution) {
|
|
|
171
177
|
for (const result of topResults) {
|
|
172
178
|
reinforceFromSearch(result.memory.id);
|
|
173
179
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
}
|
|
184
|
-
else {
|
|
185
|
-
try {
|
|
186
|
-
db.prepare('INSERT INTO memory_links (source_id, target_id, relationship, strength) VALUES (?, ?, ?, ?)').run(idA, idB, 'related', 0.2);
|
|
187
|
-
}
|
|
188
|
-
catch (e) {
|
|
189
|
-
if (!(e instanceof Error && e.message.includes('UNIQUE constraint'))) {
|
|
190
|
-
console.warn('[shieldcortex] Unexpected error linking co-returned memories:', e);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
180
|
+
// NOTE (Phase 17 B2): the automatic all-pairs "co-access" linking that used
|
|
181
|
+
// to run here was removed. It linked every pair of the top-K results as
|
|
182
|
+
// `related` (strength 0.2), creating C(K,2) ≈ K² spurious graph edges and
|
|
183
|
+
// running one `SELECT existing` + INSERT/UPDATE per pair on every recall.
|
|
184
|
+
// Co-appearing in a single search is not a genuine relationship — these
|
|
185
|
+
// edges polluted the knowledge graph and drove an N² per-pair query storm.
|
|
186
|
+
// Genuine links are still created elsewhere (addMemory similarity links,
|
|
187
|
+
// explicit contradiction/relationship links); recall now only reinforces
|
|
188
|
+
// individual results above.
|
|
197
189
|
if (sortedResults.length > 0 && options.query && options.query.length > 30) {
|
|
198
190
|
const topResult = sortedResults[0];
|
|
199
191
|
const queryWords = new Set(options.query.toLowerCase().split(/\s+/).filter(w => w.length > 3));
|
|
@@ -210,6 +202,12 @@ async function searchMemoriesInternal(options, config, source, execution) {
|
|
|
210
202
|
}
|
|
211
203
|
}
|
|
212
204
|
const finalResults = sortedResults.slice(0, limit);
|
|
205
|
+
// Per-result contradiction links, then their counterpart titles. The title
|
|
206
|
+
// lookup was an N+1-within-N+1 (one SELECT title per contradiction per
|
|
207
|
+
// result); collect every counterpart id first and resolve all titles with a
|
|
208
|
+
// single `WHERE id IN (...)`, then read from the id→title map below.
|
|
209
|
+
const contradictionsByResult = new Map();
|
|
210
|
+
const counterpartIds = new Set();
|
|
213
211
|
for (const result of finalResults) {
|
|
214
212
|
const contradictions = db.prepare(`
|
|
215
213
|
SELECT ml.strength,
|
|
@@ -219,10 +217,27 @@ async function searchMemoriesInternal(options, config, source, execution) {
|
|
|
219
217
|
AND (ml.source_id = ? OR ml.target_id = ?)
|
|
220
218
|
`).all(result.memory.id, result.memory.id, result.memory.id);
|
|
221
219
|
if (contradictions.length > 0) {
|
|
222
|
-
result.
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
220
|
+
contradictionsByResult.set(result.memory.id, contradictions);
|
|
221
|
+
for (const c of contradictions)
|
|
222
|
+
counterpartIds.add(c.other_id);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
const counterpartTitles = new Map();
|
|
226
|
+
if (counterpartIds.size > 0) {
|
|
227
|
+
const ids = [...counterpartIds];
|
|
228
|
+
const placeholders = ids.map(() => '?').join(',');
|
|
229
|
+
const titleRows = db.prepare(`SELECT id, title FROM memories WHERE id IN (${placeholders})`).all(...ids);
|
|
230
|
+
for (const tr of titleRows)
|
|
231
|
+
counterpartTitles.set(tr.id, tr.title);
|
|
232
|
+
}
|
|
233
|
+
for (const result of finalResults) {
|
|
234
|
+
const contradictions = contradictionsByResult.get(result.memory.id);
|
|
235
|
+
if (contradictions && contradictions.length > 0) {
|
|
236
|
+
result.contradictions = contradictions.map((contradiction) => ({
|
|
237
|
+
memoryId: contradiction.other_id,
|
|
238
|
+
title: counterpartTitles.get(contradiction.other_id) || 'Unknown',
|
|
239
|
+
score: contradiction.strength,
|
|
240
|
+
}));
|
|
226
241
|
if (result.explanation) {
|
|
227
242
|
result.explanation.reasons.push(`${contradictions.length} contradiction link${contradictions.length === 1 ? '' : 's'} attached`);
|
|
228
243
|
}
|
|
@@ -230,8 +245,20 @@ async function searchMemoriesInternal(options, config, source, execution) {
|
|
|
230
245
|
}
|
|
231
246
|
if (source) {
|
|
232
247
|
const db2 = getDatabase();
|
|
248
|
+
// ACL lookup was an N+1 (one `SELECT source, sensitivity_level WHERE id = ?`
|
|
249
|
+
// per result); fetch all result rows in one `WHERE id IN (...)` and read the
|
|
250
|
+
// per-result source/sensitivity from the map. checkAccess/logAccessDenial
|
|
251
|
+
// logic and filter order are unchanged.
|
|
252
|
+
const aclIds = finalResults.map((result) => result.memory.id);
|
|
253
|
+
const aclRows = new Map();
|
|
254
|
+
if (aclIds.length > 0) {
|
|
255
|
+
const placeholders = aclIds.map(() => '?').join(',');
|
|
256
|
+
const fetched = db2.prepare(`SELECT id, source, sensitivity_level FROM memories WHERE id IN (${placeholders})`).all(...aclIds);
|
|
257
|
+
for (const row of fetched)
|
|
258
|
+
aclRows.set(row.id, row);
|
|
259
|
+
}
|
|
233
260
|
return finalResults.filter(result => {
|
|
234
|
-
const row =
|
|
261
|
+
const row = aclRows.get(result.memory.id);
|
|
235
262
|
const policy = checkAccess({ id: result.memory.id, source: row?.source, sensitivity_level: row?.sensitivity_level }, source, 'read');
|
|
236
263
|
if (!policy.canRead) {
|
|
237
264
|
logAccessDenial(result.memory.id, source, policy.reason);
|
|
@@ -334,10 +361,37 @@ function scoreWithRrf(input) {
|
|
|
334
361
|
}
|
|
335
362
|
// Vector and graph rank lists may contain ids the FTS WHERE would have
|
|
336
363
|
// filtered out — fetch + filter to enforce the same constraints.
|
|
364
|
+
const sortedVectorIds = Array.from(vectorResults.entries())
|
|
365
|
+
.sort((a, b) => b[1] - a[1])
|
|
366
|
+
.map(([id]) => id);
|
|
367
|
+
const graphLimit = Math.max(limit * 3, 50);
|
|
368
|
+
const graphResults = query && query.trim()
|
|
369
|
+
? graphRankFromQuery(query, db, { project: options.project, limit: graphLimit })
|
|
370
|
+
: [];
|
|
371
|
+
const candidateGraphIds = graphResults.map((r) => r.memoryId);
|
|
372
|
+
// Batch-hydrate every candidate not already covered by the FTS rows in ONE
|
|
373
|
+
// query (was an N+1: one `SELECT * WHERE id = ?` per vector/graph candidate).
|
|
374
|
+
// considerCandidate then reads from this prefetched map, keeping the exact
|
|
375
|
+
// per-id filter semantics, list order, and memoryMap side effect.
|
|
376
|
+
const candidateIdsToFetch = new Set();
|
|
377
|
+
for (const id of sortedVectorIds)
|
|
378
|
+
if (!memoryMap.has(id))
|
|
379
|
+
candidateIdsToFetch.add(id);
|
|
380
|
+
for (const id of candidateGraphIds)
|
|
381
|
+
if (!memoryMap.has(id))
|
|
382
|
+
candidateIdsToFetch.add(id);
|
|
383
|
+
const prefetchedRows = new Map();
|
|
384
|
+
if (candidateIdsToFetch.size > 0) {
|
|
385
|
+
const ids = [...candidateIdsToFetch];
|
|
386
|
+
const placeholders = ids.map(() => '?').join(',');
|
|
387
|
+
const fetched = db.prepare(`SELECT * FROM memories WHERE id IN (${placeholders})`).all(...ids);
|
|
388
|
+
for (const row of fetched)
|
|
389
|
+
prefetchedRows.set(row.id, row);
|
|
390
|
+
}
|
|
337
391
|
const considerCandidate = (id) => {
|
|
338
392
|
if (memoryMap.has(id))
|
|
339
393
|
return true;
|
|
340
|
-
const row =
|
|
394
|
+
const row = prefetchedRows.get(id);
|
|
341
395
|
if (!row)
|
|
342
396
|
return false;
|
|
343
397
|
const memory = rowToMemory(row);
|
|
@@ -346,15 +400,8 @@ function scoreWithRrf(input) {
|
|
|
346
400
|
memoryMap.set(memory.id, memory);
|
|
347
401
|
return true;
|
|
348
402
|
};
|
|
349
|
-
const vectorIds =
|
|
350
|
-
|
|
351
|
-
.map(([id]) => id)
|
|
352
|
-
.filter(considerCandidate);
|
|
353
|
-
const graphLimit = Math.max(limit * 3, 50);
|
|
354
|
-
const graphResults = query && query.trim()
|
|
355
|
-
? graphRankFromQuery(query, db, { project: options.project, limit: graphLimit })
|
|
356
|
-
: [];
|
|
357
|
-
const graphIds = graphResults.map((r) => r.memoryId).filter(considerCandidate);
|
|
403
|
+
const vectorIds = sortedVectorIds.filter(considerCandidate);
|
|
404
|
+
const graphIds = candidateGraphIds.filter(considerCandidate);
|
|
358
405
|
return runHybridRanker({
|
|
359
406
|
rankLists: [
|
|
360
407
|
{ name: 'fts', ids: ftsIds, weight: rankerConfig.weights.fts },
|
|
@@ -462,7 +509,10 @@ export async function recallWithEmbeddings(query, options) {
|
|
|
462
509
|
sql += ` AND (project = ? OR scope = 'global')`;
|
|
463
510
|
params.push(options.project);
|
|
464
511
|
}
|
|
465
|
-
|
|
512
|
+
// Prefilter the embedding-fallback candidate pool on the persisted decayed
|
|
513
|
+
// score (COALESCE to raw salience for rows not yet scored — see the FTS
|
|
514
|
+
// prefilter above for the NULL rationale).
|
|
515
|
+
sql += ' ORDER BY COALESCE(decayed_score, salience) DESC, last_accessed DESC LIMIT 200';
|
|
466
516
|
const candidates = db.prepare(sql).all(...params);
|
|
467
517
|
// Filter out memories already returned by FTS
|
|
468
518
|
const newCandidates = candidates.filter(c => !ftsIds.has(c.id));
|
|
@@ -476,14 +526,22 @@ export async function recallWithEmbeddings(query, options) {
|
|
|
476
526
|
// Find similar memories using embeddings
|
|
477
527
|
const remainingSlots = limit - ftsMemories.length;
|
|
478
528
|
const similar = await findSimilarMemories(query, newCandidates, remainingSlots, queryEmbedding);
|
|
479
|
-
// Filter by threshold
|
|
529
|
+
// Filter by threshold, then hydrate the survivors in ONE query. Was an N+1
|
|
530
|
+
// (one `SELECT * WHERE id = ?` per hit); now a single `WHERE id IN (...)`
|
|
531
|
+
// with an id→row map, mapping the threshold-passing ids through it so the
|
|
532
|
+
// original similarity order (and the skip-missing-row behaviour) is kept.
|
|
533
|
+
const hitIds = similar.filter((hit) => hit.score >= threshold).map((hit) => hit.id);
|
|
480
534
|
const embeddingMemories = [];
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
const
|
|
485
|
-
|
|
486
|
-
|
|
535
|
+
if (hitIds.length > 0) {
|
|
536
|
+
const placeholders = hitIds.map(() => '?').join(',');
|
|
537
|
+
const rowsById = new Map();
|
|
538
|
+
const fetched = db.prepare(`SELECT * FROM memories WHERE id IN (${placeholders})`).all(...hitIds);
|
|
539
|
+
for (const row of fetched)
|
|
540
|
+
rowsById.set(row.id, row);
|
|
541
|
+
for (const id of hitIds) {
|
|
542
|
+
const row = rowsById.get(id);
|
|
543
|
+
if (row)
|
|
544
|
+
embeddingMemories.push(rowToMemory(row));
|
|
487
545
|
}
|
|
488
546
|
}
|
|
489
547
|
// Step 4: Merge — FTS results first, then embedding results
|
package/dist/memory/search.d.ts
CHANGED
|
@@ -26,13 +26,29 @@ export interface SearchScoreValues {
|
|
|
26
26
|
contradictionPenalty: number;
|
|
27
27
|
finalScore: number;
|
|
28
28
|
}
|
|
29
|
-
export type MemoryRowConverter = (row: Record<string, unknown>) => Memory;
|
|
30
29
|
export declare function detectQueryCategory(query: string): MemoryCategory | null;
|
|
31
30
|
export declare function calculateLinkBoost(memoryId: number, db: Database.Database): number;
|
|
32
31
|
export declare function calculateTagScore(queryTags: string[], memoryTags: string[]): number;
|
|
33
32
|
export declare function extractQueryTags(query: string): string[];
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
/**
|
|
34
|
+
* Decode a persisted `memories.embedding` BLOB into a Float32Array view.
|
|
35
|
+
*
|
|
36
|
+
* The embedding column is written as the raw little-endian bytes of a 384-dim
|
|
37
|
+
* Float32Array (addMemory: `Buffer.from(embedding.buffer)`). better-sqlite3 hands
|
|
38
|
+
* it back as a Node Buffer; this returns a zero-copy Float32Array view over those
|
|
39
|
+
* bytes. Shared by `vectorSearch` and the recall reuse path (`findSimilarMemories`)
|
|
40
|
+
* so the BLOB→vector decode lives in exactly one place.
|
|
41
|
+
*/
|
|
42
|
+
export declare function decodeEmbeddingBlob(buf: Buffer): Float32Array;
|
|
43
|
+
/**
|
|
44
|
+
* Score embedded memories against a query embedding and return the top-k by
|
|
45
|
+
* cosine similarity. Selects ONLY `id, embedding` and returns lean
|
|
46
|
+
* `{ id, similarity }` pairs — the sole caller (search-recall) needs nothing
|
|
47
|
+
* more, so per-row Memory hydration (rowToMemory: 2 JSON parses + several
|
|
48
|
+
* `new Date()` per row) is deferred to whoever actually loads the survivors.
|
|
49
|
+
*/
|
|
50
|
+
export declare function vectorSearch(db: Database.Database, queryEmbedding: Float32Array, limit: number, project?: string, includeGlobal?: boolean): Array<{
|
|
51
|
+
id: number;
|
|
36
52
|
similarity: number;
|
|
37
53
|
}>;
|
|
38
54
|
export declare function buildSearchExplanation(memory: Memory, context: SearchScoringContext, values: SearchScoreValues): SearchResult['explanation'];
|
package/dist/memory/search.js
CHANGED
|
@@ -63,9 +63,28 @@ export function extractQueryTags(query) {
|
|
|
63
63
|
/^[a-z][a-z0-9-]*$/.test(word) &&
|
|
64
64
|
!['the', 'and', 'for', 'with', 'how', 'what', 'when', 'where', 'why'].includes(word));
|
|
65
65
|
}
|
|
66
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Decode a persisted `memories.embedding` BLOB into a Float32Array view.
|
|
68
|
+
*
|
|
69
|
+
* The embedding column is written as the raw little-endian bytes of a 384-dim
|
|
70
|
+
* Float32Array (addMemory: `Buffer.from(embedding.buffer)`). better-sqlite3 hands
|
|
71
|
+
* it back as a Node Buffer; this returns a zero-copy Float32Array view over those
|
|
72
|
+
* bytes. Shared by `vectorSearch` and the recall reuse path (`findSimilarMemories`)
|
|
73
|
+
* so the BLOB→vector decode lives in exactly one place.
|
|
74
|
+
*/
|
|
75
|
+
export function decodeEmbeddingBlob(buf) {
|
|
76
|
+
return new Float32Array(buf.buffer, buf.byteOffset, buf.length / 4);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Score embedded memories against a query embedding and return the top-k by
|
|
80
|
+
* cosine similarity. Selects ONLY `id, embedding` and returns lean
|
|
81
|
+
* `{ id, similarity }` pairs — the sole caller (search-recall) needs nothing
|
|
82
|
+
* more, so per-row Memory hydration (rowToMemory: 2 JSON parses + several
|
|
83
|
+
* `new Date()` per row) is deferred to whoever actually loads the survivors.
|
|
84
|
+
*/
|
|
85
|
+
export function vectorSearch(db, queryEmbedding, limit, project, includeGlobal = true) {
|
|
67
86
|
let query = `
|
|
68
|
-
SELECT
|
|
87
|
+
SELECT id, embedding FROM memories
|
|
69
88
|
WHERE embedding IS NOT NULL
|
|
70
89
|
`;
|
|
71
90
|
const params = [];
|
|
@@ -79,14 +98,10 @@ export function vectorSearch(db, rowToMemory, queryEmbedding, limit, project, in
|
|
|
79
98
|
}
|
|
80
99
|
const rows = db.prepare(query).all(...params);
|
|
81
100
|
return rows
|
|
82
|
-
.map((row) => {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
memory: rowToMemory(row),
|
|
87
|
-
similarity: cosineSimilarity(queryEmbedding, embedding),
|
|
88
|
-
};
|
|
89
|
-
})
|
|
101
|
+
.map((row) => ({
|
|
102
|
+
id: row.id,
|
|
103
|
+
similarity: cosineSimilarity(queryEmbedding, decodeEmbeddingBlob(row.embedding)),
|
|
104
|
+
}))
|
|
90
105
|
.filter((result) => result.similarity > 0.3)
|
|
91
106
|
.sort((a, b) => b.similarity - a.similarity)
|
|
92
107
|
.slice(0, limit);
|
package/dist/memory/store.d.ts
CHANGED
|
@@ -58,7 +58,16 @@ export declare function getProjectMemories(project: string, config?: MemoryConfi
|
|
|
58
58
|
/**
|
|
59
59
|
* Get recent memories
|
|
60
60
|
*/
|
|
61
|
-
export
|
|
61
|
+
export interface MemoryListFilters {
|
|
62
|
+
type?: string;
|
|
63
|
+
category?: string;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Count memories matching the project + type/category filters. Used by the
|
|
67
|
+
* dashboard memories route so `total`/`hasMore` reflect the filtered set.
|
|
68
|
+
*/
|
|
69
|
+
export declare function countMemories(project?: string, filters?: MemoryListFilters): number;
|
|
70
|
+
export declare function getRecentMemories(limit?: number, project?: string, source?: DefenceSource, filters?: MemoryListFilters): Memory[];
|
|
62
71
|
/**
|
|
63
72
|
* Get memories by type
|
|
64
73
|
*/
|
|
@@ -66,7 +75,9 @@ export declare function getMemoriesByType(type: MemoryType, limit?: number): Mem
|
|
|
66
75
|
/**
|
|
67
76
|
* Get high-priority memories (for context injection)
|
|
68
77
|
*/
|
|
69
|
-
export declare function getHighPriorityMemories(limit?: number, project?: string, source?: DefenceSource): Memory[];
|
|
78
|
+
export declare function getHighPriorityMemories(limit?: number, project?: string, source?: DefenceSource, filters?: MemoryListFilters): Memory[];
|
|
79
|
+
/** Count high-priority (salience >= 0.6) memories matching the filters. */
|
|
80
|
+
export declare function countHighPriorityMemories(project?: string, filters?: MemoryListFilters): number;
|
|
70
81
|
/**
|
|
71
82
|
* Get memory statistics
|
|
72
83
|
*/
|
package/dist/memory/store.js
CHANGED
|
@@ -350,6 +350,8 @@ export function addMemory(input, config = DEFAULT_CONFIG, source) {
|
|
|
350
350
|
threat_indicators: indicators,
|
|
351
351
|
anomaly_score: defenceResult.firewall.anomalyScore,
|
|
352
352
|
firewall_result: defenceResult.firewall.result,
|
|
353
|
+
project: input.project ?? null,
|
|
354
|
+
sensitivity_level: defenceResult.sensitivity.level,
|
|
353
355
|
});
|
|
354
356
|
}
|
|
355
357
|
catch {
|
|
@@ -539,6 +541,39 @@ export function getMemoryById(id, source) {
|
|
|
539
541
|
}
|
|
540
542
|
return rowToMemory(row);
|
|
541
543
|
}
|
|
544
|
+
/**
|
|
545
|
+
* Recompute and persist the `memories.embedding` vector for a memory whose
|
|
546
|
+
* embedded text (title/content) just changed. Fire-and-forget, mirroring
|
|
547
|
+
* addMemory's write: the caller is expected to have already cleared the column
|
|
548
|
+
* (`embedding = NULL`) synchronously so no stale vector is readable in the gap
|
|
549
|
+
* before this lands. No-ops cleanly when embeddings are disabled/unavailable.
|
|
550
|
+
*/
|
|
551
|
+
function refreshEmbeddingAsync(memoryId, title, content) {
|
|
552
|
+
const db = getDatabase();
|
|
553
|
+
generateEmbedding(title + ' ' + content)
|
|
554
|
+
.then((embedding) => {
|
|
555
|
+
try {
|
|
556
|
+
if (embedding && embedding.buffer) {
|
|
557
|
+
db.prepare('UPDATE memories SET embedding = ? WHERE id = ?')
|
|
558
|
+
.run(Buffer.from(embedding.buffer), memoryId);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
catch (e) {
|
|
562
|
+
const errMsg = e instanceof Error ? e.message : String(e);
|
|
563
|
+
if (/database connection is not open/i.test(errMsg))
|
|
564
|
+
return;
|
|
565
|
+
console.error('[shieldcortex] Failed to store refreshed embedding:', e);
|
|
566
|
+
}
|
|
567
|
+
})
|
|
568
|
+
.catch((e) => {
|
|
569
|
+
if (e instanceof Error &&
|
|
570
|
+
(e.message.includes('Embedding worker unavailable') ||
|
|
571
|
+
e.message.includes('Embeddings disabled via SHIELDCORTEX_SKIP_EMBEDDINGS=1'))) {
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
console.error('[shieldcortex] Failed to regenerate embedding:', e);
|
|
575
|
+
});
|
|
576
|
+
}
|
|
542
577
|
/**
|
|
543
578
|
* Update a memory
|
|
544
579
|
*/
|
|
@@ -635,11 +670,26 @@ export function updateMemory(id, updates) {
|
|
|
635
670
|
fields.push('memory_scope = ?');
|
|
636
671
|
values.push(updates.memoryScope);
|
|
637
672
|
}
|
|
673
|
+
// STALENESS: if the embedded text (title/content) changes, the persisted
|
|
674
|
+
// `memories.embedding` no longer reflects the current content. The recall reuse
|
|
675
|
+
// path (findSimilarMemories) scores candidates straight off this column, so a
|
|
676
|
+
// stale vector would let recall match on outdated content. Clear it in the SAME
|
|
677
|
+
// UPDATE — no window where the old vector is readable — then recompute below,
|
|
678
|
+
// mirroring addMemory's fire-and-forget embedding write. Cleared-but-not-yet-
|
|
679
|
+
// recomputed rows are simply absent from vector recall until the recompute
|
|
680
|
+
// lands (FTS still covers them); a stale match is the unacceptable outcome.
|
|
681
|
+
const embeddedTextChanged = updates.title !== undefined || updates.content !== undefined;
|
|
682
|
+
if (embeddedTextChanged) {
|
|
683
|
+
fields.push('embedding = NULL');
|
|
684
|
+
}
|
|
638
685
|
if (fields.length === 0)
|
|
639
686
|
return existing;
|
|
640
687
|
values.push(id);
|
|
641
688
|
db.prepare(`UPDATE memories SET ${fields.join(', ')}, updated_at = CURRENT_TIMESTAMP WHERE id = ?`).run(...values);
|
|
642
689
|
const updatedMemory = getMemoryById(id);
|
|
690
|
+
if (embeddedTextChanged) {
|
|
691
|
+
refreshEmbeddingAsync(updatedMemory.id, updatedMemory.title, updatedMemory.content);
|
|
692
|
+
}
|
|
643
693
|
const shouldRefreshGraph = updates.title !== undefined ||
|
|
644
694
|
updates.content !== undefined ||
|
|
645
695
|
updates.category !== undefined;
|
|
@@ -750,6 +800,7 @@ export function mergeMemories(keptId, removedId, options, source = { type: 'cli'
|
|
|
750
800
|
cloud_excluded = ?,
|
|
751
801
|
access_count = ?,
|
|
752
802
|
last_accessed = ?,
|
|
803
|
+
embedding = NULL,
|
|
753
804
|
updated_at = CURRENT_TIMESTAMP
|
|
754
805
|
WHERE id = ?
|
|
755
806
|
`).run(mergedContent, JSON.stringify(mergedTags), mergedSalience, mergedProject, JSON.stringify(mergedMetadata), mergedScope, mergedTransferable ? 1 : 0, mergedStatus, mergedPinned ? 1 : 0, mergedReviewedBy, new Date().toISOString(), mergedTrustScore, mergedSensitivity, mergedCloudExcluded ? 1 : 0, mergedAccessCount, mergedLastAccessed, kept.id);
|
|
@@ -761,6 +812,10 @@ export function mergeMemories(keptId, removedId, options, source = { type: 'cli'
|
|
|
761
812
|
catch (e) {
|
|
762
813
|
console.error('[shieldcortex] Entity extraction refresh failed after merge:', e);
|
|
763
814
|
}
|
|
815
|
+
// The merge UPDATE cleared `embedding` (the merged content differs from the
|
|
816
|
+
// pre-merge vector); recompute it for the new canonical content so the recall
|
|
817
|
+
// reuse path never scores against a stale pre-merge vector.
|
|
818
|
+
refreshEmbeddingAsync(updatedMemory.id, updatedMemory.title, updatedMemory.content);
|
|
764
819
|
emitMemoryUpdated(updatedMemory);
|
|
765
820
|
persistEvent('memory_updated', { memory: updatedMemory, mergedFromId: removed.id });
|
|
766
821
|
if (isFeatureEnabled('cloud_sync')) {
|
|
@@ -827,18 +882,43 @@ export function getProjectMemories(project, config = DEFAULT_CONFIG) {
|
|
|
827
882
|
});
|
|
828
883
|
}
|
|
829
884
|
/**
|
|
830
|
-
*
|
|
885
|
+
* Build the shared `WHERE` fragment for project + type + category filters.
|
|
886
|
+
* Returned `clause` is the full `WHERE ...` string (empty when no filters),
|
|
887
|
+
* so the SAME predicate drives both the page query and its COUNT(*) — keeping
|
|
888
|
+
* pagination `total`/`hasMore` honest under filters (Phase 17 A3).
|
|
831
889
|
*/
|
|
832
|
-
|
|
833
|
-
const
|
|
834
|
-
let sql = 'SELECT * FROM memories';
|
|
890
|
+
function buildMemoryFilterClause(project, filters) {
|
|
891
|
+
const conds = [];
|
|
835
892
|
const params = [];
|
|
836
893
|
if (project) {
|
|
837
|
-
|
|
894
|
+
conds.push('project = ?');
|
|
838
895
|
params.push(project);
|
|
839
896
|
}
|
|
897
|
+
if (filters?.type) {
|
|
898
|
+
conds.push('type = ?');
|
|
899
|
+
params.push(filters.type);
|
|
900
|
+
}
|
|
901
|
+
if (filters?.category) {
|
|
902
|
+
conds.push('category = ?');
|
|
903
|
+
params.push(filters.category);
|
|
904
|
+
}
|
|
905
|
+
return { clause: conds.length ? `WHERE ${conds.join(' AND ')}` : '', params };
|
|
906
|
+
}
|
|
907
|
+
/**
|
|
908
|
+
* Count memories matching the project + type/category filters. Used by the
|
|
909
|
+
* dashboard memories route so `total`/`hasMore` reflect the filtered set.
|
|
910
|
+
*/
|
|
911
|
+
export function countMemories(project, filters) {
|
|
912
|
+
const db = getDatabase();
|
|
913
|
+
const { clause, params } = buildMemoryFilterClause(project, filters);
|
|
914
|
+
return db.prepare(`SELECT COUNT(*) as count FROM memories ${clause}`).get(...params).count;
|
|
915
|
+
}
|
|
916
|
+
export function getRecentMemories(limit = 10, project, source, filters) {
|
|
917
|
+
const db = getDatabase();
|
|
918
|
+
const { clause, params } = buildMemoryFilterClause(project, filters);
|
|
919
|
+
let sql = `SELECT * FROM memories ${clause}`;
|
|
840
920
|
sql += ' ORDER BY last_accessed DESC LIMIT ?';
|
|
841
|
-
params.push(source ? limit * 2 : limit); // over-fetch when filtering
|
|
921
|
+
params.push(source ? limit * 2 : limit); // over-fetch when access-filtering
|
|
842
922
|
let rows = db.prepare(sql).all(...params);
|
|
843
923
|
if (source)
|
|
844
924
|
rows = filterRowsByAccess(rows, source);
|
|
@@ -860,17 +940,22 @@ export function getMemoriesByType(type, limit = 50) {
|
|
|
860
940
|
/**
|
|
861
941
|
* Get high-priority memories (for context injection)
|
|
862
942
|
*/
|
|
863
|
-
export function getHighPriorityMemories(limit = 10, project, source) {
|
|
943
|
+
export function getHighPriorityMemories(limit = 10, project, source, filters) {
|
|
864
944
|
const db = getDatabase();
|
|
865
|
-
let sql = `
|
|
866
|
-
SELECT * FROM memories
|
|
867
|
-
WHERE salience >= 0.6
|
|
868
|
-
`;
|
|
945
|
+
let sql = `SELECT * FROM memories WHERE salience >= 0.6`;
|
|
869
946
|
const params = [];
|
|
870
947
|
if (project) {
|
|
871
948
|
sql += ' AND project = ?';
|
|
872
949
|
params.push(project);
|
|
873
950
|
}
|
|
951
|
+
if (filters?.type) {
|
|
952
|
+
sql += ' AND type = ?';
|
|
953
|
+
params.push(filters.type);
|
|
954
|
+
}
|
|
955
|
+
if (filters?.category) {
|
|
956
|
+
sql += ' AND category = ?';
|
|
957
|
+
params.push(filters.category);
|
|
958
|
+
}
|
|
874
959
|
sql += ' ORDER BY salience DESC, last_accessed DESC LIMIT ?';
|
|
875
960
|
params.push(source ? limit * 2 : limit);
|
|
876
961
|
let rows = db.prepare(sql).all(...params);
|
|
@@ -878,6 +963,25 @@ export function getHighPriorityMemories(limit = 10, project, source) {
|
|
|
878
963
|
rows = filterRowsByAccess(rows, source);
|
|
879
964
|
return rows.slice(0, limit).map(rowToMemory);
|
|
880
965
|
}
|
|
966
|
+
/** Count high-priority (salience >= 0.6) memories matching the filters. */
|
|
967
|
+
export function countHighPriorityMemories(project, filters) {
|
|
968
|
+
const db = getDatabase();
|
|
969
|
+
let sql = `SELECT COUNT(*) as count FROM memories WHERE salience >= 0.6`;
|
|
970
|
+
const params = [];
|
|
971
|
+
if (project) {
|
|
972
|
+
sql += ' AND project = ?';
|
|
973
|
+
params.push(project);
|
|
974
|
+
}
|
|
975
|
+
if (filters?.type) {
|
|
976
|
+
sql += ' AND type = ?';
|
|
977
|
+
params.push(filters.type);
|
|
978
|
+
}
|
|
979
|
+
if (filters?.category) {
|
|
980
|
+
sql += ' AND category = ?';
|
|
981
|
+
params.push(filters.category);
|
|
982
|
+
}
|
|
983
|
+
return db.prepare(sql).get(...params).count;
|
|
984
|
+
}
|
|
881
985
|
/**
|
|
882
986
|
* Get memory statistics
|
|
883
987
|
*/
|