2sagaco48 1.0.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/diagnostics.mjs +141 -0
- package/dist/compute.worker-j5ahIpF-.js +1 -0
- package/dist/graph.worker-DG6iGCB9.js +1 -0
- package/dist/index.html +2314 -0
- package/flatten-guide.md +248 -0
- package/index.html +12 -0
- package/package.json +38 -0
- package/src/App.orig.tsx +204 -0
- package/src/App.orig1.tsx +27 -0
- package/src/App.orig2.tsx +25 -0
- package/src/App.tsx +3 -0
- package/src/BaseApp.tsx +18 -0
- package/src/INTEGRATION_LEDGER.md +22 -0
- package/src/PERSIST_CANARY.orig.txt +1 -0
- package/src/PERSIST_CANARY.txt +1 -0
- package/src/REGRESSION_LEDGER.md +651 -0
- package/src/TEMPLATE_PIPELINE_AUDIT.md +208 -0
- package/src/WILLIAMS_PERSONA_GUIDE.md +62 -0
- package/src/chat/VeritasChat.tsx +69 -0
- package/src/chat/synthesis.ts +31 -0
- package/src/chat/tier.ts +45 -0
- package/src/components/AdaptersPage.orig.tsx +99 -0
- package/src/components/AdaptersPage.tsx +3 -0
- package/src/components/AdversarialPanel.tsx +136 -0
- package/src/components/AnchorBaselinePanel.tsx +75 -0
- package/src/components/AnswerPanel.tsx +60 -0
- package/src/components/ArtifactPanel.tsx +43 -0
- package/src/components/ChatApp.orig.tsx +1582 -0
- package/src/components/ChatApp.orig1.tsx +722 -0
- package/src/components/ChatApp.tsx +95 -0
- package/src/components/ChatAugmentPanels.tsx +73 -0
- package/src/components/CitationLedgerPanel.tsx +313 -0
- package/src/components/ComputeSandboxPanel.tsx +130 -0
- package/src/components/ConfigPanel.tsx +110 -0
- package/src/components/ControlPlanePage.tsx +195 -0
- package/src/components/CreativeTreeLifePage.tsx +234 -0
- package/src/components/CreativeTreeOfLifePanel.tsx +149 -0
- package/src/components/DebugTracePanel.tsx +137 -0
- package/src/components/DeepReasoningTrace.tsx +48 -0
- package/src/components/EntitySheetPanel.tsx +51 -0
- package/src/components/FailureModesPanel.tsx +104 -0
- package/src/components/GBSDashboard.tsx +239 -0
- package/src/components/GraphView.tsx +116 -0
- package/src/components/HUD.tsx +125 -0
- package/src/components/HypothesisPanel.tsx +67 -0
- package/src/components/InnovationGenomeEngine.tsx +792 -0
- package/src/components/InnovationPersonaGuide.tsx +348 -0
- package/src/components/InnovationPersonaPanel.tsx +289 -0
- package/src/components/LiveResourceHUD.tsx +109 -0
- package/src/components/LongWriterPanel.tsx +112 -0
- package/src/components/MainPipelineV10Bridge.tsx +72 -0
- package/src/components/MarkdownLite.tsx +63 -0
- package/src/components/MemoryInspector.tsx +38 -0
- package/src/components/MemoryMonitor.tsx +52 -0
- package/src/components/MemoryStressPanel.tsx +176 -0
- package/src/components/ModulesPage.tsx +171 -0
- package/src/components/PipelineDebugConsole.orig.tsx +1856 -0
- package/src/components/PipelineDebugConsole.tsx +3 -0
- package/src/components/PreFlightHUD.tsx +67 -0
- package/src/components/PrismaFetchTracePanel.tsx +87 -0
- package/src/components/ReportOSPanel.tsx +165 -0
- package/src/components/ResourceEstimatorPage.tsx +327 -0
- package/src/components/RichText.tsx +181 -0
- package/src/components/SagaOsPanel.tsx +605 -0
- package/src/components/SagaOsReference.tsx +421 -0
- package/src/components/SagaOsV2Panel.tsx +594 -0
- package/src/components/SagaStyleTab.tsx +382 -0
- package/src/components/SageBlueprintPanel.tsx +416 -0
- package/src/components/SharedChatInput.tsx +77 -0
- package/src/components/StatFinancePanel.tsx +190 -0
- package/src/components/StylePersonaPanel.tsx +128 -0
- package/src/components/TemplatesPage.tsx +300 -0
- package/src/components/TestPanel.tsx +63 -0
- package/src/components/TraceLog.tsx +89 -0
- package/src/components/V15CalibrationAugment.tsx +1134 -0
- package/src/components/V15CalibrationDialog.tsx +1871 -0
- package/src/components/V15Overlay.orig.tsx +120 -0
- package/src/components/V15Overlay.tsx +4 -0
- package/src/components/V15OverlayWrapper.tsx +362 -0
- package/src/components/V15Toggle.tsx +34 -0
- package/src/console/DiagnosticRecoveryPanel.tsx +358 -0
- package/src/console/EngineeringConsole.tsx +103 -0
- package/src/console/FictionSystemPanels.tsx +882 -0
- package/src/console/InspectorPanels.tsx +254 -0
- package/src/console/ManuscriptGraderPanel.tsx +182 -0
- package/src/console/RecursiveReviserPanel.tsx +245 -0
- package/src/console/SeedControlPanel.tsx +135 -0
- package/src/console/StoryControllerPanel.tsx +443 -0
- package/src/console/engineBridge.ts +258 -0
- package/src/console/gemini.ts +106 -0
- package/src/console/grading.ts +250 -0
- package/src/console/util.ts +45 -0
- package/src/fiction/continuity.ts +372 -0
- package/src/fiction/crash-protection.ts +111 -0
- package/src/fiction/diagnostics.ts +208 -0
- package/src/fiction/diff.ts +74 -0
- package/src/fiction/entity-state-machine.ts +214 -0
- package/src/fiction/nive-engine.ts +404 -0
- package/src/fiction/pipeline-selftest.ts +132 -0
- package/src/fiction/seed-control.ts +193 -0
- package/src/fiction/story-engine.ts +326 -0
- package/src/fiction/types.ts +68 -0
- package/src/flatten-guide.md +379 -0
- package/src/index.css +14 -0
- package/src/index.orig.css +13 -0
- package/src/lib/academic-sources.base.ts +188 -0
- package/src/lib/academic-sources.orig.ts +28 -0
- package/src/lib/academic-sources.ts +10 -0
- package/src/lib/advanced-math.ts +119 -0
- package/src/lib/adversarial-engine.base.ts +409 -0
- package/src/lib/adversarial-engine.ts +82 -0
- package/src/lib/ai-revision.ts +623 -0
- package/src/lib/app-state.tsx +426 -0
- package/src/lib/artifact-registry.ts +97 -0
- package/src/lib/artifacts.ts +180 -0
- package/src/lib/atlas-dr.ts +167 -0
- package/src/lib/browser-mtls.ts +127 -0
- package/src/lib/browser-queue.ts +221 -0
- package/src/lib/browser-search-scraper.base.ts +382 -0
- package/src/lib/browser-search-scraper.orig.ts +90 -0
- package/src/lib/browser-search-scraper.ts +10 -0
- package/src/lib/calc-interceptor.ts +82 -0
- package/src/lib/citation-lane-tap.ts +78 -0
- package/src/lib/citation-ledger-store.ts +369 -0
- package/src/lib/citation-ledger.ts +203 -0
- package/src/lib/compute-sandbox.ts +215 -0
- package/src/lib/compute.worker.ts +153 -0
- package/src/lib/connectors/gemini.ts +120 -0
- package/src/lib/connectors/jina.ts +233 -0
- package/src/lib/connectors/marketdata.ts +51 -0
- package/src/lib/connectors/prismafetch.base.ts +175 -0
- package/src/lib/connectors/prismafetch.ts +1 -0
- package/src/lib/connectors/serpapi.ts +65 -0
- package/src/lib/connectors/wikidata.ts +44 -0
- package/src/lib/constraints.ts +331 -0
- package/src/lib/continuation-detector.base.ts +153 -0
- package/src/lib/continuation-detector.ts +48 -0
- package/src/lib/contradraft.ts +168 -0
- package/src/lib/cors-proxy.ts +120 -0
- package/src/lib/coverage.ts +81 -0
- package/src/lib/debug/architecture-prescription.ts +556 -0
- package/src/lib/debug/covea-repair.ts +543 -0
- package/src/lib/debug/helios-ground.ts +319 -0
- package/src/lib/debug/intent-decomposer.ts +281 -0
- package/src/lib/debug/intent-lattice.ts +349 -0
- package/src/lib/debug/pipeline-diagnosis.ts +1149 -0
- package/src/lib/debug/pipeline-trace-bus.ts +424 -0
- package/src/lib/debug/prompt-forge.ts +678 -0
- package/src/lib/debug/repair-sites.ts +513 -0
- package/src/lib/debug/research-phase.ts +266 -0
- package/src/lib/debug/retrieval-context.ts +76 -0
- package/src/lib/debug/retrieval-hardener.ts +142 -0
- package/src/lib/debug/scraper-debug-runner.ts +576 -0
- package/src/lib/debug/scraper-forensics.ts +418 -0
- package/src/lib/debug/scraper-lane-roadmap.ts +136 -0
- package/src/lib/debug/self-test.ts +415 -0
- package/src/lib/debug/step-attribution.ts +211 -0
- package/src/lib/debug/template-rubric.ts +301 -0
- package/src/lib/debug/unified-innovation.ts +126 -0
- package/src/lib/debug/veritas-hybrid-scraper.ts +335 -0
- package/src/lib/defense-registry.ts +104 -0
- package/src/lib/defenses.ts +162 -0
- package/src/lib/deterministic-citation-ledger.ts +174 -0
- package/src/lib/elo-registry.base.ts +117 -0
- package/src/lib/elo-registry.ts +1 -0
- package/src/lib/entity-resolver.ts +291 -0
- package/src/lib/failure-modes.ts +267 -0
- package/src/lib/feature-registry.ts +69 -0
- package/src/lib/flaw-registry.ts +143 -0
- package/src/lib/flaws/_template.ts +52 -0
- package/src/lib/flaws/builtins.ts +63 -0
- package/src/lib/flaws/finance.ts +169 -0
- package/src/lib/flaws/fixers.ts +10 -0
- package/src/lib/flaws/index.ts +32 -0
- package/src/lib/flaws/legal.ts +157 -0
- package/src/lib/flaws/medical.ts +188 -0
- package/src/lib/flaws/original-defenses-pack.ts +81 -0
- package/src/lib/flaws/sample-declarative-pack.json +38 -0
- package/src/lib/flaws/selftest.ts +201 -0
- package/src/lib/flaws/software-extended.ts +125 -0
- package/src/lib/flaws/software-rn-webgl.ts +182 -0
- package/src/lib/flaws/statistics-advanced.ts +46 -0
- package/src/lib/flaws/statistics.ts +61 -0
- package/src/lib/gbse/config.ts +20 -0
- package/src/lib/gbse/engine.ts +226 -0
- package/src/lib/gbse/graph.ts +118 -0
- package/src/lib/gbse/graph.worker.ts +21 -0
- package/src/lib/gbse/tests.ts +117 -0
- package/src/lib/gbse/tiers.ts +65 -0
- package/src/lib/gbse/types.ts +94 -0
- package/src/lib/innovation-genome-engine-v2.orig.ts +1001 -0
- package/src/lib/innovation-genome-engine-v2.ts +3 -0
- package/src/lib/innovation-genome-engine.orig.ts +330 -0
- package/src/lib/innovation-genome-engine.ts +3 -0
- package/src/lib/innovation-genome-v10.orig.ts +314 -0
- package/src/lib/innovation-genome-v10.ts +2 -0
- package/src/lib/innovation-genome-v3.orig.ts +2015 -0
- package/src/lib/innovation-genome-v3.ts +2 -0
- package/src/lib/innovation-genome-v4.orig.ts +1959 -0
- package/src/lib/innovation-genome-v4.ts +2 -0
- package/src/lib/innovation-genome-v5.orig.ts +1210 -0
- package/src/lib/innovation-genome-v5.ts +2 -0
- package/src/lib/innovation-genome-v7.orig.ts +2549 -0
- package/src/lib/innovation-genome-v7.ts +2 -0
- package/src/lib/innovation-genome-v8.orig.ts +1485 -0
- package/src/lib/innovation-genome-v8.ts +2 -0
- package/src/lib/innovation-genome-v9.orig.ts +643 -0
- package/src/lib/innovation-genome-v9.ts +2 -0
- package/src/lib/jina.base.ts +293 -0
- package/src/lib/jina.ts +1 -0
- package/src/lib/live-telemetry.ts +61 -0
- package/src/lib/longwriter.ts +84 -0
- package/src/lib/manuscript-grade-v2.ts +298 -0
- package/src/lib/memory-governor.ts +173 -0
- package/src/lib/memory-stress-tests.ts +248 -0
- package/src/lib/model-intelligence.ts +48 -0
- package/src/lib/model-rotator.ts +75 -0
- package/src/lib/models.orig.ts +513 -0
- package/src/lib/models.ts +151 -0
- package/src/lib/n-deep.base.ts +592 -0
- package/src/lib/n-deep.ts +51 -0
- package/src/lib/nih-simulator.ts +56 -0
- package/src/lib/nih-vulnerability-fixes.ts +460 -0
- package/src/lib/omega-templates.base.ts +294 -0
- package/src/lib/omega-templates.ts +225 -0
- package/src/lib/omni-nexus.ts +64 -0
- package/src/lib/oracle-adapters.ts +67 -0
- package/src/lib/oracle-registry.ts +163 -0
- package/src/lib/orchestrator.ts +357 -0
- package/src/lib/output-boundary.ts +235 -0
- package/src/lib/overrides/vite-native-chaos-harness.ts +154 -0
- package/src/lib/overrides/vite-native-contract-plane.ts +245 -0
- package/src/lib/overrides/vite-native-doctor-plane.ts +208 -0
- package/src/lib/overrides/vite-native-knowledge-store.ts +267 -0
- package/src/lib/overrides/vite-native-policy-plane.ts +190 -0
- package/src/lib/overrides/vite-native-replay-plane.ts +197 -0
- package/src/lib/overrides/vite-native-runtime-plane.ts +106 -0
- package/src/lib/overrides/vite-native-scraper.ts +848 -0
- package/src/lib/overrides/vite-native-selftest-functional.ts +217 -0
- package/src/lib/overrides/vite-native-selftest.ts +183 -0
- package/src/lib/overrides/vite-native-snapshot-plane.ts +123 -0
- package/src/lib/philosophy-toolkit.ts +75 -0
- package/src/lib/pipeline.orig.ts +659 -0
- package/src/lib/pipeline.ts +42 -0
- package/src/lib/precache.ts +128 -0
- package/src/lib/py-sandbox.ts +205 -0
- package/src/lib/quality-score.ts +96 -0
- package/src/lib/quant-engine.ts +231 -0
- package/src/lib/quant-lib.ts +80 -0
- package/src/lib/reportos.ts +175 -0
- package/src/lib/research-os.ts +306 -0
- package/src/lib/resource-estimator.ts +114 -0
- package/src/lib/rpm-governor.ts +93 -0
- package/src/lib/runtime-estimator.ts +135 -0
- package/src/lib/sage/empty-space-v6.ts +560 -0
- package/src/lib/sage/empty-space-v7.ts +222 -0
- package/src/lib/sage/empty-space.ts +733 -0
- package/src/lib/sage/engine.ts +786 -0
- package/src/lib/sage/index.ts +17 -0
- package/src/lib/sage/judge.ts +246 -0
- package/src/lib/sage/prng.ts +53 -0
- package/src/lib/sage/reality-grounding.ts +380 -0
- package/src/lib/sage/repetition.ts +151 -0
- package/src/lib/sage/saga-os-v2-engines.ts +1870 -0
- package/src/lib/sage/saga-os-v2.ts +274 -0
- package/src/lib/sage/saga-os-v3-core.ts +1491 -0
- package/src/lib/sage/saga-os-v3-release.ts +739 -0
- package/src/lib/sage/saga-os-v4-aureate.ts +1161 -0
- package/src/lib/sage/saga-os-v4.ts +212 -0
- package/src/lib/sage/saga-os-v5.ts +205 -0
- package/src/lib/sage/saga-os-v6.ts +346 -0
- package/src/lib/sage/saga-os-v7.ts +314 -0
- package/src/lib/sage/saga-os-v8.ts +505 -0
- package/src/lib/sage/saga-os.ts +329 -0
- package/src/lib/sage/taxonomy.ts +403 -0
- package/src/lib/sage/unified-roll.ts +524 -0
- package/src/lib/sage/worked-sketches.ts +44 -0
- package/src/lib/sage.ts +166 -0
- package/src/lib/scraper-debug-bus.ts +53 -0
- package/src/lib/scraper-enhanced.orig.ts +153 -0
- package/src/lib/scraper-enhanced.ts +10 -0
- package/src/lib/scraper-hardener.base.orig.ts +155 -0
- package/src/lib/scraper-hardener.base.ts +317 -0
- package/src/lib/scraper-hardener.ts +1 -0
- package/src/lib/scraper-palisade/palisade-adjudicator.orig.ts +419 -0
- package/src/lib/scraper-palisade/palisade-adjudicator.ts +13 -0
- package/src/lib/scraper-vnext/arbiter-omega.orig.ts +688 -0
- package/src/lib/scraper-vnext/arbiter-omega.ts +13 -0
- package/src/lib/scraper-vnext/canonical-portfolio-augments.ts +479 -0
- package/src/lib/scraper-vnext/canonical-portfolio-orchestrator.orig.ts +1529 -0
- package/src/lib/scraper-vnext/canonical-portfolio-orchestrator.ts +13 -0
- package/src/lib/scraper-vnext/conclave-omega.ts +1830 -0
- package/src/lib/scraper-vnext/content-extractor-v2.ts +226 -0
- package/src/lib/scraper-vnext/diagnostics-suite.ts +36 -0
- package/src/lib/scraper-vnext/epistemic-packer.ts +97 -0
- package/src/lib/scraper-vnext/fusion-v2.ts +65 -0
- package/src/lib/scraper-vnext/hydra-reader.orig.ts +1216 -0
- package/src/lib/scraper-vnext/hydra-reader.ts +13 -0
- package/src/lib/scraper-vnext/native-scraper-browser-vnext.orig.ts +91 -0
- package/src/lib/scraper-vnext/native-scraper-browser-vnext.ts +13 -0
- package/src/lib/scraper-vnext/nexus-consensus.orig.ts +905 -0
- package/src/lib/scraper-vnext/nexus-consensus.ts +13 -0
- package/src/lib/scraper-vnext/portfolio-consensus-adjudicator.ts +804 -0
- package/src/lib/scraper-vnext/portfolio-consensus-memory.ts +377 -0
- package/src/lib/scraper-vnext/portfolio-terminal-governor.ts +548 -0
- package/src/lib/scraper-vnext/query-strategist.orig.ts +224 -0
- package/src/lib/scraper-vnext/query-strategist.ts +423 -0
- package/src/lib/scraper-vnext/retrieval-accelerator.ts +708 -0
- package/src/lib/scraper-vnext/retrieval-audit-augments.ts +477 -0
- package/src/lib/scraper-vnext/retrieval-control-plane.ts +904 -0
- package/src/lib/scraper-vnext/retrieval-policy-augments.ts +358 -0
- package/src/lib/scraper-vnext/safe-fetch-v2.ts +157 -0
- package/src/lib/scraper-vnext/sentinel-omega.ts +56 -0
- package/src/lib/scraper-vnext/sentinel-orchestrator.ts +69 -0
- package/src/lib/scraper-vnext/sibyl-oracle.orig.ts +413 -0
- package/src/lib/scraper-vnext/sibyl-oracle.ts +13 -0
- package/src/lib/scraper-vnext/smart-read-v2.ts +55 -0
- package/src/lib/scraper-vnext/spa-rescue-bridge.ts +608 -0
- package/src/lib/scraper-vnext/strata-engine.orig.ts +2666 -0
- package/src/lib/scraper-vnext/strata-engine.ts +13 -0
- package/src/lib/scraper-vnext/structured-source-adapter.orig.ts +369 -0
- package/src/lib/scraper-vnext/structured-source-adapter.ts +34 -0
- package/src/lib/scraper-vnext/terminal-complete.ts +224 -0
- package/src/lib/scraper-vnext/terminal-final.ts +277 -0
- package/src/lib/scraper-vnext/terminal-saturation.ts +345 -0
- package/src/lib/scraper-vnext/terminal-wire.ts +425 -0
- package/src/lib/scraper-vnext/vanguard-titanium.orig.ts +467 -0
- package/src/lib/scraper-vnext/vanguard-titanium.ts +17 -0
- package/src/lib/search-cache.ts +138 -0
- package/src/lib/sloop-runner.base.ts +223 -0
- package/src/lib/sloop-runner.ts +104 -0
- package/src/lib/sloop.ts +114 -0
- package/src/lib/small-model-adapters.ts +82 -0
- package/src/lib/sscp.ts +86 -0
- package/src/lib/system-map.ts +54 -0
- package/src/lib/uni-node.ts +86 -0
- package/src/lib/universal-rigor-guard.ts +433 -0
- package/src/lib/v15-gate-testbed.ts +274 -0
- package/src/lib/v15-gemini.base.ts +89 -0
- package/src/lib/v15-gemini.ts +1 -0
- package/src/lib/v15-grounding.orig.ts +241 -0
- package/src/lib/v15-grounding.ts +79 -0
- package/src/lib/v15-pipeline.base.ts +769 -0
- package/src/lib/v15-pipeline.orig.ts +1154 -0
- package/src/lib/v15-pipeline.ts +674 -0
- package/src/lib/v15-questions.ts +64 -0
- package/src/lib/v15-rate-limiter.orig.ts +91 -0
- package/src/lib/v15-rate-limiter.ts +48 -0
- package/src/lib/v15-state.base.ts +87 -0
- package/src/lib/v15-state.ts +28 -0
- package/src/lib/visual-table-generator.tsx +207 -0
- package/src/lib/wasm-runtime.ts +133 -0
- package/src/lib/williams-persona-guide.ts +265 -0
- package/src/lib/williams-style.base.ts +464 -0
- package/src/lib/williams-style.ts +59 -0
- package/src/lib/worker-pool.ts +96 -0
- package/src/lib/writing-tiers.ts +125 -0
- package/src/main.orig.tsx +10 -0
- package/src/main.tsx +10 -0
- package/src/utils/cn.orig.ts +6 -0
- package/src/utils/cn.ts +6 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.json +31 -0
- package/unify.mjs +537 -0
- package/vite.config.ts +18 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vite-native-doctor-plane.ts — L4: Aggregated Health & Remediation
|
|
3
|
+
* Dynamically imports all planes to avoid circular dependencies.
|
|
4
|
+
* Zero-dependency: node:* only.
|
|
5
|
+
*/
|
|
6
|
+
async function optionalImport(specifier: string): Promise<{ ok: boolean; mod?: any; error?: string }> {
|
|
7
|
+
try {
|
|
8
|
+
const mod = await import(specifier);
|
|
9
|
+
return { ok: true, mod };
|
|
10
|
+
} catch (e: any) {
|
|
11
|
+
return { ok: false, error: e?.message ?? 'Import failed' };
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type HealthStatus = 'green' | 'yellow' | 'red';
|
|
16
|
+
|
|
17
|
+
export interface DoctorSection {
|
|
18
|
+
available: boolean;
|
|
19
|
+
error?: string;
|
|
20
|
+
data?: Record<string, unknown>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface DoctorReport {
|
|
24
|
+
status: HealthStatus;
|
|
25
|
+
ts: number;
|
|
26
|
+
pressure: string;
|
|
27
|
+
criticalFailed: number;
|
|
28
|
+
highFailed: number;
|
|
29
|
+
indexConsistent: boolean;
|
|
30
|
+
recommendations: string[];
|
|
31
|
+
sections: {
|
|
32
|
+
runtime: DoctorSection;
|
|
33
|
+
policy: DoctorSection;
|
|
34
|
+
knowledge: DoctorSection;
|
|
35
|
+
contract: DoctorSection;
|
|
36
|
+
snapshot: DoctorSection;
|
|
37
|
+
selftest?: DoctorSection;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function pickStatus(opts: {
|
|
42
|
+
criticalFailed: number;
|
|
43
|
+
pressure: string;
|
|
44
|
+
indexConsistent: boolean;
|
|
45
|
+
highFailed: number;
|
|
46
|
+
}): HealthStatus {
|
|
47
|
+
if (opts.criticalFailed > 0 || opts.pressure === 'hot') return 'red';
|
|
48
|
+
if (!opts.indexConsistent || opts.highFailed > 0 || opts.pressure === 'warm') return 'yellow';
|
|
49
|
+
return 'green';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export async function buildDoctorReport(opts: { deep?: boolean } = {}): Promise<DoctorReport> {
|
|
53
|
+
const ts = Date.now();
|
|
54
|
+
const recommendations: string[] = [];
|
|
55
|
+
let criticalFailed = 0;
|
|
56
|
+
let highFailed = 0;
|
|
57
|
+
let pressure = 'ok';
|
|
58
|
+
let indexConsistent = true;
|
|
59
|
+
|
|
60
|
+
// ── Runtime section ────────────────────────────────────────────────────
|
|
61
|
+
// Hand-trace: if getRuntimeStats() throws an Error:
|
|
62
|
+
// sections.runtime = { available: true, error: 'Error message string', data: {} }
|
|
63
|
+
// criticalFailed is NOT incremented (runtime errors are not critical failures)
|
|
64
|
+
const runtimeSection: DoctorSection = { available: true };
|
|
65
|
+
const runtimeImport = await optionalImport('./vite-native-runtime-plane.js');
|
|
66
|
+
if (!runtimeImport.ok) {
|
|
67
|
+
runtimeSection.available = true;
|
|
68
|
+
runtimeSection.error = runtimeImport.error;
|
|
69
|
+
criticalFailed++;
|
|
70
|
+
} else {
|
|
71
|
+
try {
|
|
72
|
+
const stats = runtimeImport.mod.getRuntimeStats();
|
|
73
|
+
pressure = stats.pressure;
|
|
74
|
+
runtimeSection.data = stats;
|
|
75
|
+
} catch (e: any) {
|
|
76
|
+
runtimeSection.error = e?.message ?? 'getRuntimeStats failed';
|
|
77
|
+
runtimeSection.data = {};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// ── Policy section ─────────────────────────────────────────────────────
|
|
82
|
+
const policySection: DoctorSection = { available: true };
|
|
83
|
+
const policyImport = await optionalImport('./vite-native-policy-plane.js');
|
|
84
|
+
if (!policyImport.ok) {
|
|
85
|
+
policySection.available = true;
|
|
86
|
+
policySection.error = policyImport.error;
|
|
87
|
+
criticalFailed++;
|
|
88
|
+
} else {
|
|
89
|
+
try {
|
|
90
|
+
const policy = policyImport.mod.evaluatePolicy({ pressure });
|
|
91
|
+
policySection.data = policy;
|
|
92
|
+
} catch (e: any) {
|
|
93
|
+
policySection.error = e?.message ?? 'evaluatePolicy failed';
|
|
94
|
+
highFailed++;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ── Knowledge section ──────────────────────────────────────────────────
|
|
99
|
+
const knowledgeSection: DoctorSection = { available: true };
|
|
100
|
+
const knowledgeImport = await optionalImport('./vite-native-knowledge-store.js');
|
|
101
|
+
if (!knowledgeImport.ok) {
|
|
102
|
+
knowledgeSection.available = true;
|
|
103
|
+
knowledgeSection.error = knowledgeImport.error;
|
|
104
|
+
criticalFailed++;
|
|
105
|
+
} else {
|
|
106
|
+
try {
|
|
107
|
+
const stats = knowledgeImport.mod.getKnowledgeStats();
|
|
108
|
+
knowledgeSection.data = stats;
|
|
109
|
+
// Check FTS index consistency
|
|
110
|
+
if (stats.totalRecords > 0 && !stats.available) {
|
|
111
|
+
indexConsistent = false;
|
|
112
|
+
recommendations.push('Run /api/native-knowledge/repair-index to heal FTS drift.');
|
|
113
|
+
}
|
|
114
|
+
} catch (e: any) {
|
|
115
|
+
knowledgeSection.error = e?.message ?? 'getKnowledgeStats failed';
|
|
116
|
+
highFailed++;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// ── Contract section ───────────────────────────────────────────────────
|
|
121
|
+
const contractSection: DoctorSection = { available: true };
|
|
122
|
+
const contractImport = await optionalImport('./vite-native-contract-plane.js');
|
|
123
|
+
if (!contractImport.ok) {
|
|
124
|
+
contractSection.available = true;
|
|
125
|
+
contractSection.error = contractImport.error;
|
|
126
|
+
highFailed++;
|
|
127
|
+
} else {
|
|
128
|
+
try {
|
|
129
|
+
const result = contractImport.mod.contractSelfTest();
|
|
130
|
+
contractSection.data = result;
|
|
131
|
+
if (!result.passed) highFailed++;
|
|
132
|
+
} catch (e: any) {
|
|
133
|
+
contractSection.error = e?.message ?? 'contractSelfTest failed';
|
|
134
|
+
highFailed++;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// ── Snapshot section ───────────────────────────────────────────────────
|
|
139
|
+
const snapshotSection: DoctorSection = { available: true };
|
|
140
|
+
const snapshotImport = await optionalImport('./vite-native-snapshot-plane.js');
|
|
141
|
+
if (!snapshotImport.ok) {
|
|
142
|
+
snapshotSection.available = true;
|
|
143
|
+
snapshotSection.error = snapshotImport.error;
|
|
144
|
+
} else {
|
|
145
|
+
try {
|
|
146
|
+
const manifest = await snapshotImport.mod.getSnapshotManifest();
|
|
147
|
+
snapshotSection.data = manifest;
|
|
148
|
+
// Maintenance recommendation: >32MB reclaimable space
|
|
149
|
+
if (manifest.sizeBytes > 32 * 1024 * 1024) {
|
|
150
|
+
recommendations.push('Run /api/native-maintenance/run to reclaim SQLite space.');
|
|
151
|
+
}
|
|
152
|
+
} catch (e: any) {
|
|
153
|
+
snapshotSection.error = e?.message ?? 'getSnapshotManifest failed';
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// ── Optional deep self-test ────────────────────────────────────────────
|
|
158
|
+
let selftestSection: DoctorSection | undefined;
|
|
159
|
+
if (opts.deep) {
|
|
160
|
+
selftestSection = { available: true };
|
|
161
|
+
const stImport = await optionalImport('./vite-native-selftest.js');
|
|
162
|
+
if (!stImport.ok) {
|
|
163
|
+
selftestSection.available = true;
|
|
164
|
+
selftestSection.error = stImport.error;
|
|
165
|
+
criticalFailed++;
|
|
166
|
+
} else {
|
|
167
|
+
try {
|
|
168
|
+
const result = stImport.mod.runStaticSelfTest();
|
|
169
|
+
selftestSection.data = result;
|
|
170
|
+
if (!result.passed) {
|
|
171
|
+
highFailed += result.failures?.length ?? 1;
|
|
172
|
+
// Trigger policy remediation for known failures
|
|
173
|
+
if (policyImport.ok) {
|
|
174
|
+
policyImport.mod.applySelfTestRemediation(result);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
} catch (e: any) {
|
|
178
|
+
selftestSection.error = e?.message ?? 'Static self-test failed';
|
|
179
|
+
criticalFailed++;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Add index inconsistency recommendation
|
|
185
|
+
if (!indexConsistent) {
|
|
186
|
+
recommendations.push('Run /api/native-knowledge/repair-index to heal FTS drift.');
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const status = pickStatus({ criticalFailed, pressure, indexConsistent, highFailed });
|
|
190
|
+
|
|
191
|
+
return {
|
|
192
|
+
status,
|
|
193
|
+
ts,
|
|
194
|
+
pressure,
|
|
195
|
+
criticalFailed,
|
|
196
|
+
highFailed,
|
|
197
|
+
indexConsistent,
|
|
198
|
+
recommendations: [...new Set(recommendations)],
|
|
199
|
+
sections: {
|
|
200
|
+
runtime: runtimeSection,
|
|
201
|
+
policy: policySection,
|
|
202
|
+
knowledge: knowledgeSection,
|
|
203
|
+
contract: contractSection,
|
|
204
|
+
snapshot: snapshotSection,
|
|
205
|
+
...(selftestSection && { selftest: selftestSection }),
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
}
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vite-native-knowledge-store.ts — L1: Persistence & Vector/Lexical Math
|
|
3
|
+
* Zero-dependency SQLite storage for scraped content, RAG chunks, and Merkle-lite audit logs.
|
|
4
|
+
* All imports are from node:* only.
|
|
5
|
+
*/
|
|
6
|
+
import { createHash } from 'node:crypto';
|
|
7
|
+
import { existsSync, mkdirSync } from 'node:fs';
|
|
8
|
+
import { createRequire } from 'node:module';
|
|
9
|
+
import { join, dirname } from 'node:path';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
11
|
+
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
+
const __dirname = dirname(__filename);
|
|
14
|
+
|
|
15
|
+
// ── Ghost Load Pattern: avoids Rollup static analysis crash ──────────────
|
|
16
|
+
let DatabaseSync: any = null;
|
|
17
|
+
let dbAvailable = false;
|
|
18
|
+
try {
|
|
19
|
+
const anyProc: any = globalThis.process as any;
|
|
20
|
+
if (anyProc && typeof anyProc.getBuiltinModule === 'function') {
|
|
21
|
+
const mod = anyProc.getBuiltinModule('node:sqlite');
|
|
22
|
+
if (mod?.DatabaseSync) { DatabaseSync = mod.DatabaseSync; dbAvailable = true; }
|
|
23
|
+
}
|
|
24
|
+
} catch {}
|
|
25
|
+
if (!dbAvailable) {
|
|
26
|
+
try {
|
|
27
|
+
const req = createRequire(import.meta.url);
|
|
28
|
+
({ DatabaseSync } = req('node:sqlite'));
|
|
29
|
+
dbAvailable = !!DatabaseSync;
|
|
30
|
+
} catch { dbAvailable = false; }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const AUDIT_DIR = join(__dirname, '..', '..', '..', 'src', 'audit');
|
|
34
|
+
const DB_PATH = join(AUDIT_DIR, 'knowledge.db');
|
|
35
|
+
|
|
36
|
+
let db: any = null;
|
|
37
|
+
|
|
38
|
+
function ensureDb(): boolean {
|
|
39
|
+
if (db) return true;
|
|
40
|
+
if (!dbAvailable) return false;
|
|
41
|
+
try {
|
|
42
|
+
if (!existsSync(AUDIT_DIR)) mkdirSync(AUDIT_DIR, { recursive: true });
|
|
43
|
+
db = new DatabaseSync(DB_PATH);
|
|
44
|
+
// Exact pragmas — MUST execute immediately after open
|
|
45
|
+
db.exec('PRAGMA journal_mode = WAL;');
|
|
46
|
+
db.exec('PRAGMA synchronous = NORMAL;');
|
|
47
|
+
db.exec('PRAGMA busy_timeout = 3000;');
|
|
48
|
+
initSchema();
|
|
49
|
+
return true;
|
|
50
|
+
} catch (e: any) {
|
|
51
|
+
console.warn('[knowledge-store] DB init failed:', e?.message);
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function initSchema(): void {
|
|
57
|
+
db.exec(`
|
|
58
|
+
CREATE TABLE IF NOT EXISTS knowledge (
|
|
59
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
60
|
+
kind TEXT NOT NULL,
|
|
61
|
+
ref TEXT NOT NULL,
|
|
62
|
+
summary TEXT NOT NULL,
|
|
63
|
+
ts INTEGER NOT NULL,
|
|
64
|
+
refHash TEXT NOT NULL,
|
|
65
|
+
simHash TEXT NOT NULL
|
|
66
|
+
);
|
|
67
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS knowledge_fts
|
|
68
|
+
USING fts5(summary, content='knowledge', content_rowid='id');
|
|
69
|
+
`);
|
|
70
|
+
// Exact FTS5 triggers — must NOT deviate
|
|
71
|
+
db.exec(`
|
|
72
|
+
CREATE TRIGGER IF NOT EXISTS tbl_ai AFTER INSERT ON knowledge BEGIN
|
|
73
|
+
INSERT INTO knowledge_fts(rowid, summary) VALUES (new.id, new.summary);
|
|
74
|
+
END;
|
|
75
|
+
CREATE TRIGGER IF NOT EXISTS tbl_ad AFTER DELETE ON knowledge BEGIN
|
|
76
|
+
INSERT INTO knowledge_fts(knowledge_fts, rowid, summary) VALUES('delete', old.id, old.summary);
|
|
77
|
+
END;
|
|
78
|
+
CREATE TRIGGER IF NOT EXISTS tbl_au AFTER UPDATE ON knowledge BEGIN
|
|
79
|
+
INSERT INTO knowledge_fts(knowledge_fts, rowid, summary) VALUES('delete', old.id, old.summary);
|
|
80
|
+
INSERT INTO knowledge_fts(rowid, summary) VALUES (new.id, new.summary);
|
|
81
|
+
END;
|
|
82
|
+
`);
|
|
83
|
+
db.exec(`
|
|
84
|
+
CREATE TABLE IF NOT EXISTS audit_log (
|
|
85
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
86
|
+
kind TEXT NOT NULL,
|
|
87
|
+
ref TEXT NOT NULL,
|
|
88
|
+
merkleHash TEXT NOT NULL,
|
|
89
|
+
ts INTEGER NOT NULL
|
|
90
|
+
);
|
|
91
|
+
`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ── 64-bit SimHash using BigInt — NO Number bitwise ops allowed ──────────
|
|
95
|
+
// Hand-trace: "hello world"
|
|
96
|
+
// toks = ["hello","world"]
|
|
97
|
+
// For "hello": sha256 -> 32 bytes; use first 8 bytes as BigInt
|
|
98
|
+
// bits = byte[0]<<56 | byte[1]<<48 | ... | byte[7]<<0 (using BigInt shifts)
|
|
99
|
+
// For each bit position b in 0..63: v[b] += ((bits >> BigInt(b)) & 1n) === 1n ? 1 : -1
|
|
100
|
+
// After all tokens, fp: for b in 0..63 if v[b]>0 then fp |= 1n<<BigInt(b)
|
|
101
|
+
// Return fp.toString(16).padStart(16,'0')
|
|
102
|
+
export function computeSimHash64(text: string): string {
|
|
103
|
+
const toks = text.toLowerCase().match(/[a-z0-9]+/g) || [];
|
|
104
|
+
const v = new Array(64).fill(0);
|
|
105
|
+
for (const tok of toks) {
|
|
106
|
+
const hashBuffer = createHash('sha256').update(tok, 'utf8').digest();
|
|
107
|
+
// Construct 64-bit BigInt from first 8 bytes — strictly BigInt arithmetic
|
|
108
|
+
let bits = 0n;
|
|
109
|
+
for (let i = 0; i < 8; i++) bits = (bits << 8n) | BigInt(hashBuffer[i]);
|
|
110
|
+
// Project onto 64-dimensional vector
|
|
111
|
+
for (let b = 0; b < 64; b++) v[b] += ((bits >> BigInt(b)) & 1n) === 1n ? 1 : -1;
|
|
112
|
+
}
|
|
113
|
+
// Collapse vector to fingerprint — MUST use BigInt, not Number bitwise
|
|
114
|
+
let fp = 0n;
|
|
115
|
+
for (let b = 0; b < 64; b++) if (v[b] > 0) fp |= (1n << BigInt(b));
|
|
116
|
+
return fp.toString(16).padStart(16, '0');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function hammingDistance64(a: string, b: string): number {
|
|
120
|
+
let diff = BigInt(`0x${a}`) ^ BigInt(`0x${b}`);
|
|
121
|
+
let dist = 0;
|
|
122
|
+
while (diff > 0n) { dist += Number(diff & 1n); diff >>= 1n; }
|
|
123
|
+
return dist;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ── Secret redaction before any data hits disk ───────────────────────────
|
|
127
|
+
export function redactSecrets(text: string): string {
|
|
128
|
+
// AWS keys
|
|
129
|
+
let r = text.replace(/AKIA[0-9A-Z]{16}/g, '[REDACTED_AWS_KEY]');
|
|
130
|
+
// GitHub PATs
|
|
131
|
+
r = r.replace(/ghp_[A-Za-z0-9]{36}/g, '[REDACTED_GH_PAT]');
|
|
132
|
+
r = r.replace(/github_pat_[A-Za-z0-9_]{82}/g, '[REDACTED_GH_PAT]');
|
|
133
|
+
// Generic secrets — bearer tokens, API keys in headers
|
|
134
|
+
r = r.replace(/Bearer\s+[A-Za-z0-9._\-]{20,}/gi, 'Bearer [REDACTED]');
|
|
135
|
+
r = r.replace(/api[_-]?key["\s:=]+[A-Za-z0-9_\-]{20,}/gi, 'api_key=[REDACTED]');
|
|
136
|
+
return r;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// ── Prompt injection scanner ──────────────────────────────────────────────
|
|
140
|
+
export function scanForInjection(text: string): boolean {
|
|
141
|
+
const lower = text.toLowerCase();
|
|
142
|
+
const injectionPatterns = [
|
|
143
|
+
'ignore previous instructions',
|
|
144
|
+
'ignore all instructions',
|
|
145
|
+
'system prompt:',
|
|
146
|
+
'new instruction:',
|
|
147
|
+
'prompt injection',
|
|
148
|
+
'</system>',
|
|
149
|
+
'<|im_start|>',
|
|
150
|
+
'jailbreak',
|
|
151
|
+
'dan mode',
|
|
152
|
+
];
|
|
153
|
+
return injectionPatterns.some(p => lower.includes(p));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ── Core storage API ─────────────────────────────────────────────────────
|
|
157
|
+
export interface KnowledgeRecord {
|
|
158
|
+
id?: number;
|
|
159
|
+
kind: string;
|
|
160
|
+
ref: string;
|
|
161
|
+
summary: string;
|
|
162
|
+
ts: number;
|
|
163
|
+
refHash: string;
|
|
164
|
+
simHash: string;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function recordKnowledge(kind: string, ref: string, rawSummary: string): { id: number } | null {
|
|
168
|
+
if (!ensureDb()) return null;
|
|
169
|
+
// Redact secrets before writing
|
|
170
|
+
const summary = redactSecrets(rawSummary).slice(0, 4000);
|
|
171
|
+
// Block injection attempts
|
|
172
|
+
if (scanForInjection(summary)) {
|
|
173
|
+
console.warn('[knowledge-store] Injection attempt detected in summary, blocking.');
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
const ts = Date.now();
|
|
177
|
+
const refHash = createHash('sha256').update(ref, 'utf8').digest('hex');
|
|
178
|
+
const simHash = computeSimHash64(summary);
|
|
179
|
+
try {
|
|
180
|
+
const stmt = db.prepare(`
|
|
181
|
+
INSERT INTO knowledge (kind, ref, summary, ts, refHash, simHash)
|
|
182
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
183
|
+
`);
|
|
184
|
+
const result = stmt.run(kind, ref, summary, ts, refHash, simHash);
|
|
185
|
+
return { id: Number(result.lastInsertRowid) };
|
|
186
|
+
} catch (e: any) {
|
|
187
|
+
console.warn('[knowledge-store] recordKnowledge failed:', e?.message);
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export function searchKnowledge(query: string, limit = 10): KnowledgeRecord[] {
|
|
193
|
+
if (!ensureDb()) return [];
|
|
194
|
+
try {
|
|
195
|
+
const stmt = db.prepare(`
|
|
196
|
+
SELECT k.* FROM knowledge k
|
|
197
|
+
JOIN knowledge_fts f ON f.rowid = k.id
|
|
198
|
+
WHERE knowledge_fts MATCH ?
|
|
199
|
+
ORDER BY rank
|
|
200
|
+
LIMIT ?
|
|
201
|
+
`);
|
|
202
|
+
return stmt.all(query, limit) as KnowledgeRecord[];
|
|
203
|
+
} catch {
|
|
204
|
+
// Fallback to LIKE if FTS fails
|
|
205
|
+
try {
|
|
206
|
+
const stmt = db.prepare(`SELECT * FROM knowledge WHERE summary LIKE ? LIMIT ?`);
|
|
207
|
+
return stmt.all(`%${query}%`, limit) as KnowledgeRecord[];
|
|
208
|
+
} catch { return []; }
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export function getKnowledgeById(id: number): KnowledgeRecord | null {
|
|
213
|
+
if (!ensureDb()) return null;
|
|
214
|
+
try {
|
|
215
|
+
const stmt = db.prepare(`SELECT * FROM knowledge WHERE id = ?`);
|
|
216
|
+
return (stmt.get(id) as KnowledgeRecord) || null;
|
|
217
|
+
} catch { return null; }
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export function deleteKnowledge(id: number): boolean {
|
|
221
|
+
if (!ensureDb()) return false;
|
|
222
|
+
try {
|
|
223
|
+
const stmt = db.prepare(`DELETE FROM knowledge WHERE id = ?`);
|
|
224
|
+
stmt.run(id);
|
|
225
|
+
return true;
|
|
226
|
+
} catch { return false; }
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export function repairKnowledgeFts(): boolean {
|
|
230
|
+
if (!ensureDb()) return false;
|
|
231
|
+
try {
|
|
232
|
+
db.exec(`INSERT INTO knowledge_fts(knowledge_fts) VALUES('rebuild')`);
|
|
233
|
+
return true;
|
|
234
|
+
} catch { return false; }
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// ── Autophagy: purge ghost files (refs no longer on disk) ────────────────
|
|
238
|
+
export function purgeGhostFiles(): number {
|
|
239
|
+
if (!ensureDb()) return 0;
|
|
240
|
+
try {
|
|
241
|
+
const rows = db.prepare(`SELECT id, ref FROM knowledge WHERE kind = 'file'`).all() as Array<{id:number, ref:string}>;
|
|
242
|
+
let purged = 0;
|
|
243
|
+
for (const row of rows) {
|
|
244
|
+
if (!existsSync(row.ref)) {
|
|
245
|
+
db.prepare(`DELETE FROM knowledge WHERE id = ?`).run(row.id);
|
|
246
|
+
purged++;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return purged;
|
|
250
|
+
} catch { return 0; }
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// ── Stats ─────────────────────────────────────────────────────────────────
|
|
254
|
+
export function getKnowledgeStats(): { totalRecords: number; kinds: Record<string, number>; dbPath: string; available: boolean } {
|
|
255
|
+
if (!ensureDb()) return { totalRecords: 0, kinds: {}, dbPath: DB_PATH, available: false };
|
|
256
|
+
try {
|
|
257
|
+
const total = (db.prepare(`SELECT COUNT(*) as c FROM knowledge`).get() as any)?.c ?? 0;
|
|
258
|
+
const kindRows = db.prepare(`SELECT kind, COUNT(*) as c FROM knowledge GROUP BY kind`).all() as Array<{kind:string,c:number}>;
|
|
259
|
+
const kinds: Record<string, number> = {};
|
|
260
|
+
for (const r of kindRows) kinds[r.kind] = r.c;
|
|
261
|
+
return { totalRecords: total, kinds, dbPath: DB_PATH, available: true };
|
|
262
|
+
} catch { return { totalRecords: 0, kinds: {}, dbPath: DB_PATH, available: false }; }
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export function getDb(): any { ensureDb(); return db; }
|
|
266
|
+
export function getDbPath(): string { return DB_PATH; }
|
|
267
|
+
export function isDbAvailable(): boolean { return dbAvailable && !!db; }
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vite-native-policy-plane.ts — L2: Dynamic Feature Flags & Overrides
|
|
3
|
+
* Dynamic feature flagging backed by SQLite, allowing runtime degradation.
|
|
4
|
+
* Zero-dependency: node:* only.
|
|
5
|
+
*/
|
|
6
|
+
import { createRequire } from 'node:module';
|
|
7
|
+
import { existsSync, mkdirSync } from 'node:fs';
|
|
8
|
+
import { join, dirname } from 'node:path';
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
10
|
+
|
|
11
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
+
const __dirname = dirname(__filename);
|
|
13
|
+
|
|
14
|
+
// Ghost load for SQLite
|
|
15
|
+
let DatabaseSync: any = null;
|
|
16
|
+
let dbAvailable = false;
|
|
17
|
+
try {
|
|
18
|
+
const anyProc: any = globalThis.process as any;
|
|
19
|
+
if (anyProc && typeof anyProc.getBuiltinModule === 'function') {
|
|
20
|
+
const mod = anyProc.getBuiltinModule('node:sqlite');
|
|
21
|
+
if (mod?.DatabaseSync) { DatabaseSync = mod.DatabaseSync; dbAvailable = true; }
|
|
22
|
+
}
|
|
23
|
+
} catch {}
|
|
24
|
+
if (!dbAvailable) {
|
|
25
|
+
try {
|
|
26
|
+
const req = createRequire(import.meta.url);
|
|
27
|
+
({ DatabaseSync } = req('node:sqlite'));
|
|
28
|
+
dbAvailable = !!DatabaseSync;
|
|
29
|
+
} catch { dbAvailable = false; }
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const AUDIT_DIR = join(__dirname, '..', '..', '..', 'src', 'audit');
|
|
33
|
+
const DB_PATH = join(AUDIT_DIR, 'knowledge.db');
|
|
34
|
+
|
|
35
|
+
let db: any = null;
|
|
36
|
+
|
|
37
|
+
function ensureDb(): boolean {
|
|
38
|
+
if (db) return true;
|
|
39
|
+
if (!dbAvailable) return false;
|
|
40
|
+
try {
|
|
41
|
+
if (!existsSync(AUDIT_DIR)) mkdirSync(AUDIT_DIR, { recursive: true });
|
|
42
|
+
db = new DatabaseSync(DB_PATH);
|
|
43
|
+
db.exec('PRAGMA journal_mode = WAL;');
|
|
44
|
+
db.exec('PRAGMA synchronous = NORMAL;');
|
|
45
|
+
db.exec('PRAGMA busy_timeout = 3000;');
|
|
46
|
+
db.exec(`
|
|
47
|
+
CREATE TABLE IF NOT EXISTS policy_flags (
|
|
48
|
+
name TEXT PRIMARY KEY,
|
|
49
|
+
valueJson TEXT NOT NULL,
|
|
50
|
+
ts INTEGER NOT NULL
|
|
51
|
+
);
|
|
52
|
+
`);
|
|
53
|
+
return true;
|
|
54
|
+
} catch (e: any) {
|
|
55
|
+
console.warn('[policy-plane] DB init failed:', e?.message);
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface PolicyState {
|
|
61
|
+
useDdg: boolean;
|
|
62
|
+
useBing: boolean;
|
|
63
|
+
useYahoo: boolean;
|
|
64
|
+
useMojeek: boolean;
|
|
65
|
+
enableSSE: boolean;
|
|
66
|
+
enablePrefetch: boolean;
|
|
67
|
+
enableAutoRag: boolean;
|
|
68
|
+
enableRateLimit: boolean;
|
|
69
|
+
enableCircuitBreaker: boolean;
|
|
70
|
+
maxResultsPerEngine: number;
|
|
71
|
+
searchTimeoutMs: number;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const DEFAULT_POLICY: PolicyState = {
|
|
75
|
+
useDdg: true,
|
|
76
|
+
useBing: true,
|
|
77
|
+
useYahoo: true,
|
|
78
|
+
useMojeek: true,
|
|
79
|
+
enableSSE: true,
|
|
80
|
+
enablePrefetch: true,
|
|
81
|
+
enableAutoRag: true,
|
|
82
|
+
enableRateLimit: true,
|
|
83
|
+
enableCircuitBreaker: true,
|
|
84
|
+
maxResultsPerEngine: 5,
|
|
85
|
+
searchTimeoutMs: 8000,
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export function getPolicyOverrides(): Partial<PolicyState> {
|
|
89
|
+
if (!ensureDb()) return {};
|
|
90
|
+
try {
|
|
91
|
+
const rows = db.prepare(`SELECT name, valueJson FROM policy_flags`).all() as Array<{name: string; valueJson: string}>;
|
|
92
|
+
const result: Partial<PolicyState> = {};
|
|
93
|
+
for (const row of rows) {
|
|
94
|
+
try {
|
|
95
|
+
// Wrap JSON.parse — corrupted rows must be ignored, not thrown
|
|
96
|
+
const val = JSON.parse(row.valueJson);
|
|
97
|
+
(result as any)[row.name] = val;
|
|
98
|
+
} catch {
|
|
99
|
+
// Silently ignore corrupted DB rows
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return result;
|
|
103
|
+
} catch { return {}; }
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// UPSERT implementation for SQLite
|
|
107
|
+
export function setPolicyOverride(name: keyof PolicyState | string, value: unknown): boolean {
|
|
108
|
+
if (!ensureDb()) return false;
|
|
109
|
+
try {
|
|
110
|
+
// Hand-trace: calling twice with same name — second call hits ON CONFLICT
|
|
111
|
+
// First: INSERT succeeds, row created with name, valueJson, ts
|
|
112
|
+
// Second: INSERT fails ON CONFLICT(name), DO UPDATE SET fires instead
|
|
113
|
+
// Both calls result in the same row with updated valueJson and ts
|
|
114
|
+
const stmt = db.prepare(`
|
|
115
|
+
INSERT INTO policy_flags (name, valueJson, ts)
|
|
116
|
+
VALUES (?, ?, ?)
|
|
117
|
+
ON CONFLICT(name) DO UPDATE SET valueJson = excluded.valueJson, ts = excluded.ts
|
|
118
|
+
`);
|
|
119
|
+
stmt.run(name, JSON.stringify(value), Date.now());
|
|
120
|
+
return true;
|
|
121
|
+
} catch { return false; }
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function deletePolicyOverride(name: string): boolean {
|
|
125
|
+
if (!ensureDb()) return false;
|
|
126
|
+
try {
|
|
127
|
+
db.prepare(`DELETE FROM policy_flags WHERE name = ?`).run(name);
|
|
128
|
+
return true;
|
|
129
|
+
} catch { return false; }
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ── Policy Evaluation ─────────────────────────────────────────────────────
|
|
133
|
+
// Hand-trace: DB override sets enablePrefetch = true, but ctx.pressure = 'hot'
|
|
134
|
+
// Step 1: merged = {...DEFAULT_POLICY, ...overrides} => enablePrefetch = true
|
|
135
|
+
// Step 2: pressure === 'hot' => forcefully set enablePrefetch = false, enableSSE = false, enableAutoRag = false
|
|
136
|
+
// Final value of enablePrefetch = FALSE (hot pressure wins, ignores DB override)
|
|
137
|
+
export function evaluatePolicy(ctx: { pressure: 'ok' | 'warm' | 'hot' }): PolicyState {
|
|
138
|
+
const overrides = getPolicyOverrides();
|
|
139
|
+
const merged: PolicyState = { ...DEFAULT_POLICY, ...overrides };
|
|
140
|
+
|
|
141
|
+
// Hot pressure: force shed non-critical features — DB overrides are IGNORED
|
|
142
|
+
if (ctx.pressure === 'hot') {
|
|
143
|
+
merged.enablePrefetch = false;
|
|
144
|
+
merged.enableSSE = false;
|
|
145
|
+
merged.enableAutoRag = false;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Total engine blackout prevention: force useDdg if all four engines disabled
|
|
149
|
+
if (!merged.useDdg && !merged.useBing && !merged.useYahoo && !merged.useMojeek) {
|
|
150
|
+
merged.useDdg = true;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return merged;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ── Self-test remediation ─────────────────────────────────────────────────
|
|
157
|
+
export interface SelfTestResult {
|
|
158
|
+
passed: boolean;
|
|
159
|
+
failures: string[];
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export function applySelfTestRemediation(result: SelfTestResult): void {
|
|
163
|
+
for (const failure of result.failures) {
|
|
164
|
+
if (failure.includes('parser.bing.href.capture')) {
|
|
165
|
+
console.warn('[policy-plane] Bing parser failure detected — disabling Bing engine');
|
|
166
|
+
setPolicyOverride('useBing', false);
|
|
167
|
+
}
|
|
168
|
+
if (failure.includes('parser.ddg.href.capture')) {
|
|
169
|
+
console.warn('[policy-plane] DDG parser failure detected — disabling DDG engine');
|
|
170
|
+
setPolicyOverride('useDdg', false);
|
|
171
|
+
}
|
|
172
|
+
if (failure.includes('parser.yahoo.href.capture')) {
|
|
173
|
+
setPolicyOverride('useYahoo', false);
|
|
174
|
+
}
|
|
175
|
+
if (failure.includes('parser.mojeek.href.capture')) {
|
|
176
|
+
setPolicyOverride('useMojeek', false);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function getAllPolicyFlags(): Array<{ name: string; value: unknown; ts: number }> {
|
|
182
|
+
if (!ensureDb()) return [];
|
|
183
|
+
try {
|
|
184
|
+
const rows = db.prepare(`SELECT name, valueJson, ts FROM policy_flags ORDER BY name`).all() as Array<{name:string;valueJson:string;ts:number}>;
|
|
185
|
+
return rows.map(r => {
|
|
186
|
+
try { return { name: r.name, value: JSON.parse(r.valueJson), ts: r.ts }; }
|
|
187
|
+
catch { return { name: r.name, value: null, ts: r.ts }; }
|
|
188
|
+
});
|
|
189
|
+
} catch { return []; }
|
|
190
|
+
}
|