shieldcortex 4.25.5 → 4.27.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/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/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/dist/cli/doctor.js +1 -1
- package/dist/cli/update.js +21 -0
- package/dist/database/init.js +2 -755
- package/dist/database/inline-schema.d.ts +15 -0
- package/dist/database/inline-schema.js +319 -0
- package/dist/database/migrations.d.ts +48 -0
- package/dist/database/migrations.js +506 -0
- package/dist/setup/quickstart.js +54 -0
- package/package.json +1 -1
- package/scripts/lib/dashboard-hint.mjs +71 -0
- package/scripts/postinstall.mjs +13 -0
- /package/dashboard/.next/standalone/dashboard/.next/static/{eiXzjGydPq7Vc5bq6Ohjr → CGvPUupL70GmSXZuLa4TO}/_buildManifest.js +0 -0
- /package/dashboard/.next/standalone/dashboard/.next/static/{eiXzjGydPq7Vc5bq6Ohjr → CGvPUupL70GmSXZuLa4TO}/_clientMiddlewareManifest.json +0 -0
- /package/dashboard/.next/standalone/dashboard/.next/static/{eiXzjGydPq7Vc5bq6Ohjr → CGvPUupL70GmSXZuLa4TO}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema migrations for existing ShieldCortex databases (extracted from
|
|
3
|
+
* src/database/init.ts in v4.26.0 to keep init.ts focused on connection
|
|
4
|
+
* lifecycle).
|
|
5
|
+
*
|
|
6
|
+
* `runMigrations()` is called during `initDatabase()` AFTER the connection is
|
|
7
|
+
* open but BEFORE the inline/file schema (`CREATE TABLE IF NOT EXISTS`)
|
|
8
|
+
* is applied. The split lets us:
|
|
9
|
+
* - ALTER TABLE pre-existing rows for new columns the schema introduces
|
|
10
|
+
* - Backfill data into those columns
|
|
11
|
+
* - Create extra tables (Pro-feature surface, knowledge graph, sync queue)
|
|
12
|
+
* that the canonical schema file may not yet declare on older installs
|
|
13
|
+
*
|
|
14
|
+
* Most migrations here are idempotent — guarded by either `IF NOT EXISTS`
|
|
15
|
+
* (CREATE TABLE / CREATE INDEX) or a `PRAGMA table_info(...)` check before
|
|
16
|
+
* `ALTER TABLE ADD COLUMN`. The broad try/catch blocks around the larger
|
|
17
|
+
* DDL clusters use `logIfUnexpectedDdlError` to keep idempotent re-runs
|
|
18
|
+
* silent while still surfacing genuinely-unexpected failures (disk full,
|
|
19
|
+
* permission denied, schema corruption, FK conflict).
|
|
20
|
+
*
|
|
21
|
+
* Adding a new migration: add a guarded block at the end of this function.
|
|
22
|
+
* NEVER reorder existing migrations — that breaks upgrade paths on older
|
|
23
|
+
* databases that have only partially run them.
|
|
24
|
+
*/
|
|
25
|
+
import { randomUUID } from 'crypto';
|
|
26
|
+
import { seedDefaultFirewallRules } from './seed-firewall-rules.js';
|
|
27
|
+
/**
|
|
28
|
+
* Log unexpected errors from idempotent DDL operations (v4.26.0).
|
|
29
|
+
*
|
|
30
|
+
* Most schema migrations are guarded by either:
|
|
31
|
+
* - `IF NOT EXISTS` (CREATE TABLE / CREATE INDEX), or
|
|
32
|
+
* - A PRAGMA check (ALTER TABLE ADD COLUMN, only fires when column missing)
|
|
33
|
+
*
|
|
34
|
+
* Those guards mean the typical re-run case is silent and safe. But the broad
|
|
35
|
+
* `catch {}` blocks that wrap them also swallow genuinely-unexpected failures
|
|
36
|
+
* (disk full, permission denied, schema corruption, FK conflict). This helper
|
|
37
|
+
* filters known-idempotent SQLite errors but surfaces anything else on stderr
|
|
38
|
+
* so the doctor / operator can spot real problems.
|
|
39
|
+
*/
|
|
40
|
+
export function logIfUnexpectedDdlError(err, op) {
|
|
41
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
42
|
+
// SQLite errors that are EXPECTED on partial-migration re-runs.
|
|
43
|
+
const expected = [
|
|
44
|
+
/already exists/i,
|
|
45
|
+
/duplicate column/i,
|
|
46
|
+
/no such table/i, // PRAGMA on a missing table when guarding ALTERs
|
|
47
|
+
/no such column/i,
|
|
48
|
+
/no such index/i,
|
|
49
|
+
];
|
|
50
|
+
if (expected.some((p) => p.test(msg)))
|
|
51
|
+
return;
|
|
52
|
+
console.error(`[database] unexpected migration error in ${op}: ${msg}`);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Run database migrations for existing databases.
|
|
56
|
+
*
|
|
57
|
+
* Skips entirely on fresh databases (the schema file creates everything in
|
|
58
|
+
* its post-migration form). For existing databases, it walks every
|
|
59
|
+
* column-add / table-create / backfill that has shipped across ShieldCortex
|
|
60
|
+
* v1.x → v4.x.
|
|
61
|
+
*/
|
|
62
|
+
export function runMigrations(database) {
|
|
63
|
+
// Check if memories table exists (skip migrations on fresh database)
|
|
64
|
+
const tableExists = database.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='memories'").get();
|
|
65
|
+
if (!tableExists) {
|
|
66
|
+
// Fresh database - schema will create everything
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
// Check existing columns
|
|
70
|
+
const tableInfo = database.prepare("PRAGMA table_info(memories)").all();
|
|
71
|
+
const columnNames = new Set(tableInfo.map(col => col.name));
|
|
72
|
+
// Migration: decayed_score column
|
|
73
|
+
if (!columnNames.has('decayed_score')) {
|
|
74
|
+
database.exec('ALTER TABLE memories ADD COLUMN decayed_score REAL');
|
|
75
|
+
database.exec('CREATE INDEX IF NOT EXISTS idx_memories_decayed_score ON memories(decayed_score DESC)');
|
|
76
|
+
}
|
|
77
|
+
// Migration: embedding column for semantic search
|
|
78
|
+
if (!columnNames.has('embedding')) {
|
|
79
|
+
database.exec('ALTER TABLE memories ADD COLUMN embedding BLOB');
|
|
80
|
+
}
|
|
81
|
+
// Migration: scope column for cross-project knowledge
|
|
82
|
+
if (!columnNames.has('scope')) {
|
|
83
|
+
database.exec("ALTER TABLE memories ADD COLUMN scope TEXT DEFAULT 'project'");
|
|
84
|
+
}
|
|
85
|
+
// Migration: transferable column for cross-project sharing
|
|
86
|
+
if (!columnNames.has('transferable')) {
|
|
87
|
+
database.exec('ALTER TABLE memories ADD COLUMN transferable INTEGER DEFAULT 0');
|
|
88
|
+
}
|
|
89
|
+
// Migration: Defence columns on memories table
|
|
90
|
+
if (!columnNames.has('trust_score')) {
|
|
91
|
+
database.exec("ALTER TABLE memories ADD COLUMN trust_score REAL DEFAULT 1.0");
|
|
92
|
+
}
|
|
93
|
+
if (!columnNames.has('sensitivity_level')) {
|
|
94
|
+
database.exec("ALTER TABLE memories ADD COLUMN sensitivity_level TEXT DEFAULT 'INTERNAL'");
|
|
95
|
+
}
|
|
96
|
+
if (!columnNames.has('source')) {
|
|
97
|
+
database.exec("ALTER TABLE memories ADD COLUMN source TEXT DEFAULT 'user:direct'");
|
|
98
|
+
}
|
|
99
|
+
if (!columnNames.has('status')) {
|
|
100
|
+
database.exec("ALTER TABLE memories ADD COLUMN status TEXT DEFAULT 'active'");
|
|
101
|
+
}
|
|
102
|
+
if (!columnNames.has('pinned')) {
|
|
103
|
+
database.exec('ALTER TABLE memories ADD COLUMN pinned INTEGER DEFAULT 0');
|
|
104
|
+
}
|
|
105
|
+
if (!columnNames.has('reviewed_at')) {
|
|
106
|
+
database.exec('ALTER TABLE memories ADD COLUMN reviewed_at TIMESTAMP');
|
|
107
|
+
}
|
|
108
|
+
if (!columnNames.has('reviewed_by')) {
|
|
109
|
+
database.exec('ALTER TABLE memories ADD COLUMN reviewed_by TEXT');
|
|
110
|
+
}
|
|
111
|
+
if (!columnNames.has('source_kind')) {
|
|
112
|
+
database.exec("ALTER TABLE memories ADD COLUMN source_kind TEXT DEFAULT 'user'");
|
|
113
|
+
}
|
|
114
|
+
if (!columnNames.has('capture_method')) {
|
|
115
|
+
database.exec("ALTER TABLE memories ADD COLUMN capture_method TEXT DEFAULT 'manual'");
|
|
116
|
+
}
|
|
117
|
+
if (!columnNames.has('cloud_excluded')) {
|
|
118
|
+
database.exec('ALTER TABLE memories ADD COLUMN cloud_excluded INTEGER DEFAULT 0');
|
|
119
|
+
}
|
|
120
|
+
if (!columnNames.has('uuid')) {
|
|
121
|
+
database.exec("ALTER TABLE memories ADD COLUMN uuid TEXT");
|
|
122
|
+
}
|
|
123
|
+
if (!columnNames.has('updated_at')) {
|
|
124
|
+
database.exec('ALTER TABLE memories ADD COLUMN updated_at TIMESTAMP');
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
const rowsWithoutUuid = database.prepare('SELECT id FROM memories WHERE uuid IS NULL OR uuid = ?').all('');
|
|
128
|
+
const setUuid = database.prepare('UPDATE memories SET uuid = ? WHERE id = ?');
|
|
129
|
+
for (const row of rowsWithoutUuid) {
|
|
130
|
+
setUuid.run(randomUUID(), row.id);
|
|
131
|
+
}
|
|
132
|
+
database.exec('UPDATE memories SET updated_at = COALESCE(updated_at, created_at, CURRENT_TIMESTAMP) WHERE updated_at IS NULL');
|
|
133
|
+
database.exec("UPDATE memories SET status = COALESCE(status, 'active') WHERE status IS NULL OR status = ''");
|
|
134
|
+
database.exec('UPDATE memories SET pinned = COALESCE(pinned, 0) WHERE pinned IS NULL');
|
|
135
|
+
database.exec(`
|
|
136
|
+
UPDATE memories
|
|
137
|
+
SET source = CASE
|
|
138
|
+
WHEN source = 'user:direct' AND tags LIKE '%session-end%' THEN 'hook:openclaw-session-end'
|
|
139
|
+
WHEN source = 'user:direct' AND tags LIKE '%session-stop%' THEN 'hook:openclaw-session-stop'
|
|
140
|
+
WHEN source = 'user:direct' AND tags LIKE '%keyword-trigger%' THEN 'hook:openclaw-keyword'
|
|
141
|
+
WHEN source IS NULL AND tags LIKE '%llm-output%' THEN 'agent:openclaw-plugin'
|
|
142
|
+
ELSE source
|
|
143
|
+
END
|
|
144
|
+
WHERE
|
|
145
|
+
(source = 'user:direct' OR source IS NULL)
|
|
146
|
+
AND (
|
|
147
|
+
tags LIKE '%session-end%'
|
|
148
|
+
OR tags LIKE '%session-stop%'
|
|
149
|
+
OR tags LIKE '%keyword-trigger%'
|
|
150
|
+
OR tags LIKE '%llm-output%'
|
|
151
|
+
OR tags LIKE '%realtime-plugin%'
|
|
152
|
+
OR tags LIKE '%openclaw-hook%'
|
|
153
|
+
)
|
|
154
|
+
`);
|
|
155
|
+
database.exec("UPDATE memories SET source_kind = CASE WHEN source LIKE 'hook:%' THEN 'hook' WHEN source LIKE 'api:%' THEN 'api' WHEN source LIKE 'agent:%' THEN 'agent' WHEN source LIKE 'cli:%' THEN 'cli' ELSE COALESCE(source_kind, 'user') END WHERE source_kind IS NULL OR source_kind = ''");
|
|
156
|
+
database.exec("UPDATE memories SET capture_method = CASE WHEN tags LIKE '%auto-extracted%' THEN 'auto' WHEN source_kind = 'hook' THEN 'hook' WHEN source_kind = 'api' THEN 'api' WHEN source_kind = 'agent' THEN 'plugin' WHEN source_kind = 'cli' THEN 'manual' ELSE COALESCE(capture_method, 'manual') END WHERE capture_method IS NULL OR capture_method = ''");
|
|
157
|
+
database.exec(`
|
|
158
|
+
UPDATE memories
|
|
159
|
+
SET source_kind = CASE
|
|
160
|
+
WHEN tags LIKE '%session-end%' OR tags LIKE '%session-stop%' OR tags LIKE '%keyword-trigger%' OR tags LIKE '%openclaw-hook%' THEN 'hook'
|
|
161
|
+
WHEN tags LIKE '%llm-output%' OR tags LIKE '%realtime-plugin%' THEN 'agent'
|
|
162
|
+
ELSE source_kind
|
|
163
|
+
END,
|
|
164
|
+
capture_method = CASE
|
|
165
|
+
WHEN tags LIKE '%session-end%' OR tags LIKE '%session-stop%' OR tags LIKE '%openclaw-hook%' THEN 'auto'
|
|
166
|
+
WHEN tags LIKE '%keyword-trigger%' THEN 'hook'
|
|
167
|
+
WHEN tags LIKE '%llm-output%' OR tags LIKE '%realtime-plugin%' THEN 'auto'
|
|
168
|
+
ELSE capture_method
|
|
169
|
+
END
|
|
170
|
+
WHERE
|
|
171
|
+
tags LIKE '%session-end%'
|
|
172
|
+
OR tags LIKE '%session-stop%'
|
|
173
|
+
OR tags LIKE '%keyword-trigger%'
|
|
174
|
+
OR tags LIKE '%openclaw-hook%'
|
|
175
|
+
OR tags LIKE '%llm-output%'
|
|
176
|
+
OR tags LIKE '%realtime-plugin%'
|
|
177
|
+
`);
|
|
178
|
+
database.exec('UPDATE memories SET cloud_excluded = COALESCE(cloud_excluded, 0) WHERE cloud_excluded IS NULL');
|
|
179
|
+
database.exec('CREATE UNIQUE INDEX IF NOT EXISTS idx_memories_uuid ON memories(uuid)');
|
|
180
|
+
database.exec('CREATE INDEX IF NOT EXISTS idx_memories_updated ON memories(updated_at DESC)');
|
|
181
|
+
database.exec('CREATE INDEX IF NOT EXISTS idx_memories_status ON memories(status)');
|
|
182
|
+
database.exec('CREATE INDEX IF NOT EXISTS idx_memories_pinned ON memories(pinned DESC)');
|
|
183
|
+
database.exec('CREATE INDEX IF NOT EXISTS idx_memories_source_kind ON memories(source_kind)');
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
logIfUnexpectedDdlError(err, 'memories indexes + uuid backfill');
|
|
187
|
+
// Note: idempotent failures (re-run, columns already present) stay silent.
|
|
188
|
+
}
|
|
189
|
+
// Migration: Defence tables (defence_audit, quarantine, fragmentation_entities)
|
|
190
|
+
try {
|
|
191
|
+
database.exec(`
|
|
192
|
+
CREATE TABLE IF NOT EXISTS defence_audit (
|
|
193
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
194
|
+
memory_id INTEGER,
|
|
195
|
+
project TEXT,
|
|
196
|
+
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
197
|
+
source_type TEXT NOT NULL,
|
|
198
|
+
source_identifier TEXT NOT NULL,
|
|
199
|
+
trust_score REAL NOT NULL,
|
|
200
|
+
sensitivity_level TEXT NOT NULL DEFAULT 'INTERNAL',
|
|
201
|
+
firewall_result TEXT NOT NULL CHECK(firewall_result IN ('ALLOW', 'BLOCK', 'QUARANTINE')),
|
|
202
|
+
anomaly_score REAL DEFAULT 0.0,
|
|
203
|
+
threat_indicators TEXT DEFAULT '[]',
|
|
204
|
+
blocked_patterns TEXT DEFAULT '[]',
|
|
205
|
+
reason TEXT,
|
|
206
|
+
fragmentation_score REAL,
|
|
207
|
+
pipeline_duration_ms INTEGER,
|
|
208
|
+
FOREIGN KEY (memory_id) REFERENCES memories(id) ON DELETE SET NULL
|
|
209
|
+
);
|
|
210
|
+
CREATE INDEX IF NOT EXISTS idx_audit_memory ON defence_audit(memory_id);
|
|
211
|
+
CREATE INDEX IF NOT EXISTS idx_audit_timestamp ON defence_audit(timestamp DESC);
|
|
212
|
+
CREATE INDEX IF NOT EXISTS idx_audit_result ON defence_audit(firewall_result);
|
|
213
|
+
CREATE INDEX IF NOT EXISTS idx_audit_source ON defence_audit(source_type);
|
|
214
|
+
CREATE INDEX IF NOT EXISTS idx_audit_project ON defence_audit(project);
|
|
215
|
+
|
|
216
|
+
CREATE TABLE IF NOT EXISTS quarantine (
|
|
217
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
218
|
+
original_content TEXT NOT NULL,
|
|
219
|
+
original_title TEXT,
|
|
220
|
+
project TEXT,
|
|
221
|
+
source_type TEXT NOT NULL,
|
|
222
|
+
source_identifier TEXT NOT NULL,
|
|
223
|
+
reason TEXT NOT NULL,
|
|
224
|
+
threat_indicators TEXT DEFAULT '[]',
|
|
225
|
+
anomaly_score REAL DEFAULT 0.0,
|
|
226
|
+
firewall_result TEXT NOT NULL CHECK(firewall_result IN ('BLOCK', 'QUARANTINE')),
|
|
227
|
+
status TEXT NOT NULL DEFAULT 'pending' CHECK(status IN ('pending', 'approved', 'rejected', 'expired')),
|
|
228
|
+
reviewed_at TIMESTAMP,
|
|
229
|
+
reviewed_by TEXT,
|
|
230
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
231
|
+
expires_at TIMESTAMP,
|
|
232
|
+
audit_id INTEGER,
|
|
233
|
+
FOREIGN KEY (audit_id) REFERENCES defence_audit(id) ON DELETE SET NULL
|
|
234
|
+
);
|
|
235
|
+
CREATE INDEX IF NOT EXISTS idx_quarantine_status ON quarantine(status);
|
|
236
|
+
CREATE INDEX IF NOT EXISTS idx_quarantine_created ON quarantine(created_at DESC);
|
|
237
|
+
|
|
238
|
+
CREATE TABLE IF NOT EXISTS quarantine_annotations (
|
|
239
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
240
|
+
item_id INTEGER NOT NULL,
|
|
241
|
+
category TEXT NOT NULL,
|
|
242
|
+
suggested_action TEXT NOT NULL,
|
|
243
|
+
confidence REAL NOT NULL,
|
|
244
|
+
similar_group_key TEXT,
|
|
245
|
+
copilot_version TEXT NOT NULL,
|
|
246
|
+
annotation_json TEXT NOT NULL,
|
|
247
|
+
generated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
248
|
+
FOREIGN KEY (item_id) REFERENCES quarantine(id) ON DELETE CASCADE,
|
|
249
|
+
UNIQUE(item_id, copilot_version)
|
|
250
|
+
);
|
|
251
|
+
CREATE INDEX IF NOT EXISTS idx_quarantine_annotations_item ON quarantine_annotations(item_id);
|
|
252
|
+
CREATE INDEX IF NOT EXISTS idx_quarantine_annotations_category ON quarantine_annotations(category);
|
|
253
|
+
CREATE INDEX IF NOT EXISTS idx_quarantine_annotations_action ON quarantine_annotations(suggested_action);
|
|
254
|
+
CREATE INDEX IF NOT EXISTS idx_quarantine_annotations_group ON quarantine_annotations(similar_group_key);
|
|
255
|
+
|
|
256
|
+
CREATE TABLE IF NOT EXISTS fragmentation_entities (
|
|
257
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
258
|
+
memory_id INTEGER NOT NULL,
|
|
259
|
+
entity_value TEXT NOT NULL,
|
|
260
|
+
entity_type TEXT NOT NULL,
|
|
261
|
+
context_snippet TEXT,
|
|
262
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
263
|
+
FOREIGN KEY (memory_id) REFERENCES memories(id) ON DELETE CASCADE
|
|
264
|
+
);
|
|
265
|
+
CREATE INDEX IF NOT EXISTS idx_frag_entities_memory ON fragmentation_entities(memory_id);
|
|
266
|
+
CREATE INDEX IF NOT EXISTS idx_frag_entities_text ON fragmentation_entities(entity_value);
|
|
267
|
+
CREATE INDEX IF NOT EXISTS idx_frag_entities_type ON fragmentation_entities(entity_type);
|
|
268
|
+
|
|
269
|
+
CREATE TABLE IF NOT EXISTS hook_invocations (
|
|
270
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
271
|
+
hook_name TEXT NOT NULL,
|
|
272
|
+
invoked_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
273
|
+
exit_code INTEGER,
|
|
274
|
+
duration_ms INTEGER,
|
|
275
|
+
memories_extracted INTEGER DEFAULT 0,
|
|
276
|
+
transcript_bytes INTEGER,
|
|
277
|
+
notes TEXT
|
|
278
|
+
);
|
|
279
|
+
CREATE INDEX IF NOT EXISTS idx_hook_invocations_name_time ON hook_invocations(hook_name, invoked_at DESC);
|
|
280
|
+
`);
|
|
281
|
+
}
|
|
282
|
+
catch (err) {
|
|
283
|
+
logIfUnexpectedDdlError(err, 'fragmentation_entities + hook_invocations tables');
|
|
284
|
+
}
|
|
285
|
+
// Migration: project column on defence_audit and quarantine tables
|
|
286
|
+
try {
|
|
287
|
+
const auditCols = database.prepare("PRAGMA table_info(defence_audit)").all();
|
|
288
|
+
if (auditCols.length > 0 && !auditCols.some(c => c.name === 'project')) {
|
|
289
|
+
database.exec('ALTER TABLE defence_audit ADD COLUMN project TEXT');
|
|
290
|
+
database.exec('CREATE INDEX IF NOT EXISTS idx_audit_project ON defence_audit(project)');
|
|
291
|
+
}
|
|
292
|
+
const quarantineCols = database.prepare("PRAGMA table_info(quarantine)").all();
|
|
293
|
+
if (quarantineCols.length > 0 && !quarantineCols.some(c => c.name === 'project')) {
|
|
294
|
+
database.exec('ALTER TABLE quarantine ADD COLUMN project TEXT');
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
catch (err) {
|
|
298
|
+
logIfUnexpectedDdlError(err, 'defence_audit/quarantine project column add');
|
|
299
|
+
}
|
|
300
|
+
// Backfill: set project on defence_audit/quarantine entries that have NULL project
|
|
301
|
+
try {
|
|
302
|
+
const nullCount = database.prepare("SELECT COUNT(*) as cnt FROM defence_audit WHERE project IS NULL").get()?.cnt ?? 0;
|
|
303
|
+
if (nullCount > 0) {
|
|
304
|
+
// From linked memories
|
|
305
|
+
database.exec(`UPDATE defence_audit SET project = (
|
|
306
|
+
SELECT m.project FROM memories m WHERE m.id = defence_audit.memory_id
|
|
307
|
+
) WHERE memory_id IS NOT NULL AND project IS NULL`);
|
|
308
|
+
// Remaining: use most common project
|
|
309
|
+
database.exec(`UPDATE defence_audit SET project = (
|
|
310
|
+
SELECT project FROM memories WHERE project IS NOT NULL GROUP BY project ORDER BY COUNT(*) DESC LIMIT 1
|
|
311
|
+
) WHERE project IS NULL`);
|
|
312
|
+
}
|
|
313
|
+
const qNullCount = database.prepare("SELECT COUNT(*) as cnt FROM quarantine WHERE project IS NULL").get()?.cnt ?? 0;
|
|
314
|
+
if (qNullCount > 0) {
|
|
315
|
+
database.exec(`UPDATE quarantine SET project = (
|
|
316
|
+
SELECT project FROM memories WHERE project IS NOT NULL GROUP BY project ORDER BY COUNT(*) DESC LIMIT 1
|
|
317
|
+
) WHERE project IS NULL`);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
catch (err) {
|
|
321
|
+
logIfUnexpectedDdlError(err, 'defence_audit/quarantine project backfill (data migration)');
|
|
322
|
+
}
|
|
323
|
+
// Migration: sync_queue table for cloud sync retry
|
|
324
|
+
try {
|
|
325
|
+
database.exec(`
|
|
326
|
+
CREATE TABLE IF NOT EXISTS sync_queue (
|
|
327
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
328
|
+
payload TEXT NOT NULL,
|
|
329
|
+
attempts INTEGER DEFAULT 0,
|
|
330
|
+
max_attempts INTEGER DEFAULT 3,
|
|
331
|
+
next_retry_at TEXT NOT NULL,
|
|
332
|
+
status TEXT NOT NULL DEFAULT 'pending' CHECK(status IN ('pending','failed','synced')),
|
|
333
|
+
last_error TEXT,
|
|
334
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
335
|
+
synced_at TEXT
|
|
336
|
+
);
|
|
337
|
+
CREATE INDEX IF NOT EXISTS idx_sync_queue_status_retry ON sync_queue(status, next_retry_at);
|
|
338
|
+
`);
|
|
339
|
+
}
|
|
340
|
+
catch (err) {
|
|
341
|
+
logIfUnexpectedDdlError(err, 'sync_queue table + index');
|
|
342
|
+
}
|
|
343
|
+
// Migration: Ontology tables (entities, triples, memory_entities)
|
|
344
|
+
try {
|
|
345
|
+
database.exec(`
|
|
346
|
+
CREATE TABLE IF NOT EXISTS entities (
|
|
347
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
348
|
+
name TEXT NOT NULL,
|
|
349
|
+
type TEXT NOT NULL,
|
|
350
|
+
aliases TEXT DEFAULT '[]',
|
|
351
|
+
first_seen TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
352
|
+
memory_count INTEGER DEFAULT 0,
|
|
353
|
+
UNIQUE(name, type)
|
|
354
|
+
);
|
|
355
|
+
CREATE INDEX IF NOT EXISTS idx_entities_name ON entities(name);
|
|
356
|
+
CREATE INDEX IF NOT EXISTS idx_entities_type ON entities(type);
|
|
357
|
+
|
|
358
|
+
CREATE TABLE IF NOT EXISTS triples (
|
|
359
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
360
|
+
subject_id INTEGER NOT NULL,
|
|
361
|
+
predicate TEXT NOT NULL,
|
|
362
|
+
object_id INTEGER NOT NULL,
|
|
363
|
+
source_memory_id INTEGER,
|
|
364
|
+
confidence REAL DEFAULT 0.8,
|
|
365
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
366
|
+
FOREIGN KEY (subject_id) REFERENCES entities(id) ON DELETE CASCADE,
|
|
367
|
+
FOREIGN KEY (object_id) REFERENCES entities(id) ON DELETE CASCADE,
|
|
368
|
+
FOREIGN KEY (source_memory_id) REFERENCES memories(id) ON DELETE SET NULL,
|
|
369
|
+
UNIQUE(subject_id, predicate, object_id)
|
|
370
|
+
);
|
|
371
|
+
CREATE INDEX IF NOT EXISTS idx_triples_subject ON triples(subject_id);
|
|
372
|
+
CREATE INDEX IF NOT EXISTS idx_triples_object ON triples(object_id);
|
|
373
|
+
CREATE INDEX IF NOT EXISTS idx_triples_predicate ON triples(predicate);
|
|
374
|
+
|
|
375
|
+
CREATE TABLE IF NOT EXISTS memory_entities (
|
|
376
|
+
memory_id INTEGER NOT NULL,
|
|
377
|
+
entity_id INTEGER NOT NULL,
|
|
378
|
+
role TEXT DEFAULT 'mention',
|
|
379
|
+
FOREIGN KEY (memory_id) REFERENCES memories(id) ON DELETE CASCADE,
|
|
380
|
+
FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE,
|
|
381
|
+
PRIMARY KEY (memory_id, entity_id)
|
|
382
|
+
);
|
|
383
|
+
`);
|
|
384
|
+
}
|
|
385
|
+
catch (err) {
|
|
386
|
+
logIfUnexpectedDdlError(err, 'knowledge-graph tables (entities/triples/memory_entities)');
|
|
387
|
+
}
|
|
388
|
+
// Migration: graph_extraction_version column for incremental graph backfill
|
|
389
|
+
if (!columnNames.has('graph_extraction_version')) {
|
|
390
|
+
database.exec('ALTER TABLE memories ADD COLUMN graph_extraction_version INTEGER DEFAULT 0');
|
|
391
|
+
}
|
|
392
|
+
// Migration: v4.0.0 — memory_purpose for type taxonomy
|
|
393
|
+
if (!columnNames.has('memory_purpose')) {
|
|
394
|
+
database.exec("ALTER TABLE memories ADD COLUMN memory_purpose TEXT DEFAULT 'project'");
|
|
395
|
+
}
|
|
396
|
+
// Migration: v4.0.0 — memory_scope for private/team visibility
|
|
397
|
+
if (!columnNames.has('memory_scope')) {
|
|
398
|
+
database.exec("ALTER TABLE memories ADD COLUMN memory_scope TEXT DEFAULT 'private'");
|
|
399
|
+
}
|
|
400
|
+
// Migration: v4.25.0 — downvote_count for negative-feedback salience.
|
|
401
|
+
// When a user marks a memory unhelpful via `shieldcortex memory downvote
|
|
402
|
+
// <id>`, the count grows and the recall hook's effective-salience
|
|
403
|
+
// calculation multiplies in a (1 - 0.3 × n) penalty (floored at 0.1).
|
|
404
|
+
if (!columnNames.has('downvote_count')) {
|
|
405
|
+
database.exec('ALTER TABLE memories ADD COLUMN downvote_count INTEGER DEFAULT 0');
|
|
406
|
+
}
|
|
407
|
+
if (!columnNames.has('last_downvoted_at')) {
|
|
408
|
+
database.exec('ALTER TABLE memories ADD COLUMN last_downvoted_at TIMESTAMP');
|
|
409
|
+
}
|
|
410
|
+
// Sparse partial index — only indexes rows that have been downvoted.
|
|
411
|
+
// Cheap to maintain (most rows never downvoted) and lets the CLI list
|
|
412
|
+
// downvoted memories without a full scan.
|
|
413
|
+
database.exec('CREATE INDEX IF NOT EXISTS idx_memories_downvote_count ON memories(downvote_count) WHERE downvote_count > 0');
|
|
414
|
+
// Migration: Pro feature tables (custom_patterns, iron_dome_policies, firewall_rules)
|
|
415
|
+
try {
|
|
416
|
+
database.exec(`
|
|
417
|
+
CREATE TABLE IF NOT EXISTS custom_patterns (
|
|
418
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
419
|
+
name TEXT NOT NULL,
|
|
420
|
+
category TEXT NOT NULL DEFAULT 'custom',
|
|
421
|
+
severity TEXT NOT NULL DEFAULT 'medium' CHECK(severity IN ('critical', 'high', 'medium', 'low')),
|
|
422
|
+
regex TEXT NOT NULL,
|
|
423
|
+
description TEXT DEFAULT '',
|
|
424
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
425
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
426
|
+
);
|
|
427
|
+
CREATE INDEX IF NOT EXISTS idx_custom_patterns_enabled ON custom_patterns(enabled);
|
|
428
|
+
|
|
429
|
+
CREATE TABLE IF NOT EXISTS iron_dome_policies (
|
|
430
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
431
|
+
name TEXT NOT NULL,
|
|
432
|
+
description TEXT DEFAULT '',
|
|
433
|
+
config TEXT NOT NULL DEFAULT '{}',
|
|
434
|
+
is_active INTEGER NOT NULL DEFAULT 0,
|
|
435
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
436
|
+
);
|
|
437
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_dome_policies_active ON iron_dome_policies(is_active) WHERE is_active = 1;
|
|
438
|
+
|
|
439
|
+
CREATE TABLE IF NOT EXISTS firewall_rules (
|
|
440
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
441
|
+
name TEXT NOT NULL,
|
|
442
|
+
priority INTEGER NOT NULL DEFAULT 100,
|
|
443
|
+
condition_type TEXT NOT NULL,
|
|
444
|
+
condition_value TEXT NOT NULL,
|
|
445
|
+
action TEXT NOT NULL CHECK(action IN ('block', 'allow', 'quarantine')),
|
|
446
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
447
|
+
built_in INTEGER NOT NULL DEFAULT 0,
|
|
448
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
449
|
+
);
|
|
450
|
+
CREATE INDEX IF NOT EXISTS idx_firewall_rules_priority ON firewall_rules(priority);
|
|
451
|
+
CREATE INDEX IF NOT EXISTS idx_firewall_rules_enabled ON firewall_rules(enabled);
|
|
452
|
+
CREATE INDEX IF NOT EXISTS idx_firewall_rules_built_in ON firewall_rules(built_in);
|
|
453
|
+
|
|
454
|
+
CREATE TABLE IF NOT EXISTS rate_limits (
|
|
455
|
+
source_key TEXT PRIMARY KEY,
|
|
456
|
+
write_count INTEGER NOT NULL DEFAULT 1,
|
|
457
|
+
window_start_ms INTEGER NOT NULL
|
|
458
|
+
);
|
|
459
|
+
`);
|
|
460
|
+
}
|
|
461
|
+
catch (err) {
|
|
462
|
+
logIfUnexpectedDdlError(err, 'firewall_rules + rate_limits tables');
|
|
463
|
+
}
|
|
464
|
+
// Migration: built_in column on pre-existing firewall_rules (added in v4.15)
|
|
465
|
+
try {
|
|
466
|
+
const cols = database.prepare("PRAGMA table_info(firewall_rules)").all();
|
|
467
|
+
if (!cols.some(c => c.name === 'built_in')) {
|
|
468
|
+
database.exec('ALTER TABLE firewall_rules ADD COLUMN built_in INTEGER NOT NULL DEFAULT 0');
|
|
469
|
+
database.exec('CREATE INDEX IF NOT EXISTS idx_firewall_rules_built_in ON firewall_rules(built_in)');
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
catch (err) {
|
|
473
|
+
logIfUnexpectedDdlError(err, 'firewall_rules.built_in column add');
|
|
474
|
+
// (pipeline handles missing column gracefully; this is informational)
|
|
475
|
+
}
|
|
476
|
+
// Seed default built-in firewall rules on first init.
|
|
477
|
+
try {
|
|
478
|
+
seedDefaultFirewallRules(database);
|
|
479
|
+
}
|
|
480
|
+
catch {
|
|
481
|
+
// Seeder runs idempotently; failures here should never block startup.
|
|
482
|
+
}
|
|
483
|
+
// Migration: session_events.content_hash + dedupe UNIQUE index (v4.17).
|
|
484
|
+
// DBs created between the foundation commit and the importer commit have
|
|
485
|
+
// session_events but no content_hash column. ALTER + idempotent index
|
|
486
|
+
// upgrades them without touching fresh installs (schema.sql handles those).
|
|
487
|
+
try {
|
|
488
|
+
const sessionEventsTable = database
|
|
489
|
+
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='session_events'")
|
|
490
|
+
.get();
|
|
491
|
+
if (sessionEventsTable) {
|
|
492
|
+
const sessionCols = database
|
|
493
|
+
.prepare("PRAGMA table_info(session_events)")
|
|
494
|
+
.all();
|
|
495
|
+
const sessionColNames = new Set(sessionCols.map((c) => c.name));
|
|
496
|
+
if (!sessionColNames.has('content_hash')) {
|
|
497
|
+
database.exec('ALTER TABLE session_events ADD COLUMN content_hash TEXT');
|
|
498
|
+
}
|
|
499
|
+
database.exec('CREATE UNIQUE INDEX IF NOT EXISTS idx_session_events_dedupe ON session_events(session_id, ts, kind, content_hash)');
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
catch (err) {
|
|
503
|
+
logIfUnexpectedDdlError(err, 'session_events.content_hash column + dedupe index');
|
|
504
|
+
// (importer-side INSERT OR IGNORE handles missing index gracefully)
|
|
505
|
+
}
|
|
506
|
+
}
|
package/dist/setup/quickstart.js
CHANGED
|
@@ -125,6 +125,37 @@ async function promptYesNo(question, defaultYes = true) {
|
|
|
125
125
|
rl.close();
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* Outcome-based picker: routes the user by what they want rather than by
|
|
130
|
+
* which integration they happen to have installed. Returns 'skip' if the
|
|
131
|
+
* user picks "show me commands" or enters anything unrecognised, which
|
|
132
|
+
* preserves the pre-v4.27 behaviour (auto-guide + per-target prompts).
|
|
133
|
+
*/
|
|
134
|
+
async function promptIntent() {
|
|
135
|
+
const rl = readline.createInterface({
|
|
136
|
+
input: process.stdin,
|
|
137
|
+
output: process.stdout,
|
|
138
|
+
});
|
|
139
|
+
try {
|
|
140
|
+
console.log('What are you here for?');
|
|
141
|
+
console.log(' 1. Memory for my AI agents (recall, project context, auto-extracted decisions)');
|
|
142
|
+
console.log(' 2. Defence scanning (prompt-injection, credential leaks, quarantine)');
|
|
143
|
+
console.log(' 3. Both (memory + defence, recommended)');
|
|
144
|
+
console.log(' 4. Just show me the commands');
|
|
145
|
+
console.log('');
|
|
146
|
+
const answer = (await rl.question('Pick one [1-4, default 3]: ')).trim().toLowerCase();
|
|
147
|
+
if (!answer || answer === '3' || answer === 'both' || answer === 'b')
|
|
148
|
+
return 'both';
|
|
149
|
+
if (answer === '1' || answer === 'memory' || answer === 'm')
|
|
150
|
+
return 'memory';
|
|
151
|
+
if (answer === '2' || answer === 'defence' || answer === 'defense' || answer === 'd')
|
|
152
|
+
return 'defence';
|
|
153
|
+
return 'skip';
|
|
154
|
+
}
|
|
155
|
+
finally {
|
|
156
|
+
rl.close();
|
|
157
|
+
}
|
|
158
|
+
}
|
|
128
159
|
function detectedInstallers(env) {
|
|
129
160
|
const installers = [];
|
|
130
161
|
if (env.claude)
|
|
@@ -189,6 +220,29 @@ async function promptDetectedInstalls(autoApprove = false) {
|
|
|
189
220
|
export async function handleQuickstartCommand(target) {
|
|
190
221
|
if (!target) {
|
|
191
222
|
printAutoGuide();
|
|
223
|
+
// Interactive runs get the outcome-based picker first; non-TTY runs (CI,
|
|
224
|
+
// piped output) fall through to the historical per-target prompt flow so
|
|
225
|
+
// existing automation keeps working.
|
|
226
|
+
if (isInteractiveTerminal()) {
|
|
227
|
+
const intent = await promptIntent();
|
|
228
|
+
console.log('');
|
|
229
|
+
switch (intent) {
|
|
230
|
+
case 'memory':
|
|
231
|
+
await promptDetectedInstalls(false);
|
|
232
|
+
return;
|
|
233
|
+
case 'defence':
|
|
234
|
+
printSecurityGuide();
|
|
235
|
+
return;
|
|
236
|
+
case 'both':
|
|
237
|
+
await promptDetectedInstalls(false);
|
|
238
|
+
console.log('');
|
|
239
|
+
printSecurityGuide();
|
|
240
|
+
return;
|
|
241
|
+
case 'skip':
|
|
242
|
+
// Fall through to the historical prompt flow.
|
|
243
|
+
break;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
192
246
|
await promptDetectedInstalls(false);
|
|
193
247
|
return;
|
|
194
248
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shieldcortex",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.27.0",
|
|
4
4
|
"description": "Trustworthy memory and security for AI agents. Recall debugging, review queue, OpenClaw session capture, and memory poisoning defence for Claude Code, Codex, OpenClaw, LangChain, and MCP agents.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard discovery hint.
|
|
3
|
+
*
|
|
4
|
+
* The dashboard never auto-launches. On non-headless systems where it is not
|
|
5
|
+
* already running, this helper returns a structured hint so callers can format
|
|
6
|
+
* it consistently. Returns null when the hint is not applicable (headless
|
|
7
|
+
* host, dashboard already up).
|
|
8
|
+
*
|
|
9
|
+
* Used by:
|
|
10
|
+
* - scripts/postinstall.mjs — surface after the install banner
|
|
11
|
+
* - src/cli/update.ts — surface after a successful update
|
|
12
|
+
* - src/cli/doctor.ts — enrich the dashboard fix line
|
|
13
|
+
*/
|
|
14
|
+
import http from 'node:http';
|
|
15
|
+
|
|
16
|
+
export const DASHBOARD_URL = 'http://localhost:3030';
|
|
17
|
+
export const DASHBOARD_PORT = 3030;
|
|
18
|
+
export const DASHBOARD_COMMAND = 'shieldcortex dashboard';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* A "headless" system is one where launching a browser to view the dashboard
|
|
22
|
+
* would not work without forwarding. macOS and Windows are treated as headed
|
|
23
|
+
* by default; on Linux, the absence of DISPLAY/WAYLAND_DISPLAY is the signal
|
|
24
|
+
* (matches the existing doctor.ts heuristic).
|
|
25
|
+
*/
|
|
26
|
+
export function isHeadlessSystem() {
|
|
27
|
+
if (process.platform === 'darwin' || process.platform === 'win32') return false;
|
|
28
|
+
return !process.env.DISPLAY && !process.env.WAYLAND_DISPLAY;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Probe the local dashboard port. Returns true for any non-5xx response —
|
|
33
|
+
* the goal is detecting *something* listening, not validating the response.
|
|
34
|
+
* Times out fast so it never delays a postinstall or update flow.
|
|
35
|
+
*/
|
|
36
|
+
export function isDashboardRunning(timeoutMs = 800) {
|
|
37
|
+
return new Promise((resolve) => {
|
|
38
|
+
let settled = false;
|
|
39
|
+
const settle = (v) => { if (!settled) { settled = true; resolve(v); } };
|
|
40
|
+
|
|
41
|
+
const req = http.get(
|
|
42
|
+
{ host: '127.0.0.1', port: DASHBOARD_PORT, path: '/', timeout: timeoutMs },
|
|
43
|
+
(res) => {
|
|
44
|
+
const ok = typeof res.statusCode === 'number' && res.statusCode < 500;
|
|
45
|
+
res.resume();
|
|
46
|
+
settle(ok);
|
|
47
|
+
},
|
|
48
|
+
);
|
|
49
|
+
req.on('error', () => settle(false));
|
|
50
|
+
req.on('timeout', () => { try { req.destroy(); } catch { /* ignore */ } settle(false); });
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Returns the hint payload, or null when the dashboard should not be advertised
|
|
56
|
+
* in this environment. Never throws.
|
|
57
|
+
*/
|
|
58
|
+
export async function getDashboardHint() {
|
|
59
|
+
try {
|
|
60
|
+
if (isHeadlessSystem()) return null;
|
|
61
|
+
if (await isDashboardRunning()) return null;
|
|
62
|
+
return {
|
|
63
|
+
title: 'Open the ShieldCortex dashboard',
|
|
64
|
+
command: DASHBOARD_COMMAND,
|
|
65
|
+
url: DASHBOARD_URL,
|
|
66
|
+
detail: 'Inspect memories, review quarantine, and watch real-time scans.',
|
|
67
|
+
};
|
|
68
|
+
} catch {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
package/scripts/postinstall.mjs
CHANGED
|
@@ -15,6 +15,7 @@ import { homedir } from 'os';
|
|
|
15
15
|
import { spawnSync } from 'child_process';
|
|
16
16
|
import { fileURLToPath } from 'url';
|
|
17
17
|
import { createRequire } from 'module';
|
|
18
|
+
import { getDashboardHint } from './lib/dashboard-hint.mjs';
|
|
18
19
|
|
|
19
20
|
const isGlobal = process.env.npm_config_global === 'true';
|
|
20
21
|
const isCI = process.env.CI === 'true' || process.env.CONTINUOUS_INTEGRATION === 'true';
|
|
@@ -228,4 +229,16 @@ if (isGlobal && !isCI) {
|
|
|
228
229
|
console.log('\x1b[2m shieldcortex config --proactive-recall true|false\x1b[0m');
|
|
229
230
|
}
|
|
230
231
|
console.log('');
|
|
232
|
+
|
|
233
|
+
// Dashboard discovery hint — only shown on non-headless systems where the
|
|
234
|
+
// local dashboard isn't already running. Best-effort, never blocks install.
|
|
235
|
+
try {
|
|
236
|
+
const hint = await getDashboardHint();
|
|
237
|
+
if (hint) {
|
|
238
|
+
console.log(`\x1b[36m${hint.title}:\x1b[0m`);
|
|
239
|
+
console.log(` \x1b[33m${hint.command}\x1b[0m \x1b[2m→ ${hint.url}\x1b[0m`);
|
|
240
|
+
console.log(` \x1b[2m${hint.detail}\x1b[0m`);
|
|
241
|
+
console.log('');
|
|
242
|
+
}
|
|
243
|
+
} catch { /* never fail postinstall on a hint */ }
|
|
231
244
|
}
|