@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.
Files changed (597) hide show
  1. package/.claude-plugin/plugin.json +21 -0
  2. package/.mcp.json +9 -0
  3. package/CHANGELOG.md +3333 -0
  4. package/LICENSE +123 -0
  5. package/README.md +673 -0
  6. package/agents/brain-query.md +80 -0
  7. package/agents/framework-runner.md +237 -0
  8. package/agents/grading.md +188 -0
  9. package/agents/investor.md +128 -0
  10. package/agents/larry-extended.md +135 -0
  11. package/agents/opportunity-scanner.md +91 -0
  12. package/agents/persona-analyst.md +132 -0
  13. package/agents/research.md +89 -0
  14. package/agents/reverse-salient-agent.md +27 -0
  15. package/bin/cli.js +142 -0
  16. package/bin/mindrian-mcp-server.cjs +182 -0
  17. package/bin/mindrian-tools.cjs +765 -0
  18. package/commands/act.md +439 -0
  19. package/commands/admin.md +404 -0
  20. package/commands/analyze-needs.md +42 -0
  21. package/commands/analyze-systems.md +39 -0
  22. package/commands/analyze-timing.md +42 -0
  23. package/commands/auto-explore.md +64 -0
  24. package/commands/beautiful-question.md +40 -0
  25. package/commands/brain-derive.md +78 -0
  26. package/commands/build-knowledge.md +42 -0
  27. package/commands/build-thesis.md +46 -0
  28. package/commands/causal.md +234 -0
  29. package/commands/challenge-assumptions.md +33 -0
  30. package/commands/compare-ventures.md +83 -0
  31. package/commands/dashboard.md +110 -0
  32. package/commands/deep-grade.md +82 -0
  33. package/commands/diagnose.md +58 -0
  34. package/commands/diagnostics.md +151 -0
  35. package/commands/doctor.md +151 -0
  36. package/commands/dominant-designs.md +40 -0
  37. package/commands/explain-decision.md +87 -0
  38. package/commands/explore-domains.md +42 -0
  39. package/commands/explore-futures.md +40 -0
  40. package/commands/explore-trends.md +42 -0
  41. package/commands/export.md +103 -0
  42. package/commands/file-meeting.md +724 -0
  43. package/commands/find-analogies.md +188 -0
  44. package/commands/find-bottlenecks.md +62 -0
  45. package/commands/find-connections.md +76 -0
  46. package/commands/funding.md +81 -0
  47. package/commands/grade.md +203 -0
  48. package/commands/graph.md +128 -0
  49. package/commands/hat-briefing.md +125 -0
  50. package/commands/heal.md +196 -0
  51. package/commands/help.md +399 -0
  52. package/commands/hmi-status.md +172 -0
  53. package/commands/jtbd.md +241 -0
  54. package/commands/leadership.md +73 -0
  55. package/commands/lean-canvas.md +40 -0
  56. package/commands/macro-trends.md +40 -0
  57. package/commands/map-unknowns.md +40 -0
  58. package/commands/memory.md +173 -0
  59. package/commands/models.md +175 -0
  60. package/commands/mos-reason.md +285 -0
  61. package/commands/mullins.md +120 -0
  62. package/commands/new-project.md +481 -0
  63. package/commands/onboard.md +434 -0
  64. package/commands/operator.md +149 -0
  65. package/commands/opportunities.md +144 -0
  66. package/commands/organize.md +497 -0
  67. package/commands/persona.md +198 -0
  68. package/commands/pipeline.md +112 -0
  69. package/commands/present.md +91 -0
  70. package/commands/publish.md +201 -0
  71. package/commands/query.md +124 -0
  72. package/commands/radar.md +72 -0
  73. package/commands/reanalyze.md +91 -0
  74. package/commands/research.md +196 -0
  75. package/commands/room.md +352 -0
  76. package/commands/rooms.md +598 -0
  77. package/commands/root-cause.md +40 -0
  78. package/commands/rs-experts.md +85 -0
  79. package/commands/rs-explain.md +100 -0
  80. package/commands/rs-fetch.md +94 -0
  81. package/commands/rs-thesis.md +85 -0
  82. package/commands/scenario-plan.md +40 -0
  83. package/commands/scheduled-tasks.md +285 -0
  84. package/commands/score-innovation.md +43 -0
  85. package/commands/scout.md +239 -0
  86. package/commands/setup.md +618 -0
  87. package/commands/snapshot.md +147 -0
  88. package/commands/speakers.md +84 -0
  89. package/commands/splash.md +28 -0
  90. package/commands/status.md +75 -0
  91. package/commands/structure-argument.md +42 -0
  92. package/commands/suggest-next.md +80 -0
  93. package/commands/systems-thinking.md +40 -0
  94. package/commands/think-hats.md +42 -0
  95. package/commands/update.md +181 -0
  96. package/commands/user-needs.md +40 -0
  97. package/commands/validate.md +40 -0
  98. package/commands/value-proposition.md +61 -0
  99. package/commands/vault.md +180 -0
  100. package/commands/visualize.md +52 -0
  101. package/commands/whitespace.md +507 -0
  102. package/commands/wiki.md +69 -0
  103. package/hooks/hooks.json +381 -0
  104. package/hooks/run-hook.cmd +64 -0
  105. package/lib/__init__.py +0 -0
  106. package/lib/__pycache__/__init__.cpython-312.pyc +0 -0
  107. package/lib/agents/auto-explore-agent.cjs +1043 -0
  108. package/lib/agents/reverse-salient-agent.cjs +679 -0
  109. package/lib/agents/tension-hook-agent.cjs +544 -0
  110. package/lib/brain/ROOM.md +44 -0
  111. package/lib/brain/chain-recommender.cjs +301 -0
  112. package/lib/chat/chat-context.js +185 -0
  113. package/lib/chat/chat-panel.js +721 -0
  114. package/lib/chat/fabric-chat.cjs +288 -0
  115. package/lib/chat/generative-tools.js +219 -0
  116. package/lib/conversation/ROOM.md +39 -0
  117. package/lib/conversation/classifier-rules.json +38 -0
  118. package/lib/conversation/classifier.cjs +264 -0
  119. package/lib/conversation/operator.cjs +287 -0
  120. package/lib/copy/115-spec-strings.cjs +55 -0
  121. package/lib/core/__init__.py +0 -0
  122. package/lib/core/__nav-stub.cjs +14 -0
  123. package/lib/core/__pycache__/__init__.cpython-312.pyc +0 -0
  124. package/lib/core/__pycache__/rs-math.cpython-312.pyc +0 -0
  125. package/lib/core/__pycache__/rs_cache.cpython-312.pyc +0 -0
  126. package/lib/core/__pycache__/rs_corpus.cpython-312.pyc +0 -0
  127. package/lib/core/__pycache__/rs_hybrid.cpython-312.pyc +0 -0
  128. package/lib/core/__pycache__/rs_math.cpython-312.pyc +0 -0
  129. package/lib/core/__pycache__/rs_rooms.cpython-312.pyc +0 -0
  130. package/lib/core/artifact-id.cjs +148 -0
  131. package/lib/core/asset-ops.cjs +151 -0
  132. package/lib/core/auto-commit-throttle.cjs +129 -0
  133. package/lib/core/bearer-token.cjs +199 -0
  134. package/lib/core/brain-client.cjs +865 -0
  135. package/lib/core/brain-derivation-prompts.cjs +326 -0
  136. package/lib/core/brain-derivation-queue.cjs +431 -0
  137. package/lib/core/brain-derivation.cjs +580 -0
  138. package/lib/core/brain-md-schema.cjs +528 -0
  139. package/lib/core/brain-md-staleness.cjs +357 -0
  140. package/lib/core/brain-response-sanitize.cjs +188 -0
  141. package/lib/core/bridge-writer.cjs +477 -0
  142. package/lib/core/chat-context-builder.cjs +253 -0
  143. package/lib/core/cross-room-aggregator.cjs +762 -0
  144. package/lib/core/daily-briefing.cjs +438 -0
  145. package/lib/core/decision-capture.cjs +618 -0
  146. package/lib/core/deep-links.cjs +82 -0
  147. package/lib/core/dispatch-optimizer.cjs +354 -0
  148. package/lib/core/dual-path-detector.cjs +84 -0
  149. package/lib/core/dual-path-detector.test.cjs +334 -0
  150. package/lib/core/exports-log.cjs +79 -0
  151. package/lib/core/feynman-minto-invariants.cjs +605 -0
  152. package/lib/core/folder-memory-async.cjs +338 -0
  153. package/lib/core/folder-memory-shared.cjs +890 -0
  154. package/lib/core/folder-memory.cjs +416 -0
  155. package/lib/core/framework-chain-composer.cjs +411 -0
  156. package/lib/core/frontmatter-schemas.cjs +330 -0
  157. package/lib/core/git-ops.cjs +141 -0
  158. package/lib/core/graph-ops.cjs +258 -0
  159. package/lib/core/hat-persistence.cjs +362 -0
  160. package/lib/core/index.cjs +60 -0
  161. package/lib/core/integration-registry.cjs +232 -0
  162. package/lib/core/intelligence-cascade.cjs +661 -0
  163. package/lib/core/lazygraph-ops.cjs +1057 -0
  164. package/lib/core/lru-cache.cjs +139 -0
  165. package/lib/core/mcp-profiles.cjs +182 -0
  166. package/lib/core/meeting-ops.cjs +54 -0
  167. package/lib/core/memory-ops.cjs +600 -0
  168. package/lib/core/migrations/ROOM.md +33 -0
  169. package/lib/core/migrations/phase-109-nodes-provenance.cjs +339 -0
  170. package/lib/core/migrations/phase-109-session-focus.cjs +99 -0
  171. package/lib/core/model-profiles.cjs +246 -0
  172. package/lib/core/mullins-scaffold.cjs +160 -0
  173. package/lib/core/nav-dial.cjs +316 -0
  174. package/lib/core/navigation/ROOM.md +15 -0
  175. package/lib/core/navigation/explanation.cjs +43 -0
  176. package/lib/core/navigation/focus.cjs +135 -0
  177. package/lib/core/navigation/ingestion.cjs +82 -0
  178. package/lib/core/navigation/insights.cjs +350 -0
  179. package/lib/core/navigation/memory-events.cjs +118 -0
  180. package/lib/core/navigation/neighborhood.cjs +78 -0
  181. package/lib/core/navigation/packet.cjs +182 -0
  182. package/lib/core/navigation/room-home.cjs +127 -0
  183. package/lib/core/navigation/transitions.cjs +82 -0
  184. package/lib/core/navigation-engine-shared.cjs +242 -0
  185. package/lib/core/navigation-engine.cjs +664 -0
  186. package/lib/core/navigation.cjs +60 -0
  187. package/lib/core/nl-graph-queries.cjs +164 -0
  188. package/lib/core/offer-presenter.cjs +406 -0
  189. package/lib/core/opportunity-extractor.cjs +183 -0
  190. package/lib/core/opportunity-ops.cjs +1371 -0
  191. package/lib/core/persona-ops.cjs +537 -0
  192. package/lib/core/persona-taxonomy.cjs +190 -0
  193. package/lib/core/platform-gates.cjs +120 -0
  194. package/lib/core/platform.cjs +257 -0
  195. package/lib/core/proactive-intelligence.cjs +528 -0
  196. package/lib/core/problem-type-router.cjs +315 -0
  197. package/lib/core/reasoning-ops.cjs +639 -0
  198. package/lib/core/reverse-salient-persona-suffix.cjs +115 -0
  199. package/lib/core/room-classifier-strict-mode.cjs +229 -0
  200. package/lib/core/room-db.cjs +127 -0
  201. package/lib/core/room-ops-async.cjs +92 -0
  202. package/lib/core/room-ops-shared.cjs +64 -0
  203. package/lib/core/room-ops-sync.cjs +70 -0
  204. package/lib/core/room-ops.cjs +32 -0
  205. package/lib/core/room-type-detector.cjs +386 -0
  206. package/lib/core/rs-brain-substrate-prompts.cjs +129 -0
  207. package/lib/core/rs-brain-substrate.cjs +570 -0
  208. package/lib/core/rs-breakthrough-scorer.cjs +255 -0
  209. package/lib/core/rs-canon-violations.cjs +82 -0
  210. package/lib/core/rs-chain-feeder.cjs +343 -0
  211. package/lib/core/rs-commercial-assessor.cjs +280 -0
  212. package/lib/core/rs-differential-scorer.cjs +376 -0
  213. package/lib/core/rs-domain-analyzer.cjs +385 -0
  214. package/lib/core/rs-egress-prompts.cjs +113 -0
  215. package/lib/core/rs-egress-telemetry.cjs +225 -0
  216. package/lib/core/rs-egress-violations.cjs +53 -0
  217. package/lib/core/rs-expert-mapper.cjs +467 -0
  218. package/lib/core/rs-fetcher-academic.cjs +697 -0
  219. package/lib/core/rs-fetcher-experts.cjs +314 -0
  220. package/lib/core/rs-fetcher-industry.cjs +731 -0
  221. package/lib/core/rs-fetcher-patents.cjs +564 -0
  222. package/lib/core/rs-innovation-classifier.cjs +194 -0
  223. package/lib/core/rs-mind-map.cjs +656 -0
  224. package/lib/core/rs-neo4j-writer.cjs +388 -0
  225. package/lib/core/rs-nl-to-query.cjs +425 -0
  226. package/lib/core/rs-pinecone-bridge.cjs +303 -0
  227. package/lib/core/rs-preprocessor.cjs +350 -0
  228. package/lib/core/rs-query-matrix.cjs +316 -0
  229. package/lib/core/rs-query-to-text.cjs +438 -0
  230. package/lib/core/rs-sqlite-mirror.cjs +443 -0
  231. package/lib/core/rs-thesis-generator.cjs +188 -0
  232. package/lib/core/rs_cache.py +479 -0
  233. package/lib/core/rs_corpus.py +468 -0
  234. package/lib/core/rs_hybrid.py +586 -0
  235. package/lib/core/rs_math.py +287 -0
  236. package/lib/core/rs_rooms.py +193 -0
  237. package/lib/core/scheduled-scanner.cjs +463 -0
  238. package/lib/core/scratchpad-ops.cjs +201 -0
  239. package/lib/core/section-8-trace-schema.cjs +138 -0
  240. package/lib/core/section-registry.cjs +111 -0
  241. package/lib/core/session-state.cjs +144 -0
  242. package/lib/core/shallow-doc-parser.cjs +174 -0
  243. package/lib/core/shallow-doc-parser.test.cjs +226 -0
  244. package/lib/core/skill-activation-router.cjs +284 -0
  245. package/lib/core/state-ops.cjs +46 -0
  246. package/lib/core/statusline-cache.cjs +266 -0
  247. package/lib/core/token-estimator.cjs +348 -0
  248. package/lib/core/user-archetype.cjs +239 -0
  249. package/lib/core/user-md-ops.cjs +524 -0
  250. package/lib/core/visual-ops.cjs +624 -0
  251. package/lib/core/write-lock.cjs +149 -0
  252. package/lib/graph/canvas-graph.js +467 -0
  253. package/lib/graph/constellation-config.cjs +299 -0
  254. package/lib/graph/graph-detail-panel.js +165 -0
  255. package/lib/hmi/ROOM.md +47 -0
  256. package/lib/hmi/across-session-memory.cjs +604 -0
  257. package/lib/hmi/cross-room-memory.cjs +575 -0
  258. package/lib/hmi/decoy-tier.cjs +395 -0
  259. package/lib/hmi/jtbd-classifier.cjs +219 -0
  260. package/lib/hmi/jtbd-state.cjs +199 -0
  261. package/lib/hmi/jtbd-taxonomy.json +392 -0
  262. package/lib/hmi/selector-dispatcher.cjs +546 -0
  263. package/lib/hmi/selector-telemetry.cjs +263 -0
  264. package/lib/hmi/shape-f0-renderer.cjs +139 -0
  265. package/lib/hmi/shape-f1-fallback.cjs +80 -0
  266. package/lib/hmi/shape-f1-renderer.cjs +138 -0
  267. package/lib/hmi/shape-f2-renderer.cjs +132 -0
  268. package/lib/hmi/shape-f3-renderer.cjs +66 -0
  269. package/lib/hmi/shape-f4-renderer.cjs +72 -0
  270. package/lib/hmi/shape-f5-renderer.cjs +155 -0
  271. package/lib/hmi/shape-f6-plan-review-renderer.cjs +312 -0
  272. package/lib/hmi/shape-f6-renderer.cjs +144 -0
  273. package/lib/hmi/shape-g-renderer.cjs +219 -0
  274. package/lib/hmi/shape-h-renderer.cjs +222 -0
  275. package/lib/hmi/tier-check.cjs +63 -0
  276. package/lib/import/PRECONDITIONS.md +41 -0
  277. package/lib/import/branding.cjs +210 -0
  278. package/lib/import/branding.test.cjs +235 -0
  279. package/lib/import/classifications-sync.cjs +104 -0
  280. package/lib/import/classifications-sync.test.cjs +129 -0
  281. package/lib/import/enricher.cjs +296 -0
  282. package/lib/import/enricher.test.cjs +273 -0
  283. package/lib/import/integration.test.cjs +376 -0
  284. package/lib/import/manifest.cjs +129 -0
  285. package/lib/import/manifest.schema.json +185 -0
  286. package/lib/import/manifest.test.cjs +123 -0
  287. package/lib/import/meeting-detector.cjs +92 -0
  288. package/lib/import/meeting-detector.test.cjs +100 -0
  289. package/lib/import/person-detector.cjs +229 -0
  290. package/lib/import/person-detector.test.cjs +149 -0
  291. package/lib/import/report.cjs +186 -0
  292. package/lib/import/report.test.cjs +186 -0
  293. package/lib/import/room-md-scaffolder.cjs +49 -0
  294. package/lib/import/router.cjs +224 -0
  295. package/lib/import/router.test.cjs +356 -0
  296. package/lib/import/run-all-tests.cjs +36 -0
  297. package/lib/import/smoke-test.cjs +213 -0
  298. package/lib/import/smoke-test.test.cjs +148 -0
  299. package/lib/import/test-fixtures/collision-vault/preexisting-room/STATE.md +8 -0
  300. package/lib/import/test-fixtures/collision-vault/preexisting-room/problem-definition/onboarding/onboarding.md +7 -0
  301. package/lib/import/test-fixtures/collision-vault/source/onboarding.md +5 -0
  302. package/lib/import/test-fixtures/obsidian-vault/.obsidian/workspace.json +1 -0
  303. package/lib/import/test-fixtures/obsidian-vault/notes/with-wikilinks.md +4 -0
  304. package/lib/import/test-fixtures/tiny-vault/notes/2026-01-15-team-sync.md +9 -0
  305. package/lib/import/test-fixtures/tiny-vault/notes/empty.md +3 -0
  306. package/lib/import/test-fixtures/tiny-vault/notes/onboarding.md +5 -0
  307. package/lib/import/test-fixtures/tiny-vault/notes/pricing.md +5 -0
  308. package/lib/import/test-fixtures/tiny-vault/notes/random.md +4 -0
  309. package/lib/import/undo.test.cjs +199 -0
  310. package/lib/import/vault-scanner.cjs +105 -0
  311. package/lib/import/vault-scanner.test.cjs +67 -0
  312. package/lib/mcp/app-html/dashboard.html +316 -0
  313. package/lib/mcp/app-html/graph.html +428 -0
  314. package/lib/mcp/app-html/mindrian-platform.html +1841 -0
  315. package/lib/mcp/app-html/wiki.html +383 -0
  316. package/lib/mcp/app-views.cjs +322 -0
  317. package/lib/mcp/brain-router.cjs +418 -0
  318. package/lib/mcp/capability-registry.cjs +62 -0
  319. package/lib/mcp/larry-context.cjs +46 -0
  320. package/lib/mcp/larry-server-instructions.md +114 -0
  321. package/lib/mcp/pipeline-state.cjs +275 -0
  322. package/lib/mcp/prompts.cjs +302 -0
  323. package/lib/mcp/resources.cjs +227 -0
  324. package/lib/mcp/session-catchup.cjs +327 -0
  325. package/lib/mcp/surface-detect.cjs +75 -0
  326. package/lib/mcp/tool-router.cjs +1034 -0
  327. package/lib/memory/aaak-compress.cjs +403 -0
  328. package/lib/memory/aaak-compress.test.cjs +288 -0
  329. package/lib/memory/async-artifact-auto-commit.test.cjs +223 -0
  330. package/lib/memory/bearer-token.test.cjs +315 -0
  331. package/lib/memory/brain-cache-lru.test.cjs +259 -0
  332. package/lib/memory/brain-client-query-shape.test.cjs +160 -0
  333. package/lib/memory/brain-derivation-graceful-degradation.test.cjs +1019 -0
  334. package/lib/memory/brain-derivation-queue.test.cjs +539 -0
  335. package/lib/memory/brain-derivation.test.cjs +634 -0
  336. package/lib/memory/brain-derive-command.test.cjs +534 -0
  337. package/lib/memory/brain-md-invariants-validator.test.cjs +704 -0
  338. package/lib/memory/brain-md-schema.test.cjs +467 -0
  339. package/lib/memory/brain-md-staleness.test.cjs +525 -0
  340. package/lib/memory/brain-server-resolution.test.cjs +314 -0
  341. package/lib/memory/chain-recommender.test.cjs +233 -0
  342. package/lib/memory/chat-context.test.cjs +128 -0
  343. package/lib/memory/command-registry.test.cjs +220 -0
  344. package/lib/memory/cross-room-aggregator.test.cjs +909 -0
  345. package/lib/memory/dashboard-server.test.cjs +256 -0
  346. package/lib/memory/debouncer-drain-at-prompt.test.cjs +389 -0
  347. package/lib/memory/decision-capture.test.cjs +632 -0
  348. package/lib/memory/decision-capture.worker.cjs +70 -0
  349. package/lib/memory/explain-decision-command.test.cjs +521 -0
  350. package/lib/memory/explain-decision-footer.test.cjs +316 -0
  351. package/lib/memory/explored-materials-store.cjs +392 -0
  352. package/lib/memory/feynman-minto-guardian.test.cjs +736 -0
  353. package/lib/memory/feynman-minto-invariants.test.cjs +511 -0
  354. package/lib/memory/feynman-prompts-drift.test.cjs +144 -0
  355. package/lib/memory/feynman-prompts.cjs +151 -0
  356. package/lib/memory/feynman-prompts.test.cjs +96 -0
  357. package/lib/memory/folder-memory-quadruple.test.cjs +548 -0
  358. package/lib/memory/folder-memory.test.cjs +503 -0
  359. package/lib/memory/framework-chain-composer.test.cjs +515 -0
  360. package/lib/memory/frontmatter-schema-validator.test.cjs +290 -0
  361. package/lib/memory/heal-command.test.cjs +604 -0
  362. package/lib/memory/index-artifact-transaction.test.cjs +333 -0
  363. package/lib/memory/lazygraph-rs-discoveries-view.test.cjs +122 -0
  364. package/lib/memory/mcp-input-validation.test.cjs +240 -0
  365. package/lib/memory/mcp-server-brain-deps.test.cjs +270 -0
  366. package/lib/memory/mcp-stack-fallback.test.cjs +433 -0
  367. package/lib/memory/minto-debouncer.test.cjs +407 -0
  368. package/lib/memory/minto-debouncer.worker.cjs +46 -0
  369. package/lib/memory/minto-migration-v88.test.cjs +265 -0
  370. package/lib/memory/minto-schema-v88.test.cjs +390 -0
  371. package/lib/memory/mos-status-renderer.test.cjs +631 -0
  372. package/lib/memory/narrative-schema.cjs +376 -0
  373. package/lib/memory/narrative-schema.test.cjs +209 -0
  374. package/lib/memory/nav-dial.test.cjs +414 -0
  375. package/lib/memory/navigation-engine-core.test.cjs +722 -0
  376. package/lib/memory/navigation-invariants.test.cjs +483 -0
  377. package/lib/memory/offer-presenter.test.cjs +554 -0
  378. package/lib/memory/on-stop-snapshot.test.cjs +404 -0
  379. package/lib/memory/pending-tension-store.cjs +373 -0
  380. package/lib/memory/post-compact-reinjection.test.cjs +854 -0
  381. package/lib/memory/post-write-triple.test.cjs +317 -0
  382. package/lib/memory/pre-compact-snapshot.test.cjs +495 -0
  383. package/lib/memory/problem-type-router.test.cjs +656 -0
  384. package/lib/memory/query-efficiency-telemetry.test.cjs +370 -0
  385. package/lib/memory/recompile-room-references.test.cjs +392 -0
  386. package/lib/memory/recompile-room-references.worker.cjs +42 -0
  387. package/lib/memory/record-decision-dual-write.test.cjs +454 -0
  388. package/lib/memory/room-classifier-strict-mode.test.cjs +417 -0
  389. package/lib/memory/room-minto-hook.test.cjs +398 -0
  390. package/lib/memory/rs-discovery-engine.test.cjs +323 -0
  391. package/lib/memory/run-feynman-tests.cjs +1247 -0
  392. package/lib/memory/security-trifecta.test.cjs +312 -0
  393. package/lib/memory/session-start-brain-staleness.test.cjs +363 -0
  394. package/lib/memory/session-start-triple-injection.test.cjs +514 -0
  395. package/lib/memory/sessionstart-banner-formatter.cjs +318 -0
  396. package/lib/memory/sessionstart-minto-banner.test.cjs +373 -0
  397. package/lib/memory/skill-activation-router.test.cjs +419 -0
  398. package/lib/memory/stamp-artifact-write.test.cjs +304 -0
  399. package/lib/memory/statusline-active-room.test.cjs +315 -0
  400. package/lib/memory/statusline-minto-segment.test.cjs +292 -0
  401. package/lib/memory/sync-async-entry-points.test.cjs +204 -0
  402. package/lib/memory/test-bridge-writer-enhanced.cjs +452 -0
  403. package/lib/memory/test-rs-brain-substrate-shape.cjs +529 -0
  404. package/lib/memory/test-rs-brain-substrate.cjs +636 -0
  405. package/lib/memory/test-rs-breakthrough-scorer.cjs +375 -0
  406. package/lib/memory/test-rs-canon-violations.cjs +218 -0
  407. package/lib/memory/test-rs-chain-feeder-core.cjs +344 -0
  408. package/lib/memory/test-rs-chain-feeder-skill-spawn.cjs +297 -0
  409. package/lib/memory/test-rs-commercial-assessor.cjs +385 -0
  410. package/lib/memory/test-rs-differential-scorer.cjs +480 -0
  411. package/lib/memory/test-rs-discovery-engine.cjs +603 -0
  412. package/lib/memory/test-rs-domain-analyzer.cjs +492 -0
  413. package/lib/memory/test-rs-egress-primitives.cjs +420 -0
  414. package/lib/memory/test-rs-expert-mapper.cjs +547 -0
  415. package/lib/memory/test-rs-explain-command.cjs +443 -0
  416. package/lib/memory/test-rs-fetcher-academic.cjs +848 -0
  417. package/lib/memory/test-rs-fetcher-experts.cjs +496 -0
  418. package/lib/memory/test-rs-fetcher-industry.cjs +702 -0
  419. package/lib/memory/test-rs-fetcher-patents.cjs +674 -0
  420. package/lib/memory/test-rs-innovation-classifier.cjs +301 -0
  421. package/lib/memory/test-rs-mind-map.cjs +646 -0
  422. package/lib/memory/test-rs-neo4j-writer.cjs +518 -0
  423. package/lib/memory/test-rs-nl-to-query.cjs +449 -0
  424. package/lib/memory/test-rs-pinecone-bridge.cjs +277 -0
  425. package/lib/memory/test-rs-preprocessor.cjs +433 -0
  426. package/lib/memory/test-rs-query-matrix.cjs +391 -0
  427. package/lib/memory/test-rs-query-to-text.cjs +551 -0
  428. package/lib/memory/test-rs-sqlite-mirror.cjs +649 -0
  429. package/lib/memory/test-rs-thesis-generator.cjs +360 -0
  430. package/lib/memory/triple-context-formatter.cjs +473 -0
  431. package/lib/memory/triple-context-formatter.test.cjs +442 -0
  432. package/lib/memory/user-md-persona.test.cjs +565 -0
  433. package/lib/memory/userpromptsubmit-integration.test.cjs +690 -0
  434. package/lib/memory/validators/README.md +157 -0
  435. package/lib/memory/validators/brain-md-invariants.cjs +475 -0
  436. package/lib/memory/validators/brain-substrate-invariants.cjs +285 -0
  437. package/lib/memory/validators/external-academic-invariants.cjs +249 -0
  438. package/lib/memory/validators/external-industry-invariants.cjs +271 -0
  439. package/lib/memory/validators/external-patents-invariants.cjs +266 -0
  440. package/lib/memory/validators/minto-invariants.cjs +62 -0
  441. package/lib/memory/validators/navigation-invariants.cjs +340 -0
  442. package/lib/memory/validators/queue-health.cjs +95 -0
  443. package/lib/memory/validators/snapshot-integrity.cjs +129 -0
  444. package/lib/memory/validators/stale-lifecycle.cjs +116 -0
  445. package/lib/memory/vault-section-minto-generator-atomic.test.cjs +556 -0
  446. package/lib/memory/vault-section-minto-generator-atomic.worker.cjs +73 -0
  447. package/lib/memory/write-lock-atomic.test.cjs +137 -0
  448. package/lib/memory/write-lock-atomic.worker.cjs +55 -0
  449. package/lib/parity/check-parity.cjs +83 -0
  450. package/lib/presentation/presentation-server.cjs +101 -0
  451. package/lib/presentation/presentation-watcher.cjs +123 -0
  452. package/lib/quickview/hub-server.cjs +719 -0
  453. package/lib/quickview/server.cjs +533 -0
  454. package/lib/render/JTBD-PALETTES.md +145 -0
  455. package/lib/render/ROOM.md +59 -0
  456. package/lib/render/render-v2.cjs +486 -0
  457. package/lib/render/render-v2.test.cjs +267 -0
  458. package/lib/render/render.cjs +65 -0
  459. package/lib/state/ROOM.md +46 -0
  460. package/lib/state/state-md-parser.cjs +215 -0
  461. package/lib/statusline/ROOM.md +38 -0
  462. package/lib/statusline/banner-suppression.cjs +50 -0
  463. package/lib/statusline/surface-detect.cjs +85 -0
  464. package/lib/update-bootstrap.sh.template +145 -0
  465. package/lib/vault/frontmatter-schema.cjs +297 -0
  466. package/lib/vault/room-scanner.cjs +352 -0
  467. package/lib/vault/wikilink-builder.cjs +231 -0
  468. package/lib/vault/wikilink-builder.test.cjs +182 -0
  469. package/lib/wiki/graph-links.cjs +281 -0
  470. package/lib/wiki/page-renderer.cjs +229 -0
  471. package/lib/wiki/wiki-chat.cjs +81 -0
  472. package/lib/wiki/wiki-layout.cjs +1459 -0
  473. package/lib/wiki/wiki-search.cjs +142 -0
  474. package/lib/wiki/wiki-server.cjs +678 -0
  475. package/lib/wiki/wiki-watcher.cjs +105 -0
  476. package/lib/workflow/ROOM.md +47 -0
  477. package/lib/workflow/command-resolver.cjs +155 -0
  478. package/lib/workflow/command-resolver.test.cjs +235 -0
  479. package/package.json +44 -0
  480. package/pipelines/analogy/01-decompose.md +80 -0
  481. package/pipelines/analogy/02-abstract.md +87 -0
  482. package/pipelines/analogy/03-search.md +135 -0
  483. package/pipelines/analogy/04-transfer.md +101 -0
  484. package/pipelines/analogy/05-validate.md +106 -0
  485. package/pipelines/analogy/CHAIN.md +56 -0
  486. package/pipelines/discovery/01-explore-domains.md +44 -0
  487. package/pipelines/discovery/02-think-hats.md +50 -0
  488. package/pipelines/discovery/03-analyze-needs.md +54 -0
  489. package/pipelines/discovery/CHAIN.md +37 -0
  490. package/pipelines/thesis/01-structure-argument.md +45 -0
  491. package/pipelines/thesis/02-challenge-assumptions.md +48 -0
  492. package/pipelines/thesis/03-build-thesis.md +54 -0
  493. package/pipelines/thesis/CHAIN.md +37 -0
  494. package/references/brain/causal-directives.md +91 -0
  495. package/references/brain/causal-enrichment.cypher +165 -0
  496. package/references/brain/command-triggers-schema.md +226 -0
  497. package/references/brain/graph-architecture.md +317 -0
  498. package/references/brain/query-patterns.md +460 -0
  499. package/references/brain/room-hierarchy-schema.md +218 -0
  500. package/references/brain/schema.md +76 -0
  501. package/references/capability-radar/capabilities-index.md +241 -0
  502. package/references/capability-radar/changelog-cache.md +81 -0
  503. package/references/causal/causal-schema.md +103 -0
  504. package/references/design/email-template-standard.md +155 -0
  505. package/references/design/graph-visualization-standard.md +178 -0
  506. package/references/document-generation.md +179 -0
  507. package/references/hsi/HSI-TOOLS-REFERENCE.md +222 -0
  508. package/references/import-config.md +141 -0
  509. package/references/integrations/detection-patterns.md +101 -0
  510. package/references/meeting/artifact-template.md +377 -0
  511. package/references/meeting/cross-meeting-intelligence.md +216 -0
  512. package/references/meeting/cross-relationship-patterns.md +202 -0
  513. package/references/meeting/live-join-interface.md +244 -0
  514. package/references/meeting/section-mapping.md +192 -0
  515. package/references/meeting/segment-classification.md +258 -0
  516. package/references/meeting/speaker-profile-template.md +219 -0
  517. package/references/meeting/summary-template.md +348 -0
  518. package/references/meeting/transcript-patterns.md +226 -0
  519. package/references/methodology/analyze-needs.md +135 -0
  520. package/references/methodology/analyze-systems.md +121 -0
  521. package/references/methodology/analyze-timing.md +149 -0
  522. package/references/methodology/beautiful-question.md +109 -0
  523. package/references/methodology/build-knowledge.md +161 -0
  524. package/references/methodology/build-thesis.md +237 -0
  525. package/references/methodology/challenge-assumptions.md +127 -0
  526. package/references/methodology/diagnose.md +169 -0
  527. package/references/methodology/dominant-designs.md +212 -0
  528. package/references/methodology/explore-domains.md +147 -0
  529. package/references/methodology/explore-futures.md +163 -0
  530. package/references/methodology/explore-trends.md +129 -0
  531. package/references/methodology/find-bottlenecks.md +131 -0
  532. package/references/methodology/grade.md +211 -0
  533. package/references/methodology/index.md +97 -0
  534. package/references/methodology/leadership.md +200 -0
  535. package/references/methodology/lean-canvas.md +116 -0
  536. package/references/methodology/macro-trends.md +192 -0
  537. package/references/methodology/map-unknowns.md +137 -0
  538. package/references/methodology/mullins-7-domains.md +104 -0
  539. package/references/methodology/problem-types.md +65 -0
  540. package/references/methodology/root-cause.md +178 -0
  541. package/references/methodology/sapphire-encoding.md +355 -0
  542. package/references/methodology/scenario-plan.md +178 -0
  543. package/references/methodology/score-innovation.md +154 -0
  544. package/references/methodology/structure-argument.md +158 -0
  545. package/references/methodology/systems-thinking.md +159 -0
  546. package/references/methodology/think-hats.md +147 -0
  547. package/references/methodology/triz-matrix.json +751 -0
  548. package/references/methodology/triz-principles.md +501 -0
  549. package/references/methodology/user-needs.md +199 -0
  550. package/references/methodology/validate.md +163 -0
  551. package/references/methodology/value-proposition.md +244 -0
  552. package/references/opportunities/funding-lifecycle.md +103 -0
  553. package/references/opportunities/grant-api-patterns.md +99 -0
  554. package/references/opportunities/opportunity-template.md +84 -0
  555. package/references/personality/assessment-philosophy.md +72 -0
  556. package/references/personality/lexicon.md +100 -0
  557. package/references/personality/persona-chains.md +56 -0
  558. package/references/personality/pws-lexicon-full.md +499 -0
  559. package/references/personality/voice-dna.md +156 -0
  560. package/references/personas/hat-perspectives.md +76 -0
  561. package/references/personas/persona-template.md +63 -0
  562. package/references/pipeline/act-output-contract.md +88 -0
  563. package/references/pipeline/chains-index.md +39 -0
  564. package/references/pws-profile-generation.md +79 -0
  565. package/references/reasoning/reasoning-schema.md +143 -0
  566. package/references/reasoning/reasoning-template.md +68 -0
  567. package/references/reasoning/run-template.md +38 -0
  568. package/references/research/RESEARCH_14_CLAUDE_CODE_SOURCE_ARCHITECTURE.md +209 -0
  569. package/references/research/RESEARCH_15_V1.8_OPTIMIZATION_JTBD.md +375 -0
  570. package/references/research/RESEARCH_16_NATIVE_FIRST_PLUGIN_ARCHITECTURE.md +575 -0
  571. package/references/research/RESEARCH_17_MCP_UI_FRAMEWORKS.md +272 -0
  572. package/references/taxonomy/TAXONOMY.md +192 -0
  573. package/references/templates/MINTO.md +36 -0
  574. package/references/user-research/2026-04-05-leah-lawrence-session.md +202 -0
  575. package/references/vault-kit/README.md +35 -0
  576. package/references/vault-kit/app.json +12 -0
  577. package/references/vault-kit/appearance.json +12 -0
  578. package/references/vault-kit/graph.json +35 -0
  579. package/references/vault-kit/snippets/mindrian-destijl.css +297 -0
  580. package/references/vault-kit/templates/new-artifact.md +37 -0
  581. package/references/vault-kit/templates/new-meeting-note.md +35 -0
  582. package/references/vault-kit/templates/new-team-profile.md +29 -0
  583. package/references/vault-kit/templates/new-xref.md +35 -0
  584. package/references/visual/symbol-system.md +151 -0
  585. package/skills/MOSDeckEngine/SKILL.md +325 -0
  586. package/skills/brain-connector/SKILL.md +114 -0
  587. package/skills/context-engine/SKILL.md +147 -0
  588. package/skills/conversation-mode/SKILL.md +102 -0
  589. package/skills/larry-personality/SKILL.md +219 -0
  590. package/skills/larry-personality/framework-chains.md +92 -0
  591. package/skills/larry-personality/mode-engine.md +185 -0
  592. package/skills/mullins-scaffold/SKILL.md +61 -0
  593. package/skills/mullins-scaffold/scaffold.json +146 -0
  594. package/skills/pws-methodology/SKILL.md +49 -0
  595. package/skills/room-passive/SKILL.md +165 -0
  596. package/skills/room-proactive/SKILL.md +250 -0
  597. package/skills/ui-system/SKILL.md +277 -0
@@ -0,0 +1,528 @@
1
+ /**
2
+ * MindrianOS Plugin -- Proactive Intelligence Persistence
3
+ * Parses analyze-room output, persists insights with repeat suppression,
4
+ * and tracks cross-room relationships.
5
+ *
6
+ * Exports: persistIntelligence, loadIntelligence, shouldSuppress, addCrossRoomRelationship
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const fs = require('fs');
12
+ const path = require('path');
13
+
14
+ const INTELLIGENCE_FILE = '.proactive-intelligence.json';
15
+ const SUPPRESS_THRESHOLD = 3;
16
+
17
+ /**
18
+ * Load existing intelligence from room directory.
19
+ * @param {string} roomDir - Absolute path to room directory
20
+ * @returns {{ insights: Array, cross_room: Array, updated: string }}
21
+ */
22
+ function loadIntelligence(roomDir) {
23
+ const filePath = path.join(roomDir, INTELLIGENCE_FILE);
24
+ try {
25
+ if (fs.existsSync(filePath)) {
26
+ const raw = fs.readFileSync(filePath, 'utf8');
27
+ const data = JSON.parse(raw);
28
+ return {
29
+ insights: Array.isArray(data.insights) ? data.insights : [],
30
+ cross_room: Array.isArray(data.cross_room) ? data.cross_room : [],
31
+ updated: data.updated || ''
32
+ };
33
+ }
34
+ } catch (_) {
35
+ // Corrupted file -- start fresh
36
+ }
37
+ return { insights: [], cross_room: [], updated: '' };
38
+ }
39
+
40
+ /**
41
+ * Parse analyze-room stdout into structured insight objects.
42
+ * Handles: GAP:STRUCTURAL, GAP:SEMANTIC, GAP:ADJACENT, CONVERGE, CONTRADICT lines.
43
+ * @param {string} analyzeOutput - Raw stdout from analyze-room script
44
+ * @returns {Array<{ type: string, section?: string, term?: string, message: string, confidence: string }>}
45
+ */
46
+ function parseAnalyzeOutput(analyzeOutput) {
47
+ if (!analyzeOutput || typeof analyzeOutput !== 'string') return [];
48
+
49
+ const insights = [];
50
+ const lines = analyzeOutput.split('\n');
51
+
52
+ for (const line of lines) {
53
+ const trimmed = line.trim();
54
+
55
+ // GAP:STRUCTURAL:{section}:{confidence}:{message}
56
+ // GAP:SEMANTIC:{section}:{confidence}:{message}
57
+ // GAP:ADJACENT:{section}:{confidence}:{message}
58
+ const gapMatch = trimmed.match(/^GAP:(STRUCTURAL|SEMANTIC|ADJACENT):([^:]+):([^:]+):(.+)$/);
59
+ if (gapMatch) {
60
+ insights.push({
61
+ type: 'gap',
62
+ subtype: gapMatch[1].toLowerCase(),
63
+ section: gapMatch[2],
64
+ confidence: gapMatch[3],
65
+ message: gapMatch[4]
66
+ });
67
+ continue;
68
+ }
69
+
70
+ // CONVERGE:{term}:{count}:{confidence}:{message}
71
+ const convergeMatch = trimmed.match(/^CONVERGE:([^:]+):(\d+):([^:]+):(.+)$/);
72
+ if (convergeMatch) {
73
+ insights.push({
74
+ type: 'convergence',
75
+ term: convergeMatch[1],
76
+ count: parseInt(convergeMatch[2], 10),
77
+ confidence: convergeMatch[3],
78
+ message: convergeMatch[4]
79
+ });
80
+ continue;
81
+ }
82
+
83
+ // CONTRADICT:{section1}:{section2}:{confidence}:{message}
84
+ const contradictMatch = trimmed.match(/^CONTRADICT:([^:]+):([^:]+):([^:]+):(.+)$/);
85
+ if (contradictMatch) {
86
+ insights.push({
87
+ type: 'contradiction',
88
+ section: contradictMatch[1],
89
+ section2: contradictMatch[2],
90
+ confidence: contradictMatch[3],
91
+ message: contradictMatch[4]
92
+ });
93
+ continue;
94
+ }
95
+ }
96
+
97
+ return insights;
98
+ }
99
+
100
+ /**
101
+ * Match key for deduplication: type + section (for gaps/contradictions) or type + term (for convergence).
102
+ * @param {{ type: string, section?: string, term?: string, section2?: string }} insight
103
+ * @returns {string}
104
+ */
105
+ function insightKey(insight) {
106
+ if (insight.type === 'convergence') {
107
+ return `convergence:${insight.term || ''}`;
108
+ }
109
+ if (insight.type === 'contradiction') {
110
+ return `contradiction:${insight.section || ''}:${insight.section2 || ''}`;
111
+ }
112
+ return `gap:${insight.subtype || ''}:${insight.section || ''}`;
113
+ }
114
+
115
+ /**
116
+ * Read recent semantic findings from the lazygraph and map them to insight
117
+ * records that match parseAnalyzeOutput()'s shape exactly so insightKey()
118
+ * dedup folds graph and bash-script findings together.
119
+ *
120
+ * Queries CONTRADICTS, CONVERGES, INVALIDATES edges with created_at
121
+ * greater than sinceTimestamp, walks INFORMS edges to Stakeholder nodes,
122
+ * and emits one insight per edge in the same shape as parseAnalyzeOutput.
123
+ * Empty array on any failure path. Never throws.
124
+ *
125
+ * @param {string} roomDir - Absolute path to room directory
126
+ * @param {number} sinceTimestamp - Unix ms; only edges with created_at greater than this
127
+ * @returns {Array<object>} insights in parseAnalyzeOutput() shape
128
+ */
129
+ function readGraphFindings(roomDir, sinceTimestamp) {
130
+ try {
131
+ const lazygraph = require('./lazygraph-ops.cjs');
132
+ let handle;
133
+ try {
134
+ // Direct sync open of the room.db so we can run inside the cascade
135
+ // without await. If the file is missing, return empty findings.
136
+ const fsLocal = require('fs');
137
+ const pathLocal = require('path');
138
+ const { DatabaseSync } = require('node:sqlite');
139
+ const dbPath = pathLocal.join(pathLocal.resolve(roomDir), '.mindrian', 'room.db');
140
+ if (!fsLocal.existsSync(dbPath)) return [];
141
+ const db = new DatabaseSync(dbPath, { open: true, readOnly: true });
142
+ handle = { db, conn: db, _opened: 'sync' };
143
+ } catch (_) {
144
+ return [];
145
+ }
146
+
147
+ const db = handle.db || handle.conn;
148
+ // Reference lazygraph to silence linters and signal contract dependency
149
+ void lazygraph;
150
+ const sinceMs = typeof sinceTimestamp === 'number' ? sinceTimestamp : 0;
151
+ const insights = [];
152
+
153
+ let edges = [];
154
+ try {
155
+ edges = db.prepare(
156
+ `SELECT source, target, type, properties FROM edges
157
+ WHERE type IN ('CONTRADICTS', 'CONVERGES', 'INVALIDATES')
158
+ LIMIT 50`
159
+ ).all();
160
+ } catch (_) {
161
+ edges = [];
162
+ }
163
+
164
+ for (const edge of edges) {
165
+ // Filter by created_at when present in properties JSON
166
+ let createdAt = 0;
167
+ try {
168
+ const props = edge.properties ? JSON.parse(edge.properties) : {};
169
+ if (typeof props.created_at === 'number') createdAt = props.created_at;
170
+ } catch (_) {
171
+ createdAt = 0;
172
+ }
173
+ if (sinceMs > 0 && createdAt > 0 && createdAt <= sinceMs) continue;
174
+
175
+ // Resolve endpoint section names for shape-compatible insight keys
176
+ let sourceSection = '';
177
+ let targetSection = '';
178
+ try {
179
+ const srcNode = db.prepare("SELECT properties FROM nodes WHERE id = ?").get(edge.source);
180
+ const tgtNode = db.prepare("SELECT properties FROM nodes WHERE id = ?").get(edge.target);
181
+ if (srcNode && srcNode.properties) {
182
+ try { sourceSection = (JSON.parse(srcNode.properties).section) || edge.source.split('/')[0] || ''; } catch (_) { sourceSection = edge.source.split('/')[0] || ''; }
183
+ } else {
184
+ sourceSection = edge.source.split('/')[0] || '';
185
+ }
186
+ if (tgtNode && tgtNode.properties) {
187
+ try { targetSection = (JSON.parse(tgtNode.properties).section) || edge.target.split('/')[0] || ''; } catch (_) { targetSection = edge.target.split('/')[0] || ''; }
188
+ } else {
189
+ targetSection = edge.target.split('/')[0] || '';
190
+ }
191
+ } catch (_) {
192
+ sourceSection = edge.source.split('/')[0] || '';
193
+ targetSection = edge.target.split('/')[0] || '';
194
+ }
195
+
196
+ // Cap stakeholder context to 5 other claims to bound injection noise
197
+ let stakeholderContext = '';
198
+ try {
199
+ const stakeholders = lazygraph.findStakeholdersByClaim
200
+ ? db.prepare(
201
+ `SELECT s.id, s.name FROM stakeholders s
202
+ WHERE s.id IN (
203
+ SELECT source FROM edges WHERE target = ? AND type = 'INFORMS'
204
+ UNION
205
+ SELECT target FROM edges WHERE source = ? AND type = 'INFORMS'
206
+ ) LIMIT 5`
207
+ ).all(edge.source, edge.source)
208
+ : [];
209
+ if (stakeholders && stakeholders.length > 0) {
210
+ stakeholderContext = ' (stakeholders: ' + stakeholders.map(s => s.name).join(', ') + ')';
211
+ }
212
+ } catch (_) {
213
+ stakeholderContext = '';
214
+ }
215
+
216
+ if (edge.type === 'CONTRADICTS') {
217
+ insights.push({
218
+ type: 'contradiction',
219
+ section: sourceSection,
220
+ section2: targetSection,
221
+ confidence: 'medium',
222
+ message: `Graph contradiction: ${edge.source} vs ${edge.target}${stakeholderContext}`
223
+ });
224
+ } else if (edge.type === 'CONVERGES') {
225
+ insights.push({
226
+ type: 'convergence',
227
+ term: `${sourceSection}+${targetSection}`,
228
+ count: 2,
229
+ confidence: 'medium',
230
+ message: `Graph convergence: ${edge.source} and ${edge.target}${stakeholderContext}`
231
+ });
232
+ } else if (edge.type === 'INVALIDATES') {
233
+ insights.push({
234
+ type: 'gap',
235
+ subtype: 'structural',
236
+ section: targetSection,
237
+ confidence: 'medium',
238
+ message: `Graph invalidation: ${edge.source} invalidates ${edge.target}${stakeholderContext}`
239
+ });
240
+ }
241
+ }
242
+
243
+ // Close the db handle if we opened it ourselves
244
+ try {
245
+ if (handle && handle._opened === 'sync' && handle.db) {
246
+ handle.db.close();
247
+ }
248
+ } catch (_) { /* ignore */ }
249
+
250
+ return insights;
251
+ } catch (_) {
252
+ return [];
253
+ }
254
+ }
255
+
256
+ /**
257
+ * Persist intelligence from analyze-room output with repeat suppression.
258
+ * Phase 84-05: also reads graph findings via readGraphFindings() and merges
259
+ * them into the same insight stream before shouldSuppress() dedup.
260
+ * @param {string} roomDir - Absolute path to room directory
261
+ * @param {string} analyzeOutput - Raw stdout from analyze-room script
262
+ * @returns {{ persisted: number, new: number, suppressed: number }}
263
+ */
264
+ function persistIntelligence(roomDir, analyzeOutput) {
265
+ const bashParsed = parseAnalyzeOutput(analyzeOutput);
266
+
267
+ // Phase 84-05: pull graph-sourced insights using the previous run's
268
+ // updated timestamp as the high-water mark. Failures fall through to [].
269
+ let graphParsed = [];
270
+ try {
271
+ const prior = loadIntelligence(roomDir);
272
+ let sinceMs = 0;
273
+ if (prior && prior.updated) {
274
+ const t = Date.parse(prior.updated);
275
+ if (!Number.isNaN(t)) sinceMs = t;
276
+ }
277
+ graphParsed = readGraphFindings(roomDir, sinceMs) || [];
278
+ } catch (_) {
279
+ graphParsed = [];
280
+ }
281
+
282
+ const parsed = bashParsed.concat(graphParsed);
283
+ if (parsed.length === 0) {
284
+ return { persisted: 0, new: 0, suppressed: 0 };
285
+ }
286
+
287
+ const data = loadIntelligence(roomDir);
288
+ const now = new Date().toISOString();
289
+
290
+ // Build lookup by key
291
+ const existingMap = new Map();
292
+ for (let i = 0; i < data.insights.length; i++) {
293
+ existingMap.set(insightKey(data.insights[i]), i);
294
+ }
295
+
296
+ let newCount = 0;
297
+ let suppressed = 0;
298
+
299
+ for (const insight of parsed) {
300
+ const key = insightKey(insight);
301
+ const existingIdx = existingMap.get(key);
302
+
303
+ if (existingIdx !== undefined) {
304
+ // Existing insight -- check for evidence changes, then increment times_shown
305
+ const existing = data.insights[existingIdx];
306
+ // Evidence-change detection: if confidence or message changed, reset suppression
307
+ const evidenceChanged = (existing.confidence !== insight.confidence) || (existing.message !== insight.message);
308
+ if (evidenceChanged && shouldSuppress(existing)) {
309
+ existing.times_shown = 0;
310
+ existing.confidence = insight.confidence;
311
+ existing.message = insight.message;
312
+ }
313
+ existing.times_shown = (existing.times_shown || 0) + 1;
314
+ existing.last_seen = now;
315
+ if (existing.times_shown >= SUPPRESS_THRESHOLD) {
316
+ suppressed++;
317
+ }
318
+ } else {
319
+ // New insight
320
+ const entry = {
321
+ ...insight,
322
+ first_seen: now,
323
+ last_seen: now,
324
+ times_shown: 0
325
+ };
326
+ data.insights.push(entry);
327
+ existingMap.set(key, data.insights.length - 1);
328
+ newCount++;
329
+ }
330
+ }
331
+
332
+ data.updated = now;
333
+
334
+ // Write atomically
335
+ const filePath = path.join(roomDir, INTELLIGENCE_FILE);
336
+ const tmpPath = filePath + '.tmp';
337
+ fs.writeFileSync(tmpPath, JSON.stringify(data, null, 2), 'utf8');
338
+ fs.renameSync(tmpPath, filePath);
339
+
340
+ return { persisted: parsed.length, new: newCount, suppressed };
341
+ }
342
+
343
+ /**
344
+ * Check if an insight should be suppressed (shown 3+ times).
345
+ * @param {{ times_shown: number }} insight
346
+ * @returns {boolean}
347
+ */
348
+ function shouldSuppress(insight) {
349
+ return (insight && typeof insight.times_shown === 'number' && insight.times_shown >= SUPPRESS_THRESHOLD);
350
+ }
351
+
352
+ /**
353
+ * Add or update a cross-room relationship.
354
+ * @param {string} roomDir - Absolute path to room directory
355
+ * @param {string} sourceRoom - Source room name/path
356
+ * @param {string} targetRoom - Target room name/path
357
+ * @param {string[]} sharedConcepts - Array of shared concept strings
358
+ */
359
+ function addCrossRoomRelationship(roomDir, sourceRoom, targetRoom, sharedConcepts) {
360
+ const data = loadIntelligence(roomDir);
361
+ const now = new Date().toISOString();
362
+
363
+ // Find existing relationship (same source + target)
364
+ const existing = data.cross_room.find(
365
+ cr => cr.source_room === sourceRoom && cr.target_room === targetRoom
366
+ );
367
+
368
+ if (existing) {
369
+ // Union shared concepts
370
+ const conceptSet = new Set([...(existing.shared_concepts || []), ...sharedConcepts]);
371
+ existing.shared_concepts = [...conceptSet];
372
+ existing.detected = now;
373
+ } else {
374
+ data.cross_room.push({
375
+ source_room: sourceRoom,
376
+ target_room: targetRoom,
377
+ shared_concepts: [...sharedConcepts],
378
+ detected: now
379
+ });
380
+ }
381
+
382
+ data.updated = now;
383
+
384
+ // Write atomically
385
+ const filePath = path.join(roomDir, INTELLIGENCE_FILE);
386
+ const tmpPath = filePath + '.tmp';
387
+ fs.writeFileSync(tmpPath, JSON.stringify(data, null, 2), 'utf8');
388
+ fs.renameSync(tmpPath, filePath);
389
+ }
390
+
391
+ /**
392
+ * Get new or changed findings not previously seen by the user.
393
+ * Compares current analyze-room insights against persisted intelligence.
394
+ * Returns max 5 findings sorted by confidence descending.
395
+ *
396
+ * @param {string} roomDir - Absolute path to room directory
397
+ * @param {Array<{ type: string, section?: string, term?: string, confidence: string, message: string }>} currentInsights - Parsed insights from current analyze-room run
398
+ * @returns {Array<{ type: string, section?: string, term?: string, confidence: string, message: string, isNew: boolean }>}
399
+ */
400
+ function getNewFindings(roomDir, currentInsights) {
401
+ if (!Array.isArray(currentInsights) || currentInsights.length === 0) return [];
402
+
403
+ const data = loadIntelligence(roomDir);
404
+
405
+ // Build lookup of persisted insights by key
406
+ const persistedMap = new Map();
407
+ for (const insight of data.insights) {
408
+ persistedMap.set(insightKey(insight), insight);
409
+ }
410
+
411
+ const findings = [];
412
+
413
+ for (const insight of currentInsights) {
414
+ const key = insightKey(insight);
415
+ const existing = persistedMap.get(key);
416
+
417
+ // Skip insights that have been decided on
418
+ if (existing && existing.decided) continue;
419
+
420
+ // Skip suppressed insights (shown 3+ times)
421
+ if (existing && shouldSuppress(existing)) continue;
422
+
423
+ let isNew = false;
424
+ let include = false;
425
+
426
+ if (!existing) {
427
+ // Brand new insight
428
+ isNew = true;
429
+ include = true;
430
+ } else if (existing.confidence !== insight.confidence) {
431
+ // Confidence has changed -- updated finding
432
+ isNew = false;
433
+ include = true;
434
+ }
435
+
436
+ if (include) {
437
+ findings.push({
438
+ type: insight.type,
439
+ subtype: insight.subtype,
440
+ section: insight.section,
441
+ term: insight.term,
442
+ section2: insight.section2,
443
+ confidence: insight.confidence,
444
+ message: insight.message,
445
+ isNew
446
+ });
447
+ }
448
+ }
449
+
450
+ // Sort by confidence descending
451
+ findings.sort((a, b) => parseFloat(b.confidence || '0') - parseFloat(a.confidence || '0'));
452
+
453
+ // Return max 5
454
+ return findings.slice(0, 5);
455
+ }
456
+
457
+ /**
458
+ * Record a user decision (approve/reject/defer) for an insight.
459
+ * Persists to .proactive-intelligence.json and marks insight as decided.
460
+ *
461
+ * @param {string} roomDir - Absolute path to room directory
462
+ * @param {string} key - Insight key (from insightKey())
463
+ * @param {'approve'|'reject'|'defer'} decision - The user's decision
464
+ * @param {string} reason - Reason for the decision (especially important for reject)
465
+ * @returns {{ recorded: boolean, edgeType: string }}
466
+ */
467
+ function recordDecision(roomDir, key, decision, reason) {
468
+ const data = loadIntelligence(roomDir);
469
+ const now = new Date().toISOString();
470
+
471
+ // Initialize decisions array if not present
472
+ if (!Array.isArray(data.decisions)) {
473
+ data.decisions = [];
474
+ }
475
+
476
+ // Record the decision
477
+ const decisionEntry = {
478
+ insight_key: key,
479
+ decision,
480
+ reason: reason || '',
481
+ timestamp: now
482
+ };
483
+
484
+ // If rejection, store reason as separate field for graph enrichment (Decision #13)
485
+ if (decision === 'reject') {
486
+ decisionEntry.rejection_reason = reason || '';
487
+ }
488
+
489
+ data.decisions.push(decisionEntry);
490
+
491
+ // Mark the corresponding insight as decided so it won't be re-surfaced
492
+ for (const insight of data.insights) {
493
+ if (insightKey(insight) === key) {
494
+ insight.decided = true;
495
+ insight.decision_type = decision;
496
+ break;
497
+ }
498
+ }
499
+
500
+ data.updated = now;
501
+
502
+ // Write atomically (tmp + rename pattern)
503
+ const filePath = path.join(roomDir, INTELLIGENCE_FILE);
504
+ const tmpPath = filePath + '.tmp';
505
+ fs.writeFileSync(tmpPath, JSON.stringify(data, null, 2), 'utf8');
506
+ fs.renameSync(tmpPath, filePath);
507
+
508
+ // Map decision to SQLite edge type
509
+ const edgeTypeMap = {
510
+ approve: 'INVALIDATES',
511
+ reject: 'CONFIRMS',
512
+ defer: 'DEFERRED'
513
+ };
514
+
515
+ return { recorded: true, edgeType: edgeTypeMap[decision] || 'DEFERRED' };
516
+ }
517
+
518
+ module.exports = {
519
+ persistIntelligence,
520
+ loadIntelligence,
521
+ shouldSuppress,
522
+ addCrossRoomRelationship,
523
+ parseAnalyzeOutput,
524
+ insightKey,
525
+ getNewFindings,
526
+ recordDecision,
527
+ readGraphFindings
528
+ };