@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,554 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2026 Mindrian. BSL 1.1.
|
|
4
|
+
*
|
|
5
|
+
* Phase 91-04 -- Next-step offer presenter fixture tests
|
|
6
|
+
* =======================================================
|
|
7
|
+
* Exercises lib/core/offer-presenter.cjs. The presenter converts
|
|
8
|
+
* navigation-engine.decide()'s offer_next_step output into a one-line
|
|
9
|
+
* grounded suggestion that Larry surfaces at the end of the turn.
|
|
10
|
+
*
|
|
11
|
+
* Canon Part 3 (Tri-Context Decision Gate, Section 6 RECOMMENDED gate):
|
|
12
|
+
* the marker is rendered IFF mode === mode_a AND
|
|
13
|
+
* pattern_matches confidence >= 0.7 AND verb match. The engine evaluates
|
|
14
|
+
* the gate; the presenter respects the resolved
|
|
15
|
+
* decision_trace.brain_md_recommended_marker_rendered flag.
|
|
16
|
+
*
|
|
17
|
+
* Canon Part 4 (Every Choice Is Graph Data): offer outcomes (shown /
|
|
18
|
+
* ignored / acted) persist locally to .mindrian/offer-history.json so
|
|
19
|
+
* future decisions can weight against fatigue patterns. LOCAL-only
|
|
20
|
+
* (Canon Part 8); never egresses.
|
|
21
|
+
*
|
|
22
|
+
* Test map (Tests 1-15 = unit tests for presenter; Tests 16-17 = end-to-
|
|
23
|
+
* end integration through scripts/intent-classifier.cjs added in Task 2):
|
|
24
|
+
*
|
|
25
|
+
* 1. happy path: grounded MINTO reason renders one-line offer (no marker)
|
|
26
|
+
* 2. RECOMMENDED marker rendered when decision_trace flag is true
|
|
27
|
+
* 3. null offer_next_step -> no offer line, no suppression code
|
|
28
|
+
* 4. reason shorter than 15 chars -> ungrounded_reason suppression
|
|
29
|
+
* 5. generic reason ("to make progress") -> generic_reason suppression
|
|
30
|
+
* 6. signal keyword acceptance: "pattern_matches in BRAIN ..." renders
|
|
31
|
+
* 7. section name acceptance: "market-analysis section MINTO is stale"
|
|
32
|
+
* 8. history seeded with 2 ignored outcomes -> consecutive_ignores_threshold
|
|
33
|
+
* 9. suppression clears after one non-offer turn
|
|
34
|
+
* 10. max 1 per turn: second presentOffer call returns one_offer_per_turn
|
|
35
|
+
* 11. recordOfferOutcome 'ignored' appends to history atomically
|
|
36
|
+
* 12. recordOfferOutcome 'acted' appends to history
|
|
37
|
+
* 13. atomic write: 10 rapid concurrent recordOfferOutcome -> parseable JSON
|
|
38
|
+
* 14. readOfferHistory on absent file -> {version: 1, history: []}
|
|
39
|
+
* 15. readOfferHistory on malformed JSON -> {history: [], parse_failed: true}
|
|
40
|
+
* 16. integration: classifier emits 'Offer: ...' line when engine offers
|
|
41
|
+
* 17. integration: ignore loop -- turn 1 'shown'; turn 2 marks turn-1 ignored
|
|
42
|
+
*
|
|
43
|
+
* Registered in lib/memory/run-feynman-tests.cjs.
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
'use strict';
|
|
47
|
+
|
|
48
|
+
const assert = require('node:assert/strict');
|
|
49
|
+
const fs = require('node:fs');
|
|
50
|
+
const path = require('node:path');
|
|
51
|
+
const os = require('node:os');
|
|
52
|
+
const { spawnSync } = require('node:child_process');
|
|
53
|
+
|
|
54
|
+
const REPO = path.resolve(__dirname, '..', '..');
|
|
55
|
+
const PRESENTER_PATH = path.join(REPO, 'lib/core/offer-presenter.cjs');
|
|
56
|
+
const CLASSIFIER_PATH = path.join(REPO, 'scripts/intent-classifier.cjs');
|
|
57
|
+
|
|
58
|
+
function requirePresenter() {
|
|
59
|
+
// Lazy require so Task 1 RED can be written before the file exists.
|
|
60
|
+
return require(PRESENTER_PATH);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ---------- Test scaffolding ----------
|
|
64
|
+
|
|
65
|
+
let passed = 0;
|
|
66
|
+
let failed = 0;
|
|
67
|
+
function run(name, fn) {
|
|
68
|
+
try {
|
|
69
|
+
fn();
|
|
70
|
+
process.stdout.write('ok ' + name + '\n');
|
|
71
|
+
passed += 1;
|
|
72
|
+
} catch (err) {
|
|
73
|
+
process.stderr.write('FAIL ' + name + '\n');
|
|
74
|
+
process.stderr.write(String(err && err.stack ? err.stack : err) + '\n');
|
|
75
|
+
failed += 1;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ---------- Fixture builders ----------
|
|
80
|
+
|
|
81
|
+
const TMPDIRS = [];
|
|
82
|
+
|
|
83
|
+
function mkTmp(label) {
|
|
84
|
+
const d = fs.mkdtempSync(path.join(os.tmpdir(), '91-04-' + label + '-'));
|
|
85
|
+
TMPDIRS.push(d);
|
|
86
|
+
return d;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
process.on('exit', () => {
|
|
90
|
+
for (const d of TMPDIRS) {
|
|
91
|
+
try { fs.rmSync(d, { recursive: true, force: true }); } catch (_) {}
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
function makeDecision(overrides) {
|
|
96
|
+
const base = {
|
|
97
|
+
fire_skill: null,
|
|
98
|
+
suppress_skills: [],
|
|
99
|
+
persona_updates: null,
|
|
100
|
+
offer_next_step: null,
|
|
101
|
+
decision_trace: {
|
|
102
|
+
icm_scope: null,
|
|
103
|
+
sql_signals: null,
|
|
104
|
+
minto_reasoning: null,
|
|
105
|
+
brain_patterns: null,
|
|
106
|
+
intent_persona: null,
|
|
107
|
+
chosen_rationale: '',
|
|
108
|
+
brain_md_tier_mode: 'mode_a',
|
|
109
|
+
brain_md_staleness: 'fresh',
|
|
110
|
+
brain_md_stale_reason: null,
|
|
111
|
+
brain_md_weight_applied: 1.0,
|
|
112
|
+
brain_md_recommended_confidence: null,
|
|
113
|
+
brain_md_recommended_marker_rendered: false,
|
|
114
|
+
brain_md_sections_consumed: [],
|
|
115
|
+
brain_md_version: 1,
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
// Shallow merge top-level; deep merge decision_trace.
|
|
119
|
+
const out = Object.assign({}, base, overrides || {});
|
|
120
|
+
if (overrides && overrides.decision_trace) {
|
|
121
|
+
out.decision_trace = Object.assign({}, base.decision_trace, overrides.decision_trace);
|
|
122
|
+
}
|
|
123
|
+
return out;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function emptyHistory() {
|
|
127
|
+
return { version: 1, history: [] };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function freshSession() {
|
|
131
|
+
// Each test gets an isolated session context object so the
|
|
132
|
+
// one-offer-per-turn marker does not leak between tests.
|
|
133
|
+
return { offeredThisTurn: false, sessionId: 'test-session', command: null };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// =========================================================
|
|
137
|
+
// Task 1 -- Presenter unit tests (Tests 1-15)
|
|
138
|
+
// =========================================================
|
|
139
|
+
|
|
140
|
+
run('Test 1: happy path -- grounded MINTO reason renders single-line offer', () => {
|
|
141
|
+
const { presentOffer } = requirePresenter();
|
|
142
|
+
const decision = makeDecision({
|
|
143
|
+
offer_next_step: {
|
|
144
|
+
command: '/mos:validate',
|
|
145
|
+
reason: 'MINTO shows weak TAM evidence in market-analysis',
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
const out = presentOffer(decision, emptyHistory(), freshSession());
|
|
149
|
+
assert.equal(out.suppressReason, null);
|
|
150
|
+
assert.equal(out.recommendedMarker, false);
|
|
151
|
+
assert.equal(typeof out.offerLine, 'string');
|
|
152
|
+
assert.equal(out.offerLine.indexOf('Offer:') === 0, true,
|
|
153
|
+
'offer line must start with "Offer:"; got ' + out.offerLine);
|
|
154
|
+
assert.equal(out.offerLine.indexOf('MINTO shows weak TAM evidence in market-analysis') !== -1,
|
|
155
|
+
true, 'reason must appear verbatim');
|
|
156
|
+
assert.equal(out.offerLine.indexOf('/mos:validate') !== -1, true,
|
|
157
|
+
'command must appear verbatim');
|
|
158
|
+
assert.equal(out.offerLine.indexOf('Because') !== -1, true,
|
|
159
|
+
'offer must use "Because" connective');
|
|
160
|
+
// RECOMMENDED marker absent (gate not passed).
|
|
161
|
+
assert.equal(out.offerLine.indexOf('(RECOMMENDED)') === -1, true,
|
|
162
|
+
'RECOMMENDED marker must NOT appear when gate is false');
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
run('Test 2: RECOMMENDED marker rendered when decision_trace flag is true', () => {
|
|
166
|
+
const { presentOffer } = requirePresenter();
|
|
167
|
+
const decision = makeDecision({
|
|
168
|
+
offer_next_step: {
|
|
169
|
+
command: '/mos:validate',
|
|
170
|
+
reason: 'BRAIN pattern_matches confidence above 0.7 floor',
|
|
171
|
+
},
|
|
172
|
+
decision_trace: {
|
|
173
|
+
brain_md_tier_mode: 'mode_a',
|
|
174
|
+
brain_md_recommended_confidence: 0.85,
|
|
175
|
+
brain_md_recommended_marker_rendered: true,
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
const out = presentOffer(decision, emptyHistory(), freshSession());
|
|
179
|
+
assert.equal(out.suppressReason, null);
|
|
180
|
+
assert.equal(out.recommendedMarker, true);
|
|
181
|
+
assert.equal(out.offerLine.indexOf('(RECOMMENDED)') !== -1, true,
|
|
182
|
+
'RECOMMENDED marker must appear when gate is true; got ' + out.offerLine);
|
|
183
|
+
// Marker placement: '(RECOMMENDED)' immediately after 'Offer'.
|
|
184
|
+
assert.equal(out.offerLine.indexOf('Offer (RECOMMENDED):') === 0, true,
|
|
185
|
+
'marker must follow "Offer "; got ' + out.offerLine);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
run('Test 3: null offer_next_step -> no offer line, no suppression code', () => {
|
|
189
|
+
const { presentOffer } = requirePresenter();
|
|
190
|
+
const decision = makeDecision({ offer_next_step: null });
|
|
191
|
+
const out = presentOffer(decision, emptyHistory(), freshSession());
|
|
192
|
+
assert.equal(out.offerLine, null);
|
|
193
|
+
assert.equal(out.recommendedMarker, false);
|
|
194
|
+
assert.equal(out.suppressReason, null);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
run('Test 4: reason shorter than 15 chars -> ungrounded_reason', () => {
|
|
198
|
+
const { presentOffer } = requirePresenter();
|
|
199
|
+
const decision = makeDecision({
|
|
200
|
+
offer_next_step: { command: '/mos:validate', reason: 'too short' },
|
|
201
|
+
});
|
|
202
|
+
const out = presentOffer(decision, emptyHistory(), freshSession());
|
|
203
|
+
assert.equal(out.offerLine, null);
|
|
204
|
+
assert.equal(out.suppressReason, 'ungrounded_reason');
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
run('Test 5: generic reason ("to make progress") -> generic_reason', () => {
|
|
208
|
+
const { presentOffer } = requirePresenter();
|
|
209
|
+
const decision = makeDecision({
|
|
210
|
+
offer_next_step: {
|
|
211
|
+
command: '/mos:validate',
|
|
212
|
+
reason: 'to make progress quickly today',
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
const out = presentOffer(decision, emptyHistory(), freshSession());
|
|
216
|
+
assert.equal(out.offerLine, null);
|
|
217
|
+
assert.equal(out.suppressReason, 'generic_reason');
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
run('Test 6: signal keyword acceptance -- pattern + BRAIN renders', () => {
|
|
221
|
+
const { presentOffer } = requirePresenter();
|
|
222
|
+
const decision = makeDecision({
|
|
223
|
+
offer_next_step: {
|
|
224
|
+
command: '/mos:think-hats',
|
|
225
|
+
reason: 'pattern_matches in BRAIN shows SWOT precedent',
|
|
226
|
+
},
|
|
227
|
+
});
|
|
228
|
+
const out = presentOffer(decision, emptyHistory(), freshSession());
|
|
229
|
+
assert.equal(out.suppressReason, null);
|
|
230
|
+
assert.equal(typeof out.offerLine, 'string');
|
|
231
|
+
assert.equal(out.offerLine.indexOf('SWOT') !== -1, true);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
run('Test 7: section name acceptance -- "market-analysis section MINTO" renders', () => {
|
|
235
|
+
const { presentOffer } = requirePresenter();
|
|
236
|
+
const decision = makeDecision({
|
|
237
|
+
offer_next_step: {
|
|
238
|
+
command: '/mos:validate',
|
|
239
|
+
reason: 'market-analysis section MINTO is stale',
|
|
240
|
+
},
|
|
241
|
+
});
|
|
242
|
+
const out = presentOffer(decision, emptyHistory(), freshSession());
|
|
243
|
+
assert.equal(out.suppressReason, null);
|
|
244
|
+
assert.equal(typeof out.offerLine, 'string');
|
|
245
|
+
assert.equal(out.offerLine.indexOf('market-analysis') !== -1, true);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
run('Test 8: history seeded with 2 ignored -> consecutive_ignores_threshold', () => {
|
|
249
|
+
const { presentOffer } = requirePresenter();
|
|
250
|
+
const decision = makeDecision({
|
|
251
|
+
offer_next_step: {
|
|
252
|
+
command: '/mos:validate',
|
|
253
|
+
reason: 'MINTO reasoning_health_score below threshold',
|
|
254
|
+
},
|
|
255
|
+
});
|
|
256
|
+
const history = {
|
|
257
|
+
version: 1,
|
|
258
|
+
history: [
|
|
259
|
+
{ at: '2026-04-27T18:00:00Z', session_id: 'a', command: '/mos:foo', reason: 'pattern x', outcome: 'ignored' },
|
|
260
|
+
{ at: '2026-04-27T18:05:00Z', session_id: 'a', command: '/mos:bar', reason: 'pattern y', outcome: 'ignored' },
|
|
261
|
+
],
|
|
262
|
+
};
|
|
263
|
+
const out = presentOffer(decision, history, freshSession());
|
|
264
|
+
assert.equal(out.offerLine, null);
|
|
265
|
+
assert.equal(out.suppressReason, 'consecutive_ignores_threshold');
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
run('Test 9: suppression clears after one non-offer turn', () => {
|
|
269
|
+
const { presentOffer } = requirePresenter();
|
|
270
|
+
// History pattern: ignored, ignored, then a non-offer turn (no entry
|
|
271
|
+
// appended; or an entry with outcome other than 'ignored'). The
|
|
272
|
+
// simplest representation: two ignored entries separated from any
|
|
273
|
+
// newer entry by an 'acted' or 'shown' record. We use a 'reset'
|
|
274
|
+
// sentinel record with outcome other than ignored to model the
|
|
275
|
+
// "one turn without an offer" gap. The presenter checks the last
|
|
276
|
+
// 2 history entries; if not BOTH 'ignored', suppression does not
|
|
277
|
+
// fire.
|
|
278
|
+
const decision = makeDecision({
|
|
279
|
+
offer_next_step: {
|
|
280
|
+
command: '/mos:validate',
|
|
281
|
+
reason: 'MINTO weakness in evidence after audit',
|
|
282
|
+
},
|
|
283
|
+
});
|
|
284
|
+
const history = {
|
|
285
|
+
version: 1,
|
|
286
|
+
history: [
|
|
287
|
+
{ at: '2026-04-27T18:00:00Z', session_id: 'a', command: '/mos:foo', reason: 'pattern x', outcome: 'ignored' },
|
|
288
|
+
{ at: '2026-04-27T18:05:00Z', session_id: 'a', command: '/mos:bar', reason: 'pattern y', outcome: 'ignored' },
|
|
289
|
+
{ at: '2026-04-27T18:10:00Z', session_id: 'a', command: null, reason: '', outcome: 'reset' },
|
|
290
|
+
],
|
|
291
|
+
};
|
|
292
|
+
const out = presentOffer(decision, history, freshSession());
|
|
293
|
+
assert.equal(out.suppressReason, null,
|
|
294
|
+
'suppression must clear when last 2 entries are not both ignored; got ' + out.suppressReason);
|
|
295
|
+
assert.equal(typeof out.offerLine, 'string');
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
run('Test 10: max 1 per turn -- second call returns one_offer_per_turn', () => {
|
|
299
|
+
const { presentOffer } = requirePresenter();
|
|
300
|
+
const decision = makeDecision({
|
|
301
|
+
offer_next_step: {
|
|
302
|
+
command: '/mos:validate',
|
|
303
|
+
reason: 'MINTO governing thought stale per audit',
|
|
304
|
+
},
|
|
305
|
+
});
|
|
306
|
+
const session = freshSession();
|
|
307
|
+
const out1 = presentOffer(decision, emptyHistory(), session);
|
|
308
|
+
assert.equal(out1.suppressReason, null);
|
|
309
|
+
assert.equal(typeof out1.offerLine, 'string');
|
|
310
|
+
// Same session context handed to second call -- offeredThisTurn now true.
|
|
311
|
+
const out2 = presentOffer(decision, emptyHistory(), session);
|
|
312
|
+
assert.equal(out2.offerLine, null);
|
|
313
|
+
assert.equal(out2.suppressReason, 'one_offer_per_turn');
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
run('Test 11: recordOfferOutcome ignored appends atomically', () => {
|
|
317
|
+
const { recordOfferOutcome, readOfferHistory } = requirePresenter();
|
|
318
|
+
const dir = mkTmp('t11');
|
|
319
|
+
recordOfferOutcome(dir, {
|
|
320
|
+
outcome: 'ignored',
|
|
321
|
+
session_id: 's1',
|
|
322
|
+
command: '/mos:validate',
|
|
323
|
+
reason: 'pattern weak',
|
|
324
|
+
});
|
|
325
|
+
const hist = readOfferHistory(dir);
|
|
326
|
+
assert.equal(hist.history.length, 1);
|
|
327
|
+
assert.equal(hist.history[0].outcome, 'ignored');
|
|
328
|
+
assert.equal(hist.history[0].command, '/mos:validate');
|
|
329
|
+
assert.equal(typeof hist.history[0].at, 'string');
|
|
330
|
+
// ISO-8601 sanity check.
|
|
331
|
+
assert.equal(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(hist.history[0].at), true);
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
run('Test 12: recordOfferOutcome acted appends', () => {
|
|
335
|
+
const { recordOfferOutcome, readOfferHistory } = requirePresenter();
|
|
336
|
+
const dir = mkTmp('t12');
|
|
337
|
+
recordOfferOutcome(dir, {
|
|
338
|
+
outcome: 'acted',
|
|
339
|
+
session_id: 's2',
|
|
340
|
+
command: '/mos:think-hats',
|
|
341
|
+
reason: 'pattern matched',
|
|
342
|
+
});
|
|
343
|
+
const hist = readOfferHistory(dir);
|
|
344
|
+
assert.equal(hist.history.length, 1);
|
|
345
|
+
assert.equal(hist.history[0].outcome, 'acted');
|
|
346
|
+
assert.equal(hist.history[0].command, '/mos:think-hats');
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
run('Test 13: atomic write under 10 rapid concurrent record calls', () => {
|
|
350
|
+
const { recordOfferOutcome, readOfferHistory } = requirePresenter();
|
|
351
|
+
const dir = mkTmp('t13');
|
|
352
|
+
// 10 sequential rapid writes (in-process; cannot easily fork inside a
|
|
353
|
+
// single test, but rapid sequential covers the tmp+rename atomicity
|
|
354
|
+
// contract -- no partial JSON on disk after each call).
|
|
355
|
+
for (let i = 0; i < 10; i += 1) {
|
|
356
|
+
recordOfferOutcome(dir, {
|
|
357
|
+
outcome: 'shown',
|
|
358
|
+
session_id: 's' + i,
|
|
359
|
+
command: '/mos:cmd' + i,
|
|
360
|
+
reason: 'pattern ' + i,
|
|
361
|
+
});
|
|
362
|
+
// Mid-loop read must always parse cleanly.
|
|
363
|
+
const mid = readOfferHistory(dir);
|
|
364
|
+
assert.equal(typeof mid, 'object');
|
|
365
|
+
assert.equal(Array.isArray(mid.history), true);
|
|
366
|
+
}
|
|
367
|
+
const final = readOfferHistory(dir);
|
|
368
|
+
assert.equal(final.history.length, 10);
|
|
369
|
+
// Verify no .tmp.* leftovers in .mindrian.
|
|
370
|
+
const mindrianDir = path.join(dir, '.mindrian');
|
|
371
|
+
if (fs.existsSync(mindrianDir)) {
|
|
372
|
+
const leftovers = fs.readdirSync(mindrianDir).filter(function (n) {
|
|
373
|
+
return n.indexOf('offer-history.json.tmp.') === 0;
|
|
374
|
+
});
|
|
375
|
+
assert.equal(leftovers.length, 0,
|
|
376
|
+
'no .tmp.* files must remain after writes; found ' + JSON.stringify(leftovers));
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
run('Test 14: readOfferHistory on absent file -> empty history struct', () => {
|
|
381
|
+
const { readOfferHistory } = requirePresenter();
|
|
382
|
+
const dir = mkTmp('t14');
|
|
383
|
+
const hist = readOfferHistory(dir);
|
|
384
|
+
assert.equal(hist.version, 1);
|
|
385
|
+
assert.deepEqual(hist.history, []);
|
|
386
|
+
// No throws -- function returned a value.
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
run('Test 15: readOfferHistory on malformed JSON -> empty + parse_failed flag', () => {
|
|
390
|
+
const { readOfferHistory, recordOfferOutcome } = requirePresenter();
|
|
391
|
+
const dir = mkTmp('t15');
|
|
392
|
+
// Seed a corrupt offer-history.json.
|
|
393
|
+
const mindrianDir = path.join(dir, '.mindrian');
|
|
394
|
+
fs.mkdirSync(mindrianDir, { recursive: true });
|
|
395
|
+
fs.writeFileSync(path.join(mindrianDir, 'offer-history.json'), '{not valid json');
|
|
396
|
+
const hist = readOfferHistory(dir);
|
|
397
|
+
assert.deepEqual(hist.history, []);
|
|
398
|
+
assert.equal(hist.parse_failed, true);
|
|
399
|
+
// recordOfferOutcome must continue with fresh history (graceful self-heal).
|
|
400
|
+
recordOfferOutcome(dir, {
|
|
401
|
+
outcome: 'shown',
|
|
402
|
+
session_id: 's-recover',
|
|
403
|
+
command: '/mos:foo',
|
|
404
|
+
reason: 'pattern recovery',
|
|
405
|
+
});
|
|
406
|
+
const after = readOfferHistory(dir);
|
|
407
|
+
assert.equal(after.history.length, 1);
|
|
408
|
+
assert.equal(after.history[0].command, '/mos:foo');
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
// =========================================================
|
|
412
|
+
// Task 2 -- Integration tests (Tests 16-17)
|
|
413
|
+
// =========================================================
|
|
414
|
+
|
|
415
|
+
function makeRoomsFixture(label) {
|
|
416
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), '91-04-int-' + label + '-'));
|
|
417
|
+
TMPDIRS.push(tmp);
|
|
418
|
+
const root = path.join(tmp, 'MindrianRooms');
|
|
419
|
+
fs.mkdirSync(root, { recursive: true });
|
|
420
|
+
const roomDir = path.join(root, 'fixture-room');
|
|
421
|
+
fs.mkdirSync(roomDir, { recursive: true });
|
|
422
|
+
fs.writeFileSync(
|
|
423
|
+
path.join(roomDir, 'STATE.md'),
|
|
424
|
+
'---\nproject: fixture room\n---\n\n# Fixture Room\n'
|
|
425
|
+
);
|
|
426
|
+
const sectionDir = path.join(roomDir, 'market-analysis');
|
|
427
|
+
fs.mkdirSync(sectionDir, { recursive: true });
|
|
428
|
+
fs.writeFileSync(
|
|
429
|
+
path.join(sectionDir, 'MINTO.md'),
|
|
430
|
+
'---\ngoverning_thought: Customers will pay\nreasoning_health_score: 0.6\n---\n\n# Market analysis\n'
|
|
431
|
+
);
|
|
432
|
+
fs.writeFileSync(
|
|
433
|
+
path.join(sectionDir, 'ROOM.md'),
|
|
434
|
+
'# market-analysis section\n'
|
|
435
|
+
);
|
|
436
|
+
const regDir = path.join(root, '.rooms');
|
|
437
|
+
fs.mkdirSync(regDir, { recursive: true });
|
|
438
|
+
fs.writeFileSync(
|
|
439
|
+
path.join(regDir, 'registry.json'),
|
|
440
|
+
JSON.stringify({ active: 'fixture-room', rooms: ['fixture-room'] }, null, 2)
|
|
441
|
+
);
|
|
442
|
+
return { tmp: tmp, root: root, roomDir: roomDir, sectionDir: sectionDir };
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
function runHook(rootEnv, extraEnv, prompt) {
|
|
446
|
+
const env = Object.assign({}, process.env, {
|
|
447
|
+
MINDRIAN_ROOMS_ROOT: rootEnv,
|
|
448
|
+
MINDRIAN_ROOMS_HOME: rootEnv,
|
|
449
|
+
MINDRIAN_COPILOT_INJECT_FINDINGS: '0',
|
|
450
|
+
}, extraEnv || {});
|
|
451
|
+
return spawnSync(process.execPath, [CLASSIFIER_PATH], {
|
|
452
|
+
input: JSON.stringify({ user_message: prompt || 'analyze market sizing' }),
|
|
453
|
+
env: env,
|
|
454
|
+
encoding: 'utf8',
|
|
455
|
+
timeout: 5000,
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
function classifierIntegrated() {
|
|
460
|
+
// Gate Tests 16-17 on the Task 2 wiring landing in scripts/intent-
|
|
461
|
+
// classifier.cjs. Until then, skip them so RED of Task 1 only shows
|
|
462
|
+
// the 15 presenter unit tests.
|
|
463
|
+
const src = fs.readFileSync(CLASSIFIER_PATH, 'utf8');
|
|
464
|
+
return src.indexOf('offer-presenter') !== -1;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
if (classifierIntegrated()) {
|
|
468
|
+
run('Test 16: integration -- engine offer renders Offer line in additionalContext', () => {
|
|
469
|
+
const fix = makeRoomsFixture('t16');
|
|
470
|
+
const res = runHook(fix.root, {
|
|
471
|
+
MOS_NAV_TEST_OFFER_COMMAND: '/mos:validate',
|
|
472
|
+
MOS_NAV_TEST_OFFER_REASON: 'MINTO shows weak TAM evidence in market-analysis',
|
|
473
|
+
});
|
|
474
|
+
assert.equal(res.status === 0, true,
|
|
475
|
+
'classifier exited non-zero: ' + res.status + '\nstderr: ' + (res.stderr || ''));
|
|
476
|
+
const out = res.stdout || '';
|
|
477
|
+
assert.equal(
|
|
478
|
+
out.indexOf('Offer:') !== -1,
|
|
479
|
+
true,
|
|
480
|
+
'expected Offer: line in stdout; got: ' + out
|
|
481
|
+
);
|
|
482
|
+
assert.equal(
|
|
483
|
+
out.indexOf('MINTO shows weak TAM evidence in market-analysis') !== -1,
|
|
484
|
+
true,
|
|
485
|
+
'expected reason in offer line; got: ' + out
|
|
486
|
+
);
|
|
487
|
+
assert.equal(
|
|
488
|
+
out.indexOf('/mos:validate') !== -1,
|
|
489
|
+
true,
|
|
490
|
+
'expected command in offer line; got: ' + out
|
|
491
|
+
);
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
run('Test 17: integration -- ignore loop turn 1 shown, turn 2 marks turn-1 ignored', () => {
|
|
495
|
+
const fix = makeRoomsFixture('t17');
|
|
496
|
+
// Turn 1: engine offers /mos:validate. Presenter should record 'shown'.
|
|
497
|
+
const res1 = runHook(fix.root, {
|
|
498
|
+
MOS_NAV_TEST_OFFER_COMMAND: '/mos:validate',
|
|
499
|
+
MOS_NAV_TEST_OFFER_REASON: 'MINTO weak evidence after recent audit',
|
|
500
|
+
CLAUDE_SESSION_ID: 'session-t17',
|
|
501
|
+
}, 'audit my market-analysis section');
|
|
502
|
+
assert.equal(res1.status === 0, true,
|
|
503
|
+
'turn 1 classifier exited non-zero: ' + res1.status);
|
|
504
|
+
const histPath = path.join(fix.roomDir, '.mindrian', 'offer-history.json');
|
|
505
|
+
assert.equal(fs.existsSync(histPath), true,
|
|
506
|
+
'turn 1 must create offer-history.json; missing at ' + histPath);
|
|
507
|
+
let hist1;
|
|
508
|
+
try {
|
|
509
|
+
hist1 = JSON.parse(fs.readFileSync(histPath, 'utf8'));
|
|
510
|
+
} catch (e) {
|
|
511
|
+
throw new Error('turn 1 offer-history.json malformed: ' + e.message);
|
|
512
|
+
}
|
|
513
|
+
assert.equal(hist1.history.length >= 1, true,
|
|
514
|
+
'turn 1 must append at least one entry; got ' + hist1.history.length);
|
|
515
|
+
const turn1Entry = hist1.history[hist1.history.length - 1];
|
|
516
|
+
assert.equal(turn1Entry.outcome, 'shown',
|
|
517
|
+
'turn 1 outcome must be shown; got ' + turn1Entry.outcome);
|
|
518
|
+
assert.equal(turn1Entry.command, '/mos:validate');
|
|
519
|
+
|
|
520
|
+
// Turn 2: engine offers nothing; user does NOT invoke /mos:validate.
|
|
521
|
+
// Presenter should reclassify turn-1 outcome as 'ignored'.
|
|
522
|
+
const res2 = runHook(fix.root, {
|
|
523
|
+
MOS_NAV_TEST_OFFER_COMMAND: '__NULL__',
|
|
524
|
+
CLAUDE_SESSION_ID: 'session-t17',
|
|
525
|
+
}, 'tell me about competitors instead');
|
|
526
|
+
assert.equal(res2.status === 0, true,
|
|
527
|
+
'turn 2 classifier exited non-zero: ' + res2.status);
|
|
528
|
+
let hist2;
|
|
529
|
+
try {
|
|
530
|
+
hist2 = JSON.parse(fs.readFileSync(histPath, 'utf8'));
|
|
531
|
+
} catch (e) {
|
|
532
|
+
throw new Error('turn 2 offer-history.json malformed: ' + e.message);
|
|
533
|
+
}
|
|
534
|
+
// Turn-1 entry's outcome must have been updated to 'ignored'.
|
|
535
|
+
const turn1AfterTurn2 = hist2.history.find(function (e) {
|
|
536
|
+
return e.session_id === 'session-t17' && e.command === '/mos:validate';
|
|
537
|
+
});
|
|
538
|
+
assert.equal(turn1AfterTurn2 !== undefined, true,
|
|
539
|
+
'turn-1 entry must still exist after turn 2');
|
|
540
|
+
assert.equal(turn1AfterTurn2.outcome, 'ignored',
|
|
541
|
+
'turn-1 outcome must be reclassified to ignored after turn 2; got ' +
|
|
542
|
+
turn1AfterTurn2.outcome);
|
|
543
|
+
});
|
|
544
|
+
} else {
|
|
545
|
+
process.stdout.write(
|
|
546
|
+
'skip Tests 16-17 (intent-classifier.cjs not yet integrated with offer-presenter; gate clears in Task 2)\n'
|
|
547
|
+
);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// ---------- Summary ----------
|
|
551
|
+
|
|
552
|
+
const total = passed + failed;
|
|
553
|
+
process.stdout.write('\noffer-presenter.test: ' + passed + '/' + total + ' passed\n');
|
|
554
|
+
process.exit(failed === 0 ? 0 : 1);
|