@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,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MindrianOS Plugin -- Mullins Scaffold Loader (Phase 84-04)
|
|
3
|
+
*
|
|
4
|
+
* Loads the canonical Mullins 7-domain venture assessment scaffold from
|
|
5
|
+
* skills/mullins-scaffold/scaffold.json and exposes a small read-only API for
|
|
6
|
+
* callers that want to enumerate sections, fetch a single section, or test for
|
|
7
|
+
* existence. The scaffold is a TEMPLATE, not a mandatory skeleton: rooms that
|
|
8
|
+
* reference it gain structure, rooms that ignore it are structurally
|
|
9
|
+
* unaffected. Materialization (writing sections into a room) is deferred to
|
|
10
|
+
* v1.10.9; this module never touches disk and never mutates STATE.md.
|
|
11
|
+
*
|
|
12
|
+
* The scaffold JSON is loaded lazily and cached in module scope. Internal
|
|
13
|
+
* failures (missing file, malformed JSON) degrade to safe fallbacks ([], null,
|
|
14
|
+
* false) so early-hook callers cannot crash the plugin if the file is absent.
|
|
15
|
+
*
|
|
16
|
+
* Closes SCOPE-NB-01 and SCOPE-NB-02.
|
|
17
|
+
*
|
|
18
|
+
* Exports: loadScaffold, listSections, getSection, sectionExists,
|
|
19
|
+
* getDomainsForSection
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
'use strict';
|
|
23
|
+
|
|
24
|
+
const fs = require('fs');
|
|
25
|
+
const path = require('path');
|
|
26
|
+
|
|
27
|
+
const SCAFFOLD_PATH = path.join(
|
|
28
|
+
__dirname,
|
|
29
|
+
'..',
|
|
30
|
+
'..',
|
|
31
|
+
'skills',
|
|
32
|
+
'mullins-scaffold',
|
|
33
|
+
'scaffold.json'
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
let cache = null;
|
|
37
|
+
let loadAttempted = false;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Read and parse skills/mullins-scaffold/scaffold.json once and cache the
|
|
41
|
+
* result in module scope. Subsequent calls return the cached value. On any
|
|
42
|
+
* filesystem or JSON parse error, the cache is set to a safe empty document
|
|
43
|
+
* and a debug line is written to stderr; callers always receive a usable
|
|
44
|
+
* object shape.
|
|
45
|
+
*
|
|
46
|
+
* @returns {{version: number, generated_from: string, sections: Array<object>}}
|
|
47
|
+
* The parsed scaffold document, or an empty fallback document on error.
|
|
48
|
+
*/
|
|
49
|
+
function loadScaffold() {
|
|
50
|
+
if (cache !== null) return cache;
|
|
51
|
+
if (loadAttempted) return cache || { version: 0, generated_from: '', sections: [] };
|
|
52
|
+
loadAttempted = true;
|
|
53
|
+
try {
|
|
54
|
+
const raw = fs.readFileSync(SCAFFOLD_PATH, 'utf8');
|
|
55
|
+
const parsed = JSON.parse(raw);
|
|
56
|
+
if (!parsed || !Array.isArray(parsed.sections)) {
|
|
57
|
+
throw new Error('scaffold.json missing sections array');
|
|
58
|
+
}
|
|
59
|
+
cache = parsed;
|
|
60
|
+
return cache;
|
|
61
|
+
} catch (err) {
|
|
62
|
+
if (process.env.MOS_DEBUG) {
|
|
63
|
+
process.stderr.write(
|
|
64
|
+
'[mullins-scaffold] loadScaffold failed: ' + (err && err.message) + '\n'
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
cache = { version: 0, generated_from: '', sections: [] };
|
|
68
|
+
return cache;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Return all scaffold sections as a shallow-cloned array. Callers may mutate
|
|
74
|
+
* the returned array without affecting the module cache. Returns an empty
|
|
75
|
+
* array if the scaffold could not be loaded.
|
|
76
|
+
*
|
|
77
|
+
* @returns {Array<{id: string, domain: string, title: string, prompt: string, required: boolean}>}
|
|
78
|
+
*/
|
|
79
|
+
function listSections() {
|
|
80
|
+
try {
|
|
81
|
+
const doc = loadScaffold();
|
|
82
|
+
if (!doc || !Array.isArray(doc.sections)) return [];
|
|
83
|
+
return doc.sections.map(function (s) {
|
|
84
|
+
return Object.assign({}, s);
|
|
85
|
+
});
|
|
86
|
+
} catch (err) {
|
|
87
|
+
if (process.env.MOS_DEBUG) {
|
|
88
|
+
process.stderr.write(
|
|
89
|
+
'[mullins-scaffold] listSections failed: ' + (err && err.message) + '\n'
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Return a single section by its kebab-case id, or null if no such section
|
|
98
|
+
* exists. The returned object is a shallow clone so callers cannot mutate the
|
|
99
|
+
* module cache.
|
|
100
|
+
*
|
|
101
|
+
* @param {string} id - The section id (e.g. 'market-size-now').
|
|
102
|
+
* @returns {{id: string, domain: string, title: string, prompt: string, required: boolean}|null}
|
|
103
|
+
*/
|
|
104
|
+
function getSection(id) {
|
|
105
|
+
try {
|
|
106
|
+
if (typeof id !== 'string' || id.length === 0) return null;
|
|
107
|
+
const doc = loadScaffold();
|
|
108
|
+
if (!doc || !Array.isArray(doc.sections)) return null;
|
|
109
|
+
const found = doc.sections.find(function (s) {
|
|
110
|
+
return s && s.id === id;
|
|
111
|
+
});
|
|
112
|
+
return found ? Object.assign({}, found) : null;
|
|
113
|
+
} catch (err) {
|
|
114
|
+
if (process.env.MOS_DEBUG) {
|
|
115
|
+
process.stderr.write(
|
|
116
|
+
'[mullins-scaffold] getSection failed: ' + (err && err.message) + '\n'
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Test whether a section id exists in the scaffold.
|
|
125
|
+
*
|
|
126
|
+
* @param {string} id - The section id to test.
|
|
127
|
+
* @returns {boolean} True if a section with this id exists, false otherwise.
|
|
128
|
+
*/
|
|
129
|
+
function sectionExists(id) {
|
|
130
|
+
try {
|
|
131
|
+
return getSection(id) !== null;
|
|
132
|
+
} catch (err) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Return the Mullins domain string for a given section id, or null if the
|
|
139
|
+
* section is unknown. Useful for routing logic that wants to group artifacts
|
|
140
|
+
* by domain without re-parsing the scaffold.
|
|
141
|
+
*
|
|
142
|
+
* @param {string} id - The section id.
|
|
143
|
+
* @returns {string|null} The domain slug (e.g. 'market-attractiveness') or null.
|
|
144
|
+
*/
|
|
145
|
+
function getDomainsForSection(id) {
|
|
146
|
+
try {
|
|
147
|
+
const section = getSection(id);
|
|
148
|
+
return section && section.domain ? section.domain : null;
|
|
149
|
+
} catch (err) {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
module.exports = {
|
|
155
|
+
loadScaffold: loadScaffold,
|
|
156
|
+
listSections: listSections,
|
|
157
|
+
getSection: getSection,
|
|
158
|
+
sectionExists: sectionExists,
|
|
159
|
+
getDomainsForSection: getDomainsForSection,
|
|
160
|
+
};
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2026 Mindrian. BSL 1.1.
|
|
3
|
+
*
|
|
4
|
+
* Phase 91-06 -- Larry dial: pure resolver + formatter for the statusline
|
|
5
|
+
* navigation indicator
|
|
6
|
+
* =======================================================================
|
|
7
|
+
* Pure-function module. Zero I/O. Caller (scripts/context-monitor) reads
|
|
8
|
+
* the latest decision-trace entry from .mindrian/decision-traces/<session>
|
|
9
|
+
* .json and passes it in as a plain object. This module returns the dial
|
|
10
|
+
* position and a formatted segment string for the statusline.
|
|
11
|
+
*
|
|
12
|
+
* Three positions: Investigate | Blend | Insight. The active position
|
|
13
|
+
* carries a glyph (check / warn / low / --) drawn from the Canon Part 2
|
|
14
|
+
* UI vocabulary, byte-identical with Plan 88.1-04 statusline-cache
|
|
15
|
+
* classifyHealth (mirrored here, not require'd, to keep lib/core/ self-
|
|
16
|
+
* contained and lib/memory/ <-> lib/core/ decoupled).
|
|
17
|
+
*
|
|
18
|
+
* Position mapping (engine-state-derived):
|
|
19
|
+
* - tier_0 -> Investigate / -- / null
|
|
20
|
+
* - mode_b OR weight < 0.3 -> Investigate / warn / active
|
|
21
|
+
* - mode_a + weight 0.3..0.7 -> Blend / warn / active
|
|
22
|
+
* - mode_a + weight 0.7..0.9 -> Blend / check / active
|
|
23
|
+
* - mode_a + weight >= 0.9 + insight rationale -> Insight / check / active
|
|
24
|
+
* - mode_a + weight >= 0.9 + non-insight -> Blend / check / active
|
|
25
|
+
* - null trace OR malformed -> Investigate / -- / null
|
|
26
|
+
*
|
|
27
|
+
* Insight markers: 'synthesize' | 'insight' | 'converge' (case-insensitive)
|
|
28
|
+
* appearing anywhere in chosen_rationale promote weight >= 0.9 from Blend
|
|
29
|
+
* to Insight. The keyword set is canonical to Phase 91 and matches the
|
|
30
|
+
* Canon Part 3 verb 'Synthesize' (collapse branches back to insight).
|
|
31
|
+
*
|
|
32
|
+
* Canon references:
|
|
33
|
+
* Part 2 UI glyph vocabulary -- check / warn / low / --, byte-identical
|
|
34
|
+
* to lib/core/statusline-cache.cjs classifyHealth (see line 94 of that
|
|
35
|
+
* file). Mirrored here as a 4-line function to keep this module
|
|
36
|
+
* dependency-free.
|
|
37
|
+
* Part 3 Tri-Context Decision Gate -- dial position reflects the
|
|
38
|
+
* triangulated tier_mode + weight_applied result; never an arbitrary
|
|
39
|
+
* scrollwheel state. Updates per turn as new traces land.
|
|
40
|
+
* Part 8 Graph Boundary -- this module performs ZERO I/O. Caller does
|
|
41
|
+
* all reads from .mindrian/decision-traces/<session>.json (LOCAL only).
|
|
42
|
+
* No fetch, no Brain client, no shell-out, no network surface.
|
|
43
|
+
*
|
|
44
|
+
* Tyler meeting quote (Canon Appendix D / Phase 91-CONTEXT R4):
|
|
45
|
+
* "my students almost unanimously said, 'We love the slider.'"
|
|
46
|
+
* The dial is pedagogically meaningful (tied to engine state), not a
|
|
47
|
+
* gimmick. The reason field is the audit trail; /mos:explain-decision
|
|
48
|
+
* surfaces the same chosen_rationale that drove the dial.
|
|
49
|
+
*
|
|
50
|
+
* API:
|
|
51
|
+
* resolveDialPosition(trace) -> {label, glyph, highlight, reason}
|
|
52
|
+
* - trace: a decision-trace entry (the last element of traces[] in
|
|
53
|
+
* a .mindrian/decision-traces/<session>.json file). null is allowed.
|
|
54
|
+
* - label: 'Investigate' | 'Blend' | 'Insight'
|
|
55
|
+
* - glyph: 'check' | 'warn' | 'low' | '--'
|
|
56
|
+
* - highlight: 'active' | null
|
|
57
|
+
* - reason: human-readable string explaining why this position
|
|
58
|
+
*
|
|
59
|
+
* formatDialSegment(position) -> string
|
|
60
|
+
* - position: object returned by resolveDialPosition
|
|
61
|
+
* - returns: 'Larry: Investigate | Blend | Insight' with the active
|
|
62
|
+
* position visually emphasized via De Stijl ANSI color codes
|
|
63
|
+
* (mirrors visual-ops.cjs ANSI palette without requiring it)
|
|
64
|
+
* - byte-budget: visible chars (ANSI-stripped) <= 60
|
|
65
|
+
*
|
|
66
|
+
* classifyHealth(score) -> 'check' | 'warn' | 'low' | '--'
|
|
67
|
+
* - mirror of lib/core/statusline-cache.cjs classifyHealth
|
|
68
|
+
* - 0.7 -> check; 0.4 -> warn; 0.0 -> low; null/NaN/string -> '--'
|
|
69
|
+
*
|
|
70
|
+
* Three-surface compatible: pure CJS, node built-ins not even used (the
|
|
71
|
+
* module imports nothing). Works the same on CLI + Desktop MCP + Cowork.
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
'use strict';
|
|
75
|
+
|
|
76
|
+
// ---------- Frozen constants ----------
|
|
77
|
+
|
|
78
|
+
// Insight markers in chosen_rationale (case-insensitive).
|
|
79
|
+
// Synthesize: Canon Part 3 verb 7 (collapse branches back to insight).
|
|
80
|
+
// Converge: Canon Part 4 cross-relationship signal (3+ sections agree).
|
|
81
|
+
// Insight: plain English; the engine signals when it has reached one.
|
|
82
|
+
const INSIGHT_MARKERS = ['synthesize', 'insight', 'converge'];
|
|
83
|
+
|
|
84
|
+
// Canon Part 2 thresholds. Byte-identical to Plan 88.1-04
|
|
85
|
+
// statusline-cache.cjs classifyHealth (lines 94-99 of that file).
|
|
86
|
+
const HEALTH_CHECK_THRESHOLD = 0.7;
|
|
87
|
+
const HEALTH_WARN_THRESHOLD = 0.4;
|
|
88
|
+
|
|
89
|
+
// Tier-mode weight bands (Phase 91 D-04 mapping).
|
|
90
|
+
// weight < BLEND_FLOOR -> Investigate (low confidence band)
|
|
91
|
+
// BLEND_FLOOR <= weight < BLEND_STRONG -> Blend / warn
|
|
92
|
+
// BLEND_STRONG <= weight < INSIGHT_FLOOR -> Blend / check
|
|
93
|
+
// weight >= INSIGHT_FLOOR + insight markers -> Insight / check
|
|
94
|
+
const BLEND_FLOOR = 0.3;
|
|
95
|
+
const BLEND_STRONG = 0.7;
|
|
96
|
+
const INSIGHT_FLOOR = 0.9;
|
|
97
|
+
|
|
98
|
+
// ---------- classifyHealth (Canon Part 2 mirror) ----------
|
|
99
|
+
//
|
|
100
|
+
// Mirrors lib/core/statusline-cache.cjs classifyHealth byte-identically.
|
|
101
|
+
// This is the canonical glyph vocabulary across L3 surfaces (statusline,
|
|
102
|
+
// hook systemMessage, /mos:status, the dial). Re-mirrored instead of
|
|
103
|
+
// require'd so this module stays dependency-free and three-surface.
|
|
104
|
+
function classifyHealth(score) {
|
|
105
|
+
if (typeof score !== 'number' || !Number.isFinite(score)) return '--';
|
|
106
|
+
if (score >= HEALTH_CHECK_THRESHOLD) return 'check';
|
|
107
|
+
if (score >= HEALTH_WARN_THRESHOLD) return 'warn';
|
|
108
|
+
return 'low';
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ---------- resolveDialPosition ----------
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Map a decision-trace entry to a dial position.
|
|
115
|
+
*
|
|
116
|
+
* The trace shape is the same one Plan 91-02 writes and Plan 91-05 reads.
|
|
117
|
+
* The function never throws; every malformed input falls through to the
|
|
118
|
+
* Investigate / -- / null default ('no_trace_available' or 'malformed').
|
|
119
|
+
*
|
|
120
|
+
* @param {object|null} trace - decision-trace entry (last of traces[])
|
|
121
|
+
* @returns {{label: string, glyph: string, highlight: string|null, reason: string}}
|
|
122
|
+
*/
|
|
123
|
+
function resolveDialPosition(trace) {
|
|
124
|
+
// Null / non-object trace -> default.
|
|
125
|
+
if (!trace || typeof trace !== 'object') {
|
|
126
|
+
return {
|
|
127
|
+
label: 'Investigate',
|
|
128
|
+
glyph: '--',
|
|
129
|
+
highlight: null,
|
|
130
|
+
reason: 'no_trace_available'
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const tierMode = trace.brain_md_tier_mode;
|
|
135
|
+
const weight = trace.brain_md_weight_applied;
|
|
136
|
+
const rationale = typeof trace.chosen_rationale === 'string'
|
|
137
|
+
? trace.chosen_rationale
|
|
138
|
+
: '';
|
|
139
|
+
|
|
140
|
+
// Tier 0: pre-engine, default investigate state. No highlight (the dial
|
|
141
|
+
// shows three positions but none is active until the engine has spoken).
|
|
142
|
+
if (tierMode === 'tier_0') {
|
|
143
|
+
return {
|
|
144
|
+
label: 'Investigate',
|
|
145
|
+
glyph: '--',
|
|
146
|
+
highlight: null,
|
|
147
|
+
reason: 'tier_0_fallback'
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Mode B: Brain offline. Engine running on local triple only. Investigate
|
|
152
|
+
// with a warn glyph -- the engine has spoken, but the signal is partial.
|
|
153
|
+
if (tierMode === 'mode_b') {
|
|
154
|
+
return {
|
|
155
|
+
label: 'Investigate',
|
|
156
|
+
glyph: 'warn',
|
|
157
|
+
highlight: 'active',
|
|
158
|
+
reason: 'Brain offline; investigating locally with MINTO + SQL only'
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Mode A: full triangulation. Weight band picks the position.
|
|
163
|
+
if (tierMode === 'mode_a') {
|
|
164
|
+
if (typeof weight !== 'number' || !Number.isFinite(weight)) {
|
|
165
|
+
// Missing weight on a mode_a trace is malformed; soft-fail to default.
|
|
166
|
+
return {
|
|
167
|
+
label: 'Investigate',
|
|
168
|
+
glyph: '--',
|
|
169
|
+
highlight: null,
|
|
170
|
+
reason: 'malformed_trace_missing_weight'
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Low-confidence band: still in investigate territory.
|
|
175
|
+
if (weight < BLEND_FLOOR) {
|
|
176
|
+
return {
|
|
177
|
+
label: 'Investigate',
|
|
178
|
+
glyph: 'warn',
|
|
179
|
+
highlight: 'active',
|
|
180
|
+
reason: 'low_confidence_or_offline'
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Mid blend band: Blend with warn glyph.
|
|
185
|
+
if (weight < BLEND_STRONG) {
|
|
186
|
+
return {
|
|
187
|
+
label: 'Blend',
|
|
188
|
+
glyph: 'warn',
|
|
189
|
+
highlight: 'active',
|
|
190
|
+
reason: 'Blending MINTO + Brain at ' + weight.toFixed(2) + ' weight'
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Strong blend band: Blend with check glyph.
|
|
195
|
+
if (weight < INSIGHT_FLOOR) {
|
|
196
|
+
return {
|
|
197
|
+
label: 'Blend',
|
|
198
|
+
glyph: 'check',
|
|
199
|
+
highlight: 'active',
|
|
200
|
+
reason: 'Strong MINTO + Brain agreement, blending'
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Insight band: weight >= 0.9. Promote to Insight only when rationale
|
|
205
|
+
// carries insight markers. Otherwise stay in Blend / check (high
|
|
206
|
+
// confidence routine framework lookup, not a synthesis moment).
|
|
207
|
+
const lower = rationale.toLowerCase();
|
|
208
|
+
let isInsight = false;
|
|
209
|
+
for (const marker of INSIGHT_MARKERS) {
|
|
210
|
+
if (lower.indexOf(marker) !== -1) {
|
|
211
|
+
isInsight = true;
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (isInsight) {
|
|
216
|
+
return {
|
|
217
|
+
label: 'Insight',
|
|
218
|
+
glyph: 'check',
|
|
219
|
+
highlight: 'active',
|
|
220
|
+
reason: 'Converging signals, insight mode'
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
return {
|
|
224
|
+
label: 'Blend',
|
|
225
|
+
glyph: 'check',
|
|
226
|
+
highlight: 'active',
|
|
227
|
+
reason: 'High confidence, blending without explicit insight marker'
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Unknown tier_mode (forward-compat with future engine modes) -> default.
|
|
232
|
+
return {
|
|
233
|
+
label: 'Investigate',
|
|
234
|
+
glyph: '--',
|
|
235
|
+
highlight: null,
|
|
236
|
+
reason: 'unknown_tier_mode'
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// ---------- formatDialSegment ----------
|
|
241
|
+
|
|
242
|
+
// De Stijl ANSI palette (mirror of lib/core/visual-ops.cjs ANSI struct;
|
|
243
|
+
// duplicated here so this module imports nothing). The five colors used
|
|
244
|
+
// by the dial are dim/muted (inactive label), green (check), yellow
|
|
245
|
+
// (warn), red (low), and bold (highlight).
|
|
246
|
+
const ANSI = {
|
|
247
|
+
reset: '\x1b[0m',
|
|
248
|
+
bold: '\x1b[1m',
|
|
249
|
+
dim: '\x1b[2m',
|
|
250
|
+
green: '\x1b[38;2;45;107;74m', // ds-green
|
|
251
|
+
yellow: '\x1b[38;2;200;164;60m', // ds-yellow
|
|
252
|
+
red: '\x1b[38;2;166;61;47m', // ds-red
|
|
253
|
+
muted: '\x1b[38;2;160;154;144m' // ds-muted
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
const DIAL_LABELS = ['Investigate', 'Blend', 'Insight'];
|
|
257
|
+
|
|
258
|
+
function glyphColor(glyph) {
|
|
259
|
+
if (glyph === 'check') return ANSI.green;
|
|
260
|
+
if (glyph === 'warn') return ANSI.yellow;
|
|
261
|
+
if (glyph === 'low') return ANSI.red;
|
|
262
|
+
return ANSI.muted;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Render the dial segment string for the statusline.
|
|
267
|
+
*
|
|
268
|
+
* Format (no highlight): 'Larry: Investigate | Blend | Insight'
|
|
269
|
+
* Format (highlighted): 'Larry: Investigate | [bold]Blend[/bold] | Insight'
|
|
270
|
+
* plus a leading colored glyph indicator on the active label.
|
|
271
|
+
*
|
|
272
|
+
* Visible byte-length stripped of ANSI is <= 60 chars (Test 10 contract).
|
|
273
|
+
* The longest variant is 'Larry: Investigate | Blend | Insight' = 36 chars,
|
|
274
|
+
* well under the budget. Highlight does not add visible chars.
|
|
275
|
+
*
|
|
276
|
+
* @param {{label: string, glyph: string, highlight: string|null}} position
|
|
277
|
+
* @returns {string} the formatted segment string ('' on null/invalid input)
|
|
278
|
+
*/
|
|
279
|
+
function formatDialSegment(position) {
|
|
280
|
+
if (!position || typeof position !== 'object') return '';
|
|
281
|
+
if (typeof position.label !== 'string') return '';
|
|
282
|
+
|
|
283
|
+
const labels = DIAL_LABELS.map((label) => {
|
|
284
|
+
if (label === position.label && position.highlight === 'active') {
|
|
285
|
+
// Active label: bold + glyph color so the eye lands here.
|
|
286
|
+
return ANSI.bold + glyphColor(position.glyph) + label + ANSI.reset;
|
|
287
|
+
}
|
|
288
|
+
// Inactive label: dim/muted.
|
|
289
|
+
return ANSI.dim + ANSI.muted + label + ANSI.reset;
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
// Separator between labels.
|
|
293
|
+
const sep = ' ' + ANSI.muted + '|' + ANSI.reset + ' ';
|
|
294
|
+
|
|
295
|
+
// 'Larry:' prefix in dim white so it doesn't compete with the active
|
|
296
|
+
// label for attention.
|
|
297
|
+
const prefix = ANSI.dim + 'Larry:' + ANSI.reset + ' ';
|
|
298
|
+
|
|
299
|
+
return prefix + labels.join(sep);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// ---------- Exports ----------
|
|
303
|
+
|
|
304
|
+
module.exports = {
|
|
305
|
+
// Pure functions.
|
|
306
|
+
resolveDialPosition: resolveDialPosition,
|
|
307
|
+
formatDialSegment: formatDialSegment,
|
|
308
|
+
classifyHealth: classifyHealth,
|
|
309
|
+
// Frozen constants (exposed for tests + future composition).
|
|
310
|
+
INSIGHT_MARKERS: INSIGHT_MARKERS,
|
|
311
|
+
HEALTH_CHECK_THRESHOLD: HEALTH_CHECK_THRESHOLD,
|
|
312
|
+
HEALTH_WARN_THRESHOLD: HEALTH_WARN_THRESHOLD,
|
|
313
|
+
BLEND_FLOOR: BLEND_FLOOR,
|
|
314
|
+
BLEND_STRONG: BLEND_STRONG,
|
|
315
|
+
INSIGHT_FLOOR: INSIGHT_FLOOR
|
|
316
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# lib/core/navigation/
|
|
2
|
+
|
|
3
|
+
Phase 109 navigation spine internal helpers. Each .cjs file in this directory is an internal helper that lib/core/navigation.cjs (Plan 109-04) re-exports as part of the closed 13-function API surface.
|
|
4
|
+
|
|
5
|
+
Files:
|
|
6
|
+
- focus.cjs - getActiveFocus + setFocus + computeAutoFocus (Plan 109-02 / NAV-109-01)
|
|
7
|
+
- neighborhood.cjs - getNeighborhood recursive CTE wrapper (Plan 109-04 / NAV-109-02; not yet shipped)
|
|
8
|
+
- insights.cjs - 7 insight query primitives (Plan 109-05 / NAV-109-04; not yet shipped)
|
|
9
|
+
- packet.cjs - buildBrainPacket + storeBrainSuggestions (Plans 109-07 + 109-08 / NAV-109-06 + NAV-109-07; not yet shipped)
|
|
10
|
+
- room-home.cjs - getRoomHomeView composition (Plan 109-09 / NAV-109-08; not yet shipped)
|
|
11
|
+
- transitions.cjs - promoteNodeStatus chokepoint (Plan 109-04 / NAV-109-05; not yet shipped)
|
|
12
|
+
|
|
13
|
+
All helpers accept the open db handle as the first parameter; never call openRoomDb internally (the chokepoint module owns the lifecycle).
|
|
14
|
+
|
|
15
|
+
Owner: Phase 109 SQL Context-Memory Navigation Spine.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// Phase 109-05 templated explanation renderer. ZERO LLM in the loop per RESEARCH section 2.5.
|
|
3
|
+
// Closed kind enum; each kind has a deterministic template using typed edge labels.
|
|
4
|
+
//
|
|
5
|
+
// Canon Part 4: every choice is graph data; explanation strings render the typed
|
|
6
|
+
// edge labels (CONTRADICTS, SUPPORTS, DEPENDS_ON, ENABLES, EVIDENCES) directly so
|
|
7
|
+
// users can read "the graph paths AS the explanation".
|
|
8
|
+
// Canon Part 9: ZERO LLM in the loop; the "graph paths as explanation" pattern is
|
|
9
|
+
// the structural substitute for prompt-generated narrative.
|
|
10
|
+
|
|
11
|
+
function shortId(id) {
|
|
12
|
+
if (typeof id !== 'string') return String(id);
|
|
13
|
+
const parts = id.split(':');
|
|
14
|
+
if (parts.length < 2) return id;
|
|
15
|
+
return parts[0] + ':' + parts.slice(1).join(':');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function daysSince(epochMs) {
|
|
19
|
+
const dms = Date.now() - epochMs;
|
|
20
|
+
return Math.max(0, Math.floor(dms / (24 * 60 * 60 * 1000)));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function renderExplanation(kind, payload) {
|
|
24
|
+
const p = payload || {};
|
|
25
|
+
switch (kind) {
|
|
26
|
+
case 'contradiction':
|
|
27
|
+
return shortId(p.claimA) + ' CONTRADICTS ' + shortId(p.claimB) + ' (depth ' + (p.depth != null ? p.depth : 1) + ')';
|
|
28
|
+
case 'unsupported':
|
|
29
|
+
return shortId(p.claim) + ' is ' + (p.reviewStatus || 'confirmed') + ' but has no SUPPORTS edge (last touched ' + daysSince(p.lastSeenAt || Date.now()) + ' days ago)';
|
|
30
|
+
case 'blocking':
|
|
31
|
+
return shortId(p.assumption) + ' blocks ' + shortId(p.goal) + ' via path ' + (Array.isArray(p.cascadePath) ? p.cascadePath.map(shortId).join(' -> ') : '');
|
|
32
|
+
case 'stale':
|
|
33
|
+
return shortId(p.decision) + ' is confirmed but has not been touched in ' + daysSince(p.lastSeenAt) + ' days';
|
|
34
|
+
case 'open':
|
|
35
|
+
return shortId(p.question) + ' has been open for ' + daysSince(p.createdAt) + ' days with no SUPPORTS or EVIDENCES edge';
|
|
36
|
+
case 'opportunity':
|
|
37
|
+
return shortId(p.opportunityId) + ' (' + (p.hsiBand || 'unknown') + ' HSI band; ' + (p.jtbdMatch > 0 ? 'matches active JTBD' : 'no JTBD overlap') + '; ' + (p.depth != null ? p.depth : '?') + ' hop(s) from focus)';
|
|
38
|
+
default:
|
|
39
|
+
return '[explanation unavailable for kind=' + kind + ']';
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = { renderExplanation, shortId, daysSince };
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// Phase 109-02 focus helpers. Internal to lib/core/navigation/.
|
|
3
|
+
// Re-exported by lib/core/navigation.cjs (Plan 109-04) as the closed surface.
|
|
4
|
+
//
|
|
5
|
+
// Canon Part 1: the focus node is the wicked navigator's working-memory
|
|
6
|
+
// anchor. Canon Part 4: every setFocus writes a focus_changed memory_event
|
|
7
|
+
// (audit trail). Canon Part 9: focus persists in room.db, never in process
|
|
8
|
+
// memory.
|
|
9
|
+
|
|
10
|
+
const path = require('node:path');
|
|
11
|
+
const crypto = require('node:crypto');
|
|
12
|
+
|
|
13
|
+
const VALID_SET_BY = new Set(['user', 'larry', 'auto-from-jtbd', 'auto-from-operator', 'auto-from-state']);
|
|
14
|
+
|
|
15
|
+
function getActiveFocus(db, sessionId) {
|
|
16
|
+
const row = db.prepare(
|
|
17
|
+
"SELECT sf.session_id, sf.focus_node_id, sf.focus_type, sf.set_at, sf.set_by " +
|
|
18
|
+
"FROM session_focus sf " +
|
|
19
|
+
"WHERE sf.session_id = ?"
|
|
20
|
+
).get(sessionId);
|
|
21
|
+
if (!row) return null;
|
|
22
|
+
return {
|
|
23
|
+
sessionId: row.session_id,
|
|
24
|
+
focusNodeId: row.focus_node_id,
|
|
25
|
+
focusType: row.focus_type,
|
|
26
|
+
setAt: row.set_at,
|
|
27
|
+
setBy: row.set_by,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function lookupNodeType(db, nodeId) {
|
|
32
|
+
const row = db.prepare('SELECT type FROM nodes WHERE id = ?').get(nodeId);
|
|
33
|
+
return row ? row.type : null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function setFocus(db, sessionId, nodeId, setBy) {
|
|
37
|
+
if (!VALID_SET_BY.has(setBy)) {
|
|
38
|
+
return { ok: false, reason: 'invalid_set_by' };
|
|
39
|
+
}
|
|
40
|
+
const nodeType = lookupNodeType(db, nodeId);
|
|
41
|
+
if (!nodeType) {
|
|
42
|
+
return { ok: false, reason: 'unknown_node' };
|
|
43
|
+
}
|
|
44
|
+
// Capture previous focus for the focus_changed event payload.
|
|
45
|
+
const prior = getActiveFocus(db, sessionId);
|
|
46
|
+
const previousId = prior ? prior.focusNodeId : null;
|
|
47
|
+
const nowMs = Date.now();
|
|
48
|
+
const eventId = 'memory_event:focus_changed:' + sessionId + ':' + nowMs + ':' + crypto.randomBytes(4).toString('hex');
|
|
49
|
+
db.exec('BEGIN');
|
|
50
|
+
try {
|
|
51
|
+
db.prepare(
|
|
52
|
+
"INSERT OR REPLACE INTO session_focus (session_id, focus_node_id, focus_type, set_at, set_by) VALUES (?, ?, ?, ?, ?)"
|
|
53
|
+
).run(sessionId, nodeId, nodeType, nowMs, setBy);
|
|
54
|
+
const props = JSON.stringify({
|
|
55
|
+
event_type: 'focus_changed',
|
|
56
|
+
session_id: sessionId,
|
|
57
|
+
previous_focus_node_id: previousId,
|
|
58
|
+
new_focus_node_id: nodeId,
|
|
59
|
+
set_by: setBy,
|
|
60
|
+
});
|
|
61
|
+
db.prepare(
|
|
62
|
+
"INSERT INTO nodes (id, type, properties, source_path, created_by, confidence, review_status, created_at, last_seen_at) " +
|
|
63
|
+
"VALUES (?, 'memory_event', ?, ?, 'system', NULL, 'confirmed', ?, ?)"
|
|
64
|
+
).run(eventId, props, 'session:' + sessionId, nowMs, nowMs);
|
|
65
|
+
db.exec('COMMIT');
|
|
66
|
+
} catch (err) {
|
|
67
|
+
db.exec('ROLLBACK');
|
|
68
|
+
return { ok: false, reason: err.message };
|
|
69
|
+
}
|
|
70
|
+
return { ok: true, eventId };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function loadJtbdState(roomDir, mocks) {
|
|
74
|
+
if (mocks && mocks.jtbd) return mocks.jtbd;
|
|
75
|
+
try {
|
|
76
|
+
return require(path.resolve(__dirname, '..', '..', 'hmi', 'jtbd-state.cjs'));
|
|
77
|
+
} catch (_) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function loadOperator(roomDir, mocks) {
|
|
83
|
+
if (mocks && mocks.operator) return mocks.operator;
|
|
84
|
+
try {
|
|
85
|
+
return require(path.resolve(__dirname, '..', '..', 'conversation', 'operator.cjs'));
|
|
86
|
+
} catch (_) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function ensureNodeExists(db, nodeId) {
|
|
92
|
+
const row = db.prepare('SELECT id FROM nodes WHERE id = ?').get(nodeId);
|
|
93
|
+
return Boolean(row);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function computeAutoFocus(db, roomDir, sessionId, opts) {
|
|
97
|
+
const options = opts || {};
|
|
98
|
+
const mocks = options._mocks;
|
|
99
|
+
const roomId = options.roomId || (roomDir ? path.basename(roomDir) : null);
|
|
100
|
+
|
|
101
|
+
// Rule 1: active JTBD.
|
|
102
|
+
const jtbdMod = loadJtbdState(roomDir, mocks);
|
|
103
|
+
const jtbd = jtbdMod ? jtbdMod.getCurrent(roomDir) : null;
|
|
104
|
+
if (jtbd && jtbd.current && jtbd.current.id) {
|
|
105
|
+
const candidate = 'jtbd:' + jtbd.current.id;
|
|
106
|
+
if (ensureNodeExists(db, candidate)) {
|
|
107
|
+
return { focusNodeId: candidate, focusType: 'jtbd', setBy: 'auto-from-jtbd' };
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Rule 2: operator DECISION_GATE -> most recent unconfirmed decision.
|
|
112
|
+
const opMod = loadOperator(roomDir, mocks);
|
|
113
|
+
const op = opMod ? opMod.getCurrent(roomDir) : null;
|
|
114
|
+
if (op && op.current === 'DECISION_GATE') {
|
|
115
|
+
const row = db.prepare(
|
|
116
|
+
"SELECT id, type FROM nodes WHERE type = 'decision' AND review_status IN ('proposed','needs_evidence') ORDER BY created_at DESC LIMIT 1"
|
|
117
|
+
).get();
|
|
118
|
+
if (row) {
|
|
119
|
+
return { focusNodeId: row.id, focusType: row.type, setBy: 'auto-from-operator' };
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Rule 3: room root node.
|
|
124
|
+
if (roomId) {
|
|
125
|
+
const candidate = 'room:' + roomId;
|
|
126
|
+
if (ensureNodeExists(db, candidate)) {
|
|
127
|
+
return { focusNodeId: candidate, focusType: 'room', setBy: 'auto-from-state' };
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Rule 4: cold start.
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
module.exports = { getActiveFocus, setFocus, computeAutoFocus, VALID_SET_BY };
|