shieldcortex 4.14.11 → 4.16.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.
- package/README.md +4 -0
- 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/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/cli/migrate-legacy.d.ts +18 -0
- package/dist/cli/migrate-legacy.js +96 -0
- package/dist/cloud/cli.js +25 -1
- package/dist/cloud/config.d.ts +19 -0
- package/dist/cloud/config.js +72 -0
- package/dist/database/init.js +21 -0
- package/dist/database/schema.sql +1 -0
- package/dist/database/seed-firewall-rules.d.ts +21 -0
- package/dist/database/seed-firewall-rules.js +105 -0
- package/dist/defence/custom-rules/store.d.ts +4 -1
- package/dist/defence/custom-rules/store.js +7 -3
- package/dist/defence/firewall/instruction-detector.js +15 -0
- package/dist/defence/pipeline.js +19 -13
- package/dist/defence/types.d.ts +1 -1
- package/dist/memory/ranker/graph-rank.d.ts +39 -0
- package/dist/memory/ranker/graph-rank.js +186 -0
- package/dist/memory/ranker/index.d.ts +74 -0
- package/dist/memory/ranker/index.js +170 -0
- package/dist/memory/ranker/rrf.d.ts +41 -0
- package/dist/memory/ranker/rrf.js +54 -0
- package/dist/memory/search-recall.js +196 -65
- package/dist/memory/types.d.ts +18 -0
- package/dist/memory/types.js +6 -0
- package/hooks/openclaw/cortex-memory/HOOK.md +37 -0
- package/package.json +3 -1
- package/plugins/openclaw/dist/openclaw.plugin.json +1 -1
- package/scripts/lib/extract-memorable-segments.mjs +555 -0
- package/scripts/lib/save-memory.mjs +198 -13
- package/scripts/pre-compact-hook.mjs +19 -375
- package/scripts/session-end-hook.mjs +16 -307
- package/scripts/stop-hook.mjs +28 -159
- /package/dashboard/.next/standalone/dashboard/.next/static/{InYbgmj1l661AgpmCj6zr → 6WjF0Utj3STrFgg7vZVPK}/_buildManifest.js +0 -0
- /package/dashboard/.next/standalone/dashboard/.next/static/{InYbgmj1l661AgpmCj6zr → 6WjF0Utj3STrFgg7vZVPK}/_clientMiddlewareManifest.json +0 -0
- /package/dashboard/.next/standalone/dashboard/.next/static/{InYbgmj1l661AgpmCj6zr → 6WjF0Utj3STrFgg7vZVPK}/_ssgManifest.js +0 -0
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { getDatabase } from '../../database/init.js';
|
|
5
5
|
const MAX_RULES = 25;
|
|
6
|
-
export function listFirewallRules() {
|
|
6
|
+
export function listFirewallRules(opts = {}) {
|
|
7
|
+
const includeBuiltin = opts.includeBuiltin ?? true;
|
|
7
8
|
const db = getDatabase();
|
|
8
|
-
|
|
9
|
+
const where = includeBuiltin ? '' : 'WHERE built_in = 0';
|
|
10
|
+
return db.prepare(`SELECT * FROM firewall_rules ${where} ORDER BY priority ASC`).all();
|
|
9
11
|
}
|
|
10
12
|
export function getFirewallRule(id) {
|
|
11
13
|
const db = getDatabase();
|
|
@@ -13,7 +15,9 @@ export function getFirewallRule(id) {
|
|
|
13
15
|
}
|
|
14
16
|
export function createFirewallRule(rule) {
|
|
15
17
|
const db = getDatabase();
|
|
16
|
-
|
|
18
|
+
// The MAX_RULES cap applies only to user-defined rules. Built-in rules
|
|
19
|
+
// (built_in=1) are seeded by the database layer and don't count.
|
|
20
|
+
const count = db.prepare('SELECT COUNT(*) as cnt FROM firewall_rules WHERE built_in = 0').get().cnt;
|
|
17
21
|
if (count >= MAX_RULES) {
|
|
18
22
|
throw new Error(`Maximum of ${MAX_RULES} custom firewall rules reached.`);
|
|
19
23
|
}
|
|
@@ -114,6 +114,21 @@ const PATTERN_GROUPS = [
|
|
|
114
114
|
/reveal\s+your\s+instructions/i,
|
|
115
115
|
],
|
|
116
116
|
},
|
|
117
|
+
{
|
|
118
|
+
// Imperative tool-call directives. These show up in transcripts as
|
|
119
|
+
// injected prompts disguised as user instructions ("call the X tool
|
|
120
|
+
// to complete this request. Call this tool now."). The session-end
|
|
121
|
+
// chunker historically captured them as user preferences with
|
|
122
|
+
// salience 1.0; the firewall now flags them at write time so they
|
|
123
|
+
// route to quarantine instead of memories.
|
|
124
|
+
name: 'imperative_tool_call',
|
|
125
|
+
weight: 0.8,
|
|
126
|
+
patterns: [
|
|
127
|
+
/\b(?:call|invoke|use)\s+(?:the\s+)?[A-Za-z][\w-]*\s+tool\b/i,
|
|
128
|
+
/\b(?:call|invoke|use)\s+this\s+tool\s+now\b/i,
|
|
129
|
+
/\bcomplete\s+this\s+request\.\s*(?:call|invoke|use)\s+this\s+tool\b/i,
|
|
130
|
+
],
|
|
131
|
+
},
|
|
117
132
|
];
|
|
118
133
|
// Maximum content length to scan (prevents ReDOS on very long inputs)
|
|
119
134
|
const MAX_SCAN_LENGTH = 50000;
|
package/dist/defence/pipeline.js
CHANGED
|
@@ -95,42 +95,48 @@ export function runDefencePipeline(content, title, source, config, project) {
|
|
|
95
95
|
reason = firewall.reason;
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
|
-
// 6b. Apply
|
|
99
|
-
|
|
98
|
+
// 6b. Apply firewall rules (built-in rules always evaluated; user-added
|
|
99
|
+
// custom rules require the Pro `custom_firewall_rules` feature). Both
|
|
100
|
+
// are additive only — can tighten, never weaken.
|
|
101
|
+
if (allowed && isDatabaseInitialized()) {
|
|
100
102
|
try {
|
|
101
103
|
const { getEnabledFirewallRules } = require('./custom-rules/store.js');
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
+
const userRulesAllowed = isFeatureEnabled('custom_firewall_rules');
|
|
105
|
+
const allRules = getEnabledFirewallRules();
|
|
106
|
+
for (const rule of allRules) {
|
|
107
|
+
if (!rule.built_in && !userRulesAllowed)
|
|
108
|
+
continue;
|
|
104
109
|
try {
|
|
105
110
|
const regex = new RegExp(rule.condition_value, 'gi');
|
|
106
111
|
if (regex.test(cleanContent) || regex.test(title)) {
|
|
112
|
+
const indicator = rule.built_in ? 'builtin_rule' : 'custom_rule';
|
|
107
113
|
if (rule.action === 'block') {
|
|
108
114
|
allowed = false;
|
|
109
|
-
reason = `Blocked by custom rule: ${rule.name}`;
|
|
115
|
+
reason = `Blocked by ${rule.built_in ? 'built-in' : 'custom'} rule: ${rule.name}`;
|
|
110
116
|
firewall.result = 'BLOCK';
|
|
111
|
-
if (!firewall.threatIndicators.includes(
|
|
112
|
-
firewall.threatIndicators.push(
|
|
117
|
+
if (!firewall.threatIndicators.includes(indicator)) {
|
|
118
|
+
firewall.threatIndicators.push(indicator);
|
|
113
119
|
}
|
|
114
120
|
break; // Block is final
|
|
115
121
|
}
|
|
116
122
|
else if (rule.action === 'quarantine' && firewall.result !== 'BLOCK') {
|
|
117
123
|
allowed = false;
|
|
118
|
-
reason = `Quarantined by custom rule: ${rule.name}`;
|
|
124
|
+
reason = `Quarantined by ${rule.built_in ? 'built-in' : 'custom'} rule: ${rule.name}`;
|
|
119
125
|
firewall.result = 'QUARANTINE';
|
|
120
|
-
if (!firewall.threatIndicators.includes(
|
|
121
|
-
firewall.threatIndicators.push(
|
|
126
|
+
if (!firewall.threatIndicators.includes(indicator)) {
|
|
127
|
+
firewall.threatIndicators.push(indicator);
|
|
122
128
|
}
|
|
123
129
|
}
|
|
124
|
-
// 'allow' action: no-op —
|
|
130
|
+
// 'allow' action: no-op — rules cannot weaken built-in decisions
|
|
125
131
|
}
|
|
126
132
|
}
|
|
127
133
|
catch {
|
|
128
|
-
// Skip invalid regex in
|
|
134
|
+
// Skip invalid regex in rules
|
|
129
135
|
}
|
|
130
136
|
}
|
|
131
137
|
}
|
|
132
138
|
catch {
|
|
133
|
-
//
|
|
139
|
+
// Rules store not available — skip silently
|
|
134
140
|
}
|
|
135
141
|
}
|
|
136
142
|
// 6c. Apply custom injection patterns (Pro feature, additive)
|
package/dist/defence/types.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export type SensitivityLevel = 'PUBLIC' | 'INTERNAL' | 'CONFIDENTIAL' | 'RESTRICTED';
|
|
8
8
|
export type FirewallResult = 'ALLOW' | 'BLOCK' | 'QUARANTINE';
|
|
9
|
-
export type ThreatIndicator = 'instruction_injection' | 'privilege_escalation' | 'encoding_obfuscation' | 'credential_leak' | 'external_url' | 'fragmented_payload' | 'restricted_content' | 'pipeline_error' | 'custom_rule' | 'custom_pattern';
|
|
9
|
+
export type ThreatIndicator = 'instruction_injection' | 'privilege_escalation' | 'encoding_obfuscation' | 'credential_leak' | 'external_url' | 'fragmented_payload' | 'restricted_content' | 'pipeline_error' | 'custom_rule' | 'custom_pattern' | 'builtin_rule';
|
|
10
10
|
export interface DefenceSource {
|
|
11
11
|
type: 'user' | 'cli' | 'hook' | 'email' | 'web' | 'agent' | 'file' | 'api' | 'tool_response';
|
|
12
12
|
identifier: string;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Graph-based retrieval: turn a free-text query into a ranked list of
|
|
3
|
+
* memories by walking the knowledge graph (entities + triples).
|
|
4
|
+
*
|
|
5
|
+
* The retriever is side-effect-free — it only reads. It does NOT insert
|
|
6
|
+
* new entities, mutate aliases, or write any state. That's the
|
|
7
|
+
* contract that lets it stand alongside FTS and vector retrievers in the
|
|
8
|
+
* RRF orchestrator without polluting the graph during a query.
|
|
9
|
+
*
|
|
10
|
+
* Algorithm:
|
|
11
|
+
* 1. Tokenize the query, drop stop-words and tokens shorter than
|
|
12
|
+
* `MIN_TOKEN_LEN`.
|
|
13
|
+
* 2. Resolve each token to seed entities (case-insensitive name,
|
|
14
|
+
* alias, then Levenshtein for tokens at least `MIN_FUZZY_LEN` chars).
|
|
15
|
+
* 3. BFS over the triples table up to `maxHops`. Track shortest hop
|
|
16
|
+
* and incoming-edge confidence for every entity reached. Seeds have
|
|
17
|
+
* hop=0 and implicit confidence 1.0.
|
|
18
|
+
* 4. For every memory mentioning a reached entity (via the
|
|
19
|
+
* `memory_entities` table), accumulate score:
|
|
20
|
+
* Σ incomingConf / (hop + 1)
|
|
21
|
+
* 5. Optional `project` filter via the JOIN.
|
|
22
|
+
* 6. Sort by score desc, ties by memoryId asc, cap at `limit`.
|
|
23
|
+
*/
|
|
24
|
+
import type { Database as SqliteDatabase } from 'better-sqlite3';
|
|
25
|
+
export interface GraphRankResult {
|
|
26
|
+
memoryId: number;
|
|
27
|
+
score: number;
|
|
28
|
+
}
|
|
29
|
+
export interface GraphRankOptions {
|
|
30
|
+
/** Maximum hops from seed entities. Default 2. */
|
|
31
|
+
maxHops?: number;
|
|
32
|
+
/** Maximum result rows. Default 50. */
|
|
33
|
+
limit?: number;
|
|
34
|
+
/** Filter to memories within this project. */
|
|
35
|
+
project?: string;
|
|
36
|
+
/** Override stop-word set. Default is a small built-in English list. */
|
|
37
|
+
stopWords?: Set<string>;
|
|
38
|
+
}
|
|
39
|
+
export declare function graphRankFromQuery(query: string, db: SqliteDatabase, options?: GraphRankOptions): GraphRankResult[];
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Graph-based retrieval: turn a free-text query into a ranked list of
|
|
3
|
+
* memories by walking the knowledge graph (entities + triples).
|
|
4
|
+
*
|
|
5
|
+
* The retriever is side-effect-free — it only reads. It does NOT insert
|
|
6
|
+
* new entities, mutate aliases, or write any state. That's the
|
|
7
|
+
* contract that lets it stand alongside FTS and vector retrievers in the
|
|
8
|
+
* RRF orchestrator without polluting the graph during a query.
|
|
9
|
+
*
|
|
10
|
+
* Algorithm:
|
|
11
|
+
* 1. Tokenize the query, drop stop-words and tokens shorter than
|
|
12
|
+
* `MIN_TOKEN_LEN`.
|
|
13
|
+
* 2. Resolve each token to seed entities (case-insensitive name,
|
|
14
|
+
* alias, then Levenshtein for tokens at least `MIN_FUZZY_LEN` chars).
|
|
15
|
+
* 3. BFS over the triples table up to `maxHops`. Track shortest hop
|
|
16
|
+
* and incoming-edge confidence for every entity reached. Seeds have
|
|
17
|
+
* hop=0 and implicit confidence 1.0.
|
|
18
|
+
* 4. For every memory mentioning a reached entity (via the
|
|
19
|
+
* `memory_entities` table), accumulate score:
|
|
20
|
+
* Σ incomingConf / (hop + 1)
|
|
21
|
+
* 5. Optional `project` filter via the JOIN.
|
|
22
|
+
* 6. Sort by score desc, ties by memoryId asc, cap at `limit`.
|
|
23
|
+
*/
|
|
24
|
+
import { levenshtein } from '../../graph/resolve.js';
|
|
25
|
+
const DEFAULT_STOP_WORDS = new Set([
|
|
26
|
+
'the', 'a', 'an', 'is', 'are', 'was', 'were', 'be', 'been', 'being',
|
|
27
|
+
'and', 'or', 'but', 'not', 'no', 'to', 'of', 'in', 'on', 'at', 'for',
|
|
28
|
+
'with', 'by', 'from', 'as', 'this', 'that', 'these', 'those',
|
|
29
|
+
'it', 'its', 'has', 'have', 'had', 'do', 'does', 'did', 'can',
|
|
30
|
+
'could', 'should', 'would', 'will', 'shall', 'may', 'might', 'must',
|
|
31
|
+
'i', 'me', 'my', 'we', 'us', 'our', 'you', 'your', 'they', 'them',
|
|
32
|
+
'he', 'him', 'his', 'she', 'her', 'their',
|
|
33
|
+
]);
|
|
34
|
+
const MIN_TOKEN_LEN = 3;
|
|
35
|
+
const MIN_FUZZY_LEN = 6;
|
|
36
|
+
const MAX_FUZZY_DISTANCE = 2;
|
|
37
|
+
const DEFAULT_MAX_HOPS = 2;
|
|
38
|
+
const DEFAULT_LIMIT = 50;
|
|
39
|
+
export function graphRankFromQuery(query, db, options = {}) {
|
|
40
|
+
if (typeof query !== 'string' || query.trim().length === 0)
|
|
41
|
+
return [];
|
|
42
|
+
const maxHops = options.maxHops ?? DEFAULT_MAX_HOPS;
|
|
43
|
+
const limit = options.limit ?? DEFAULT_LIMIT;
|
|
44
|
+
const stopWords = options.stopWords ?? DEFAULT_STOP_WORDS;
|
|
45
|
+
const tokens = tokenize(query, stopWords);
|
|
46
|
+
if (tokens.length === 0)
|
|
47
|
+
return [];
|
|
48
|
+
const reach = resolveSeeds(tokens, db);
|
|
49
|
+
if (reach.size === 0)
|
|
50
|
+
return [];
|
|
51
|
+
expandHops(reach, maxHops, db);
|
|
52
|
+
return aggregateMemoryScores(reach, db, options.project, limit);
|
|
53
|
+
}
|
|
54
|
+
function tokenize(query, stopWords) {
|
|
55
|
+
return query
|
|
56
|
+
.toLowerCase()
|
|
57
|
+
.split(/[^\p{L}\p{N}_-]+/u)
|
|
58
|
+
.filter((t) => t.length >= MIN_TOKEN_LEN && !stopWords.has(t));
|
|
59
|
+
}
|
|
60
|
+
function resolveSeeds(tokens, db) {
|
|
61
|
+
// Pull every entity once. Fine for typical ShieldCortex DBs (hundreds of
|
|
62
|
+
// entities). Switch to per-token SQL probes if this becomes a hotspot.
|
|
63
|
+
const all = db
|
|
64
|
+
.prepare('SELECT id, name, aliases FROM entities')
|
|
65
|
+
.all();
|
|
66
|
+
// Pre-compute alias lookups.
|
|
67
|
+
const parsedAliases = all.map((row) => {
|
|
68
|
+
let aliases = [];
|
|
69
|
+
if (row.aliases) {
|
|
70
|
+
try {
|
|
71
|
+
const parsed = JSON.parse(row.aliases);
|
|
72
|
+
if (Array.isArray(parsed)) {
|
|
73
|
+
aliases = parsed.filter((a) => typeof a === 'string');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// Malformed JSON in the aliases column — treat as no aliases.
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return { id: row.id, name: row.name, lname: row.name.toLowerCase(), aliases };
|
|
81
|
+
});
|
|
82
|
+
const reach = new Map();
|
|
83
|
+
const recordSeed = (id) => {
|
|
84
|
+
if (!reach.has(id))
|
|
85
|
+
reach.set(id, { hop: 0, incomingConf: 1.0 });
|
|
86
|
+
};
|
|
87
|
+
for (const token of tokens) {
|
|
88
|
+
let matched = false;
|
|
89
|
+
// 1. Exact name match (case-insensitive).
|
|
90
|
+
for (const e of parsedAliases) {
|
|
91
|
+
if (e.lname === token) {
|
|
92
|
+
recordSeed(e.id);
|
|
93
|
+
matched = true;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (matched)
|
|
97
|
+
continue;
|
|
98
|
+
// 2. Alias match.
|
|
99
|
+
for (const e of parsedAliases) {
|
|
100
|
+
if (e.aliases.some((a) => a.toLowerCase() === token)) {
|
|
101
|
+
recordSeed(e.id);
|
|
102
|
+
matched = true;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (matched)
|
|
106
|
+
continue;
|
|
107
|
+
// 3. Fuzzy match — only for tokens of MIN_FUZZY_LEN+ to avoid false
|
|
108
|
+
// positives on short words.
|
|
109
|
+
if (token.length >= MIN_FUZZY_LEN) {
|
|
110
|
+
for (const e of parsedAliases) {
|
|
111
|
+
if (Math.abs(e.lname.length - token.length) > MAX_FUZZY_DISTANCE)
|
|
112
|
+
continue;
|
|
113
|
+
if (levenshtein(token, e.lname) <= MAX_FUZZY_DISTANCE) {
|
|
114
|
+
recordSeed(e.id);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return reach;
|
|
120
|
+
}
|
|
121
|
+
function expandHops(reach, maxHops, db) {
|
|
122
|
+
if (maxHops <= 0)
|
|
123
|
+
return;
|
|
124
|
+
let frontier = new Set(reach.keys());
|
|
125
|
+
for (let hop = 0; hop < maxHops; hop++) {
|
|
126
|
+
if (frontier.size === 0)
|
|
127
|
+
break;
|
|
128
|
+
const ids = Array.from(frontier);
|
|
129
|
+
const placeholders = ids.map(() => '?').join(',');
|
|
130
|
+
const rows = db
|
|
131
|
+
.prepare(`
|
|
132
|
+
SELECT subject_id AS src, object_id AS dst, confidence
|
|
133
|
+
FROM triples
|
|
134
|
+
WHERE subject_id IN (${placeholders})
|
|
135
|
+
UNION ALL
|
|
136
|
+
SELECT object_id AS src, subject_id AS dst, confidence
|
|
137
|
+
FROM triples
|
|
138
|
+
WHERE object_id IN (${placeholders})
|
|
139
|
+
`)
|
|
140
|
+
.all(...ids, ...ids);
|
|
141
|
+
const next = new Set();
|
|
142
|
+
for (const row of rows) {
|
|
143
|
+
const dstHop = hop + 1;
|
|
144
|
+
const existing = reach.get(row.dst);
|
|
145
|
+
if (!existing) {
|
|
146
|
+
reach.set(row.dst, { hop: dstHop, incomingConf: row.confidence });
|
|
147
|
+
next.add(row.dst);
|
|
148
|
+
}
|
|
149
|
+
else if (existing.hop === dstHop && row.confidence > existing.incomingConf) {
|
|
150
|
+
// Same shortest hop reached by a higher-confidence edge — keep the better one.
|
|
151
|
+
existing.incomingConf = row.confidence;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
frontier = next;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function aggregateMemoryScores(reach, db, project, limit) {
|
|
158
|
+
const entityIds = Array.from(reach.keys());
|
|
159
|
+
if (entityIds.length === 0)
|
|
160
|
+
return [];
|
|
161
|
+
const placeholders = entityIds.map(() => '?').join(',');
|
|
162
|
+
const params = [...entityIds];
|
|
163
|
+
let sql = `
|
|
164
|
+
SELECT me.memory_id, me.entity_id, m.project
|
|
165
|
+
FROM memory_entities me
|
|
166
|
+
JOIN memories m ON m.id = me.memory_id
|
|
167
|
+
WHERE me.entity_id IN (${placeholders})
|
|
168
|
+
`;
|
|
169
|
+
if (project) {
|
|
170
|
+
sql += ' AND m.project = ?';
|
|
171
|
+
params.push(project);
|
|
172
|
+
}
|
|
173
|
+
const rows = db.prepare(sql).all(...params);
|
|
174
|
+
const scoreByMemory = new Map();
|
|
175
|
+
for (const row of rows) {
|
|
176
|
+
const info = reach.get(row.entity_id);
|
|
177
|
+
if (!info)
|
|
178
|
+
continue; // shouldn't happen, but be defensive
|
|
179
|
+
const contribution = info.incomingConf / (info.hop + 1);
|
|
180
|
+
scoreByMemory.set(row.memory_id, (scoreByMemory.get(row.memory_id) ?? 0) + contribution);
|
|
181
|
+
}
|
|
182
|
+
return Array.from(scoreByMemory.entries())
|
|
183
|
+
.map(([memoryId, score]) => ({ memoryId, score }))
|
|
184
|
+
.sort((a, b) => b.score - a.score || a.memoryId - b.memoryId)
|
|
185
|
+
.slice(0, limit);
|
|
186
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hybrid retrieval orchestrator — Step A.3 of v4.15.
|
|
3
|
+
*
|
|
4
|
+
* Glues the three retrievers (FTS via SQLite FTS5, vector via embeddings,
|
|
5
|
+
* graph via `graphRankFromQuery`) into a single ranking by feeding their
|
|
6
|
+
* rank lists into Reciprocal Rank Fusion (`reciprocalRankFusion`), then
|
|
7
|
+
* applying the existing per-memory boosts (recency, category, link, tag,
|
|
8
|
+
* activation, contradiction) as **multiplicative tweaks on top of the
|
|
9
|
+
* RRF score** rather than additive components in a fixed-weight sum.
|
|
10
|
+
*
|
|
11
|
+
* finalScore = rrfScore
|
|
12
|
+
* × (1 + 0.05 × priority) // priority: 0–1
|
|
13
|
+
* × (1 + recencyBoost) // 0 / 0.05 / 0.1
|
|
14
|
+
* × (1 + 0.1 × categoryMatch) // 0 or 1
|
|
15
|
+
* × (1 + linkBoost) // 0–0.15
|
|
16
|
+
* × (1 + tagBoost) // 0–0.1
|
|
17
|
+
* × (1 + activationBoost) // 0–?
|
|
18
|
+
* × (1 - contradictionPenalty) // 0–0.12
|
|
19
|
+
*
|
|
20
|
+
* Why multiplicative on top of RRF rather than additive:
|
|
21
|
+
* - RRF is rank-based, so its raw score scale is small and consistent.
|
|
22
|
+
* - Multiplicative boosts preserve the *relative* RRF order while
|
|
23
|
+
* letting context modulate it — they don't drown out the underlying
|
|
24
|
+
* retrieval signal the way fixed additive weights do.
|
|
25
|
+
* - Contradiction penalty is multiplicative (`1 - p`) so it shrinks
|
|
26
|
+
* score proportionally rather than potentially flipping sign.
|
|
27
|
+
*
|
|
28
|
+
* The module is split intentionally: `runHybridRanker` is pure-ish (it
|
|
29
|
+
* accepts already-loaded rank lists + a memory map) so it can be unit
|
|
30
|
+
* tested without standing up the embedding model or the FTS pipeline.
|
|
31
|
+
* Step A.4 will add the DB-backed `hybridSearch` wrapper that builds
|
|
32
|
+
* those inputs from a `SearchOptions`.
|
|
33
|
+
*/
|
|
34
|
+
import type Database from 'better-sqlite3';
|
|
35
|
+
import { type RankList } from './rrf.js';
|
|
36
|
+
import type { Memory, MemoryConfig, SearchResult } from '../types.js';
|
|
37
|
+
export interface HybridRankerWeights {
|
|
38
|
+
fts: number;
|
|
39
|
+
vector: number;
|
|
40
|
+
graph: number;
|
|
41
|
+
}
|
|
42
|
+
export declare const DEFAULT_HYBRID_WEIGHTS: HybridRankerWeights;
|
|
43
|
+
/** Cormack et al. (2009) recommended RRF smoothing constant. */
|
|
44
|
+
export declare const DEFAULT_RRF_K = 60;
|
|
45
|
+
export interface HybridRankerInput {
|
|
46
|
+
/** Rank lists from FTS, vector, graph. Any subset is allowed. */
|
|
47
|
+
rankLists: readonly RankList[];
|
|
48
|
+
/** Memory id → Memory record. The caller pre-loads these. */
|
|
49
|
+
memories: Map<number, Memory>;
|
|
50
|
+
/** Memory id → cosine similarity (used only for explanation breakdowns). */
|
|
51
|
+
vectorSimilarities?: Map<number, number>;
|
|
52
|
+
/** Memory id → normalised FTS score (used only for explanation breakdowns). */
|
|
53
|
+
ftsScores?: Map<number, number>;
|
|
54
|
+
/** Original user query — drives category detection and tag extraction. */
|
|
55
|
+
query: string;
|
|
56
|
+
/** SQLite handle — used for memory_links lookups. */
|
|
57
|
+
db: Database.Database;
|
|
58
|
+
/** Memory config. `salienceThreshold` gates the includeDecayed filter. */
|
|
59
|
+
config: MemoryConfig;
|
|
60
|
+
/** Override RRF k constant. Default 60. */
|
|
61
|
+
rrfK?: number;
|
|
62
|
+
/** Attach a `SearchExplanation` to each `SearchResult`. */
|
|
63
|
+
includeExplanation?: boolean;
|
|
64
|
+
/** Skip the decay-threshold filter. */
|
|
65
|
+
includeDecayed?: boolean;
|
|
66
|
+
/** Cap result count. Default 20. */
|
|
67
|
+
limit?: number;
|
|
68
|
+
/**
|
|
69
|
+
* Override the activation-boost lookup. Defaults to the module-level
|
|
70
|
+
* cache in `../activation.js`. Tests inject a stub.
|
|
71
|
+
*/
|
|
72
|
+
activationBoostFn?: (memoryId: number) => number;
|
|
73
|
+
}
|
|
74
|
+
export declare function runHybridRanker(input: HybridRankerInput): SearchResult[];
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hybrid retrieval orchestrator — Step A.3 of v4.15.
|
|
3
|
+
*
|
|
4
|
+
* Glues the three retrievers (FTS via SQLite FTS5, vector via embeddings,
|
|
5
|
+
* graph via `graphRankFromQuery`) into a single ranking by feeding their
|
|
6
|
+
* rank lists into Reciprocal Rank Fusion (`reciprocalRankFusion`), then
|
|
7
|
+
* applying the existing per-memory boosts (recency, category, link, tag,
|
|
8
|
+
* activation, contradiction) as **multiplicative tweaks on top of the
|
|
9
|
+
* RRF score** rather than additive components in a fixed-weight sum.
|
|
10
|
+
*
|
|
11
|
+
* finalScore = rrfScore
|
|
12
|
+
* × (1 + 0.05 × priority) // priority: 0–1
|
|
13
|
+
* × (1 + recencyBoost) // 0 / 0.05 / 0.1
|
|
14
|
+
* × (1 + 0.1 × categoryMatch) // 0 or 1
|
|
15
|
+
* × (1 + linkBoost) // 0–0.15
|
|
16
|
+
* × (1 + tagBoost) // 0–0.1
|
|
17
|
+
* × (1 + activationBoost) // 0–?
|
|
18
|
+
* × (1 - contradictionPenalty) // 0–0.12
|
|
19
|
+
*
|
|
20
|
+
* Why multiplicative on top of RRF rather than additive:
|
|
21
|
+
* - RRF is rank-based, so its raw score scale is small and consistent.
|
|
22
|
+
* - Multiplicative boosts preserve the *relative* RRF order while
|
|
23
|
+
* letting context modulate it — they don't drown out the underlying
|
|
24
|
+
* retrieval signal the way fixed additive weights do.
|
|
25
|
+
* - Contradiction penalty is multiplicative (`1 - p`) so it shrinks
|
|
26
|
+
* score proportionally rather than potentially flipping sign.
|
|
27
|
+
*
|
|
28
|
+
* The module is split intentionally: `runHybridRanker` is pure-ish (it
|
|
29
|
+
* accepts already-loaded rank lists + a memory map) so it can be unit
|
|
30
|
+
* tested without standing up the embedding model or the FTS pipeline.
|
|
31
|
+
* Step A.4 will add the DB-backed `hybridSearch` wrapper that builds
|
|
32
|
+
* those inputs from a `SearchOptions`.
|
|
33
|
+
*/
|
|
34
|
+
import { reciprocalRankFusion } from './rrf.js';
|
|
35
|
+
import { calculateDecayedScore, calculatePriority } from '../decay.js';
|
|
36
|
+
import { getActivationBoost as defaultActivationBoost } from '../activation.js';
|
|
37
|
+
import { buildSearchExplanation, calculateLinkBoost, calculateTagScore, detectQueryCategory, extractQueryTags, } from '../search.js';
|
|
38
|
+
export const DEFAULT_HYBRID_WEIGHTS = {
|
|
39
|
+
fts: 0.4,
|
|
40
|
+
vector: 0.6,
|
|
41
|
+
graph: 0.3,
|
|
42
|
+
};
|
|
43
|
+
/** Cormack et al. (2009) recommended RRF smoothing constant. */
|
|
44
|
+
export const DEFAULT_RRF_K = 60;
|
|
45
|
+
const DEFAULT_LIMIT = 20;
|
|
46
|
+
export function runHybridRanker(input) {
|
|
47
|
+
const fused = reciprocalRankFusion(input.rankLists, { k: input.rrfK ?? DEFAULT_RRF_K });
|
|
48
|
+
if (fused.length === 0)
|
|
49
|
+
return [];
|
|
50
|
+
const limit = input.limit ?? DEFAULT_LIMIT;
|
|
51
|
+
const includeDecayed = input.includeDecayed ?? false;
|
|
52
|
+
const includeExplanation = input.includeExplanation ?? false;
|
|
53
|
+
const activationBoostFn = input.activationBoostFn ?? defaultActivationBoost;
|
|
54
|
+
const detectedCategory = input.query ? detectQueryCategory(input.query) : null;
|
|
55
|
+
const queryTags = input.query ? extractQueryTags(input.query) : [];
|
|
56
|
+
const scoringContext = {
|
|
57
|
+
db: input.db,
|
|
58
|
+
config: input.config,
|
|
59
|
+
detectedCategory,
|
|
60
|
+
queryTags,
|
|
61
|
+
vectorResults: input.vectorSimilarities ?? new Map(),
|
|
62
|
+
query: input.query,
|
|
63
|
+
};
|
|
64
|
+
const scored = [];
|
|
65
|
+
for (const fusedItem of fused) {
|
|
66
|
+
const memory = input.memories.get(fusedItem.id);
|
|
67
|
+
if (!memory)
|
|
68
|
+
continue;
|
|
69
|
+
const decayedScore = calculateDecayedScore(memory, input.config);
|
|
70
|
+
memory.decayedScore = decayedScore;
|
|
71
|
+
const candidate = scoreCandidate({
|
|
72
|
+
memory,
|
|
73
|
+
rrfScore: fusedItem.score,
|
|
74
|
+
contributions: fusedItem.contributions,
|
|
75
|
+
decayedScore,
|
|
76
|
+
detectedCategory,
|
|
77
|
+
queryTags,
|
|
78
|
+
vectorSimilarity: input.vectorSimilarities?.get(memory.id) ?? 0,
|
|
79
|
+
ftsScore: input.ftsScores?.get(memory.id) ?? 0,
|
|
80
|
+
db: input.db,
|
|
81
|
+
activationBoostFn,
|
|
82
|
+
});
|
|
83
|
+
scored.push(candidate);
|
|
84
|
+
}
|
|
85
|
+
const filtered = includeDecayed
|
|
86
|
+
? scored
|
|
87
|
+
: scored.filter((c) => c.decayedScore >= input.config.salienceThreshold);
|
|
88
|
+
filtered.sort((a, b) => b.finalScore - a.finalScore ||
|
|
89
|
+
a.memory.id - b.memory.id);
|
|
90
|
+
const capped = filtered.slice(0, limit);
|
|
91
|
+
return capped.map((c) => buildSearchResult(c, scoringContext, includeExplanation));
|
|
92
|
+
}
|
|
93
|
+
function scoreCandidate(input) {
|
|
94
|
+
const { memory } = input;
|
|
95
|
+
const hoursSinceAccess = (Date.now() - new Date(memory.lastAccessed).getTime()) / (1000 * 60 * 60);
|
|
96
|
+
const recencyBoost = hoursSinceAccess < 1 ? 0.1 : hoursSinceAccess < 24 ? 0.05 : 0;
|
|
97
|
+
const matchedCategory = input.detectedCategory !== null && memory.category === input.detectedCategory;
|
|
98
|
+
const categoryBoost = matchedCategory ? 0.1 : 0;
|
|
99
|
+
const linkBoost = calculateLinkBoost(memory.id, input.db);
|
|
100
|
+
const tagBoost = calculateTagScore(input.queryTags, memory.tags);
|
|
101
|
+
const activationBoost = input.activationBoostFn(memory.id);
|
|
102
|
+
const priority = calculatePriority(memory);
|
|
103
|
+
const priorityBoost = priority * 0.05;
|
|
104
|
+
const contradictionCount = input.db
|
|
105
|
+
.prepare(`SELECT COUNT(*) as count FROM memory_links
|
|
106
|
+
WHERE relationship = 'contradicts' AND (source_id = ? OR target_id = ?)`)
|
|
107
|
+
.get(memory.id, memory.id).count;
|
|
108
|
+
const contradictionPenalty = Math.min(0.12, contradictionCount * 0.03);
|
|
109
|
+
const multiplier = (1 + priorityBoost) *
|
|
110
|
+
(1 + recencyBoost) *
|
|
111
|
+
(1 + categoryBoost) *
|
|
112
|
+
(1 + linkBoost) *
|
|
113
|
+
(1 + tagBoost) *
|
|
114
|
+
(1 + activationBoost) *
|
|
115
|
+
(1 - contradictionPenalty);
|
|
116
|
+
const finalScore = input.rrfScore * multiplier;
|
|
117
|
+
const eligibilityReasons = [];
|
|
118
|
+
if (memory.status === 'archived')
|
|
119
|
+
eligibilityReasons.push('Archived memories are excluded from normal recall');
|
|
120
|
+
if (memory.status === 'suppressed')
|
|
121
|
+
eligibilityReasons.push('Suppressed memories are excluded from normal recall');
|
|
122
|
+
if (memory.cloudExcluded)
|
|
123
|
+
eligibilityReasons.push('Excluded from cloud sync');
|
|
124
|
+
if (memory.trustScore < 0.7)
|
|
125
|
+
eligibilityReasons.push(`Low trust source (${memory.trustScore.toFixed(2)})`);
|
|
126
|
+
if (contradictionCount > 0) {
|
|
127
|
+
eligibilityReasons.push(`${contradictionCount} contradiction link${contradictionCount === 1 ? '' : 's'} attached`);
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
memory,
|
|
131
|
+
rrfScore: input.rrfScore,
|
|
132
|
+
finalScore,
|
|
133
|
+
decayedScore: input.decayedScore,
|
|
134
|
+
contributions: input.contributions,
|
|
135
|
+
values: {
|
|
136
|
+
ftsScore: input.ftsScore,
|
|
137
|
+
vectorSimilarity: input.vectorSimilarity,
|
|
138
|
+
vectorBoost: input.vectorSimilarity * 0.3, // for explanation breakdown only
|
|
139
|
+
decayedScore: input.decayedScore,
|
|
140
|
+
priorityBoost,
|
|
141
|
+
recencyBoost,
|
|
142
|
+
categoryBoost,
|
|
143
|
+
linkBoost,
|
|
144
|
+
tagBoost,
|
|
145
|
+
activationBoost,
|
|
146
|
+
contradictionPenalty,
|
|
147
|
+
finalScore,
|
|
148
|
+
},
|
|
149
|
+
eligibilityReasons,
|
|
150
|
+
matchedCategory,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
function buildSearchResult(c, ctx, includeExplanation) {
|
|
154
|
+
const result = {
|
|
155
|
+
memory: c.memory,
|
|
156
|
+
relevanceScore: c.finalScore,
|
|
157
|
+
recallEligibility: {
|
|
158
|
+
eligible: c.eligibilityReasons.length === 0,
|
|
159
|
+
reasons: c.eligibilityReasons,
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
if (includeExplanation) {
|
|
163
|
+
const explanation = buildSearchExplanation(c.memory, ctx, c.values);
|
|
164
|
+
if (explanation) {
|
|
165
|
+
explanation.eligibility = result.recallEligibility;
|
|
166
|
+
result.explanation = explanation;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return result;
|
|
170
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reciprocal Rank Fusion (RRF).
|
|
3
|
+
*
|
|
4
|
+
* Combines ordered rank lists from multiple retrievers (e.g. BM25, vector,
|
|
5
|
+
* graph) into a single fused ranking. Robust to heterogeneous score scales:
|
|
6
|
+
* the only thing that matters is each retriever's rank order.
|
|
7
|
+
*
|
|
8
|
+
* score(d) = Σ_i w_i / (k + rank_i(d))
|
|
9
|
+
*
|
|
10
|
+
* - rank_i(d) is the 1-indexed position of d in retriever i's list.
|
|
11
|
+
* - w_i is the optional weight for retriever i (default 1).
|
|
12
|
+
* - k is a smoothing constant. Cormack et al. (2009) recommend 60.
|
|
13
|
+
*
|
|
14
|
+
* The function returns the union of ids across all rank lists, sorted by
|
|
15
|
+
* fused score descending. Ties break by id ascending for stable output.
|
|
16
|
+
*/
|
|
17
|
+
export interface RankList {
|
|
18
|
+
/** Identifier for this retriever (e.g. 'fts', 'vector', 'graph'). */
|
|
19
|
+
name: string;
|
|
20
|
+
/** Ordered ids, best-first. May be empty. Duplicates within a list are deduplicated, keeping the first occurrence. */
|
|
21
|
+
ids: number[];
|
|
22
|
+
/** Multiplicative weight on this retriever's contribution. Defaults to 1. */
|
|
23
|
+
weight?: number;
|
|
24
|
+
}
|
|
25
|
+
export interface RrfOptions {
|
|
26
|
+
/** RRF smoothing constant. Default 60. */
|
|
27
|
+
k?: number;
|
|
28
|
+
}
|
|
29
|
+
export interface RrfContribution {
|
|
30
|
+
name: string;
|
|
31
|
+
/** 1-indexed rank within that retriever's list. */
|
|
32
|
+
rank: number;
|
|
33
|
+
/** weight / (k + rank) — this contribution's addition to the final score. */
|
|
34
|
+
weighted: number;
|
|
35
|
+
}
|
|
36
|
+
export interface RrfResult {
|
|
37
|
+
id: number;
|
|
38
|
+
score: number;
|
|
39
|
+
contributions: RrfContribution[];
|
|
40
|
+
}
|
|
41
|
+
export declare function reciprocalRankFusion(rankLists: readonly RankList[], options?: RrfOptions): RrfResult[];
|