@mindrian_os/install 1.13.0-beta.11
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/.claude-plugin/plugin.json +21 -0
- package/.mcp.json +9 -0
- package/CHANGELOG.md +3333 -0
- package/LICENSE +123 -0
- package/README.md +673 -0
- package/agents/brain-query.md +80 -0
- package/agents/framework-runner.md +237 -0
- package/agents/grading.md +188 -0
- package/agents/investor.md +128 -0
- package/agents/larry-extended.md +135 -0
- package/agents/opportunity-scanner.md +91 -0
- package/agents/persona-analyst.md +132 -0
- package/agents/research.md +89 -0
- package/agents/reverse-salient-agent.md +27 -0
- package/bin/cli.js +142 -0
- package/bin/mindrian-mcp-server.cjs +182 -0
- package/bin/mindrian-tools.cjs +765 -0
- package/commands/act.md +439 -0
- package/commands/admin.md +404 -0
- package/commands/analyze-needs.md +42 -0
- package/commands/analyze-systems.md +39 -0
- package/commands/analyze-timing.md +42 -0
- package/commands/auto-explore.md +64 -0
- package/commands/beautiful-question.md +40 -0
- package/commands/brain-derive.md +78 -0
- package/commands/build-knowledge.md +42 -0
- package/commands/build-thesis.md +46 -0
- package/commands/causal.md +234 -0
- package/commands/challenge-assumptions.md +33 -0
- package/commands/compare-ventures.md +83 -0
- package/commands/dashboard.md +110 -0
- package/commands/deep-grade.md +82 -0
- package/commands/diagnose.md +58 -0
- package/commands/diagnostics.md +151 -0
- package/commands/doctor.md +151 -0
- package/commands/dominant-designs.md +40 -0
- package/commands/explain-decision.md +87 -0
- package/commands/explore-domains.md +42 -0
- package/commands/explore-futures.md +40 -0
- package/commands/explore-trends.md +42 -0
- package/commands/export.md +103 -0
- package/commands/file-meeting.md +724 -0
- package/commands/find-analogies.md +188 -0
- package/commands/find-bottlenecks.md +62 -0
- package/commands/find-connections.md +76 -0
- package/commands/funding.md +81 -0
- package/commands/grade.md +203 -0
- package/commands/graph.md +128 -0
- package/commands/hat-briefing.md +125 -0
- package/commands/heal.md +196 -0
- package/commands/help.md +399 -0
- package/commands/hmi-status.md +172 -0
- package/commands/jtbd.md +241 -0
- package/commands/leadership.md +73 -0
- package/commands/lean-canvas.md +40 -0
- package/commands/macro-trends.md +40 -0
- package/commands/map-unknowns.md +40 -0
- package/commands/memory.md +173 -0
- package/commands/models.md +175 -0
- package/commands/mos-reason.md +285 -0
- package/commands/mullins.md +120 -0
- package/commands/new-project.md +481 -0
- package/commands/onboard.md +434 -0
- package/commands/operator.md +149 -0
- package/commands/opportunities.md +144 -0
- package/commands/organize.md +497 -0
- package/commands/persona.md +198 -0
- package/commands/pipeline.md +112 -0
- package/commands/present.md +91 -0
- package/commands/publish.md +201 -0
- package/commands/query.md +124 -0
- package/commands/radar.md +72 -0
- package/commands/reanalyze.md +91 -0
- package/commands/research.md +196 -0
- package/commands/room.md +352 -0
- package/commands/rooms.md +598 -0
- package/commands/root-cause.md +40 -0
- package/commands/rs-experts.md +85 -0
- package/commands/rs-explain.md +100 -0
- package/commands/rs-fetch.md +94 -0
- package/commands/rs-thesis.md +85 -0
- package/commands/scenario-plan.md +40 -0
- package/commands/scheduled-tasks.md +285 -0
- package/commands/score-innovation.md +43 -0
- package/commands/scout.md +239 -0
- package/commands/setup.md +618 -0
- package/commands/snapshot.md +147 -0
- package/commands/speakers.md +84 -0
- package/commands/splash.md +28 -0
- package/commands/status.md +75 -0
- package/commands/structure-argument.md +42 -0
- package/commands/suggest-next.md +80 -0
- package/commands/systems-thinking.md +40 -0
- package/commands/think-hats.md +42 -0
- package/commands/update.md +181 -0
- package/commands/user-needs.md +40 -0
- package/commands/validate.md +40 -0
- package/commands/value-proposition.md +61 -0
- package/commands/vault.md +180 -0
- package/commands/visualize.md +52 -0
- package/commands/whitespace.md +507 -0
- package/commands/wiki.md +69 -0
- package/hooks/hooks.json +381 -0
- package/hooks/run-hook.cmd +64 -0
- package/lib/__init__.py +0 -0
- package/lib/__pycache__/__init__.cpython-312.pyc +0 -0
- package/lib/agents/auto-explore-agent.cjs +1043 -0
- package/lib/agents/reverse-salient-agent.cjs +679 -0
- package/lib/agents/tension-hook-agent.cjs +544 -0
- package/lib/brain/ROOM.md +44 -0
- package/lib/brain/chain-recommender.cjs +301 -0
- package/lib/chat/chat-context.js +185 -0
- package/lib/chat/chat-panel.js +721 -0
- package/lib/chat/fabric-chat.cjs +288 -0
- package/lib/chat/generative-tools.js +219 -0
- package/lib/conversation/ROOM.md +39 -0
- package/lib/conversation/classifier-rules.json +38 -0
- package/lib/conversation/classifier.cjs +264 -0
- package/lib/conversation/operator.cjs +287 -0
- package/lib/copy/115-spec-strings.cjs +55 -0
- package/lib/core/__init__.py +0 -0
- package/lib/core/__nav-stub.cjs +14 -0
- package/lib/core/__pycache__/__init__.cpython-312.pyc +0 -0
- package/lib/core/__pycache__/rs-math.cpython-312.pyc +0 -0
- package/lib/core/__pycache__/rs_cache.cpython-312.pyc +0 -0
- package/lib/core/__pycache__/rs_corpus.cpython-312.pyc +0 -0
- package/lib/core/__pycache__/rs_hybrid.cpython-312.pyc +0 -0
- package/lib/core/__pycache__/rs_math.cpython-312.pyc +0 -0
- package/lib/core/__pycache__/rs_rooms.cpython-312.pyc +0 -0
- package/lib/core/artifact-id.cjs +148 -0
- package/lib/core/asset-ops.cjs +151 -0
- package/lib/core/auto-commit-throttle.cjs +129 -0
- package/lib/core/bearer-token.cjs +199 -0
- package/lib/core/brain-client.cjs +865 -0
- package/lib/core/brain-derivation-prompts.cjs +326 -0
- package/lib/core/brain-derivation-queue.cjs +431 -0
- package/lib/core/brain-derivation.cjs +580 -0
- package/lib/core/brain-md-schema.cjs +528 -0
- package/lib/core/brain-md-staleness.cjs +357 -0
- package/lib/core/brain-response-sanitize.cjs +188 -0
- package/lib/core/bridge-writer.cjs +477 -0
- package/lib/core/chat-context-builder.cjs +253 -0
- package/lib/core/cross-room-aggregator.cjs +762 -0
- package/lib/core/daily-briefing.cjs +438 -0
- package/lib/core/decision-capture.cjs +618 -0
- package/lib/core/deep-links.cjs +82 -0
- package/lib/core/dispatch-optimizer.cjs +354 -0
- package/lib/core/dual-path-detector.cjs +84 -0
- package/lib/core/dual-path-detector.test.cjs +334 -0
- package/lib/core/exports-log.cjs +79 -0
- package/lib/core/feynman-minto-invariants.cjs +605 -0
- package/lib/core/folder-memory-async.cjs +338 -0
- package/lib/core/folder-memory-shared.cjs +890 -0
- package/lib/core/folder-memory.cjs +416 -0
- package/lib/core/framework-chain-composer.cjs +411 -0
- package/lib/core/frontmatter-schemas.cjs +330 -0
- package/lib/core/git-ops.cjs +141 -0
- package/lib/core/graph-ops.cjs +258 -0
- package/lib/core/hat-persistence.cjs +362 -0
- package/lib/core/index.cjs +60 -0
- package/lib/core/integration-registry.cjs +232 -0
- package/lib/core/intelligence-cascade.cjs +661 -0
- package/lib/core/lazygraph-ops.cjs +1057 -0
- package/lib/core/lru-cache.cjs +139 -0
- package/lib/core/mcp-profiles.cjs +182 -0
- package/lib/core/meeting-ops.cjs +54 -0
- package/lib/core/memory-ops.cjs +600 -0
- package/lib/core/migrations/ROOM.md +33 -0
- package/lib/core/migrations/phase-109-nodes-provenance.cjs +339 -0
- package/lib/core/migrations/phase-109-session-focus.cjs +99 -0
- package/lib/core/model-profiles.cjs +246 -0
- package/lib/core/mullins-scaffold.cjs +160 -0
- package/lib/core/nav-dial.cjs +316 -0
- package/lib/core/navigation/ROOM.md +15 -0
- package/lib/core/navigation/explanation.cjs +43 -0
- package/lib/core/navigation/focus.cjs +135 -0
- package/lib/core/navigation/ingestion.cjs +82 -0
- package/lib/core/navigation/insights.cjs +350 -0
- package/lib/core/navigation/memory-events.cjs +118 -0
- package/lib/core/navigation/neighborhood.cjs +78 -0
- package/lib/core/navigation/packet.cjs +182 -0
- package/lib/core/navigation/room-home.cjs +127 -0
- package/lib/core/navigation/transitions.cjs +82 -0
- package/lib/core/navigation-engine-shared.cjs +242 -0
- package/lib/core/navigation-engine.cjs +664 -0
- package/lib/core/navigation.cjs +60 -0
- package/lib/core/nl-graph-queries.cjs +164 -0
- package/lib/core/offer-presenter.cjs +406 -0
- package/lib/core/opportunity-extractor.cjs +183 -0
- package/lib/core/opportunity-ops.cjs +1371 -0
- package/lib/core/persona-ops.cjs +537 -0
- package/lib/core/persona-taxonomy.cjs +190 -0
- package/lib/core/platform-gates.cjs +120 -0
- package/lib/core/platform.cjs +257 -0
- package/lib/core/proactive-intelligence.cjs +528 -0
- package/lib/core/problem-type-router.cjs +315 -0
- package/lib/core/reasoning-ops.cjs +639 -0
- package/lib/core/reverse-salient-persona-suffix.cjs +115 -0
- package/lib/core/room-classifier-strict-mode.cjs +229 -0
- package/lib/core/room-db.cjs +127 -0
- package/lib/core/room-ops-async.cjs +92 -0
- package/lib/core/room-ops-shared.cjs +64 -0
- package/lib/core/room-ops-sync.cjs +70 -0
- package/lib/core/room-ops.cjs +32 -0
- package/lib/core/room-type-detector.cjs +386 -0
- package/lib/core/rs-brain-substrate-prompts.cjs +129 -0
- package/lib/core/rs-brain-substrate.cjs +570 -0
- package/lib/core/rs-breakthrough-scorer.cjs +255 -0
- package/lib/core/rs-canon-violations.cjs +82 -0
- package/lib/core/rs-chain-feeder.cjs +343 -0
- package/lib/core/rs-commercial-assessor.cjs +280 -0
- package/lib/core/rs-differential-scorer.cjs +376 -0
- package/lib/core/rs-domain-analyzer.cjs +385 -0
- package/lib/core/rs-egress-prompts.cjs +113 -0
- package/lib/core/rs-egress-telemetry.cjs +225 -0
- package/lib/core/rs-egress-violations.cjs +53 -0
- package/lib/core/rs-expert-mapper.cjs +467 -0
- package/lib/core/rs-fetcher-academic.cjs +697 -0
- package/lib/core/rs-fetcher-experts.cjs +314 -0
- package/lib/core/rs-fetcher-industry.cjs +731 -0
- package/lib/core/rs-fetcher-patents.cjs +564 -0
- package/lib/core/rs-innovation-classifier.cjs +194 -0
- package/lib/core/rs-mind-map.cjs +656 -0
- package/lib/core/rs-neo4j-writer.cjs +388 -0
- package/lib/core/rs-nl-to-query.cjs +425 -0
- package/lib/core/rs-pinecone-bridge.cjs +303 -0
- package/lib/core/rs-preprocessor.cjs +350 -0
- package/lib/core/rs-query-matrix.cjs +316 -0
- package/lib/core/rs-query-to-text.cjs +438 -0
- package/lib/core/rs-sqlite-mirror.cjs +443 -0
- package/lib/core/rs-thesis-generator.cjs +188 -0
- package/lib/core/rs_cache.py +479 -0
- package/lib/core/rs_corpus.py +468 -0
- package/lib/core/rs_hybrid.py +586 -0
- package/lib/core/rs_math.py +287 -0
- package/lib/core/rs_rooms.py +193 -0
- package/lib/core/scheduled-scanner.cjs +463 -0
- package/lib/core/scratchpad-ops.cjs +201 -0
- package/lib/core/section-8-trace-schema.cjs +138 -0
- package/lib/core/section-registry.cjs +111 -0
- package/lib/core/session-state.cjs +144 -0
- package/lib/core/shallow-doc-parser.cjs +174 -0
- package/lib/core/shallow-doc-parser.test.cjs +226 -0
- package/lib/core/skill-activation-router.cjs +284 -0
- package/lib/core/state-ops.cjs +46 -0
- package/lib/core/statusline-cache.cjs +266 -0
- package/lib/core/token-estimator.cjs +348 -0
- package/lib/core/user-archetype.cjs +239 -0
- package/lib/core/user-md-ops.cjs +524 -0
- package/lib/core/visual-ops.cjs +624 -0
- package/lib/core/write-lock.cjs +149 -0
- package/lib/graph/canvas-graph.js +467 -0
- package/lib/graph/constellation-config.cjs +299 -0
- package/lib/graph/graph-detail-panel.js +165 -0
- package/lib/hmi/ROOM.md +47 -0
- package/lib/hmi/across-session-memory.cjs +604 -0
- package/lib/hmi/cross-room-memory.cjs +575 -0
- package/lib/hmi/decoy-tier.cjs +395 -0
- package/lib/hmi/jtbd-classifier.cjs +219 -0
- package/lib/hmi/jtbd-state.cjs +199 -0
- package/lib/hmi/jtbd-taxonomy.json +392 -0
- package/lib/hmi/selector-dispatcher.cjs +546 -0
- package/lib/hmi/selector-telemetry.cjs +263 -0
- package/lib/hmi/shape-f0-renderer.cjs +139 -0
- package/lib/hmi/shape-f1-fallback.cjs +80 -0
- package/lib/hmi/shape-f1-renderer.cjs +138 -0
- package/lib/hmi/shape-f2-renderer.cjs +132 -0
- package/lib/hmi/shape-f3-renderer.cjs +66 -0
- package/lib/hmi/shape-f4-renderer.cjs +72 -0
- package/lib/hmi/shape-f5-renderer.cjs +155 -0
- package/lib/hmi/shape-f6-plan-review-renderer.cjs +312 -0
- package/lib/hmi/shape-f6-renderer.cjs +144 -0
- package/lib/hmi/shape-g-renderer.cjs +219 -0
- package/lib/hmi/shape-h-renderer.cjs +222 -0
- package/lib/hmi/tier-check.cjs +63 -0
- package/lib/import/PRECONDITIONS.md +41 -0
- package/lib/import/branding.cjs +210 -0
- package/lib/import/branding.test.cjs +235 -0
- package/lib/import/classifications-sync.cjs +104 -0
- package/lib/import/classifications-sync.test.cjs +129 -0
- package/lib/import/enricher.cjs +296 -0
- package/lib/import/enricher.test.cjs +273 -0
- package/lib/import/integration.test.cjs +376 -0
- package/lib/import/manifest.cjs +129 -0
- package/lib/import/manifest.schema.json +185 -0
- package/lib/import/manifest.test.cjs +123 -0
- package/lib/import/meeting-detector.cjs +92 -0
- package/lib/import/meeting-detector.test.cjs +100 -0
- package/lib/import/person-detector.cjs +229 -0
- package/lib/import/person-detector.test.cjs +149 -0
- package/lib/import/report.cjs +186 -0
- package/lib/import/report.test.cjs +186 -0
- package/lib/import/room-md-scaffolder.cjs +49 -0
- package/lib/import/router.cjs +224 -0
- package/lib/import/router.test.cjs +356 -0
- package/lib/import/run-all-tests.cjs +36 -0
- package/lib/import/smoke-test.cjs +213 -0
- package/lib/import/smoke-test.test.cjs +148 -0
- package/lib/import/test-fixtures/collision-vault/preexisting-room/STATE.md +8 -0
- package/lib/import/test-fixtures/collision-vault/preexisting-room/problem-definition/onboarding/onboarding.md +7 -0
- package/lib/import/test-fixtures/collision-vault/source/onboarding.md +5 -0
- package/lib/import/test-fixtures/obsidian-vault/.obsidian/workspace.json +1 -0
- package/lib/import/test-fixtures/obsidian-vault/notes/with-wikilinks.md +4 -0
- package/lib/import/test-fixtures/tiny-vault/notes/2026-01-15-team-sync.md +9 -0
- package/lib/import/test-fixtures/tiny-vault/notes/empty.md +3 -0
- package/lib/import/test-fixtures/tiny-vault/notes/onboarding.md +5 -0
- package/lib/import/test-fixtures/tiny-vault/notes/pricing.md +5 -0
- package/lib/import/test-fixtures/tiny-vault/notes/random.md +4 -0
- package/lib/import/undo.test.cjs +199 -0
- package/lib/import/vault-scanner.cjs +105 -0
- package/lib/import/vault-scanner.test.cjs +67 -0
- package/lib/mcp/app-html/dashboard.html +316 -0
- package/lib/mcp/app-html/graph.html +428 -0
- package/lib/mcp/app-html/mindrian-platform.html +1841 -0
- package/lib/mcp/app-html/wiki.html +383 -0
- package/lib/mcp/app-views.cjs +322 -0
- package/lib/mcp/brain-router.cjs +418 -0
- package/lib/mcp/capability-registry.cjs +62 -0
- package/lib/mcp/larry-context.cjs +46 -0
- package/lib/mcp/larry-server-instructions.md +114 -0
- package/lib/mcp/pipeline-state.cjs +275 -0
- package/lib/mcp/prompts.cjs +302 -0
- package/lib/mcp/resources.cjs +227 -0
- package/lib/mcp/session-catchup.cjs +327 -0
- package/lib/mcp/surface-detect.cjs +75 -0
- package/lib/mcp/tool-router.cjs +1034 -0
- package/lib/memory/aaak-compress.cjs +403 -0
- package/lib/memory/aaak-compress.test.cjs +288 -0
- package/lib/memory/async-artifact-auto-commit.test.cjs +223 -0
- package/lib/memory/bearer-token.test.cjs +315 -0
- package/lib/memory/brain-cache-lru.test.cjs +259 -0
- package/lib/memory/brain-client-query-shape.test.cjs +160 -0
- package/lib/memory/brain-derivation-graceful-degradation.test.cjs +1019 -0
- package/lib/memory/brain-derivation-queue.test.cjs +539 -0
- package/lib/memory/brain-derivation.test.cjs +634 -0
- package/lib/memory/brain-derive-command.test.cjs +534 -0
- package/lib/memory/brain-md-invariants-validator.test.cjs +704 -0
- package/lib/memory/brain-md-schema.test.cjs +467 -0
- package/lib/memory/brain-md-staleness.test.cjs +525 -0
- package/lib/memory/brain-server-resolution.test.cjs +314 -0
- package/lib/memory/chain-recommender.test.cjs +233 -0
- package/lib/memory/chat-context.test.cjs +128 -0
- package/lib/memory/command-registry.test.cjs +220 -0
- package/lib/memory/cross-room-aggregator.test.cjs +909 -0
- package/lib/memory/dashboard-server.test.cjs +256 -0
- package/lib/memory/debouncer-drain-at-prompt.test.cjs +389 -0
- package/lib/memory/decision-capture.test.cjs +632 -0
- package/lib/memory/decision-capture.worker.cjs +70 -0
- package/lib/memory/explain-decision-command.test.cjs +521 -0
- package/lib/memory/explain-decision-footer.test.cjs +316 -0
- package/lib/memory/explored-materials-store.cjs +392 -0
- package/lib/memory/feynman-minto-guardian.test.cjs +736 -0
- package/lib/memory/feynman-minto-invariants.test.cjs +511 -0
- package/lib/memory/feynman-prompts-drift.test.cjs +144 -0
- package/lib/memory/feynman-prompts.cjs +151 -0
- package/lib/memory/feynman-prompts.test.cjs +96 -0
- package/lib/memory/folder-memory-quadruple.test.cjs +548 -0
- package/lib/memory/folder-memory.test.cjs +503 -0
- package/lib/memory/framework-chain-composer.test.cjs +515 -0
- package/lib/memory/frontmatter-schema-validator.test.cjs +290 -0
- package/lib/memory/heal-command.test.cjs +604 -0
- package/lib/memory/index-artifact-transaction.test.cjs +333 -0
- package/lib/memory/lazygraph-rs-discoveries-view.test.cjs +122 -0
- package/lib/memory/mcp-input-validation.test.cjs +240 -0
- package/lib/memory/mcp-server-brain-deps.test.cjs +270 -0
- package/lib/memory/mcp-stack-fallback.test.cjs +433 -0
- package/lib/memory/minto-debouncer.test.cjs +407 -0
- package/lib/memory/minto-debouncer.worker.cjs +46 -0
- package/lib/memory/minto-migration-v88.test.cjs +265 -0
- package/lib/memory/minto-schema-v88.test.cjs +390 -0
- package/lib/memory/mos-status-renderer.test.cjs +631 -0
- package/lib/memory/narrative-schema.cjs +376 -0
- package/lib/memory/narrative-schema.test.cjs +209 -0
- package/lib/memory/nav-dial.test.cjs +414 -0
- package/lib/memory/navigation-engine-core.test.cjs +722 -0
- package/lib/memory/navigation-invariants.test.cjs +483 -0
- package/lib/memory/offer-presenter.test.cjs +554 -0
- package/lib/memory/on-stop-snapshot.test.cjs +404 -0
- package/lib/memory/pending-tension-store.cjs +373 -0
- package/lib/memory/post-compact-reinjection.test.cjs +854 -0
- package/lib/memory/post-write-triple.test.cjs +317 -0
- package/lib/memory/pre-compact-snapshot.test.cjs +495 -0
- package/lib/memory/problem-type-router.test.cjs +656 -0
- package/lib/memory/query-efficiency-telemetry.test.cjs +370 -0
- package/lib/memory/recompile-room-references.test.cjs +392 -0
- package/lib/memory/recompile-room-references.worker.cjs +42 -0
- package/lib/memory/record-decision-dual-write.test.cjs +454 -0
- package/lib/memory/room-classifier-strict-mode.test.cjs +417 -0
- package/lib/memory/room-minto-hook.test.cjs +398 -0
- package/lib/memory/rs-discovery-engine.test.cjs +323 -0
- package/lib/memory/run-feynman-tests.cjs +1247 -0
- package/lib/memory/security-trifecta.test.cjs +312 -0
- package/lib/memory/session-start-brain-staleness.test.cjs +363 -0
- package/lib/memory/session-start-triple-injection.test.cjs +514 -0
- package/lib/memory/sessionstart-banner-formatter.cjs +318 -0
- package/lib/memory/sessionstart-minto-banner.test.cjs +373 -0
- package/lib/memory/skill-activation-router.test.cjs +419 -0
- package/lib/memory/stamp-artifact-write.test.cjs +304 -0
- package/lib/memory/statusline-active-room.test.cjs +315 -0
- package/lib/memory/statusline-minto-segment.test.cjs +292 -0
- package/lib/memory/sync-async-entry-points.test.cjs +204 -0
- package/lib/memory/test-bridge-writer-enhanced.cjs +452 -0
- package/lib/memory/test-rs-brain-substrate-shape.cjs +529 -0
- package/lib/memory/test-rs-brain-substrate.cjs +636 -0
- package/lib/memory/test-rs-breakthrough-scorer.cjs +375 -0
- package/lib/memory/test-rs-canon-violations.cjs +218 -0
- package/lib/memory/test-rs-chain-feeder-core.cjs +344 -0
- package/lib/memory/test-rs-chain-feeder-skill-spawn.cjs +297 -0
- package/lib/memory/test-rs-commercial-assessor.cjs +385 -0
- package/lib/memory/test-rs-differential-scorer.cjs +480 -0
- package/lib/memory/test-rs-discovery-engine.cjs +603 -0
- package/lib/memory/test-rs-domain-analyzer.cjs +492 -0
- package/lib/memory/test-rs-egress-primitives.cjs +420 -0
- package/lib/memory/test-rs-expert-mapper.cjs +547 -0
- package/lib/memory/test-rs-explain-command.cjs +443 -0
- package/lib/memory/test-rs-fetcher-academic.cjs +848 -0
- package/lib/memory/test-rs-fetcher-experts.cjs +496 -0
- package/lib/memory/test-rs-fetcher-industry.cjs +702 -0
- package/lib/memory/test-rs-fetcher-patents.cjs +674 -0
- package/lib/memory/test-rs-innovation-classifier.cjs +301 -0
- package/lib/memory/test-rs-mind-map.cjs +646 -0
- package/lib/memory/test-rs-neo4j-writer.cjs +518 -0
- package/lib/memory/test-rs-nl-to-query.cjs +449 -0
- package/lib/memory/test-rs-pinecone-bridge.cjs +277 -0
- package/lib/memory/test-rs-preprocessor.cjs +433 -0
- package/lib/memory/test-rs-query-matrix.cjs +391 -0
- package/lib/memory/test-rs-query-to-text.cjs +551 -0
- package/lib/memory/test-rs-sqlite-mirror.cjs +649 -0
- package/lib/memory/test-rs-thesis-generator.cjs +360 -0
- package/lib/memory/triple-context-formatter.cjs +473 -0
- package/lib/memory/triple-context-formatter.test.cjs +442 -0
- package/lib/memory/user-md-persona.test.cjs +565 -0
- package/lib/memory/userpromptsubmit-integration.test.cjs +690 -0
- package/lib/memory/validators/README.md +157 -0
- package/lib/memory/validators/brain-md-invariants.cjs +475 -0
- package/lib/memory/validators/brain-substrate-invariants.cjs +285 -0
- package/lib/memory/validators/external-academic-invariants.cjs +249 -0
- package/lib/memory/validators/external-industry-invariants.cjs +271 -0
- package/lib/memory/validators/external-patents-invariants.cjs +266 -0
- package/lib/memory/validators/minto-invariants.cjs +62 -0
- package/lib/memory/validators/navigation-invariants.cjs +340 -0
- package/lib/memory/validators/queue-health.cjs +95 -0
- package/lib/memory/validators/snapshot-integrity.cjs +129 -0
- package/lib/memory/validators/stale-lifecycle.cjs +116 -0
- package/lib/memory/vault-section-minto-generator-atomic.test.cjs +556 -0
- package/lib/memory/vault-section-minto-generator-atomic.worker.cjs +73 -0
- package/lib/memory/write-lock-atomic.test.cjs +137 -0
- package/lib/memory/write-lock-atomic.worker.cjs +55 -0
- package/lib/parity/check-parity.cjs +83 -0
- package/lib/presentation/presentation-server.cjs +101 -0
- package/lib/presentation/presentation-watcher.cjs +123 -0
- package/lib/quickview/hub-server.cjs +719 -0
- package/lib/quickview/server.cjs +533 -0
- package/lib/render/JTBD-PALETTES.md +145 -0
- package/lib/render/ROOM.md +59 -0
- package/lib/render/render-v2.cjs +486 -0
- package/lib/render/render-v2.test.cjs +267 -0
- package/lib/render/render.cjs +65 -0
- package/lib/state/ROOM.md +46 -0
- package/lib/state/state-md-parser.cjs +215 -0
- package/lib/statusline/ROOM.md +38 -0
- package/lib/statusline/banner-suppression.cjs +50 -0
- package/lib/statusline/surface-detect.cjs +85 -0
- package/lib/update-bootstrap.sh.template +145 -0
- package/lib/vault/frontmatter-schema.cjs +297 -0
- package/lib/vault/room-scanner.cjs +352 -0
- package/lib/vault/wikilink-builder.cjs +231 -0
- package/lib/vault/wikilink-builder.test.cjs +182 -0
- package/lib/wiki/graph-links.cjs +281 -0
- package/lib/wiki/page-renderer.cjs +229 -0
- package/lib/wiki/wiki-chat.cjs +81 -0
- package/lib/wiki/wiki-layout.cjs +1459 -0
- package/lib/wiki/wiki-search.cjs +142 -0
- package/lib/wiki/wiki-server.cjs +678 -0
- package/lib/wiki/wiki-watcher.cjs +105 -0
- package/lib/workflow/ROOM.md +47 -0
- package/lib/workflow/command-resolver.cjs +155 -0
- package/lib/workflow/command-resolver.test.cjs +235 -0
- package/package.json +44 -0
- package/pipelines/analogy/01-decompose.md +80 -0
- package/pipelines/analogy/02-abstract.md +87 -0
- package/pipelines/analogy/03-search.md +135 -0
- package/pipelines/analogy/04-transfer.md +101 -0
- package/pipelines/analogy/05-validate.md +106 -0
- package/pipelines/analogy/CHAIN.md +56 -0
- package/pipelines/discovery/01-explore-domains.md +44 -0
- package/pipelines/discovery/02-think-hats.md +50 -0
- package/pipelines/discovery/03-analyze-needs.md +54 -0
- package/pipelines/discovery/CHAIN.md +37 -0
- package/pipelines/thesis/01-structure-argument.md +45 -0
- package/pipelines/thesis/02-challenge-assumptions.md +48 -0
- package/pipelines/thesis/03-build-thesis.md +54 -0
- package/pipelines/thesis/CHAIN.md +37 -0
- package/references/brain/causal-directives.md +91 -0
- package/references/brain/causal-enrichment.cypher +165 -0
- package/references/brain/command-triggers-schema.md +226 -0
- package/references/brain/graph-architecture.md +317 -0
- package/references/brain/query-patterns.md +460 -0
- package/references/brain/room-hierarchy-schema.md +218 -0
- package/references/brain/schema.md +76 -0
- package/references/capability-radar/capabilities-index.md +241 -0
- package/references/capability-radar/changelog-cache.md +81 -0
- package/references/causal/causal-schema.md +103 -0
- package/references/design/email-template-standard.md +155 -0
- package/references/design/graph-visualization-standard.md +178 -0
- package/references/document-generation.md +179 -0
- package/references/hsi/HSI-TOOLS-REFERENCE.md +222 -0
- package/references/import-config.md +141 -0
- package/references/integrations/detection-patterns.md +101 -0
- package/references/meeting/artifact-template.md +377 -0
- package/references/meeting/cross-meeting-intelligence.md +216 -0
- package/references/meeting/cross-relationship-patterns.md +202 -0
- package/references/meeting/live-join-interface.md +244 -0
- package/references/meeting/section-mapping.md +192 -0
- package/references/meeting/segment-classification.md +258 -0
- package/references/meeting/speaker-profile-template.md +219 -0
- package/references/meeting/summary-template.md +348 -0
- package/references/meeting/transcript-patterns.md +226 -0
- package/references/methodology/analyze-needs.md +135 -0
- package/references/methodology/analyze-systems.md +121 -0
- package/references/methodology/analyze-timing.md +149 -0
- package/references/methodology/beautiful-question.md +109 -0
- package/references/methodology/build-knowledge.md +161 -0
- package/references/methodology/build-thesis.md +237 -0
- package/references/methodology/challenge-assumptions.md +127 -0
- package/references/methodology/diagnose.md +169 -0
- package/references/methodology/dominant-designs.md +212 -0
- package/references/methodology/explore-domains.md +147 -0
- package/references/methodology/explore-futures.md +163 -0
- package/references/methodology/explore-trends.md +129 -0
- package/references/methodology/find-bottlenecks.md +131 -0
- package/references/methodology/grade.md +211 -0
- package/references/methodology/index.md +97 -0
- package/references/methodology/leadership.md +200 -0
- package/references/methodology/lean-canvas.md +116 -0
- package/references/methodology/macro-trends.md +192 -0
- package/references/methodology/map-unknowns.md +137 -0
- package/references/methodology/mullins-7-domains.md +104 -0
- package/references/methodology/problem-types.md +65 -0
- package/references/methodology/root-cause.md +178 -0
- package/references/methodology/sapphire-encoding.md +355 -0
- package/references/methodology/scenario-plan.md +178 -0
- package/references/methodology/score-innovation.md +154 -0
- package/references/methodology/structure-argument.md +158 -0
- package/references/methodology/systems-thinking.md +159 -0
- package/references/methodology/think-hats.md +147 -0
- package/references/methodology/triz-matrix.json +751 -0
- package/references/methodology/triz-principles.md +501 -0
- package/references/methodology/user-needs.md +199 -0
- package/references/methodology/validate.md +163 -0
- package/references/methodology/value-proposition.md +244 -0
- package/references/opportunities/funding-lifecycle.md +103 -0
- package/references/opportunities/grant-api-patterns.md +99 -0
- package/references/opportunities/opportunity-template.md +84 -0
- package/references/personality/assessment-philosophy.md +72 -0
- package/references/personality/lexicon.md +100 -0
- package/references/personality/persona-chains.md +56 -0
- package/references/personality/pws-lexicon-full.md +499 -0
- package/references/personality/voice-dna.md +156 -0
- package/references/personas/hat-perspectives.md +76 -0
- package/references/personas/persona-template.md +63 -0
- package/references/pipeline/act-output-contract.md +88 -0
- package/references/pipeline/chains-index.md +39 -0
- package/references/pws-profile-generation.md +79 -0
- package/references/reasoning/reasoning-schema.md +143 -0
- package/references/reasoning/reasoning-template.md +68 -0
- package/references/reasoning/run-template.md +38 -0
- package/references/research/RESEARCH_14_CLAUDE_CODE_SOURCE_ARCHITECTURE.md +209 -0
- package/references/research/RESEARCH_15_V1.8_OPTIMIZATION_JTBD.md +375 -0
- package/references/research/RESEARCH_16_NATIVE_FIRST_PLUGIN_ARCHITECTURE.md +575 -0
- package/references/research/RESEARCH_17_MCP_UI_FRAMEWORKS.md +272 -0
- package/references/taxonomy/TAXONOMY.md +192 -0
- package/references/templates/MINTO.md +36 -0
- package/references/user-research/2026-04-05-leah-lawrence-session.md +202 -0
- package/references/vault-kit/README.md +35 -0
- package/references/vault-kit/app.json +12 -0
- package/references/vault-kit/appearance.json +12 -0
- package/references/vault-kit/graph.json +35 -0
- package/references/vault-kit/snippets/mindrian-destijl.css +297 -0
- package/references/vault-kit/templates/new-artifact.md +37 -0
- package/references/vault-kit/templates/new-meeting-note.md +35 -0
- package/references/vault-kit/templates/new-team-profile.md +29 -0
- package/references/vault-kit/templates/new-xref.md +35 -0
- package/references/visual/symbol-system.md +151 -0
- package/skills/MOSDeckEngine/SKILL.md +325 -0
- package/skills/brain-connector/SKILL.md +114 -0
- package/skills/context-engine/SKILL.md +147 -0
- package/skills/conversation-mode/SKILL.md +102 -0
- package/skills/larry-personality/SKILL.md +219 -0
- package/skills/larry-personality/framework-chains.md +92 -0
- package/skills/larry-personality/mode-engine.md +185 -0
- package/skills/mullins-scaffold/SKILL.md +61 -0
- package/skills/mullins-scaffold/scaffold.json +146 -0
- package/skills/pws-methodology/SKILL.md +49 -0
- package/skills/room-passive/SKILL.md +165 -0
- package/skills/room-proactive/SKILL.md +250 -0
- package/skills/ui-system/SKILL.md +277 -0
|
@@ -0,0 +1,656 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2026 Mindrian. BSL 1.1.
|
|
3
|
+
* Phase 89.3 Plan 03 -- 5-branch Cytoscape mind-map generator.
|
|
4
|
+
*
|
|
5
|
+
* renderMindMap(query_filter, opts) is the read-side companion to the
|
|
6
|
+
* dual-tier writers (rs-neo4j-writer.cjs Plan 89.3-01 and
|
|
7
|
+
* rs-sqlite-mirror.cjs Plan 89.3-02). It reads from the active tier
|
|
8
|
+
* (Aura via opts.driver OR room.db via opts.roomDir) and emits a
|
|
9
|
+
* Cytoscape-compatible JSON payload split into 5 branches PLUS a
|
|
10
|
+
* standalone HTML wrapper.
|
|
11
|
+
*
|
|
12
|
+
* The 5 branches (per kickoff section 5):
|
|
13
|
+
* 1. Direct Intersections lsa > 0.6 AND bert > 0.6
|
|
14
|
+
* 2. Structural Transfer classification = structural_transfer
|
|
15
|
+
* 3. Semantic Implementation classification = semantic_implementation
|
|
16
|
+
* 4. Discovered RS ReverseSalient nodes
|
|
17
|
+
* 5. Innovation Ecosystem Innovation + Paper + Author + Institution slice
|
|
18
|
+
*
|
|
19
|
+
* Tier dispatch is transparent. Caller passes opts.tier explicitly OR
|
|
20
|
+
* the module auto-detects: if opts.driver looks like a neo4j-driver
|
|
21
|
+
* Driver, use Aura; if opts.roomDir is a string, use SQLite. If neither
|
|
22
|
+
* is provided, throws TypeError with a clear message so the caller
|
|
23
|
+
* can fix the call site.
|
|
24
|
+
*
|
|
25
|
+
* Canon Part 7 (Reuse Before Build):
|
|
26
|
+
* - Reuses lazygraph.openGraph + closeGraph (no new SQLite wrapper)
|
|
27
|
+
* - Reuses dashboard/index.html cytoscape@3.33.1 CDN URL byte-for-byte
|
|
28
|
+
* (NO new runtime dependency; no build step)
|
|
29
|
+
* - Shares ExternalEgressViolation + auditQueryObject with 89.2 fetchers
|
|
30
|
+
*
|
|
31
|
+
* Canon Part 8 (Graph Boundary -- defense-in-depth on the DISPLAY surface):
|
|
32
|
+
* the data source is trusted (user's OWN graph), but the rendered HTML
|
|
33
|
+
* wrapper may be shared, exported to the dashboard, or cached. Therefore
|
|
34
|
+
* auditQueryObject scans the FINAL HTML before return; on any
|
|
35
|
+
* FORBIDDEN_PATTERNS hit it throws ExternalEgressViolation with
|
|
36
|
+
* meta.surface = 'rs-mind-map-html' so the caller knows precisely which
|
|
37
|
+
* surface tripped the guard. Result is NEVER returned on audit failure.
|
|
38
|
+
*
|
|
39
|
+
* Pure CJS, zero npm deps, node built-ins only (no fetch, no http).
|
|
40
|
+
*/
|
|
41
|
+
'use strict';
|
|
42
|
+
|
|
43
|
+
const { ExternalEgressViolation } = require('./rs-egress-violations.cjs');
|
|
44
|
+
const { auditQueryObject } = require('./rs-egress-prompts.cjs');
|
|
45
|
+
const lazygraph = require('./lazygraph-ops.cjs');
|
|
46
|
+
|
|
47
|
+
const SURFACE = 'rs-mind-map-html';
|
|
48
|
+
const SCHEMA_VERSION = '1.0';
|
|
49
|
+
|
|
50
|
+
// The 5 canonical branches (kickoff section 5). Frozen so callers cannot
|
|
51
|
+
// mutate the canonical list and downstream renderers can rely on the
|
|
52
|
+
// fixed key set.
|
|
53
|
+
const BRANCHES = Object.freeze([
|
|
54
|
+
'Direct Intersections',
|
|
55
|
+
'Structural Transfer',
|
|
56
|
+
'Semantic Implementation',
|
|
57
|
+
'Discovered RS',
|
|
58
|
+
'Innovation Ecosystem',
|
|
59
|
+
]);
|
|
60
|
+
|
|
61
|
+
// De Stijl-derived per-branch colors. Frozen for the same reason as
|
|
62
|
+
// BRANCHES. The HTML wrapper emits these as inline styles in the
|
|
63
|
+
// legend block; the Cytoscape style block also references them via
|
|
64
|
+
// node-data lookup at render time.
|
|
65
|
+
const BRANCH_COLORS = Object.freeze({
|
|
66
|
+
'Direct Intersections': '#ff0000',
|
|
67
|
+
'Structural Transfer': '#0000ff',
|
|
68
|
+
'Semantic Implementation': '#999933',
|
|
69
|
+
'Discovered RS': '#000000',
|
|
70
|
+
'Innovation Ecosystem': '#666666',
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Cytoscape CDN URL: byte-identical to dashboard/index.html line 22.
|
|
74
|
+
// Canon Part 7 reuse: do NOT bump this version independently of the
|
|
75
|
+
// dashboard. If/when the dashboard upgrades, this constant moves with it.
|
|
76
|
+
const CYTOSCAPE_CDN_URL = 'https://unpkg.com/cytoscape@3.33.1/dist/cytoscape.min.js';
|
|
77
|
+
|
|
78
|
+
// ---------- detectTier ----------
|
|
79
|
+
//
|
|
80
|
+
// Resolution order:
|
|
81
|
+
// 1. opts.tier explicit ('aura' or 'sqlite') -- caller wins
|
|
82
|
+
// 2. opts.driver with .session function -- Tier 1 (Aura)
|
|
83
|
+
// 3. opts.roomDir string -- Tier 0 (SQLite)
|
|
84
|
+
// 4. nothing -- TypeError (fail loud, fail early)
|
|
85
|
+
|
|
86
|
+
async function detectTier(opts) {
|
|
87
|
+
if (opts && (opts.tier === 'aura' || opts.tier === 'sqlite')) return opts.tier;
|
|
88
|
+
if (opts && opts.driver && typeof opts.driver.session === 'function') return 'aura';
|
|
89
|
+
if (opts && typeof opts.roomDir === 'string' && opts.roomDir.length > 0) return 'sqlite';
|
|
90
|
+
throw new TypeError(
|
|
91
|
+
'rs-mind-map: opts.tier OR opts.driver OR opts.roomDir required'
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ---------- safeJsonParse ----------
|
|
96
|
+
//
|
|
97
|
+
// Defensive: SQLite properties column is JSON-stringified. Bad JSON
|
|
98
|
+
// (corrupted row, manual SQL edit) returns an empty object so the
|
|
99
|
+
// renderer keeps moving. We never throw on malformed JSON because that
|
|
100
|
+
// would make ONE corrupted row block the entire mind map.
|
|
101
|
+
|
|
102
|
+
function safeJsonParse(s) {
|
|
103
|
+
if (typeof s !== 'string' || s.length === 0) return {};
|
|
104
|
+
try { return JSON.parse(s); } catch (_e) { return {}; }
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ---------- buildLabel ----------
|
|
108
|
+
//
|
|
109
|
+
// Cytoscape nodes need a human-readable label. Falls back gracefully
|
|
110
|
+
// through several property paths because different node types carry
|
|
111
|
+
// the human-friendly name in different fields.
|
|
112
|
+
|
|
113
|
+
function buildLabel(props, type) {
|
|
114
|
+
if (!props || typeof props !== 'object') return type || 'node';
|
|
115
|
+
if (typeof props.title === 'string' && props.title.length > 0) return props.title;
|
|
116
|
+
if (typeof props.name === 'string' && props.name.length > 0) return props.name;
|
|
117
|
+
if (typeof props.thesis === 'string' && props.thesis.length > 0) {
|
|
118
|
+
return props.thesis.slice(0, 60);
|
|
119
|
+
}
|
|
120
|
+
if (typeof props.query_concept === 'string' && props.query_concept.length > 0) {
|
|
121
|
+
return props.query_concept;
|
|
122
|
+
}
|
|
123
|
+
return type || 'node';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ---------- toCytoscapeNode ----------
|
|
127
|
+
//
|
|
128
|
+
// Convert a (id, type, properties, branch) tuple into the Cytoscape
|
|
129
|
+
// elements format: { data: { id, label, type, branch } }. Properties
|
|
130
|
+
// are NOT spread into data (only label + type + branch + id) because
|
|
131
|
+
// the rendered HTML must not echo arbitrary user content into the
|
|
132
|
+
// node data block; the audit later catches any leak that does sneak
|
|
133
|
+
// through, but minimizing the surface is defense-in-depth design.
|
|
134
|
+
|
|
135
|
+
function toCytoscapeNode(id, type, properties, branch) {
|
|
136
|
+
return {
|
|
137
|
+
data: {
|
|
138
|
+
id: id,
|
|
139
|
+
label: buildLabel(properties, type),
|
|
140
|
+
type: type,
|
|
141
|
+
branch: branch,
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function toCytoscapeEdge(id, source, target, type, branch) {
|
|
147
|
+
return {
|
|
148
|
+
data: {
|
|
149
|
+
id: id,
|
|
150
|
+
source: source,
|
|
151
|
+
target: target,
|
|
152
|
+
label: type,
|
|
153
|
+
branch: branch,
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// ---------- readSqliteBranches ----------
|
|
159
|
+
//
|
|
160
|
+
// Tier 0 read path. Opens the room.db via lazygraph.openGraph and runs
|
|
161
|
+
// 5 SELECT queries -- one per branch. Returns:
|
|
162
|
+
// { branches: { '...': {nodes, edges}, ... }, total_nodes, total_edges }
|
|
163
|
+
//
|
|
164
|
+
// The branches map carries Cytoscape-formatted nodes + edges per
|
|
165
|
+
// branch (renderMindMap wraps the unified result later).
|
|
166
|
+
|
|
167
|
+
async function readSqliteBranches(roomDir, queryFilter) {
|
|
168
|
+
const handle = await lazygraph.openGraph(roomDir);
|
|
169
|
+
const conn = handle.conn;
|
|
170
|
+
const branches = {
|
|
171
|
+
'Direct Intersections': { nodes: [], edges: [] },
|
|
172
|
+
'Structural Transfer': { nodes: [], edges: [] },
|
|
173
|
+
'Semantic Implementation': { nodes: [], edges: [] },
|
|
174
|
+
'Discovered RS': { nodes: [], edges: [] },
|
|
175
|
+
'Innovation Ecosystem': { nodes: [], edges: [] },
|
|
176
|
+
};
|
|
177
|
+
let total_nodes = 0;
|
|
178
|
+
let total_edges = 0;
|
|
179
|
+
|
|
180
|
+
try {
|
|
181
|
+
// Branch 1: Direct Intersections (lsa > 0.6 AND bert > 0.6)
|
|
182
|
+
if (shouldEmitBranch('Direct Intersections', queryFilter)) {
|
|
183
|
+
const rows = conn.prepare(
|
|
184
|
+
'SELECT id, type, properties FROM nodes ' +
|
|
185
|
+
'WHERE type = ? ' +
|
|
186
|
+
'AND CAST(json_extract(properties, ?) AS REAL) > 0.6 ' +
|
|
187
|
+
'AND CAST(json_extract(properties, ?) AS REAL) > 0.6'
|
|
188
|
+
).all('RSDiscovery', '$.lsa', '$.bert');
|
|
189
|
+
for (const r of rows) {
|
|
190
|
+
const props = safeJsonParse(r.properties);
|
|
191
|
+
branches['Direct Intersections'].nodes.push(
|
|
192
|
+
toCytoscapeNode(r.id, r.type, props, 'Direct Intersections')
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Branch 2: Structural Transfer
|
|
198
|
+
if (shouldEmitBranch('Structural Transfer', queryFilter)) {
|
|
199
|
+
const rows = conn.prepare(
|
|
200
|
+
'SELECT id, type, properties FROM nodes ' +
|
|
201
|
+
'WHERE type = ? ' +
|
|
202
|
+
'AND json_extract(properties, ?) = ?'
|
|
203
|
+
).all('RSDiscovery', '$.classification', 'structural_transfer');
|
|
204
|
+
for (const r of rows) {
|
|
205
|
+
const props = safeJsonParse(r.properties);
|
|
206
|
+
branches['Structural Transfer'].nodes.push(
|
|
207
|
+
toCytoscapeNode(r.id, r.type, props, 'Structural Transfer')
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Branch 3: Semantic Implementation
|
|
213
|
+
if (shouldEmitBranch('Semantic Implementation', queryFilter)) {
|
|
214
|
+
const rows = conn.prepare(
|
|
215
|
+
'SELECT id, type, properties FROM nodes ' +
|
|
216
|
+
'WHERE type = ? ' +
|
|
217
|
+
'AND json_extract(properties, ?) = ?'
|
|
218
|
+
).all('RSDiscovery', '$.classification', 'semantic_implementation');
|
|
219
|
+
for (const r of rows) {
|
|
220
|
+
const props = safeJsonParse(r.properties);
|
|
221
|
+
branches['Semantic Implementation'].nodes.push(
|
|
222
|
+
toCytoscapeNode(r.id, r.type, props, 'Semantic Implementation')
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Branch 4: Discovered RS (ReverseSalient nodes)
|
|
228
|
+
if (shouldEmitBranch('Discovered RS', queryFilter)) {
|
|
229
|
+
const rows = conn.prepare(
|
|
230
|
+
'SELECT id, type, properties FROM nodes WHERE type = ?'
|
|
231
|
+
).all('ReverseSalient');
|
|
232
|
+
for (const r of rows) {
|
|
233
|
+
const props = safeJsonParse(r.properties);
|
|
234
|
+
branches['Discovered RS'].nodes.push(
|
|
235
|
+
toCytoscapeNode(r.id, r.type, props, 'Discovered RS')
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Branch 5: Innovation Ecosystem (Innovation + Paper + Author + Institution)
|
|
241
|
+
if (shouldEmitBranch('Innovation Ecosystem', queryFilter)) {
|
|
242
|
+
const ECO_TYPES = ['Innovation', 'Paper', 'Author', 'Institution'];
|
|
243
|
+
const placeholders = ECO_TYPES.map(function () { return '?'; }).join(',');
|
|
244
|
+
const rows = conn.prepare(
|
|
245
|
+
'SELECT id, type, properties FROM nodes WHERE type IN (' + placeholders + ')'
|
|
246
|
+
).all.apply(conn.prepare(
|
|
247
|
+
'SELECT id, type, properties FROM nodes WHERE type IN (' + placeholders + ')'
|
|
248
|
+
), ECO_TYPES);
|
|
249
|
+
for (const r of rows) {
|
|
250
|
+
const props = safeJsonParse(r.properties);
|
|
251
|
+
branches['Innovation Ecosystem'].nodes.push(
|
|
252
|
+
toCytoscapeNode(r.id, r.type, props, 'Innovation Ecosystem')
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
// Edges within the ecosystem.
|
|
256
|
+
const ECO_EDGE_TYPES = ['DERIVED_FROM', 'AUTHORED_BY', 'AFFILIATED_WITH', 'ENABLES'];
|
|
257
|
+
const edgePlaceholders = ECO_EDGE_TYPES.map(function () { return '?'; }).join(',');
|
|
258
|
+
const edgeRows = conn.prepare(
|
|
259
|
+
'SELECT source, target, type, properties FROM edges WHERE type IN (' + edgePlaceholders + ')'
|
|
260
|
+
).all.apply(conn.prepare(
|
|
261
|
+
'SELECT source, target, type, properties FROM edges WHERE type IN (' + edgePlaceholders + ')'
|
|
262
|
+
), ECO_EDGE_TYPES);
|
|
263
|
+
for (const r of edgeRows) {
|
|
264
|
+
branches['Innovation Ecosystem'].edges.push(
|
|
265
|
+
toCytoscapeEdge(
|
|
266
|
+
r.source + '__' + r.type + '__' + r.target,
|
|
267
|
+
r.source, r.target, r.type, 'Innovation Ecosystem'
|
|
268
|
+
)
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Compute total_nodes + total_edges from the FULL graph (for
|
|
274
|
+
// metadata; not branch-filtered because metadata reflects the
|
|
275
|
+
// raw graph state).
|
|
276
|
+
total_nodes = conn.prepare('SELECT COUNT(*) AS n FROM nodes').get().n;
|
|
277
|
+
total_edges = conn.prepare('SELECT COUNT(*) AS n FROM edges').get().n;
|
|
278
|
+
} finally {
|
|
279
|
+
try { await lazygraph.closeGraph(handle.db); } catch (_e) { /* best effort */ }
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return { branches: branches, total_nodes: total_nodes, total_edges: total_edges };
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// ---------- readAuraBranches ----------
|
|
286
|
+
//
|
|
287
|
+
// Tier 1 read path. Opens an Aura session via opts.driver and runs 5
|
|
288
|
+
// Cypher MATCH queries -- one per branch. The neo4j-driver Result has
|
|
289
|
+
// .records[] where each record exposes .get(name) returning the matched
|
|
290
|
+
// node (which itself has .properties, .labels, .identity).
|
|
291
|
+
//
|
|
292
|
+
// Multi-hop traversal is reserved for the Innovation Ecosystem branch
|
|
293
|
+
// because that is where the cross-table value concentrates (per kickoff
|
|
294
|
+
// section 5).
|
|
295
|
+
|
|
296
|
+
async function readAuraBranches(driver, queryFilter) {
|
|
297
|
+
const session = driver.session();
|
|
298
|
+
const branches = {
|
|
299
|
+
'Direct Intersections': { nodes: [], edges: [] },
|
|
300
|
+
'Structural Transfer': { nodes: [], edges: [] },
|
|
301
|
+
'Semantic Implementation': { nodes: [], edges: [] },
|
|
302
|
+
'Discovered RS': { nodes: [], edges: [] },
|
|
303
|
+
'Innovation Ecosystem': { nodes: [], edges: [] },
|
|
304
|
+
};
|
|
305
|
+
let total_nodes = 0;
|
|
306
|
+
let total_edges = 0;
|
|
307
|
+
|
|
308
|
+
try {
|
|
309
|
+
// Branch 1: Direct Intersections
|
|
310
|
+
if (shouldEmitBranch('Direct Intersections', queryFilter)) {
|
|
311
|
+
const r = await session.run(
|
|
312
|
+
'MATCH (d:RSDiscovery) WHERE d.lsa > 0.6 AND d.bert > 0.6 RETURN d'
|
|
313
|
+
);
|
|
314
|
+
for (const rec of r.records || []) {
|
|
315
|
+
const node = rec.get('d');
|
|
316
|
+
const id = recordNodeId(node, rec);
|
|
317
|
+
const props = (node && node.properties) || {};
|
|
318
|
+
branches['Direct Intersections'].nodes.push(
|
|
319
|
+
toCytoscapeNode(id, 'RSDiscovery', props, 'Direct Intersections')
|
|
320
|
+
);
|
|
321
|
+
total_nodes += 1;
|
|
322
|
+
}
|
|
323
|
+
} else {
|
|
324
|
+
// Still call run so the dispatch counter matches the 5-branch contract.
|
|
325
|
+
await session.run('MATCH (d:RSDiscovery) WHERE false RETURN d');
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Branch 2: Structural Transfer
|
|
329
|
+
if (shouldEmitBranch('Structural Transfer', queryFilter)) {
|
|
330
|
+
const r = await session.run(
|
|
331
|
+
'MATCH (d:RSDiscovery) WHERE d.classification = "structural_transfer" RETURN d'
|
|
332
|
+
);
|
|
333
|
+
for (const rec of r.records || []) {
|
|
334
|
+
const node = rec.get('d');
|
|
335
|
+
const id = recordNodeId(node, rec);
|
|
336
|
+
const props = (node && node.properties) || {};
|
|
337
|
+
branches['Structural Transfer'].nodes.push(
|
|
338
|
+
toCytoscapeNode(id, 'RSDiscovery', props, 'Structural Transfer')
|
|
339
|
+
);
|
|
340
|
+
total_nodes += 1;
|
|
341
|
+
}
|
|
342
|
+
} else {
|
|
343
|
+
await session.run('MATCH (d:RSDiscovery) WHERE false RETURN d');
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Branch 3: Semantic Implementation
|
|
347
|
+
if (shouldEmitBranch('Semantic Implementation', queryFilter)) {
|
|
348
|
+
const r = await session.run(
|
|
349
|
+
'MATCH (d:RSDiscovery) WHERE d.classification = "semantic_implementation" RETURN d'
|
|
350
|
+
);
|
|
351
|
+
for (const rec of r.records || []) {
|
|
352
|
+
const node = rec.get('d');
|
|
353
|
+
const id = recordNodeId(node, rec);
|
|
354
|
+
const props = (node && node.properties) || {};
|
|
355
|
+
branches['Semantic Implementation'].nodes.push(
|
|
356
|
+
toCytoscapeNode(id, 'RSDiscovery', props, 'Semantic Implementation')
|
|
357
|
+
);
|
|
358
|
+
total_nodes += 1;
|
|
359
|
+
}
|
|
360
|
+
} else {
|
|
361
|
+
await session.run('MATCH (d:RSDiscovery) WHERE false RETURN d');
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// Branch 4: Discovered RS
|
|
365
|
+
if (shouldEmitBranch('Discovered RS', queryFilter)) {
|
|
366
|
+
const r = await session.run('MATCH (rs:ReverseSalient) RETURN rs');
|
|
367
|
+
for (const rec of r.records || []) {
|
|
368
|
+
const node = rec.get('rs');
|
|
369
|
+
const id = recordNodeId(node, rec);
|
|
370
|
+
const props = (node && node.properties) || {};
|
|
371
|
+
branches['Discovered RS'].nodes.push(
|
|
372
|
+
toCytoscapeNode(id, 'ReverseSalient', props, 'Discovered RS')
|
|
373
|
+
);
|
|
374
|
+
total_nodes += 1;
|
|
375
|
+
}
|
|
376
|
+
} else {
|
|
377
|
+
await session.run('MATCH (rs:ReverseSalient) WHERE false RETURN rs');
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// Branch 5: Innovation Ecosystem (multi-hop where Aura adds value).
|
|
381
|
+
// Real Aura multi-hop queries return the same node many times across
|
|
382
|
+
// rows (one row per traversal path); we dedupe by id within this
|
|
383
|
+
// branch so the Cytoscape elements array stays unique. dedupeAndCombine
|
|
384
|
+
// dedupes across branches but the per-branch nodes[] is what callers
|
|
385
|
+
// commonly read directly, so the dedup must happen here too.
|
|
386
|
+
if (shouldEmitBranch('Innovation Ecosystem', queryFilter)) {
|
|
387
|
+
const r = await session.run(
|
|
388
|
+
'MATCH (i:Innovation) ' +
|
|
389
|
+
'OPTIONAL MATCH (i)<-[:ENABLES]-(d:RSDiscovery)-[:DERIVED_FROM]->(p:Paper)-[:AUTHORED_BY]->(a:Author)-[:AFFILIATED_WITH]->(inst:Institution) ' +
|
|
390
|
+
'RETURN i, p, a, inst'
|
|
391
|
+
);
|
|
392
|
+
const seen = new Set();
|
|
393
|
+
for (const rec of r.records || []) {
|
|
394
|
+
for (const key of ['i', 'p', 'a', 'inst']) {
|
|
395
|
+
let node;
|
|
396
|
+
try { node = rec.get(key); } catch (_e) { node = null; }
|
|
397
|
+
if (!node) continue;
|
|
398
|
+
const id = recordNodeId(node, rec);
|
|
399
|
+
if (seen.has(id)) continue;
|
|
400
|
+
seen.add(id);
|
|
401
|
+
const labels = (node.labels && node.labels.length > 0) ? node.labels : [keyToLabel(key)];
|
|
402
|
+
const type = labels[0];
|
|
403
|
+
const props = (node && node.properties) || {};
|
|
404
|
+
branches['Innovation Ecosystem'].nodes.push(
|
|
405
|
+
toCytoscapeNode(id, type, props, 'Innovation Ecosystem')
|
|
406
|
+
);
|
|
407
|
+
total_nodes += 1;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
} else {
|
|
411
|
+
await session.run('MATCH (i:Innovation) WHERE false RETURN i');
|
|
412
|
+
}
|
|
413
|
+
} finally {
|
|
414
|
+
try { await session.close(); } catch (_e) { /* best effort */ }
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
return { branches: branches, total_nodes: total_nodes, total_edges: total_edges };
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
function keyToLabel(key) {
|
|
421
|
+
if (key === 'i') return 'Innovation';
|
|
422
|
+
if (key === 'p') return 'Paper';
|
|
423
|
+
if (key === 'a') return 'Author';
|
|
424
|
+
if (key === 'inst') return 'Institution';
|
|
425
|
+
if (key === 'd') return 'RSDiscovery';
|
|
426
|
+
if (key === 'rs') return 'ReverseSalient';
|
|
427
|
+
return 'Unknown';
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
function recordNodeId(node, rec) {
|
|
431
|
+
if (node && node.identity && typeof node.identity.low === 'number') {
|
|
432
|
+
return 'aura-' + node.identity.low;
|
|
433
|
+
}
|
|
434
|
+
if (node && node.properties && typeof node.properties.id === 'string') {
|
|
435
|
+
return node.properties.id;
|
|
436
|
+
}
|
|
437
|
+
return 'aura-unknown-' + Math.floor(Math.random() * 1e6);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// ---------- shouldEmitBranch ----------
|
|
441
|
+
//
|
|
442
|
+
// query_filter.branch (string) limits the output to a single branch.
|
|
443
|
+
// All other branches return empty arrays. Absence of branch filter
|
|
444
|
+
// means emit all 5.
|
|
445
|
+
|
|
446
|
+
function shouldEmitBranch(branch, queryFilter) {
|
|
447
|
+
if (!queryFilter || typeof queryFilter !== 'object') return true;
|
|
448
|
+
if (typeof queryFilter.branch !== 'string' || queryFilter.branch.length === 0) return true;
|
|
449
|
+
return queryFilter.branch === branch;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// ---------- dedupeAndCombine ----------
|
|
453
|
+
//
|
|
454
|
+
// Flatten the 5 branches into a single elements.{nodes, edges}
|
|
455
|
+
// object, deduping by id. Cytoscape requires unique element ids;
|
|
456
|
+
// the same node may appear in more than one branch (for example a
|
|
457
|
+
// hybrid-classified RSDiscovery that crosses thresholds), so dedup
|
|
458
|
+
// is required.
|
|
459
|
+
|
|
460
|
+
function dedupeAndCombine(branches) {
|
|
461
|
+
const nodeMap = new Map();
|
|
462
|
+
const edgeMap = new Map();
|
|
463
|
+
for (const branch of Object.keys(branches)) {
|
|
464
|
+
const payload = branches[branch] || { nodes: [], edges: [] };
|
|
465
|
+
for (const n of payload.nodes) {
|
|
466
|
+
if (n && n.data && n.data.id && !nodeMap.has(n.data.id)) nodeMap.set(n.data.id, n);
|
|
467
|
+
}
|
|
468
|
+
for (const e of payload.edges) {
|
|
469
|
+
if (e && e.data && e.data.id && !edgeMap.has(e.data.id)) edgeMap.set(e.data.id, e);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
return {
|
|
473
|
+
nodes: Array.from(nodeMap.values()),
|
|
474
|
+
edges: Array.from(edgeMap.values()),
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// ---------- buildHtmlWrapper ----------
|
|
479
|
+
//
|
|
480
|
+
// Standalone HTML wrapper. Uses the existing dashboard cytoscape@3.33.1
|
|
481
|
+
// CDN pattern (Canon Part 7 reuse; no new runtime dependency). The
|
|
482
|
+
// elements array is JSON-serialized inline so the wrapper opens in
|
|
483
|
+
// any browser without a backing server. Legend block is inline-styled
|
|
484
|
+
// so the file works as a single self-contained artifact.
|
|
485
|
+
|
|
486
|
+
function buildHtmlWrapper(graph) {
|
|
487
|
+
const elementsJson = JSON.stringify(graph.elements || { nodes: [], edges: [] });
|
|
488
|
+
const colorsJson = JSON.stringify(graph.branch_colors || BRANCH_COLORS);
|
|
489
|
+
const branchesJson = JSON.stringify(graph.branches || {});
|
|
490
|
+
|
|
491
|
+
// Legend rows: one per branch with the canonical color swatch.
|
|
492
|
+
const legendRows = BRANCHES.map(function (b) {
|
|
493
|
+
return '<div><span style="display:inline-block;width:12px;height:12px;background:' +
|
|
494
|
+
BRANCH_COLORS[b] + ';margin-right:6px;border:1px solid #000;"></span>' +
|
|
495
|
+
escapeHtml(b) + '</div>';
|
|
496
|
+
}).join('\n ');
|
|
497
|
+
|
|
498
|
+
return '<!DOCTYPE html>\n' +
|
|
499
|
+
'<html lang="en">\n' +
|
|
500
|
+
'<head>\n' +
|
|
501
|
+
' <meta charset="UTF-8">\n' +
|
|
502
|
+
' <title>RS Mind Map: 5-Branch View</title>\n' +
|
|
503
|
+
' <script src="' + CYTOSCAPE_CDN_URL + '"></script>\n' +
|
|
504
|
+
' <style>\n' +
|
|
505
|
+
' body { margin: 0; font-family: monospace; background: #ffffff; color: #000000; }\n' +
|
|
506
|
+
' #cy { width: 100vw; height: 100vh; }\n' +
|
|
507
|
+
' .legend { position: absolute; top: 10px; left: 10px; background: #ffffff; border: 2px solid #000000; padding: 10px; z-index: 10; }\n' +
|
|
508
|
+
' .legend strong { display: block; margin-bottom: 6px; }\n' +
|
|
509
|
+
' </style>\n' +
|
|
510
|
+
'</head>\n' +
|
|
511
|
+
'<body>\n' +
|
|
512
|
+
' <div id="cy"></div>\n' +
|
|
513
|
+
' <div class="legend">\n' +
|
|
514
|
+
' <strong>Branches</strong>\n' +
|
|
515
|
+
' ' + legendRows + '\n' +
|
|
516
|
+
' </div>\n' +
|
|
517
|
+
' <script>\n' +
|
|
518
|
+
' var elements = ' + elementsJson + ';\n' +
|
|
519
|
+
' var branchColors = ' + colorsJson + ';\n' +
|
|
520
|
+
' var branches = ' + branchesJson + ';\n' +
|
|
521
|
+
' var cy = cytoscape({\n' +
|
|
522
|
+
' container: document.getElementById(\'cy\'),\n' +
|
|
523
|
+
' elements: [].concat(elements.nodes || [], elements.edges || []),\n' +
|
|
524
|
+
' style: [\n' +
|
|
525
|
+
' { selector: \'node\', style: { label: \'data(label)\', \'background-color\': function (ele) { return branchColors[ele.data(\'branch\')] || \'#999999\'; }, \'font-size\': 9, color: \'#000000\', \'text-valign\': \'bottom\', \'text-margin-y\': 6 } },\n' +
|
|
526
|
+
' { selector: \'edge\', style: { label: \'data(label)\', \'line-color\': function (ele) { return branchColors[ele.data(\'branch\')] || \'#999999\'; }, \'target-arrow-color\': function (ele) { return branchColors[ele.data(\'branch\')] || \'#999999\'; }, \'target-arrow-shape\': \'triangle\', \'curve-style\': \'bezier\', \'font-size\': 7 } }\n' +
|
|
527
|
+
' ],\n' +
|
|
528
|
+
' layout: { name: \'cose\', animate: false, padding: 30 }\n' +
|
|
529
|
+
' });\n' +
|
|
530
|
+
' </script>\n' +
|
|
531
|
+
'</body>\n' +
|
|
532
|
+
'</html>\n';
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// ---------- escapeHtml ----------
|
|
536
|
+
//
|
|
537
|
+
// Minimal HTML entity escape for the legend labels. We escape the
|
|
538
|
+
// branch names even though they are constants because future Canon
|
|
539
|
+
// amendments may extend BRANCHES with caller-supplied names; defense
|
|
540
|
+
// in depth.
|
|
541
|
+
|
|
542
|
+
function escapeHtml(s) {
|
|
543
|
+
if (typeof s !== 'string') return '';
|
|
544
|
+
return s.replace(/&/g, '&')
|
|
545
|
+
.replace(/</g, '<')
|
|
546
|
+
.replace(/>/g, '>')
|
|
547
|
+
.replace(/"/g, '"')
|
|
548
|
+
.replace(/'/g, ''');
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// ---------- renderMindMap ----------
|
|
552
|
+
//
|
|
553
|
+
// The public entry point. Orchestration:
|
|
554
|
+
// 1. Resolve tier (throws TypeError if neither driver nor roomDir provided)
|
|
555
|
+
// 2. Validate tier-specific opts
|
|
556
|
+
// 3. Read raw branches from active tier (Tier 0 SQLite or Tier 1 Aura)
|
|
557
|
+
// 4. Force all 5 branch keys to be present (empty arrays for missing branches)
|
|
558
|
+
// 5. Compute combined elements (deduped by id)
|
|
559
|
+
// 6. Build metadata (tier, branch_counts, totals, schema_version)
|
|
560
|
+
// 7. Build HTML wrapper
|
|
561
|
+
// 8. Canon Part 8 defense-in-depth: auditQueryObject on FINAL HTML
|
|
562
|
+
// (throws ExternalEgressViolation on any FORBIDDEN_PATTERNS hit;
|
|
563
|
+
// result is NEVER returned)
|
|
564
|
+
// 9. Return assembled result with html_wrapper attached
|
|
565
|
+
|
|
566
|
+
async function renderMindMap(query_filter, opts) {
|
|
567
|
+
opts = opts || {};
|
|
568
|
+
const queryFilter = (query_filter && typeof query_filter === 'object') ? query_filter : {};
|
|
569
|
+
const tier = await detectTier(opts);
|
|
570
|
+
|
|
571
|
+
let raw;
|
|
572
|
+
if (tier === 'sqlite') {
|
|
573
|
+
if (typeof opts.roomDir !== 'string' || opts.roomDir.length === 0) {
|
|
574
|
+
throw new TypeError('rs-mind-map: opts.roomDir required for sqlite tier');
|
|
575
|
+
}
|
|
576
|
+
raw = await readSqliteBranches(opts.roomDir, queryFilter);
|
|
577
|
+
} else {
|
|
578
|
+
if (!opts.driver || typeof opts.driver.session !== 'function') {
|
|
579
|
+
throw new TypeError('rs-mind-map: opts.driver required for aura tier');
|
|
580
|
+
}
|
|
581
|
+
raw = await readAuraBranches(opts.driver, queryFilter);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// Normalize: every branch key MUST be present in output (empty arrays
|
|
585
|
+
// for missing). Downstream renderers (dashboard, /mos:rs-mind-map)
|
|
586
|
+
// rely on the fixed key set.
|
|
587
|
+
const branches = {};
|
|
588
|
+
for (const b of BRANCHES) {
|
|
589
|
+
branches[b] = raw.branches[b] || { nodes: [], edges: [] };
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
const elements = dedupeAndCombine(branches);
|
|
593
|
+
|
|
594
|
+
const branch_counts = {};
|
|
595
|
+
for (const b of BRANCHES) branch_counts[b] = branches[b].nodes.length;
|
|
596
|
+
|
|
597
|
+
const result = {
|
|
598
|
+
branches: branches,
|
|
599
|
+
elements: elements,
|
|
600
|
+
branch_colors: BRANCH_COLORS,
|
|
601
|
+
metadata: {
|
|
602
|
+
tier: tier,
|
|
603
|
+
branch_counts: branch_counts,
|
|
604
|
+
total_nodes: typeof raw.total_nodes === 'number' ? raw.total_nodes : 0,
|
|
605
|
+
total_edges: typeof raw.total_edges === 'number' ? raw.total_edges : 0,
|
|
606
|
+
schema_version: SCHEMA_VERSION,
|
|
607
|
+
},
|
|
608
|
+
};
|
|
609
|
+
|
|
610
|
+
const html_wrapper = buildHtmlWrapper(result);
|
|
611
|
+
|
|
612
|
+
// Canon Part 8 defense-in-depth: audit the FINAL HTML wrapper before
|
|
613
|
+
// return. Throws ExternalEgressViolation on any FORBIDDEN_PATTERNS hit
|
|
614
|
+
// with meta.surface = 'rs-mind-map-html'. Result is NEVER returned on
|
|
615
|
+
// audit failure; the caller learns precisely which surface tripped
|
|
616
|
+
// the guard via meta.matched_pattern.
|
|
617
|
+
auditQueryObject({ html: html_wrapper }, SURFACE);
|
|
618
|
+
|
|
619
|
+
result.html_wrapper = html_wrapper;
|
|
620
|
+
return result;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// ---------- Edge type registry consumption ----------
|
|
624
|
+
//
|
|
625
|
+
// Defensive guard: warn (not throw) if EDGE_TYPES is missing the 5 RS
|
|
626
|
+
// edge types Plan 89.3-01 added. This module is read-only against the
|
|
627
|
+
// schema, so the warning surfaces upstream issues without blocking
|
|
628
|
+
// the renderer for users whose graph already has the edges.
|
|
629
|
+
|
|
630
|
+
const REQUIRED_EDGE_TYPES = ['DISCOVERED', 'DERIVED_FROM', 'ENABLES', 'AUTHORED_BY', 'AFFILIATED_WITH'];
|
|
631
|
+
for (const t of REQUIRED_EDGE_TYPES) {
|
|
632
|
+
if (!lazygraph.EDGE_TYPES.includes(t)) {
|
|
633
|
+
process.stderr.write('rs-mind-map: WARNING -- EDGE_TYPES missing required type: ' + t + '\n');
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
// ---------- Exports ----------
|
|
638
|
+
|
|
639
|
+
module.exports = {
|
|
640
|
+
renderMindMap,
|
|
641
|
+
BRANCHES,
|
|
642
|
+
BRANCH_COLORS,
|
|
643
|
+
SCHEMA_VERSION,
|
|
644
|
+
CYTOSCAPE_CDN_URL,
|
|
645
|
+
_test: {
|
|
646
|
+
detectTier,
|
|
647
|
+
readSqliteBranches,
|
|
648
|
+
readAuraBranches,
|
|
649
|
+
buildHtmlWrapper,
|
|
650
|
+
dedupeAndCombine,
|
|
651
|
+
safeJsonParse,
|
|
652
|
+
buildLabel,
|
|
653
|
+
shouldEmitBranch,
|
|
654
|
+
escapeHtml,
|
|
655
|
+
},
|
|
656
|
+
};
|