@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,115 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2026 Mindrian. BSL 1.1.
|
|
3
|
+
*
|
|
4
|
+
* Phase 89-07 Wave 2 -- ReverseSalientAgent persona suffix.
|
|
5
|
+
*
|
|
6
|
+
* Maps Phase 115 USER.md role_blend -> persona-aware F.0 header suffix.
|
|
7
|
+
* 7 canonical role keys + 2 aliases + default fallback.
|
|
8
|
+
*
|
|
9
|
+
* Lex tie-break per Phase 115 D-AMEND-04 (agents/larry-extended.md lines 78-100):
|
|
10
|
+
* 1. Filter to canonical keys with positive numeric weight
|
|
11
|
+
* 2. Sort filtered keys alphabetically
|
|
12
|
+
* 3. Walk in sorted order, keep highest-weight; on ties, alphabetical earlier wins
|
|
13
|
+
* 4. Any error / no canonical match / all-zero weights -> default
|
|
14
|
+
*
|
|
15
|
+
* Editorial copy (SCOPE B Section 6 of 89-07-RESEARCH.md, confidence: LOW):
|
|
16
|
+
* founder -> 'shipping risk'
|
|
17
|
+
* researcher -> 'evidence gap'
|
|
18
|
+
* researcher_ind -> 'evidence gap' (functionally a researcher persona)
|
|
19
|
+
* founder_grant -> 'submission risk' (grant-specific founder)
|
|
20
|
+
* investor -> 'thesis fragility'
|
|
21
|
+
* operator -> 'execution gap'
|
|
22
|
+
* mentor -> 'coaching wedge'
|
|
23
|
+
* domain_expert -> 'physical-reality friction'
|
|
24
|
+
* student -> 'understanding gap'
|
|
25
|
+
* default -> 'lagging component'
|
|
26
|
+
*
|
|
27
|
+
* Wording is tunable post-empathy-audit per RESEARCH Confidence: LOW caveat.
|
|
28
|
+
* Final copy is subject to revision after the beta.4 empathy audit, at which
|
|
29
|
+
* point both this module and any consumer test would be updated together.
|
|
30
|
+
*
|
|
31
|
+
* Pure CJS, zero dependencies, never throws.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
'use strict';
|
|
35
|
+
|
|
36
|
+
// Frozen suffix map. 9 keys + default = 10 entries.
|
|
37
|
+
const PERSONA_SUFFIX = Object.freeze({
|
|
38
|
+
founder: 'shipping risk',
|
|
39
|
+
researcher: 'evidence gap',
|
|
40
|
+
researcher_ind: 'evidence gap',
|
|
41
|
+
founder_grant: 'submission risk',
|
|
42
|
+
investor: 'thesis fragility',
|
|
43
|
+
operator: 'execution gap',
|
|
44
|
+
mentor: 'coaching wedge',
|
|
45
|
+
domain_expert: 'physical-reality friction',
|
|
46
|
+
student: 'understanding gap',
|
|
47
|
+
default: 'lagging component',
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Frozen canonical key list. Order is alphabetical (matches lex tie-break
|
|
51
|
+
// expectation in tests). 9 canonical + 'default' = 10 entries.
|
|
52
|
+
const CANONICAL_KEYS = Object.freeze([
|
|
53
|
+
'default',
|
|
54
|
+
'domain_expert',
|
|
55
|
+
'founder',
|
|
56
|
+
'founder_grant',
|
|
57
|
+
'investor',
|
|
58
|
+
'mentor',
|
|
59
|
+
'operator',
|
|
60
|
+
'researcher',
|
|
61
|
+
'researcher_ind',
|
|
62
|
+
'student',
|
|
63
|
+
]);
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Pick the persona suffix string for a USER.md role_blend object.
|
|
67
|
+
*
|
|
68
|
+
* @param {object|null|undefined} roleBlend
|
|
69
|
+
* { founder?: number, researcher?: number, ... } per Phase 115 schema.
|
|
70
|
+
* @returns {string} One of the PERSONA_SUFFIX values; 'lagging component' on
|
|
71
|
+
* any failure / cold-start / empty / all-zero / unknown-key.
|
|
72
|
+
*/
|
|
73
|
+
function suffixFor(roleBlend) {
|
|
74
|
+
try {
|
|
75
|
+
// Reject non-object, null, undefined, primitives.
|
|
76
|
+
if (roleBlend === null || roleBlend === undefined) return PERSONA_SUFFIX.default;
|
|
77
|
+
if (typeof roleBlend !== 'object') return PERSONA_SUFFIX.default;
|
|
78
|
+
// Arrays pass typeof === 'object' but their numeric-index keys never match
|
|
79
|
+
// CANONICAL_KEYS so they fall through to default. We document this rather
|
|
80
|
+
// than special-case Array.isArray(...) since the filter step handles it.
|
|
81
|
+
|
|
82
|
+
const keys = Object.keys(roleBlend);
|
|
83
|
+
if (keys.length === 0) return PERSONA_SUFFIX.default;
|
|
84
|
+
|
|
85
|
+
// Canonical-only candidates with positive numeric weight; lex tie-break by
|
|
86
|
+
// walking sorted keys (alphabetical earlier wins on ties because we keep
|
|
87
|
+
// strict > comparison and the earlier key was assigned first).
|
|
88
|
+
const canonicalSorted = keys
|
|
89
|
+
.filter((k) => CANONICAL_KEYS.indexOf(k) !== -1)
|
|
90
|
+
.sort();
|
|
91
|
+
|
|
92
|
+
let best = null;
|
|
93
|
+
let bestWeight = 0;
|
|
94
|
+
for (const k of canonicalSorted) {
|
|
95
|
+
const w = roleBlend[k];
|
|
96
|
+
if (typeof w === 'number' && Number.isFinite(w) && w > bestWeight) {
|
|
97
|
+
best = k;
|
|
98
|
+
bestWeight = w;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (best === null || bestWeight <= 0) return PERSONA_SUFFIX.default;
|
|
102
|
+
// Reliability fence: if PERSONA_SUFFIX somehow lacks the canonical key
|
|
103
|
+
// (shouldn't be possible since CANONICAL_KEYS and PERSONA_SUFFIX are
|
|
104
|
+
// co-frozen at module load), fall through to default.
|
|
105
|
+
return PERSONA_SUFFIX[best] || PERSONA_SUFFIX.default;
|
|
106
|
+
} catch (_e) {
|
|
107
|
+
return PERSONA_SUFFIX.default;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
module.exports = {
|
|
112
|
+
suffixFor: suffixFor,
|
|
113
|
+
PERSONA_SUFFIX: PERSONA_SUFFIX,
|
|
114
|
+
CANONICAL_KEYS: CANONICAL_KEYS,
|
|
115
|
+
};
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2026 Mindrian. BSL 1.1.
|
|
3
|
+
* (Business Source License 1.1; SPDX BUSL-1.1; see LICENSE.)
|
|
4
|
+
*
|
|
5
|
+
* Phase 94-06 -- Room classifier strict-mode override
|
|
6
|
+
*
|
|
7
|
+
* Pure-function detector that resolves three unambiguous user-input
|
|
8
|
+
* patterns directly to a registered room, bypassing the similarity
|
|
9
|
+
* heuristic in scripts/intent-classifier.cjs:
|
|
10
|
+
*
|
|
11
|
+
* 1. Numeric position 'switch to 8' or '8' -> registry[N-1]
|
|
12
|
+
* 2. Explicit slug 'curriculum-redesign-fall-2026' -> exact slug
|
|
13
|
+
* '/mos:rooms <slug>'
|
|
14
|
+
* 3. Quoted exact name '"Beta"' / '"Curriculum Redesign"' -> name OR slug
|
|
15
|
+
*
|
|
16
|
+
* First match wins (numeric, then slug, then quoted). When NO pattern
|
|
17
|
+
* matches, returns null and the classifier falls through to its existing
|
|
18
|
+
* similarity heuristic. The override is forward-additive: similarity
|
|
19
|
+
* heuristic is unchanged.
|
|
20
|
+
*
|
|
21
|
+
* Canon Part 3 (10-verb vocabulary preserved): strict-mode is a routing
|
|
22
|
+
* OVERRIDE, not a new verb. The 10 canonical verbs in
|
|
23
|
+
* lib/core/navigation-engine-shared.cjs are untouched.
|
|
24
|
+
*
|
|
25
|
+
* Canon Part 4 (every choice is graph data): when the override fires,
|
|
26
|
+
* the caller emits a Section-8 decision-trace edge with
|
|
27
|
+
* routing_source: 'strict_mode' so /mos:explain-decision can attribute
|
|
28
|
+
* the resolution.
|
|
29
|
+
*
|
|
30
|
+
* Canon Part 7 (reuse before build): extends scripts/intent-classifier.cjs
|
|
31
|
+
* by composition (separate helper module imported by the classifier),
|
|
32
|
+
* NOT by replacing the existing similarity heuristic. The justification
|
|
33
|
+
* bar for net-new capability is met: strict-mode handles cases the
|
|
34
|
+
* similarity heuristic cannot disambiguate (numeric position has no
|
|
35
|
+
* token overlap; explicit slug should never be misrouted; quoted exact
|
|
36
|
+
* name is the user's clearest signal).
|
|
37
|
+
*
|
|
38
|
+
* Lawrence Aronhime reproducer fence (2026-04-28 38-min live test):
|
|
39
|
+
* with two rooms loaded ('core-power-isolation' +
|
|
40
|
+
* 'curriculum-redesign-fall-2026'), Lawrence's four utterances kept
|
|
41
|
+
* resolving to the WRONG room. Plan 94-06 fences callouts 1 (numeric),
|
|
42
|
+
* 2 (slug-form), and 4 (slash command) via this module. Callout 3
|
|
43
|
+
* ('the curriculum room', natural language) is known-deferred to
|
|
44
|
+
* v1.11.3 because it requires a natural-language intent layer.
|
|
45
|
+
*
|
|
46
|
+
* Pure CJS, zero npm deps. Never throws.
|
|
47
|
+
*/
|
|
48
|
+
'use strict';
|
|
49
|
+
|
|
50
|
+
// ---------- Routing source constant ----------
|
|
51
|
+
|
|
52
|
+
// Section-8 decision-trace edge value when this layer fires. Forward-
|
|
53
|
+
// additive per Phase 91 invariant: existing routing_source values
|
|
54
|
+
// ('engine' | 'legacy' | 'mixed' | 'classifier') are unaffected.
|
|
55
|
+
const STRICT_MODE_ROUTING_SOURCE = 'strict_mode';
|
|
56
|
+
|
|
57
|
+
// ---------- Pattern regexes ----------
|
|
58
|
+
|
|
59
|
+
// Numeric: 'switch to 8' or '8' or 'go to 5' or 'jump to 3' or
|
|
60
|
+
// 'move to 2'. Bounded to a small synonym set so we don't accidentally
|
|
61
|
+
// match prose like 'jump 3 hoops' (no 'to' keyword).
|
|
62
|
+
const NUMERIC_PATTERN = /^(?:(?:switch|go|jump|move)\s+to\s+)?(\d+)$/i;
|
|
63
|
+
|
|
64
|
+
// Explicit slug: lowercase letters, digits, hyphens. 3-80 chars total.
|
|
65
|
+
// Starts AND ends with alphanumeric (no leading/trailing hyphen).
|
|
66
|
+
// Optional '/mos:rooms ' prefix to honor the canonical command form.
|
|
67
|
+
const SLUG_PATTERN = /^(?:\/mos:rooms\s+)?([a-z0-9][a-z0-9-]{1,78}[a-z0-9])$/;
|
|
68
|
+
|
|
69
|
+
// Quoted: any quoted span (single or double). The captured inner text
|
|
70
|
+
// is the candidate room name OR slug.
|
|
71
|
+
const QUOTED_PATTERN = /^['"]([^'"]+)['"]$/;
|
|
72
|
+
|
|
73
|
+
// ---------- Registry parsing ----------
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* parseRegistryRooms(reg) -> [{slug, name, path?}]
|
|
77
|
+
*
|
|
78
|
+
* Normalize the registry rooms field into a deterministic array of room
|
|
79
|
+
* records. Tolerates the array form, the object form, and the legacy
|
|
80
|
+
* string-only form. Preserves insertion order so 1-indexed numeric
|
|
81
|
+
* position is deterministic.
|
|
82
|
+
*/
|
|
83
|
+
function parseRegistryRooms(reg) {
|
|
84
|
+
if (!reg || !reg.rooms) return [];
|
|
85
|
+
const out = [];
|
|
86
|
+
if (Array.isArray(reg.rooms)) {
|
|
87
|
+
for (const r of reg.rooms) {
|
|
88
|
+
if (typeof r === 'string') {
|
|
89
|
+
out.push({ slug: r, name: r });
|
|
90
|
+
} else if (r && typeof r === 'object') {
|
|
91
|
+
const slug = (typeof r.slug === 'string' && r.slug)
|
|
92
|
+
? r.slug
|
|
93
|
+
: (typeof r.name === 'string' ? r.name : null);
|
|
94
|
+
if (!slug) continue;
|
|
95
|
+
const name = (typeof r.name === 'string' && r.name) ? r.name : slug;
|
|
96
|
+
out.push({ slug: slug, name: name, path: r.path || null });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return out;
|
|
100
|
+
}
|
|
101
|
+
if (typeof reg.rooms === 'object') {
|
|
102
|
+
// Object form: keys are slugs; values are metadata objects. Order
|
|
103
|
+
// is the JSON insertion order (V8 preserves; per ES2015 spec for
|
|
104
|
+
// string keys). 1-indexed numeric position resolves to
|
|
105
|
+
// Object.keys(...)[N-1].
|
|
106
|
+
for (const slug of Object.keys(reg.rooms)) {
|
|
107
|
+
const meta = reg.rooms[slug];
|
|
108
|
+
const name = (meta && typeof meta.venture_name === 'string' && meta.venture_name)
|
|
109
|
+
? meta.venture_name
|
|
110
|
+
: (meta && typeof meta.name === 'string' && meta.name ? meta.name : slug);
|
|
111
|
+
out.push({
|
|
112
|
+
slug: slug,
|
|
113
|
+
name: name,
|
|
114
|
+
path: (meta && typeof meta.path === 'string') ? meta.path : null,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
return out;
|
|
118
|
+
}
|
|
119
|
+
return [];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// ---------- Strict-mode detector ----------
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* detectStrictMode(prompt, registry) -> {slug, name, pattern, routing_source} | null
|
|
126
|
+
*
|
|
127
|
+
* Pure function. Tries the three strict-mode patterns in precedence
|
|
128
|
+
* order and returns the first match. Returns null when no pattern
|
|
129
|
+
* applies (caller falls through to similarity heuristic).
|
|
130
|
+
*
|
|
131
|
+
* Never throws. Defensive on registry shape (array OR object form).
|
|
132
|
+
*
|
|
133
|
+
* @param {string} prompt
|
|
134
|
+
* @param {object} registry
|
|
135
|
+
* @returns {{slug:string, name:string, pattern:string, routing_source:string} | null}
|
|
136
|
+
*/
|
|
137
|
+
function detectStrictMode(prompt, registry) {
|
|
138
|
+
if (typeof prompt !== 'string') return null;
|
|
139
|
+
const trimmed = prompt.trim();
|
|
140
|
+
if (!trimmed) return null;
|
|
141
|
+
|
|
142
|
+
const rooms = parseRegistryRooms(registry);
|
|
143
|
+
if (rooms.length === 0) return null;
|
|
144
|
+
|
|
145
|
+
// Pattern 1: numeric (1-indexed registry position).
|
|
146
|
+
const numMatch = trimmed.match(NUMERIC_PATTERN);
|
|
147
|
+
if (numMatch) {
|
|
148
|
+
const idx = parseInt(numMatch[1], 10) - 1;
|
|
149
|
+
if (idx >= 0 && idx < rooms.length) {
|
|
150
|
+
const r = rooms[idx];
|
|
151
|
+
return {
|
|
152
|
+
slug: r.slug,
|
|
153
|
+
name: r.name,
|
|
154
|
+
path: r.path,
|
|
155
|
+
pattern: 'numeric',
|
|
156
|
+
routing_source: STRICT_MODE_ROUTING_SOURCE,
|
|
157
|
+
input: prompt,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
// Numeric pattern matched syntactically but index out of bounds.
|
|
161
|
+
// Return null so the similarity heuristic gets a turn.
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Pattern 2: explicit slug (case-sensitive against registry slugs).
|
|
166
|
+
const slugMatch = trimmed.match(SLUG_PATTERN);
|
|
167
|
+
if (slugMatch) {
|
|
168
|
+
const candidate = slugMatch[1];
|
|
169
|
+
for (const r of rooms) {
|
|
170
|
+
if (r.slug === candidate) {
|
|
171
|
+
return {
|
|
172
|
+
slug: r.slug,
|
|
173
|
+
name: r.name,
|
|
174
|
+
path: r.path,
|
|
175
|
+
pattern: 'slug',
|
|
176
|
+
routing_source: STRICT_MODE_ROUTING_SOURCE,
|
|
177
|
+
input: prompt,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// Pattern matched but slug not registered. Fall through to
|
|
182
|
+
// pattern 3 / similarity (do NOT short-circuit; the slug form
|
|
183
|
+
// may also be a quoted-or-natural-language input that happens
|
|
184
|
+
// to look slug-like).
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Pattern 3: quoted exact name OR slug. Single OR double quote span.
|
|
188
|
+
// Name match is case-insensitive; slug match is case-insensitive too
|
|
189
|
+
// (slugs in registry are lowercase by convention but user may type
|
|
190
|
+
// 'Curriculum-Redesign-Fall-2026' with title case).
|
|
191
|
+
const quoteMatch = trimmed.match(QUOTED_PATTERN);
|
|
192
|
+
if (quoteMatch) {
|
|
193
|
+
const candidate = quoteMatch[1];
|
|
194
|
+
const candidateLower = candidate.toLowerCase();
|
|
195
|
+
for (const r of rooms) {
|
|
196
|
+
if (r.slug === candidate
|
|
197
|
+
|| (typeof r.name === 'string' && r.name === candidate)
|
|
198
|
+
|| (typeof r.name === 'string' && r.name.toLowerCase() === candidateLower)
|
|
199
|
+
|| r.slug.toLowerCase() === candidateLower) {
|
|
200
|
+
return {
|
|
201
|
+
slug: r.slug,
|
|
202
|
+
name: r.name,
|
|
203
|
+
path: r.path,
|
|
204
|
+
pattern: 'quoted',
|
|
205
|
+
routing_source: STRICT_MODE_ROUTING_SOURCE,
|
|
206
|
+
input: prompt,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// Pattern matched but no name/slug matches. Fall through.
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// ---------- Exports ----------
|
|
217
|
+
|
|
218
|
+
module.exports = {
|
|
219
|
+
detectStrictMode: detectStrictMode,
|
|
220
|
+
parseRegistryRooms: parseRegistryRooms,
|
|
221
|
+
STRICT_MODE_ROUTING_SOURCE: STRICT_MODE_ROUTING_SOURCE,
|
|
222
|
+
// Pattern regexes are exported for downstream tooling that wants to
|
|
223
|
+
// reuse the canonical patterns (e.g. /mos:explain-decision rendering
|
|
224
|
+
// or future natural-language layer that wants to disambiguate from
|
|
225
|
+
// strict-mode patterns).
|
|
226
|
+
NUMERIC_PATTERN: NUMERIC_PATTERN,
|
|
227
|
+
SLUG_PATTERN: SLUG_PATTERN,
|
|
228
|
+
QUOTED_PATTERN: QUOTED_PATTERN,
|
|
229
|
+
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// Composition entry point for room.db. Phase 109 chains two idempotent migrations
|
|
3
|
+
// after the existing schema init: nodes-provenance (Plan 109-01) then session_focus
|
|
4
|
+
// (Plan 109-02).
|
|
5
|
+
//
|
|
6
|
+
// Phase 109-02 contract change (parallel-worktree merge surface):
|
|
7
|
+
// openRoomDb is now SYNCHRONOUS and returns the bare node:sqlite DatabaseSync
|
|
8
|
+
// handle (not the legacy { db, conn } async tuple). Pre-Phase-109 callers that
|
|
9
|
+
// did `const handle = await openRoomDb(roomDir); handle.db.prepare(...)` need to
|
|
10
|
+
// either:
|
|
11
|
+
// (a) drop the await and use the returned db directly, or
|
|
12
|
+
// (b) call the openGraph low-level API directly.
|
|
13
|
+
// The async tuple shape was a leak from lazygraph-ops.cjs openGraph(); the
|
|
14
|
+
// navigation API (Plan 109-04) and all 109-* helpers consume the bare db.
|
|
15
|
+
// Plan 109-01's nodes-provenance migration was authored against the same
|
|
16
|
+
// sync contract; the orchestrator merges both 109-01 and 109-02 worktrees
|
|
17
|
+
// onto the same single-line migration chain shown below.
|
|
18
|
+
//
|
|
19
|
+
// Phase 109-06 addition: runtime soft-defense audit log per RESEARCH section 3.3.
|
|
20
|
+
// When openRoomDb is called from outside the navigation/* allow-list, we append
|
|
21
|
+
// one JSONL line to ~/.mindrian/telemetry/navigation-bypass.jsonl. Defensive
|
|
22
|
+
// (never throws). LOCAL only (Canon Part 8). sha256-hashed room slug. Mirrors
|
|
23
|
+
// Phase 88.1-16 query-efficiency telemetry pattern. Opt-out via env var
|
|
24
|
+
// MINDRIAN_DISABLE_BYPASS_AUDIT=1.
|
|
25
|
+
|
|
26
|
+
const path = require('node:path');
|
|
27
|
+
const fs = require('node:fs');
|
|
28
|
+
const os = require('node:os');
|
|
29
|
+
const crypto = require('node:crypto');
|
|
30
|
+
const { DatabaseSync } = require('node:sqlite');
|
|
31
|
+
const lazygraph = require('./lazygraph-ops.cjs');
|
|
32
|
+
const memory = require('./memory-ops.cjs');
|
|
33
|
+
const { runMigration: runPhase109SessionFocus } = require('./migrations/phase-109-session-focus.cjs');
|
|
34
|
+
|
|
35
|
+
// Plan 109-01 migration is loaded best-effort. In a parallel worktree where
|
|
36
|
+
// 109-01 has not yet shipped, the require will throw MODULE_NOT_FOUND and we
|
|
37
|
+
// fall back to the 109-02 migration's defensive ensureProvenanceColumns()
|
|
38
|
+
// backfill (which is a strict subset of the 109-01 schema work). Once 109-01
|
|
39
|
+
// merges, this loader resolves and the canonical migration runs first.
|
|
40
|
+
let runPhase109NodesProvenance = null;
|
|
41
|
+
try {
|
|
42
|
+
runPhase109NodesProvenance = require('./migrations/phase-109-nodes-provenance.cjs').runMigration;
|
|
43
|
+
} catch (_e) {
|
|
44
|
+
// 109-01 not present in this worktree; 109-02 migration handles its own
|
|
45
|
+
// FK target schema needs additively.
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Phase 109-06 runtime soft-defense. Inspect Error().stack to find the first
|
|
49
|
+
// frame outside this file. If that frame is NOT inside the navigation allow-list,
|
|
50
|
+
// append one JSONL line to ~/.mindrian/telemetry/navigation-bypass.jsonl with
|
|
51
|
+
// scalar fields only (timestamp, caller path, sha256 room hash). Defensive at
|
|
52
|
+
// every step: try/catch swallow, stack-parse failures default to 'unknown'.
|
|
53
|
+
function auditBypassIfNeeded(roomDir) {
|
|
54
|
+
if (process.env.MINDRIAN_DISABLE_BYPASS_AUDIT === '1') return;
|
|
55
|
+
let callerFile = 'unknown';
|
|
56
|
+
try {
|
|
57
|
+
const stack = (new Error()).stack.split('\n');
|
|
58
|
+
// Walk frames after the Error constructor. Skip any frame whose file is
|
|
59
|
+
// room-db.cjs itself (this function + openRoomDb wrapper).
|
|
60
|
+
for (let i = 1; i < Math.min(stack.length, 12); i++) {
|
|
61
|
+
const frame = stack[i];
|
|
62
|
+
// Match either '(path:line:col)' or 'at path:line:col' shapes.
|
|
63
|
+
const m = frame.match(/\(([^)]+):\d+:\d+\)/) || frame.match(/at\s+(.+):\d+:\d+/);
|
|
64
|
+
if (m && m[1] && !/room-db\.cjs$/.test(m[1])) {
|
|
65
|
+
callerFile = m[1];
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
} catch (_) { /* swallow */ }
|
|
70
|
+
const normalized = callerFile.replace(/\\/g, '/');
|
|
71
|
+
// Allow-list mirrors the pre-commit hook list. No JSONL write for legitimate
|
|
72
|
+
// navigation/* + tests + migration scripts callers.
|
|
73
|
+
if (
|
|
74
|
+
normalized.includes('/lib/core/navigation/') ||
|
|
75
|
+
normalized.endsWith('/lib/core/navigation.cjs') ||
|
|
76
|
+
/[\\/]tests[\\/]/.test(callerFile) ||
|
|
77
|
+
/[\\/]scripts[\\/]migrate-/.test(callerFile) ||
|
|
78
|
+
/[\\/]lib[\\/]core[\\/]migrations[\\/]/.test(callerFile)
|
|
79
|
+
) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
const dir = path.join(os.homedir(), '.mindrian', 'telemetry');
|
|
84
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
85
|
+
const sha = crypto.createHash('sha256').update(String(roomDir || '')).digest('hex').slice(0, 16);
|
|
86
|
+
const line = JSON.stringify({ ts: Date.now(), caller: callerFile, room_hash: sha }) + '\n';
|
|
87
|
+
fs.appendFileSync(path.join(dir, 'navigation-bypass.jsonl'), line);
|
|
88
|
+
} catch (_) { /* never throw */ }
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function openRoomDb(roomDir) {
|
|
92
|
+
// Soft-defense MUST be first so the caller is detected even when downstream
|
|
93
|
+
// schema init throws. Defensive (never throws) per Canon Part 8.
|
|
94
|
+
auditBypassIfNeeded(roomDir);
|
|
95
|
+
const resolved = path.resolve(roomDir);
|
|
96
|
+
const dbDir = path.join(resolved, '.mindrian');
|
|
97
|
+
const dbPath = path.join(dbDir, 'room.db');
|
|
98
|
+
fs.mkdirSync(dbDir, { recursive: true });
|
|
99
|
+
const db = new DatabaseSync(dbPath);
|
|
100
|
+
db.exec('PRAGMA journal_mode = WAL');
|
|
101
|
+
db.exec('PRAGMA foreign_keys = ON');
|
|
102
|
+
// Init lazygraph schema (nodes + edges + indices) sync via the same call
|
|
103
|
+
// the async wrapper makes internally.
|
|
104
|
+
lazygraph.initSchema(db);
|
|
105
|
+
// Init memory schema (identity / facts / sessions / fragments / assumptions / etc).
|
|
106
|
+
memory.initMemorySchema(db);
|
|
107
|
+
// Phase 109 migrations in order: nodes provenance first (109-01), then
|
|
108
|
+
// session_focus (109-02). Both are idempotent via identity sentinels.
|
|
109
|
+
if (runPhase109NodesProvenance) {
|
|
110
|
+
runPhase109NodesProvenance(db);
|
|
111
|
+
}
|
|
112
|
+
runPhase109SessionFocus(db);
|
|
113
|
+
return db;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function closeRoomDb(handle) {
|
|
117
|
+
// Tolerant: accept either bare DatabaseSync (current contract) or the legacy
|
|
118
|
+
// { db, conn } shape during the merge cycle.
|
|
119
|
+
const db = handle && handle.db ? handle.db : handle;
|
|
120
|
+
try {
|
|
121
|
+
db.close();
|
|
122
|
+
} catch (_e) {
|
|
123
|
+
// already closed; ignore
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
module.exports = { openRoomDb, closeRoomDb };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MindrianOS Plugin -- Room Ops (ASYNC entry point)
|
|
3
|
+
* ==================================================
|
|
4
|
+
* execFile (promisified via util.promisify) variants of the public room-ops
|
|
5
|
+
* surface. Import this from MCP tool-router and any caller that returns a
|
|
6
|
+
* Promise to the MCP runtime.
|
|
7
|
+
*
|
|
8
|
+
* NEVER call from CLI scripts that expect synchronous semantics -- use
|
|
9
|
+
* room-ops-sync.cjs. Key-set parity between sync and async is enforced by
|
|
10
|
+
* lib/memory/sync-async-entry-points.test.cjs.
|
|
11
|
+
*
|
|
12
|
+
* Phase 87-04 sync/async split (CASCADE-06). Eliminates the MCP blocking
|
|
13
|
+
* I/O footgun: env branching inside a single module made it too easy to
|
|
14
|
+
* ship synchronous subprocess I/O into the MCP handler path on accident.
|
|
15
|
+
*
|
|
16
|
+
* License: BSL 1.1 (Business Source License 1.1) -- see LICENSE.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
'use strict';
|
|
20
|
+
|
|
21
|
+
const path = require('path');
|
|
22
|
+
const util = require('util');
|
|
23
|
+
const { execFile } = require('child_process');
|
|
24
|
+
const execFileAsync = util.promisify(execFile);
|
|
25
|
+
const { discoverSections } = require('./section-registry.cjs');
|
|
26
|
+
const { resolveRoom: resolveRoomShared } = require('./room-ops-shared.cjs');
|
|
27
|
+
|
|
28
|
+
const SCRIPTS_DIR = path.resolve(__dirname, '../../scripts');
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* List discovered sections with metadata (async).
|
|
32
|
+
* Wraps the pure synchronous discoverSections() call in an async shape for
|
|
33
|
+
* API symmetry with room-ops-sync.cjs.
|
|
34
|
+
* @param {string} roomDir - Path to room directory
|
|
35
|
+
* @returns {Promise<{ sections: Array, core_count: number, extended_count: number }>}
|
|
36
|
+
*/
|
|
37
|
+
async function listSections(roomDir) {
|
|
38
|
+
const resolved = path.resolve(roomDir);
|
|
39
|
+
const discovery = discoverSections(resolved);
|
|
40
|
+
|
|
41
|
+
const sections = discovery.all.map(name => {
|
|
42
|
+
const meta = discovery.getMeta(name);
|
|
43
|
+
return {
|
|
44
|
+
name,
|
|
45
|
+
type: meta.type,
|
|
46
|
+
label: meta.label,
|
|
47
|
+
color: meta.color,
|
|
48
|
+
};
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
sections,
|
|
53
|
+
core_count: discovery.core.length,
|
|
54
|
+
extended_count: discovery.extended.length,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Run analyze-room script against a room directory (async).
|
|
60
|
+
* Uses execFile (promisified via util.promisify) rather than the blocking
|
|
61
|
+
* subprocess API, so the MCP handler loop stays non-blocking.
|
|
62
|
+
* @param {string} roomDir - Path to room directory
|
|
63
|
+
* @returns {Promise<string>} Raw script output
|
|
64
|
+
*/
|
|
65
|
+
async function analyzeRoom(roomDir) {
|
|
66
|
+
const resolved = path.resolve(roomDir);
|
|
67
|
+
const scriptPath = path.join(SCRIPTS_DIR, 'analyze-room');
|
|
68
|
+
try {
|
|
69
|
+
const { stdout } = await execFileAsync('bash', [scriptPath, resolved], {
|
|
70
|
+
timeout: 10000,
|
|
71
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
72
|
+
encoding: 'utf-8',
|
|
73
|
+
});
|
|
74
|
+
return stdout;
|
|
75
|
+
} catch (e) {
|
|
76
|
+
throw new Error(`analyze-room failed: ${e.message}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Resolve the active room directory path (async wrapper around the pure
|
|
82
|
+
* shared implementation). Wrapped in an async function for signature parity
|
|
83
|
+
* with the other async exports and to keep the test's AsyncFunction assertion
|
|
84
|
+
* uniform across every exported function name.
|
|
85
|
+
* @param {string} workDir - Workspace root directory
|
|
86
|
+
* @returns {Promise<string|null>}
|
|
87
|
+
*/
|
|
88
|
+
async function resolveRoom(workDir) {
|
|
89
|
+
return resolveRoomShared(workDir);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
module.exports = { listSections, analyzeRoom, resolveRoom };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MindrianOS Plugin -- Room Ops (shared pure logic)
|
|
3
|
+
* ==================================================
|
|
4
|
+
* Pure helpers with NO child_process I/O. Both room-ops-sync.cjs and
|
|
5
|
+
* room-ops-async.cjs import from this file. If you need to add a helper
|
|
6
|
+
* that calls execSync or execFile, put it in the sync or async entry
|
|
7
|
+
* point, not here.
|
|
8
|
+
*
|
|
9
|
+
* Phase 87-04 sync/async split (CASCADE-06). Eliminates the env-branching
|
|
10
|
+
* footgun (R4) by making the sync/async contract a require-time choice.
|
|
11
|
+
*
|
|
12
|
+
* License: BSL 1.1 (Business Source License 1.1) -- see LICENSE.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
'use strict';
|
|
16
|
+
|
|
17
|
+
const path = require('path');
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Trivial path helper kept here for symmetry with future shared utilities.
|
|
22
|
+
* Pure string/fs-path math; no I/O.
|
|
23
|
+
* @param {string} roomDir
|
|
24
|
+
* @returns {string}
|
|
25
|
+
*/
|
|
26
|
+
function resolveRoomPath(roomDir) {
|
|
27
|
+
return path.resolve(roomDir);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Resolve the active room directory path.
|
|
32
|
+
*
|
|
33
|
+
* Strategy 1: Read .rooms/registry.json and follow `active` -> rooms[active].path
|
|
34
|
+
* Strategy 2: Fall back to the legacy `room/` directory
|
|
35
|
+
*
|
|
36
|
+
* Pure fs + JSON logic, no child_process. Shared between sync and async
|
|
37
|
+
* entry points (both re-export this function under its original name).
|
|
38
|
+
*
|
|
39
|
+
* @param {string} workDir - Workspace root directory
|
|
40
|
+
* @returns {string|null} Absolute room path, or null if no room found
|
|
41
|
+
*/
|
|
42
|
+
function resolveRoom(workDir) {
|
|
43
|
+
const resolved = path.resolve(workDir);
|
|
44
|
+
const registryPath = path.join(resolved, '.rooms', 'registry.json');
|
|
45
|
+
|
|
46
|
+
// Strategy 1: Registry
|
|
47
|
+
if (fs.existsSync(registryPath)) {
|
|
48
|
+
try {
|
|
49
|
+
const reg = JSON.parse(fs.readFileSync(registryPath, 'utf8'));
|
|
50
|
+
if (reg.active && reg.rooms && reg.rooms[reg.active]) {
|
|
51
|
+
const roomPath = path.resolve(resolved, reg.rooms[reg.active].path);
|
|
52
|
+
if (fs.existsSync(roomPath)) return roomPath;
|
|
53
|
+
}
|
|
54
|
+
} catch (_e) { /* fall through to legacy */ }
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Strategy 2: Legacy
|
|
58
|
+
const legacy = path.join(resolved, 'room');
|
|
59
|
+
if (fs.existsSync(legacy)) return legacy;
|
|
60
|
+
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
module.exports = { resolveRoomPath, resolveRoom };
|