@mindrian_os/cli 1.13.0-beta.10 → 1.13.0-beta.43

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 (590) hide show
  1. package/CHANGELOG.md +340 -13
  2. package/README.md +76 -579
  3. package/bin/cli.js +166 -40
  4. package/lib/core/active-plugin-root.cjs +207 -0
  5. package/package.json +7 -13
  6. package/.claude-plugin/plugin.json +0 -21
  7. package/.mcp.json +0 -9
  8. package/agents/brain-query.md +0 -80
  9. package/agents/framework-runner.md +0 -237
  10. package/agents/grading.md +0 -188
  11. package/agents/investor.md +0 -128
  12. package/agents/larry-extended.md +0 -135
  13. package/agents/opportunity-scanner.md +0 -91
  14. package/agents/persona-analyst.md +0 -132
  15. package/agents/research.md +0 -89
  16. package/agents/reverse-salient-agent.md +0 -27
  17. package/bin/mindrian-mcp-server.cjs +0 -182
  18. package/bin/mindrian-tools.cjs +0 -765
  19. package/commands/act.md +0 -433
  20. package/commands/admin.md +0 -404
  21. package/commands/analyze-needs.md +0 -36
  22. package/commands/analyze-systems.md +0 -33
  23. package/commands/analyze-timing.md +0 -36
  24. package/commands/auto-explore.md +0 -64
  25. package/commands/beautiful-question.md +0 -34
  26. package/commands/brain-derive.md +0 -78
  27. package/commands/build-knowledge.md +0 -36
  28. package/commands/build-thesis.md +0 -40
  29. package/commands/causal.md +0 -228
  30. package/commands/challenge-assumptions.md +0 -33
  31. package/commands/compare-ventures.md +0 -77
  32. package/commands/dashboard.md +0 -110
  33. package/commands/deep-grade.md +0 -76
  34. package/commands/diagnose.md +0 -52
  35. package/commands/diagnostics.md +0 -145
  36. package/commands/doctor.md +0 -151
  37. package/commands/dominant-designs.md +0 -34
  38. package/commands/explain-decision.md +0 -87
  39. package/commands/explore-domains.md +0 -36
  40. package/commands/explore-futures.md +0 -34
  41. package/commands/explore-trends.md +0 -36
  42. package/commands/export.md +0 -103
  43. package/commands/file-meeting.md +0 -724
  44. package/commands/find-analogies.md +0 -182
  45. package/commands/find-bottlenecks.md +0 -56
  46. package/commands/find-connections.md +0 -70
  47. package/commands/funding.md +0 -81
  48. package/commands/grade.md +0 -197
  49. package/commands/graph.md +0 -128
  50. package/commands/hat-briefing.md +0 -119
  51. package/commands/heal.md +0 -196
  52. package/commands/help.md +0 -399
  53. package/commands/hmi-status.md +0 -172
  54. package/commands/jtbd.md +0 -241
  55. package/commands/leadership.md +0 -73
  56. package/commands/lean-canvas.md +0 -34
  57. package/commands/macro-trends.md +0 -34
  58. package/commands/map-unknowns.md +0 -34
  59. package/commands/memory.md +0 -173
  60. package/commands/models.md +0 -175
  61. package/commands/mos-reason.md +0 -279
  62. package/commands/mullins.md +0 -114
  63. package/commands/new-project.md +0 -481
  64. package/commands/onboard.md +0 -434
  65. package/commands/operator.md +0 -149
  66. package/commands/opportunities.md +0 -144
  67. package/commands/organize.md +0 -497
  68. package/commands/persona.md +0 -192
  69. package/commands/pipeline.md +0 -106
  70. package/commands/present.md +0 -91
  71. package/commands/publish.md +0 -201
  72. package/commands/query.md +0 -124
  73. package/commands/radar.md +0 -72
  74. package/commands/reanalyze.md +0 -91
  75. package/commands/research.md +0 -190
  76. package/commands/room.md +0 -352
  77. package/commands/rooms.md +0 -598
  78. package/commands/root-cause.md +0 -34
  79. package/commands/rs-experts.md +0 -79
  80. package/commands/rs-explain.md +0 -94
  81. package/commands/rs-fetch.md +0 -88
  82. package/commands/rs-thesis.md +0 -79
  83. package/commands/scenario-plan.md +0 -34
  84. package/commands/scheduled-tasks.md +0 -285
  85. package/commands/score-innovation.md +0 -37
  86. package/commands/scout.md +0 -239
  87. package/commands/setup.md +0 -618
  88. package/commands/snapshot.md +0 -147
  89. package/commands/speakers.md +0 -84
  90. package/commands/splash.md +0 -28
  91. package/commands/status.md +0 -75
  92. package/commands/structure-argument.md +0 -36
  93. package/commands/suggest-next.md +0 -74
  94. package/commands/systems-thinking.md +0 -34
  95. package/commands/think-hats.md +0 -36
  96. package/commands/update.md +0 -181
  97. package/commands/user-needs.md +0 -34
  98. package/commands/validate.md +0 -34
  99. package/commands/value-proposition.md +0 -55
  100. package/commands/vault.md +0 -180
  101. package/commands/visualize.md +0 -52
  102. package/commands/whitespace.md +0 -501
  103. package/commands/wiki.md +0 -69
  104. package/hooks/hooks.json +0 -381
  105. package/hooks/run-hook.cmd +0 -64
  106. package/lib/__init__.py +0 -0
  107. package/lib/__pycache__/__init__.cpython-312.pyc +0 -0
  108. package/lib/agents/auto-explore-agent.cjs +0 -1043
  109. package/lib/agents/reverse-salient-agent.cjs +0 -679
  110. package/lib/agents/tension-hook-agent.cjs +0 -544
  111. package/lib/chat/chat-context.js +0 -185
  112. package/lib/chat/chat-panel.js +0 -721
  113. package/lib/chat/fabric-chat.cjs +0 -288
  114. package/lib/chat/generative-tools.js +0 -219
  115. package/lib/conversation/ROOM.md +0 -39
  116. package/lib/conversation/classifier-rules.json +0 -38
  117. package/lib/conversation/classifier.cjs +0 -264
  118. package/lib/conversation/operator.cjs +0 -287
  119. package/lib/copy/115-spec-strings.cjs +0 -55
  120. package/lib/core/__init__.py +0 -0
  121. package/lib/core/__nav-stub.cjs +0 -14
  122. package/lib/core/__pycache__/__init__.cpython-312.pyc +0 -0
  123. package/lib/core/__pycache__/rs-math.cpython-312.pyc +0 -0
  124. package/lib/core/__pycache__/rs_cache.cpython-312.pyc +0 -0
  125. package/lib/core/__pycache__/rs_corpus.cpython-312.pyc +0 -0
  126. package/lib/core/__pycache__/rs_hybrid.cpython-312.pyc +0 -0
  127. package/lib/core/__pycache__/rs_math.cpython-312.pyc +0 -0
  128. package/lib/core/__pycache__/rs_rooms.cpython-312.pyc +0 -0
  129. package/lib/core/artifact-id.cjs +0 -148
  130. package/lib/core/asset-ops.cjs +0 -151
  131. package/lib/core/auto-commit-throttle.cjs +0 -129
  132. package/lib/core/bearer-token.cjs +0 -199
  133. package/lib/core/brain-client.cjs +0 -865
  134. package/lib/core/brain-derivation-prompts.cjs +0 -326
  135. package/lib/core/brain-derivation-queue.cjs +0 -431
  136. package/lib/core/brain-derivation.cjs +0 -580
  137. package/lib/core/brain-md-schema.cjs +0 -528
  138. package/lib/core/brain-md-staleness.cjs +0 -357
  139. package/lib/core/brain-response-sanitize.cjs +0 -188
  140. package/lib/core/bridge-writer.cjs +0 -477
  141. package/lib/core/chat-context-builder.cjs +0 -253
  142. package/lib/core/cross-room-aggregator.cjs +0 -762
  143. package/lib/core/daily-briefing.cjs +0 -438
  144. package/lib/core/decision-capture.cjs +0 -618
  145. package/lib/core/deep-links.cjs +0 -82
  146. package/lib/core/dispatch-optimizer.cjs +0 -354
  147. package/lib/core/dual-path-detector.cjs +0 -84
  148. package/lib/core/dual-path-detector.test.cjs +0 -334
  149. package/lib/core/exports-log.cjs +0 -79
  150. package/lib/core/feynman-minto-invariants.cjs +0 -605
  151. package/lib/core/folder-memory-async.cjs +0 -338
  152. package/lib/core/folder-memory-shared.cjs +0 -890
  153. package/lib/core/folder-memory.cjs +0 -416
  154. package/lib/core/framework-chain-composer.cjs +0 -411
  155. package/lib/core/frontmatter-schemas.cjs +0 -330
  156. package/lib/core/git-ops.cjs +0 -141
  157. package/lib/core/graph-ops.cjs +0 -258
  158. package/lib/core/hat-persistence.cjs +0 -362
  159. package/lib/core/index.cjs +0 -60
  160. package/lib/core/integration-registry.cjs +0 -232
  161. package/lib/core/intelligence-cascade.cjs +0 -661
  162. package/lib/core/lazygraph-ops.cjs +0 -1057
  163. package/lib/core/lru-cache.cjs +0 -139
  164. package/lib/core/mcp-profiles.cjs +0 -182
  165. package/lib/core/meeting-ops.cjs +0 -54
  166. package/lib/core/memory-ops.cjs +0 -600
  167. package/lib/core/migrations/ROOM.md +0 -33
  168. package/lib/core/migrations/phase-109-nodes-provenance.cjs +0 -339
  169. package/lib/core/migrations/phase-109-session-focus.cjs +0 -99
  170. package/lib/core/model-profiles.cjs +0 -246
  171. package/lib/core/mullins-scaffold.cjs +0 -160
  172. package/lib/core/nav-dial.cjs +0 -316
  173. package/lib/core/navigation/ROOM.md +0 -15
  174. package/lib/core/navigation/explanation.cjs +0 -43
  175. package/lib/core/navigation/focus.cjs +0 -135
  176. package/lib/core/navigation/ingestion.cjs +0 -82
  177. package/lib/core/navigation/insights.cjs +0 -350
  178. package/lib/core/navigation/memory-events.cjs +0 -118
  179. package/lib/core/navigation/neighborhood.cjs +0 -78
  180. package/lib/core/navigation/packet.cjs +0 -182
  181. package/lib/core/navigation/room-home.cjs +0 -127
  182. package/lib/core/navigation/transitions.cjs +0 -82
  183. package/lib/core/navigation-engine-shared.cjs +0 -242
  184. package/lib/core/navigation-engine.cjs +0 -664
  185. package/lib/core/navigation.cjs +0 -60
  186. package/lib/core/nl-graph-queries.cjs +0 -164
  187. package/lib/core/offer-presenter.cjs +0 -406
  188. package/lib/core/opportunity-extractor.cjs +0 -183
  189. package/lib/core/opportunity-ops.cjs +0 -1371
  190. package/lib/core/persona-ops.cjs +0 -537
  191. package/lib/core/persona-taxonomy.cjs +0 -190
  192. package/lib/core/platform-gates.cjs +0 -120
  193. package/lib/core/platform.cjs +0 -257
  194. package/lib/core/proactive-intelligence.cjs +0 -528
  195. package/lib/core/problem-type-router.cjs +0 -315
  196. package/lib/core/reasoning-ops.cjs +0 -639
  197. package/lib/core/reverse-salient-persona-suffix.cjs +0 -115
  198. package/lib/core/room-classifier-strict-mode.cjs +0 -229
  199. package/lib/core/room-db.cjs +0 -127
  200. package/lib/core/room-ops-async.cjs +0 -92
  201. package/lib/core/room-ops-shared.cjs +0 -64
  202. package/lib/core/room-ops-sync.cjs +0 -70
  203. package/lib/core/room-ops.cjs +0 -32
  204. package/lib/core/room-type-detector.cjs +0 -386
  205. package/lib/core/rs-brain-substrate-prompts.cjs +0 -129
  206. package/lib/core/rs-brain-substrate.cjs +0 -570
  207. package/lib/core/rs-breakthrough-scorer.cjs +0 -255
  208. package/lib/core/rs-canon-violations.cjs +0 -82
  209. package/lib/core/rs-chain-feeder.cjs +0 -343
  210. package/lib/core/rs-commercial-assessor.cjs +0 -280
  211. package/lib/core/rs-differential-scorer.cjs +0 -376
  212. package/lib/core/rs-domain-analyzer.cjs +0 -385
  213. package/lib/core/rs-egress-prompts.cjs +0 -113
  214. package/lib/core/rs-egress-telemetry.cjs +0 -225
  215. package/lib/core/rs-egress-violations.cjs +0 -53
  216. package/lib/core/rs-expert-mapper.cjs +0 -467
  217. package/lib/core/rs-fetcher-academic.cjs +0 -697
  218. package/lib/core/rs-fetcher-experts.cjs +0 -314
  219. package/lib/core/rs-fetcher-industry.cjs +0 -731
  220. package/lib/core/rs-fetcher-patents.cjs +0 -564
  221. package/lib/core/rs-innovation-classifier.cjs +0 -194
  222. package/lib/core/rs-mind-map.cjs +0 -656
  223. package/lib/core/rs-neo4j-writer.cjs +0 -388
  224. package/lib/core/rs-nl-to-query.cjs +0 -425
  225. package/lib/core/rs-pinecone-bridge.cjs +0 -303
  226. package/lib/core/rs-preprocessor.cjs +0 -350
  227. package/lib/core/rs-query-matrix.cjs +0 -316
  228. package/lib/core/rs-query-to-text.cjs +0 -438
  229. package/lib/core/rs-sqlite-mirror.cjs +0 -443
  230. package/lib/core/rs-thesis-generator.cjs +0 -188
  231. package/lib/core/rs_cache.py +0 -479
  232. package/lib/core/rs_corpus.py +0 -468
  233. package/lib/core/rs_hybrid.py +0 -586
  234. package/lib/core/rs_math.py +0 -287
  235. package/lib/core/rs_rooms.py +0 -193
  236. package/lib/core/scheduled-scanner.cjs +0 -463
  237. package/lib/core/scratchpad-ops.cjs +0 -201
  238. package/lib/core/section-8-trace-schema.cjs +0 -138
  239. package/lib/core/section-registry.cjs +0 -111
  240. package/lib/core/session-state.cjs +0 -144
  241. package/lib/core/shallow-doc-parser.cjs +0 -174
  242. package/lib/core/shallow-doc-parser.test.cjs +0 -226
  243. package/lib/core/skill-activation-router.cjs +0 -284
  244. package/lib/core/state-ops.cjs +0 -46
  245. package/lib/core/statusline-cache.cjs +0 -266
  246. package/lib/core/token-estimator.cjs +0 -348
  247. package/lib/core/user-archetype.cjs +0 -239
  248. package/lib/core/user-md-ops.cjs +0 -524
  249. package/lib/core/visual-ops.cjs +0 -624
  250. package/lib/core/write-lock.cjs +0 -149
  251. package/lib/graph/canvas-graph.js +0 -467
  252. package/lib/graph/constellation-config.cjs +0 -299
  253. package/lib/graph/graph-detail-panel.js +0 -165
  254. package/lib/hmi/ROOM.md +0 -47
  255. package/lib/hmi/across-session-memory.cjs +0 -604
  256. package/lib/hmi/cross-room-memory.cjs +0 -575
  257. package/lib/hmi/decoy-tier.cjs +0 -395
  258. package/lib/hmi/jtbd-classifier.cjs +0 -219
  259. package/lib/hmi/jtbd-state.cjs +0 -199
  260. package/lib/hmi/jtbd-taxonomy.json +0 -392
  261. package/lib/hmi/selector-dispatcher.cjs +0 -546
  262. package/lib/hmi/selector-telemetry.cjs +0 -263
  263. package/lib/hmi/shape-f0-renderer.cjs +0 -139
  264. package/lib/hmi/shape-f1-fallback.cjs +0 -80
  265. package/lib/hmi/shape-f1-renderer.cjs +0 -138
  266. package/lib/hmi/shape-f2-renderer.cjs +0 -132
  267. package/lib/hmi/shape-f3-renderer.cjs +0 -66
  268. package/lib/hmi/shape-f4-renderer.cjs +0 -72
  269. package/lib/hmi/shape-f5-renderer.cjs +0 -155
  270. package/lib/hmi/shape-f6-plan-review-renderer.cjs +0 -312
  271. package/lib/hmi/shape-f6-renderer.cjs +0 -144
  272. package/lib/hmi/shape-g-renderer.cjs +0 -219
  273. package/lib/hmi/shape-h-renderer.cjs +0 -222
  274. package/lib/hmi/tier-check.cjs +0 -63
  275. package/lib/import/PRECONDITIONS.md +0 -41
  276. package/lib/import/branding.cjs +0 -210
  277. package/lib/import/branding.test.cjs +0 -235
  278. package/lib/import/classifications-sync.cjs +0 -104
  279. package/lib/import/classifications-sync.test.cjs +0 -129
  280. package/lib/import/enricher.cjs +0 -296
  281. package/lib/import/enricher.test.cjs +0 -273
  282. package/lib/import/integration.test.cjs +0 -376
  283. package/lib/import/manifest.cjs +0 -129
  284. package/lib/import/manifest.schema.json +0 -185
  285. package/lib/import/manifest.test.cjs +0 -123
  286. package/lib/import/meeting-detector.cjs +0 -92
  287. package/lib/import/meeting-detector.test.cjs +0 -100
  288. package/lib/import/person-detector.cjs +0 -229
  289. package/lib/import/person-detector.test.cjs +0 -149
  290. package/lib/import/report.cjs +0 -186
  291. package/lib/import/report.test.cjs +0 -186
  292. package/lib/import/room-md-scaffolder.cjs +0 -49
  293. package/lib/import/router.cjs +0 -224
  294. package/lib/import/router.test.cjs +0 -356
  295. package/lib/import/run-all-tests.cjs +0 -36
  296. package/lib/import/smoke-test.cjs +0 -213
  297. package/lib/import/smoke-test.test.cjs +0 -148
  298. package/lib/import/test-fixtures/collision-vault/preexisting-room/STATE.md +0 -8
  299. package/lib/import/test-fixtures/collision-vault/preexisting-room/problem-definition/onboarding/onboarding.md +0 -7
  300. package/lib/import/test-fixtures/collision-vault/source/onboarding.md +0 -5
  301. package/lib/import/test-fixtures/obsidian-vault/.obsidian/workspace.json +0 -1
  302. package/lib/import/test-fixtures/obsidian-vault/notes/with-wikilinks.md +0 -4
  303. package/lib/import/test-fixtures/tiny-vault/notes/2026-01-15-team-sync.md +0 -9
  304. package/lib/import/test-fixtures/tiny-vault/notes/empty.md +0 -3
  305. package/lib/import/test-fixtures/tiny-vault/notes/onboarding.md +0 -5
  306. package/lib/import/test-fixtures/tiny-vault/notes/pricing.md +0 -5
  307. package/lib/import/test-fixtures/tiny-vault/notes/random.md +0 -4
  308. package/lib/import/undo.test.cjs +0 -199
  309. package/lib/import/vault-scanner.cjs +0 -105
  310. package/lib/import/vault-scanner.test.cjs +0 -67
  311. package/lib/mcp/app-html/dashboard.html +0 -316
  312. package/lib/mcp/app-html/graph.html +0 -428
  313. package/lib/mcp/app-html/mindrian-platform.html +0 -1841
  314. package/lib/mcp/app-html/wiki.html +0 -383
  315. package/lib/mcp/app-views.cjs +0 -322
  316. package/lib/mcp/brain-router.cjs +0 -418
  317. package/lib/mcp/capability-registry.cjs +0 -62
  318. package/lib/mcp/larry-context.cjs +0 -46
  319. package/lib/mcp/larry-server-instructions.md +0 -114
  320. package/lib/mcp/pipeline-state.cjs +0 -275
  321. package/lib/mcp/prompts.cjs +0 -302
  322. package/lib/mcp/resources.cjs +0 -227
  323. package/lib/mcp/session-catchup.cjs +0 -327
  324. package/lib/mcp/surface-detect.cjs +0 -75
  325. package/lib/mcp/tool-router.cjs +0 -1034
  326. package/lib/memory/aaak-compress.cjs +0 -403
  327. package/lib/memory/aaak-compress.test.cjs +0 -288
  328. package/lib/memory/async-artifact-auto-commit.test.cjs +0 -223
  329. package/lib/memory/bearer-token.test.cjs +0 -315
  330. package/lib/memory/brain-cache-lru.test.cjs +0 -259
  331. package/lib/memory/brain-client-query-shape.test.cjs +0 -160
  332. package/lib/memory/brain-derivation-graceful-degradation.test.cjs +0 -1019
  333. package/lib/memory/brain-derivation-queue.test.cjs +0 -539
  334. package/lib/memory/brain-derivation.test.cjs +0 -634
  335. package/lib/memory/brain-derive-command.test.cjs +0 -534
  336. package/lib/memory/brain-md-invariants-validator.test.cjs +0 -704
  337. package/lib/memory/brain-md-schema.test.cjs +0 -467
  338. package/lib/memory/brain-md-staleness.test.cjs +0 -525
  339. package/lib/memory/brain-server-resolution.test.cjs +0 -314
  340. package/lib/memory/chat-context.test.cjs +0 -128
  341. package/lib/memory/cross-room-aggregator.test.cjs +0 -909
  342. package/lib/memory/dashboard-server.test.cjs +0 -256
  343. package/lib/memory/debouncer-drain-at-prompt.test.cjs +0 -389
  344. package/lib/memory/decision-capture.test.cjs +0 -632
  345. package/lib/memory/decision-capture.worker.cjs +0 -70
  346. package/lib/memory/explain-decision-command.test.cjs +0 -521
  347. package/lib/memory/explain-decision-footer.test.cjs +0 -316
  348. package/lib/memory/explored-materials-store.cjs +0 -392
  349. package/lib/memory/feynman-minto-guardian.test.cjs +0 -736
  350. package/lib/memory/feynman-minto-invariants.test.cjs +0 -511
  351. package/lib/memory/feynman-prompts-drift.test.cjs +0 -144
  352. package/lib/memory/feynman-prompts.cjs +0 -151
  353. package/lib/memory/feynman-prompts.test.cjs +0 -96
  354. package/lib/memory/folder-memory-quadruple.test.cjs +0 -548
  355. package/lib/memory/folder-memory.test.cjs +0 -503
  356. package/lib/memory/framework-chain-composer.test.cjs +0 -515
  357. package/lib/memory/frontmatter-schema-validator.test.cjs +0 -290
  358. package/lib/memory/heal-command.test.cjs +0 -604
  359. package/lib/memory/index-artifact-transaction.test.cjs +0 -333
  360. package/lib/memory/lazygraph-rs-discoveries-view.test.cjs +0 -122
  361. package/lib/memory/mcp-input-validation.test.cjs +0 -240
  362. package/lib/memory/mcp-server-brain-deps.test.cjs +0 -270
  363. package/lib/memory/mcp-stack-fallback.test.cjs +0 -433
  364. package/lib/memory/minto-debouncer.test.cjs +0 -407
  365. package/lib/memory/minto-debouncer.worker.cjs +0 -46
  366. package/lib/memory/minto-migration-v88.test.cjs +0 -265
  367. package/lib/memory/minto-schema-v88.test.cjs +0 -390
  368. package/lib/memory/mos-status-renderer.test.cjs +0 -631
  369. package/lib/memory/narrative-schema.cjs +0 -376
  370. package/lib/memory/narrative-schema.test.cjs +0 -209
  371. package/lib/memory/nav-dial.test.cjs +0 -414
  372. package/lib/memory/navigation-engine-core.test.cjs +0 -722
  373. package/lib/memory/navigation-invariants.test.cjs +0 -483
  374. package/lib/memory/offer-presenter.test.cjs +0 -554
  375. package/lib/memory/on-stop-snapshot.test.cjs +0 -404
  376. package/lib/memory/pending-tension-store.cjs +0 -373
  377. package/lib/memory/post-compact-reinjection.test.cjs +0 -854
  378. package/lib/memory/post-write-triple.test.cjs +0 -317
  379. package/lib/memory/pre-compact-snapshot.test.cjs +0 -495
  380. package/lib/memory/problem-type-router.test.cjs +0 -656
  381. package/lib/memory/query-efficiency-telemetry.test.cjs +0 -370
  382. package/lib/memory/recompile-room-references.test.cjs +0 -392
  383. package/lib/memory/recompile-room-references.worker.cjs +0 -42
  384. package/lib/memory/record-decision-dual-write.test.cjs +0 -454
  385. package/lib/memory/room-classifier-strict-mode.test.cjs +0 -417
  386. package/lib/memory/room-minto-hook.test.cjs +0 -398
  387. package/lib/memory/rs-discovery-engine.test.cjs +0 -323
  388. package/lib/memory/run-feynman-tests.cjs +0 -1239
  389. package/lib/memory/security-trifecta.test.cjs +0 -312
  390. package/lib/memory/session-start-brain-staleness.test.cjs +0 -363
  391. package/lib/memory/session-start-triple-injection.test.cjs +0 -514
  392. package/lib/memory/sessionstart-banner-formatter.cjs +0 -318
  393. package/lib/memory/sessionstart-minto-banner.test.cjs +0 -373
  394. package/lib/memory/skill-activation-router.test.cjs +0 -419
  395. package/lib/memory/stamp-artifact-write.test.cjs +0 -304
  396. package/lib/memory/statusline-active-room.test.cjs +0 -315
  397. package/lib/memory/statusline-minto-segment.test.cjs +0 -292
  398. package/lib/memory/sync-async-entry-points.test.cjs +0 -204
  399. package/lib/memory/test-bridge-writer-enhanced.cjs +0 -452
  400. package/lib/memory/test-rs-brain-substrate-shape.cjs +0 -529
  401. package/lib/memory/test-rs-brain-substrate.cjs +0 -636
  402. package/lib/memory/test-rs-breakthrough-scorer.cjs +0 -375
  403. package/lib/memory/test-rs-canon-violations.cjs +0 -218
  404. package/lib/memory/test-rs-chain-feeder-core.cjs +0 -344
  405. package/lib/memory/test-rs-chain-feeder-skill-spawn.cjs +0 -297
  406. package/lib/memory/test-rs-commercial-assessor.cjs +0 -385
  407. package/lib/memory/test-rs-differential-scorer.cjs +0 -480
  408. package/lib/memory/test-rs-discovery-engine.cjs +0 -603
  409. package/lib/memory/test-rs-domain-analyzer.cjs +0 -492
  410. package/lib/memory/test-rs-egress-primitives.cjs +0 -420
  411. package/lib/memory/test-rs-expert-mapper.cjs +0 -547
  412. package/lib/memory/test-rs-explain-command.cjs +0 -443
  413. package/lib/memory/test-rs-fetcher-academic.cjs +0 -848
  414. package/lib/memory/test-rs-fetcher-experts.cjs +0 -496
  415. package/lib/memory/test-rs-fetcher-industry.cjs +0 -702
  416. package/lib/memory/test-rs-fetcher-patents.cjs +0 -674
  417. package/lib/memory/test-rs-innovation-classifier.cjs +0 -301
  418. package/lib/memory/test-rs-mind-map.cjs +0 -646
  419. package/lib/memory/test-rs-neo4j-writer.cjs +0 -518
  420. package/lib/memory/test-rs-nl-to-query.cjs +0 -449
  421. package/lib/memory/test-rs-pinecone-bridge.cjs +0 -277
  422. package/lib/memory/test-rs-preprocessor.cjs +0 -433
  423. package/lib/memory/test-rs-query-matrix.cjs +0 -391
  424. package/lib/memory/test-rs-query-to-text.cjs +0 -551
  425. package/lib/memory/test-rs-sqlite-mirror.cjs +0 -649
  426. package/lib/memory/test-rs-thesis-generator.cjs +0 -360
  427. package/lib/memory/triple-context-formatter.cjs +0 -473
  428. package/lib/memory/triple-context-formatter.test.cjs +0 -442
  429. package/lib/memory/user-md-persona.test.cjs +0 -565
  430. package/lib/memory/userpromptsubmit-integration.test.cjs +0 -690
  431. package/lib/memory/validators/README.md +0 -157
  432. package/lib/memory/validators/brain-md-invariants.cjs +0 -475
  433. package/lib/memory/validators/brain-substrate-invariants.cjs +0 -285
  434. package/lib/memory/validators/external-academic-invariants.cjs +0 -249
  435. package/lib/memory/validators/external-industry-invariants.cjs +0 -271
  436. package/lib/memory/validators/external-patents-invariants.cjs +0 -266
  437. package/lib/memory/validators/minto-invariants.cjs +0 -62
  438. package/lib/memory/validators/navigation-invariants.cjs +0 -340
  439. package/lib/memory/validators/queue-health.cjs +0 -95
  440. package/lib/memory/validators/snapshot-integrity.cjs +0 -129
  441. package/lib/memory/validators/stale-lifecycle.cjs +0 -116
  442. package/lib/memory/vault-section-minto-generator-atomic.test.cjs +0 -556
  443. package/lib/memory/vault-section-minto-generator-atomic.worker.cjs +0 -73
  444. package/lib/memory/write-lock-atomic.test.cjs +0 -137
  445. package/lib/memory/write-lock-atomic.worker.cjs +0 -55
  446. package/lib/parity/check-parity.cjs +0 -83
  447. package/lib/presentation/presentation-server.cjs +0 -101
  448. package/lib/presentation/presentation-watcher.cjs +0 -123
  449. package/lib/quickview/hub-server.cjs +0 -719
  450. package/lib/quickview/server.cjs +0 -533
  451. package/lib/render/JTBD-PALETTES.md +0 -145
  452. package/lib/render/ROOM.md +0 -59
  453. package/lib/render/render-v2.cjs +0 -486
  454. package/lib/render/render-v2.test.cjs +0 -267
  455. package/lib/render/render.cjs +0 -65
  456. package/lib/state/ROOM.md +0 -46
  457. package/lib/state/state-md-parser.cjs +0 -215
  458. package/lib/statusline/ROOM.md +0 -38
  459. package/lib/statusline/banner-suppression.cjs +0 -50
  460. package/lib/statusline/surface-detect.cjs +0 -85
  461. package/lib/update-bootstrap.sh.template +0 -145
  462. package/lib/vault/frontmatter-schema.cjs +0 -297
  463. package/lib/vault/room-scanner.cjs +0 -352
  464. package/lib/vault/wikilink-builder.cjs +0 -231
  465. package/lib/vault/wikilink-builder.test.cjs +0 -182
  466. package/lib/wiki/graph-links.cjs +0 -281
  467. package/lib/wiki/page-renderer.cjs +0 -229
  468. package/lib/wiki/wiki-chat.cjs +0 -81
  469. package/lib/wiki/wiki-layout.cjs +0 -1459
  470. package/lib/wiki/wiki-search.cjs +0 -142
  471. package/lib/wiki/wiki-server.cjs +0 -678
  472. package/lib/wiki/wiki-watcher.cjs +0 -105
  473. package/pipelines/analogy/01-decompose.md +0 -80
  474. package/pipelines/analogy/02-abstract.md +0 -87
  475. package/pipelines/analogy/03-search.md +0 -135
  476. package/pipelines/analogy/04-transfer.md +0 -101
  477. package/pipelines/analogy/05-validate.md +0 -106
  478. package/pipelines/analogy/CHAIN.md +0 -56
  479. package/pipelines/discovery/01-explore-domains.md +0 -44
  480. package/pipelines/discovery/02-think-hats.md +0 -50
  481. package/pipelines/discovery/03-analyze-needs.md +0 -54
  482. package/pipelines/discovery/CHAIN.md +0 -37
  483. package/pipelines/thesis/01-structure-argument.md +0 -45
  484. package/pipelines/thesis/02-challenge-assumptions.md +0 -48
  485. package/pipelines/thesis/03-build-thesis.md +0 -54
  486. package/pipelines/thesis/CHAIN.md +0 -37
  487. package/references/brain/causal-directives.md +0 -91
  488. package/references/brain/causal-enrichment.cypher +0 -165
  489. package/references/brain/command-triggers-schema.md +0 -226
  490. package/references/brain/graph-architecture.md +0 -317
  491. package/references/brain/query-patterns.md +0 -460
  492. package/references/brain/room-hierarchy-schema.md +0 -218
  493. package/references/brain/schema.md +0 -76
  494. package/references/capability-radar/capabilities-index.md +0 -241
  495. package/references/capability-radar/changelog-cache.md +0 -81
  496. package/references/causal/causal-schema.md +0 -103
  497. package/references/design/email-template-standard.md +0 -155
  498. package/references/design/graph-visualization-standard.md +0 -178
  499. package/references/document-generation.md +0 -179
  500. package/references/hsi/HSI-TOOLS-REFERENCE.md +0 -222
  501. package/references/import-config.md +0 -141
  502. package/references/integrations/detection-patterns.md +0 -101
  503. package/references/meeting/artifact-template.md +0 -377
  504. package/references/meeting/cross-meeting-intelligence.md +0 -216
  505. package/references/meeting/cross-relationship-patterns.md +0 -202
  506. package/references/meeting/live-join-interface.md +0 -244
  507. package/references/meeting/section-mapping.md +0 -192
  508. package/references/meeting/segment-classification.md +0 -258
  509. package/references/meeting/speaker-profile-template.md +0 -219
  510. package/references/meeting/summary-template.md +0 -348
  511. package/references/meeting/transcript-patterns.md +0 -226
  512. package/references/methodology/analyze-needs.md +0 -135
  513. package/references/methodology/analyze-systems.md +0 -121
  514. package/references/methodology/analyze-timing.md +0 -149
  515. package/references/methodology/beautiful-question.md +0 -109
  516. package/references/methodology/build-knowledge.md +0 -161
  517. package/references/methodology/build-thesis.md +0 -237
  518. package/references/methodology/challenge-assumptions.md +0 -127
  519. package/references/methodology/diagnose.md +0 -169
  520. package/references/methodology/dominant-designs.md +0 -212
  521. package/references/methodology/explore-domains.md +0 -147
  522. package/references/methodology/explore-futures.md +0 -163
  523. package/references/methodology/explore-trends.md +0 -129
  524. package/references/methodology/find-bottlenecks.md +0 -131
  525. package/references/methodology/grade.md +0 -211
  526. package/references/methodology/index.md +0 -97
  527. package/references/methodology/leadership.md +0 -200
  528. package/references/methodology/lean-canvas.md +0 -116
  529. package/references/methodology/macro-trends.md +0 -192
  530. package/references/methodology/map-unknowns.md +0 -137
  531. package/references/methodology/mullins-7-domains.md +0 -104
  532. package/references/methodology/problem-types.md +0 -65
  533. package/references/methodology/root-cause.md +0 -178
  534. package/references/methodology/sapphire-encoding.md +0 -355
  535. package/references/methodology/scenario-plan.md +0 -178
  536. package/references/methodology/score-innovation.md +0 -154
  537. package/references/methodology/structure-argument.md +0 -158
  538. package/references/methodology/systems-thinking.md +0 -159
  539. package/references/methodology/think-hats.md +0 -147
  540. package/references/methodology/triz-matrix.json +0 -751
  541. package/references/methodology/triz-principles.md +0 -501
  542. package/references/methodology/user-needs.md +0 -199
  543. package/references/methodology/validate.md +0 -163
  544. package/references/methodology/value-proposition.md +0 -244
  545. package/references/opportunities/funding-lifecycle.md +0 -103
  546. package/references/opportunities/grant-api-patterns.md +0 -99
  547. package/references/opportunities/opportunity-template.md +0 -84
  548. package/references/personality/assessment-philosophy.md +0 -72
  549. package/references/personality/lexicon.md +0 -100
  550. package/references/personality/persona-chains.md +0 -56
  551. package/references/personality/pws-lexicon-full.md +0 -499
  552. package/references/personality/voice-dna.md +0 -156
  553. package/references/personas/hat-perspectives.md +0 -76
  554. package/references/personas/persona-template.md +0 -63
  555. package/references/pipeline/act-output-contract.md +0 -88
  556. package/references/pipeline/chains-index.md +0 -39
  557. package/references/pws-profile-generation.md +0 -79
  558. package/references/reasoning/reasoning-schema.md +0 -143
  559. package/references/reasoning/reasoning-template.md +0 -68
  560. package/references/reasoning/run-template.md +0 -38
  561. package/references/research/RESEARCH_14_CLAUDE_CODE_SOURCE_ARCHITECTURE.md +0 -209
  562. package/references/research/RESEARCH_15_V1.8_OPTIMIZATION_JTBD.md +0 -375
  563. package/references/research/RESEARCH_16_NATIVE_FIRST_PLUGIN_ARCHITECTURE.md +0 -575
  564. package/references/research/RESEARCH_17_MCP_UI_FRAMEWORKS.md +0 -272
  565. package/references/taxonomy/TAXONOMY.md +0 -192
  566. package/references/templates/MINTO.md +0 -36
  567. package/references/user-research/2026-04-05-leah-lawrence-session.md +0 -202
  568. package/references/vault-kit/README.md +0 -35
  569. package/references/vault-kit/app.json +0 -12
  570. package/references/vault-kit/appearance.json +0 -12
  571. package/references/vault-kit/graph.json +0 -35
  572. package/references/vault-kit/snippets/mindrian-destijl.css +0 -297
  573. package/references/vault-kit/templates/new-artifact.md +0 -37
  574. package/references/vault-kit/templates/new-meeting-note.md +0 -35
  575. package/references/vault-kit/templates/new-team-profile.md +0 -29
  576. package/references/vault-kit/templates/new-xref.md +0 -35
  577. package/references/visual/symbol-system.md +0 -151
  578. package/skills/MOSDeckEngine/SKILL.md +0 -325
  579. package/skills/brain-connector/SKILL.md +0 -114
  580. package/skills/context-engine/SKILL.md +0 -147
  581. package/skills/conversation-mode/SKILL.md +0 -102
  582. package/skills/larry-personality/SKILL.md +0 -219
  583. package/skills/larry-personality/framework-chains.md +0 -92
  584. package/skills/larry-personality/mode-engine.md +0 -185
  585. package/skills/mullins-scaffold/SKILL.md +0 -61
  586. package/skills/mullins-scaffold/scaffold.json +0 -146
  587. package/skills/pws-methodology/SKILL.md +0 -49
  588. package/skills/room-passive/SKILL.md +0 -165
  589. package/skills/room-proactive/SKILL.md +0 -250
  590. package/skills/ui-system/SKILL.md +0 -277
@@ -1,1057 +0,0 @@
1
- /**
2
- * MindrianOS Plugin -- LazyGraph Operations
3
- * SQLite-backed per-project queryable knowledge graph via node:sqlite DatabaseSync.
4
- * Graph stored in room/.mindrian/room.db (WAL mode for concurrent reads).
5
- *
6
- * Exports: openGraph, closeGraph, initSchema, indexArtifact,
7
- * rebuildGraph, queryGraph, graphStats, embedArtifact,
8
- * + 12 edge-creator functions + EDGE_TYPES constant
9
- *
10
- * All functions remain async for backward compatibility with callers
11
- * that use await. Awaiting a synchronous return resolves immediately.
12
- */
13
-
14
- 'use strict';
15
-
16
- const fs = require('fs');
17
- const path = require('path');
18
- const crypto = require('crypto');
19
- const { DatabaseSync } = require('node:sqlite');
20
- const { discoverSections } = require('./section-registry.cjs');
21
-
22
- // --- Schema ---
23
-
24
- /** All relationship (edge) types in the LazyGraph */
25
- const EDGE_TYPES = ['INFORMS', 'CONTRADICTS', 'CONVERGES', 'ENABLES', 'INVALIDATES', 'BELONGS_TO', 'REASONING_INFORMS', 'HSI_CONNECTION', 'REVERSE_SALIENT', 'ANALOGOUS_TO', 'STRUCTURALLY_ISOMORPHIC', 'RESOLVES_VIA', 'CAUSES', 'ROOT_CAUSE_OF', 'CASCADES_TO', 'EXTRACTED_FROM', 'WHITESPACE_DETECTED', 'WHITESPACE_NEAR', 'DISCOVERY_CYCLE_SOURCE', 'DISCOVERED', 'DERIVED_FROM', 'AUTHORED_BY', 'AFFILIATED_WITH'];
26
-
27
- /**
28
- * Create nodes and edges tables with indexes. Idempotent.
29
- * @param {import('node:sqlite').DatabaseSync} db - node:sqlite DatabaseSync instance
30
- */
31
- function initSchema(db) {
32
- db.exec(`
33
- CREATE TABLE IF NOT EXISTS nodes (
34
- id TEXT PRIMARY KEY,
35
- type TEXT NOT NULL,
36
- properties TEXT DEFAULT '{}'
37
- );
38
- CREATE TABLE IF NOT EXISTS edges (
39
- source TEXT NOT NULL,
40
- target TEXT NOT NULL,
41
- type TEXT NOT NULL,
42
- properties TEXT DEFAULT '{}',
43
- PRIMARY KEY (source, target, type),
44
- FOREIGN KEY (source) REFERENCES nodes(id),
45
- FOREIGN KEY (target) REFERENCES nodes(id)
46
- );
47
- CREATE INDEX IF NOT EXISTS idx_nodes_type ON nodes(type);
48
- CREATE INDEX IF NOT EXISTS idx_edges_source ON edges(source);
49
- CREATE INDEX IF NOT EXISTS idx_edges_target ON edges(target);
50
- CREATE INDEX IF NOT EXISTS idx_edges_type ON edges(type);
51
- CREATE INDEX IF NOT EXISTS idx_edges_source_type ON edges(source, type);
52
- CREATE INDEX IF NOT EXISTS idx_edges_target_type ON edges(target, type);
53
- CREATE TABLE IF NOT EXISTS stakeholders (
54
- id TEXT PRIMARY KEY,
55
- type TEXT NOT NULL,
56
- name TEXT NOT NULL,
57
- canonical_ref TEXT,
58
- notes TEXT,
59
- metadata TEXT DEFAULT '{}',
60
- created_at TEXT NOT NULL,
61
- updated_at TEXT NOT NULL
62
- );
63
- CREATE INDEX IF NOT EXISTS idx_stakeholders_type ON stakeholders(type);
64
- CREATE INDEX IF NOT EXISTS idx_stakeholders_canonical ON stakeholders(canonical_ref);
65
- -- rs_discoveries: contract bridge between the RS SQLite mirror (writer) and
66
- -- the RS NL/SQL readers. rs-sqlite-mirror.cjs writes RSDiscovery records
67
- -- into the nodes table with the payload in a JSON properties bag
68
- -- (keys: classification, breakthrough_score, dominant_dimension, thesis,
69
- -- bridge_concept, diff, lsa, bert, ..., created_at, room_id, domain). The
70
- -- readers (rs-nl-to-query.cjs SQL templates and scripts/rs-thesis-command.cjs)
71
- -- query SELECT * FROM rs_discoveries WHERE room_slug = ? and
72
- -- SELECT id, thesis, rs_type, breakthrough_score, room_slug, created_at
73
- -- FROM rs_discoveries WHERE id = ? -- there was no such table, so queryGraph
74
- -- swallowed the "no such table" error as []. This VIEW closes that gap: it
75
- -- json_extract's the payload keys into the columns the queries expect and
76
- -- renames the writer's room_id JSON key to the reader's room_slug column
77
- -- and classification to rs_type. node:sqlite's bundled SQLite ships the
78
- -- JSON1 extension so json_extract works. NOTE: room_id is mapped to
79
- -- room_slug verbatim -- if ctx.room_id passed by the RS engine is ever
80
- -- not a room slug, that is a separate data-lineage fix in
81
- -- rs-discovery-engine.cjs / rs-sqlite-mirror.cjs; this view only aligns the
82
- -- column NAMES the queries already use. CREATE VIEW IF NOT EXISTS makes it
83
- -- idempotent -- existing room.db files pick it up on the next openGraph.
84
- CREATE VIEW IF NOT EXISTS rs_discoveries AS
85
- SELECT
86
- id,
87
- json_extract(properties, '$.thesis') AS thesis,
88
- json_extract(properties, '$.classification') AS rs_type,
89
- json_extract(properties, '$.breakthrough_score') AS breakthrough_score,
90
- json_extract(properties, '$.room_id') AS room_slug,
91
- json_extract(properties, '$.created_at') AS created_at,
92
- json_extract(properties, '$.bridge_concept') AS bridge_concept,
93
- json_extract(properties, '$.dominant_dimension') AS dominant_dimension,
94
- json_extract(properties, '$.diff') AS diff,
95
- json_extract(properties, '$.lsa') AS lsa,
96
- json_extract(properties, '$.bert') AS bert,
97
- json_extract(properties, '$.domain') AS domain,
98
- properties AS properties_json
99
- FROM nodes
100
- WHERE type = 'RSDiscovery';
101
- `);
102
- }
103
-
104
- // --- Stakeholder helpers (Phase 84-05, SCOPE-NB-03 / SCOPE-NB-04) ---
105
-
106
- /** Allowed stakeholder.type values per Phase 84-05 spec. */
107
- const STAKEHOLDER_TYPES = ['person', 'org', 'coalition', 'role'];
108
-
109
- /**
110
- * Validate a stakeholder type string. Throws TypeError on mismatch.
111
- * @param {string} type
112
- */
113
- function validateStakeholderType(type) {
114
- if (!STAKEHOLDER_TYPES.includes(type)) {
115
- throw new TypeError(`Invalid stakeholder type: ${type}. Must be one of ${STAKEHOLDER_TYPES.join(', ')}`);
116
- }
117
- }
118
-
119
- /**
120
- * Create a new Stakeholder row.
121
- * Generates a UUID, stamps created_at and updated_at, inserts the row.
122
- * @param {import('node:sqlite').DatabaseSync} db
123
- * @param {object} fields
124
- * @param {string} fields.type - person | org | coalition | role
125
- * @param {string} fields.name
126
- * @param {string} [fields.canonical_ref]
127
- * @param {string} [fields.notes]
128
- * @param {object|string} [fields.metadata]
129
- * @returns {Promise<object|null>} The new row or null on failure.
130
- */
131
- async function createStakeholder(db, fields) {
132
- try {
133
- const { type, name } = fields || {};
134
- validateStakeholderType(type);
135
- if (!name || typeof name !== 'string') {
136
- throw new TypeError('Stakeholder name is required');
137
- }
138
- const id = crypto.randomUUID();
139
- const now = new Date().toISOString();
140
- const canonical_ref = fields.canonical_ref || null;
141
- const notes = fields.notes || null;
142
- const metadata = typeof fields.metadata === 'string'
143
- ? fields.metadata
144
- : JSON.stringify(fields.metadata || {});
145
- db.prepare(
146
- 'INSERT INTO stakeholders (id, type, name, canonical_ref, notes, metadata, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)'
147
- ).run(id, type, name, canonical_ref, notes, metadata, now, now);
148
- return Promise.resolve({ id, type, name, canonical_ref, notes, metadata, created_at: now, updated_at: now });
149
- } catch (e) {
150
- if (e instanceof TypeError) throw e;
151
- return Promise.resolve(null);
152
- }
153
- }
154
-
155
- /**
156
- * Get a Stakeholder row by id.
157
- * @param {import('node:sqlite').DatabaseSync} db
158
- * @param {string} id
159
- * @returns {Promise<object|null>}
160
- */
161
- async function getStakeholder(db, id) {
162
- try {
163
- const row = db.prepare('SELECT * FROM stakeholders WHERE id = ?').get(id);
164
- return Promise.resolve(row || null);
165
- } catch (e) {
166
- return Promise.resolve(null);
167
- }
168
- }
169
-
170
- /**
171
- * Upsert a Stakeholder by canonical_ref. Updates in place if present, else inserts.
172
- * Updates updated_at on every call.
173
- * @param {import('node:sqlite').DatabaseSync} db
174
- * @param {string} canonical_ref
175
- * @param {object} fields
176
- * @returns {Promise<object|null>}
177
- */
178
- async function upsertStakeholder(db, canonical_ref, fields) {
179
- try {
180
- if (!canonical_ref) {
181
- throw new TypeError('canonical_ref is required for upsertStakeholder');
182
- }
183
- const existing = db.prepare('SELECT * FROM stakeholders WHERE canonical_ref = ?').get(canonical_ref);
184
- const now = new Date().toISOString();
185
- if (existing) {
186
- const type = fields.type || existing.type;
187
- validateStakeholderType(type);
188
- const name = fields.name || existing.name;
189
- const notes = fields.notes !== undefined ? fields.notes : existing.notes;
190
- const metadata = fields.metadata !== undefined
191
- ? (typeof fields.metadata === 'string' ? fields.metadata : JSON.stringify(fields.metadata))
192
- : existing.metadata;
193
- db.prepare(
194
- 'UPDATE stakeholders SET type = ?, name = ?, notes = ?, metadata = ?, updated_at = ? WHERE id = ?'
195
- ).run(type, name, notes, metadata, now, existing.id);
196
- return Promise.resolve({ ...existing, type, name, notes, metadata, updated_at: now });
197
- }
198
- return createStakeholder(db, { ...fields, canonical_ref });
199
- } catch (e) {
200
- if (e instanceof TypeError) throw e;
201
- return Promise.resolve(null);
202
- }
203
- }
204
-
205
- /**
206
- * Find stakeholders connected to a claim artifact via INFORMS edges.
207
- * Walks both directions (stakeholder INFORMS claim, claim INFORMS stakeholder).
208
- * @param {import('node:sqlite').DatabaseSync} db
209
- * @param {string} claim_artifact_id
210
- * @returns {Promise<Array<object>>}
211
- */
212
- async function findStakeholdersByClaim(db, claim_artifact_id) {
213
- try {
214
- const rows = db.prepare(
215
- `SELECT s.* FROM stakeholders s
216
- WHERE s.id IN (
217
- SELECT source FROM edges WHERE target = ? AND type = 'INFORMS'
218
- UNION
219
- SELECT target FROM edges WHERE source = ? AND type = 'INFORMS'
220
- )
221
- LIMIT 20`
222
- ).all(claim_artifact_id, claim_artifact_id);
223
- return Promise.resolve(rows || []);
224
- } catch (e) {
225
- return Promise.resolve([]);
226
- }
227
- }
228
-
229
- // --- Helpers ---
230
-
231
- /**
232
- * Get artifact ID from file path relative to room dir.
233
- * @param {string} filePath - Absolute path to .md file
234
- * @param {string} roomDir - Absolute path to room directory
235
- * @returns {string} e.g. "problem-definition/market-trends"
236
- */
237
- function getArtifactId(filePath, roomDir) {
238
- const rel = path.relative(path.resolve(roomDir), path.resolve(filePath));
239
- return rel.replace(/\.md$/, '').replace(/\\/g, '/');
240
- }
241
-
242
- /**
243
- * Extract title from first # heading in file content.
244
- * @param {string} content - File content
245
- * @param {string} filePath - Fallback basename
246
- * @returns {string}
247
- */
248
- function extractTitle(content, filePath) {
249
- const match = content.match(/^# (.+)$/m);
250
- return match ? match[1].trim() : path.basename(filePath, '.md');
251
- }
252
-
253
- /**
254
- * Extract a frontmatter field value.
255
- * @param {string} content - File content
256
- * @param {string} field - Field name
257
- * @returns {string}
258
- */
259
- function extractFrontmatter(content, field) {
260
- const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
261
- if (!fmMatch) return '';
262
- const line = fmMatch[1].split('\n').find(l => l.startsWith(field + ':'));
263
- if (!line) return '';
264
- return line.slice(field.length + 1).trim().replace(/^["']|["']$/g, '');
265
- }
266
-
267
- /**
268
- * Compute MD5 content hash (first 8 hex chars).
269
- * @param {string} content
270
- * @returns {string}
271
- */
272
- function computeHash(content) {
273
- return crypto.createHash('md5').update(content).digest('hex').slice(0, 8);
274
- }
275
-
276
- // --- Contradiction detection terms ---
277
- const CONTRADICT_TERMS = ['however', 'contradicts', 'unlike', 'disagrees', 'conflicts', 'contrary', 'opposes'];
278
-
279
- // --- Core Functions ---
280
-
281
- /**
282
- * Open (or create) a SQLite database at {roomDir}/.mindrian/room.db.
283
- * Enables WAL mode and foreign keys. Initializes schema.
284
- * @param {string} roomDir - Path to room directory
285
- * @returns {Promise<{db: import('node:sqlite').DatabaseSync, conn: import('node:sqlite').DatabaseSync}>}
286
- */
287
- async function openGraph(roomDir) {
288
- const resolved = path.resolve(roomDir);
289
- const dbDir = path.join(resolved, '.mindrian');
290
- const dbPath = path.join(dbDir, 'room.db');
291
-
292
- // Ensure directories exist
293
- fs.mkdirSync(dbDir, { recursive: true });
294
-
295
- const db = new DatabaseSync(dbPath);
296
- db.exec('PRAGMA journal_mode = WAL');
297
- db.exec('PRAGMA foreign_keys = ON');
298
-
299
- initSchema(db);
300
-
301
- // conn === db in SQLite (single object handles both)
302
- return Promise.resolve({ db, conn: db });
303
- }
304
-
305
- /**
306
- * Close SQLite database.
307
- * @param {import('node:sqlite').DatabaseSync} db - node:sqlite DatabaseSync instance
308
- */
309
- async function closeGraph(db) {
310
- try {
311
- db.close();
312
- } catch (e) {
313
- // Handle already-closed or invalid db gracefully
314
- }
315
- return Promise.resolve();
316
- }
317
-
318
- /**
319
- * Index a single .md artifact into the graph.
320
- * Creates Artifact node, Section node, BELONGS_TO edge.
321
- * Scans for [[wikilinks]] to create INFORMS edges.
322
- * Scans for contradiction terms near wikilinks to create CONTRADICTS edges.
323
- * @param {import('node:sqlite').DatabaseSync} conn - node:sqlite DatabaseSync instance
324
- * @param {string} roomDir - Absolute path to room directory
325
- * @param {string} filePath - Absolute path to .md file
326
- * @returns {Promise<{id: string, section: string, title: string, contentHash: string}>}
327
- */
328
- /**
329
- * Internal: run the INSERT body of indexArtifact WITHOUT opening a transaction.
330
- * The caller is responsible for transaction semantics. Used by:
331
- * - indexArtifact() -- wraps this in BEGIN/COMMIT/ROLLBACK
332
- * - rebuildGraph() -- calls this inside its own outer BEGIN/COMMIT so the
333
- * whole rebuild is atomic (no nested transactions, which SQLite forbids
334
- * without SAVEPOINT).
335
- * @param {import('node:sqlite').DatabaseSync} conn
336
- * @param {string} roomDir
337
- * @param {string} filePath
338
- * @returns {{id: string, section: string, title: string, contentHash: string}}
339
- */
340
- function _indexArtifactBody(conn, roomDir, filePath) {
341
- const content = fs.readFileSync(filePath, 'utf-8');
342
- const id = getArtifactId(filePath, roomDir);
343
- const section = id.split('/')[0];
344
- const title = extractTitle(content, filePath);
345
- const methodology = extractFrontmatter(content, 'methodology');
346
- const created = extractFrontmatter(content, 'date');
347
- const contentHash = computeHash(content);
348
- const enables = extractFrontmatter(content, 'enables');
349
- const invalidates = extractFrontmatter(content, 'invalidates');
350
- const wikilinks = content.match(/\[\[([^\]]+)\]\]/g) || [];
351
- const artifactProps = JSON.stringify({ title, section, methodology, created, content_hash: contentHash });
352
- const sectionLabel = section.replace(/-/g, ' ').toUpperCase();
353
- const sectionProps = JSON.stringify({ name: section, label: sectionLabel });
354
-
355
- // Upsert Artifact node
356
- conn.prepare(
357
- 'INSERT INTO nodes (id, type, properties) VALUES (?, ?, ?) ON CONFLICT(id) DO UPDATE SET type = excluded.type, properties = excluded.properties'
358
- ).run(id, 'Artifact', artifactProps);
359
-
360
- // Upsert Section node
361
- conn.prepare(
362
- 'INSERT INTO nodes (id, type, properties) VALUES (?, ?, ?) ON CONFLICT(id) DO UPDATE SET properties = excluded.properties'
363
- ).run(section, 'Section', sectionProps);
364
-
365
- // Upsert BELONGS_TO edge
366
- conn.prepare(
367
- 'INSERT INTO edges (source, target, type) VALUES (?, ?, ?) ON CONFLICT DO NOTHING'
368
- ).run(id, section, 'BELONGS_TO');
369
-
370
- // Scan for [[wikilinks]] to create INFORMS edges
371
- for (const link of wikilinks) {
372
- const target = link.replace(/\[\[|\]\]/g, '').toLowerCase().replace(/\s/g, '-');
373
-
374
- const linkIdx = content.indexOf(link);
375
- const contextStart = Math.max(0, linkIdx - 200);
376
- const contextEnd = Math.min(content.length, linkIdx + 200);
377
- const nearbyText = content.slice(contextStart, contextEnd).toLowerCase();
378
-
379
- const isContradiction = CONTRADICT_TERMS.some(term => nearbyText.includes(term));
380
-
381
- const targetArtifacts = conn.prepare(
382
- "SELECT id FROM nodes WHERE type = 'Artifact' AND json_extract(properties, '$.section') = ?"
383
- ).all(target);
384
-
385
- for (const row of targetArtifacts) {
386
- const targetId = row.id;
387
- if (targetId === id) continue;
388
-
389
- if (isContradiction) {
390
- const contradictProps = JSON.stringify({ confidence: 'medium' });
391
- conn.prepare(
392
- 'INSERT INTO edges (source, target, type, properties) VALUES (?, ?, ?, ?) ON CONFLICT(source, target, type) DO UPDATE SET properties = excluded.properties'
393
- ).run(id, targetId, 'CONTRADICTS', contradictProps);
394
- }
395
-
396
- conn.prepare(
397
- 'INSERT INTO edges (source, target, type) VALUES (?, ?, ?) ON CONFLICT DO NOTHING'
398
- ).run(id, targetId, 'INFORMS');
399
- }
400
- }
401
-
402
- if (enables) {
403
- const targetRows = conn.prepare("SELECT id FROM nodes WHERE id = ? AND type = 'Artifact'").all(enables);
404
- for (const row of targetRows) {
405
- conn.prepare(
406
- 'INSERT INTO edges (source, target, type) VALUES (?, ?, ?) ON CONFLICT DO NOTHING'
407
- ).run(id, row.id, 'ENABLES');
408
- }
409
- }
410
-
411
- if (invalidates) {
412
- const targetRows = conn.prepare("SELECT id FROM nodes WHERE id = ? AND type = 'Artifact'").all(invalidates);
413
- for (const row of targetRows) {
414
- conn.prepare(
415
- 'INSERT INTO edges (source, target, type) VALUES (?, ?, ?) ON CONFLICT DO NOTHING'
416
- ).run(id, row.id, 'INVALIDATES');
417
- }
418
- }
419
-
420
- return { id, section, title, contentHash };
421
- }
422
-
423
- async function indexArtifact(conn, roomDir, filePath) {
424
- // --- Transaction: all INSERTs or none (Plan 87-06 / CASCADE-04) ---
425
- // node:sqlite DatabaseSync does NOT expose a transaction(fn) higher-order
426
- // helper (that is a better-sqlite3 API). We use explicit BEGIN/COMMIT with
427
- // ROLLBACK on any throw. On successful completion, SQLite commits the
428
- // block; on any error, we roll back the partial writes and re-throw so
429
- // the caller sees the original error.
430
- //
431
- // Why this matters (CASCADE-04): a pre-patch throw between two INSERTs
432
- // could leave dangling nodes without their edges, or vice versa. The
433
- // BEGIN/COMMIT wrapper converts the whole indexArtifact body into a
434
- // single atomic unit. The post-condition is either "all writes survive"
435
- // or "no writes survive" -- there is no middle state.
436
- //
437
- // Pure computation (file read, hash, wikilink scan) runs inside the txn
438
- // but is idempotent and side-effect free. Moving it outside would require
439
- // duplicating it in _indexArtifactBody and the rebuildGraph call site;
440
- // keeping it inside keeps indexArtifact a thin BEGIN/COMMIT shell.
441
- conn.prepare('BEGIN').run();
442
- let result;
443
- try {
444
- result = _indexArtifactBody(conn, roomDir, filePath);
445
- conn.prepare('COMMIT').run();
446
- } catch (err) {
447
- // ROLLBACK undoes every INSERT issued since BEGIN. We swallow any error
448
- // from ROLLBACK itself (rare: can happen if the connection is already
449
- // aborted) and always re-throw the ORIGINAL error so the caller sees
450
- // the failure reason, not a ROLLBACK noise error.
451
- try { conn.prepare('ROLLBACK').run(); } catch (_rbErr) { /* ignore */ }
452
- throw err;
453
- }
454
-
455
- return Promise.resolve(result);
456
- }
457
-
458
- /**
459
- * Rebuild the entire graph from all room artifacts.
460
- * Clears existing data, walks all sections, indexes every .md file.
461
- * @param {import('node:sqlite').DatabaseSync} conn - node:sqlite DatabaseSync instance
462
- * @param {string} roomDir - Absolute path to room directory
463
- * @returns {Promise<{success: boolean, artifacts: number, sections: number}>}
464
- */
465
- async function rebuildGraph(conn, roomDir) {
466
- const resolved = path.resolve(roomDir);
467
-
468
- // Wrap entire rebuild in a transaction for atomicity.
469
- // If anything throws mid-rebuild, the DB rolls back to pre-rebuild state.
470
- //
471
- // NOTE (Plan 87-06): use explicit BEGIN/COMMIT/ROLLBACK because
472
- // node:sqlite DatabaseSync does NOT expose a transaction(fn) higher-order
473
- // helper (that is a better-sqlite3 API). Calling the inner
474
- // `_indexArtifactBody` (not `indexArtifact`) avoids a nested BEGIN that
475
- // SQLite would reject ("cannot start a transaction within a transaction"
476
- // without SAVEPOINT).
477
- const discovery = discoverSections(resolved);
478
- const sectionNames = discovery.all;
479
- let artifactCount = 0;
480
-
481
- conn.prepare('BEGIN').run();
482
- try {
483
- // Clear all existing data (edges first for FK compliance)
484
- conn.exec('DELETE FROM edges; DELETE FROM nodes;');
485
-
486
- for (const sectionName of sectionNames) {
487
- const sectionDir = path.join(resolved, sectionName);
488
- let files;
489
- try {
490
- files = fs.readdirSync(sectionDir).filter(f =>
491
- f.endsWith('.md') && f !== 'STATE.md' && f !== 'ROOM.md'
492
- );
493
- } catch (e) {
494
- continue; // skip this section
495
- }
496
-
497
- for (const file of files) {
498
- const filePath = path.join(sectionDir, file);
499
- _indexArtifactBody(conn, resolved, filePath); // inside outer BEGIN, no nested txn
500
- artifactCount++;
501
- }
502
- }
503
- conn.prepare('COMMIT').run();
504
- } catch (err) {
505
- try { conn.prepare('ROLLBACK').run(); } catch (_rbErr) { /* ignore */ }
506
- throw err;
507
- }
508
-
509
- return Promise.resolve({ success: true, artifacts: artifactCount, sections: sectionNames.length });
510
- }
511
-
512
- /**
513
- * Execute a SQL query and return all result rows.
514
- * Gracefully returns empty array on error.
515
- * @param {import('node:sqlite').DatabaseSync} conn - node:sqlite DatabaseSync instance
516
- * @param {string} sql - SQL query string
517
- * @param {Array<*>|Object} [params] - bound parameters; array for anonymous (?) placeholders, object for named ($x)
518
- * @returns {Promise<Array<object>>}
519
- */
520
- async function queryGraph(conn, sql, params) {
521
- try {
522
- const stmt = conn.prepare(sql);
523
- if (params == null) {
524
- return Promise.resolve(stmt.all());
525
- }
526
- if (Array.isArray(params)) {
527
- return Promise.resolve(params.length ? stmt.all(...params) : stmt.all());
528
- }
529
- return Promise.resolve(stmt.all(params));
530
- } catch (e) {
531
- return Promise.resolve([]);
532
- }
533
- }
534
-
535
- /**
536
- * Get graph statistics: node counts, edge counts, totals.
537
- * @param {import('node:sqlite').DatabaseSync} conn - node:sqlite DatabaseSync instance
538
- * @returns {Promise<{nodes: object, edges: object, total: {nodes: number, edges: number}}>}
539
- */
540
- async function graphStats(conn) {
541
- // Count nodes by type
542
- // Count ALL node types dynamically (not hardcoded)
543
- const nodeCounts = {};
544
- const nodeRows = conn.prepare('SELECT type, COUNT(*) AS cnt FROM nodes GROUP BY type').all();
545
- for (const row of nodeRows) {
546
- nodeCounts[row.type] = row.cnt;
547
- }
548
-
549
- // Count edges by type
550
- const edges = {};
551
- for (const edgeType of EDGE_TYPES) { edges[edgeType] = 0; }
552
- const edgeRows = conn.prepare('SELECT type, COUNT(*) AS cnt FROM edges GROUP BY type').all();
553
- for (const row of edgeRows) {
554
- if (row.type in edges) {
555
- edges[row.type] = row.cnt;
556
- }
557
- }
558
-
559
- const totalNodes = Object.values(nodeCounts).reduce((sum, n) => sum + n, 0);
560
- const totalEdges = Object.values(edges).reduce((sum, n) => sum + n, 0);
561
-
562
- return Promise.resolve({
563
- nodes: nodeCounts,
564
- edges,
565
- total: { nodes: totalNodes, edges: totalEdges },
566
- });
567
- }
568
-
569
- /**
570
- * Tier 2 Pinecone semantic layer stub.
571
- * Embeds an artifact for semantic search when Pinecone is configured.
572
- * Gracefully degrades when Pinecone env vars are not set.
573
- *
574
- * Contract: embedArtifact(roomDir, filePath) -> { success: boolean, reason?: string, embeddingId?: string }
575
- *
576
- * @param {string} roomDir - Absolute path to room directory
577
- * @param {string} filePath - Absolute path to .md artifact file
578
- * @returns {Promise<{success: boolean, reason?: string, embeddingId?: string}>}
579
- */
580
- async function embedArtifact(roomDir, filePath) {
581
- // Read the artifact content (validates the file exists)
582
- const resolved = path.resolve(filePath);
583
- if (!fs.existsSync(resolved)) {
584
- return { success: false, reason: `Artifact not found: ${filePath}` };
585
- }
586
-
587
- const apiKey = process.env.PINECONE_API_KEY;
588
- const index = process.env.PINECONE_INDEX;
589
-
590
- if (!apiKey || !index) {
591
- return {
592
- success: false,
593
- reason: 'Pinecone Tier 2 not configured - set PINECONE_API_KEY and PINECONE_INDEX to enable semantic search',
594
- };
595
- }
596
-
597
- // Pinecone env vars are set but integration not yet wired
598
- return {
599
- success: false,
600
- reason: 'Pinecone Tier 2 integration not yet implemented - stub ready for future wiring',
601
- };
602
- }
603
-
604
- // --- Design-by-Analogy Edge Creation (DBA-08) ---
605
-
606
- /**
607
- * Create an ANALOGOUS_TO edge between two artifacts.
608
- * Records functional analogy with distance, fitness, and transfer mapping.
609
- * @param {import('node:sqlite').DatabaseSync} conn - node:sqlite DatabaseSync instance
610
- * @param {string} sourceId - Source artifact ID
611
- * @param {string} targetId - Target artifact ID
612
- * @param {object} props - Edge properties
613
- * @param {string} [props.analogy_distance='near'] - near|far|cross-domain
614
- * @param {number} [props.structural_fitness=0.0] - 0-1 structural fitness score
615
- * @param {string} [props.source_domain=''] - Domain of the source analogy
616
- * @param {string} [props.transfer_map='{}'] - JSON string mapping source to target elements
617
- * @param {string} [props.discovery_method='hsi'] - hsi|brain|llm|external|user
618
- * @returns {Promise<boolean>}
619
- */
620
- async function createAnalogyEdge(conn, sourceId, targetId, props = {}) {
621
- const edgeProps = JSON.stringify({
622
- analogy_distance: props.analogy_distance || 'near',
623
- structural_fitness: props.structural_fitness || 0.0,
624
- source_domain: props.source_domain || '',
625
- transfer_map: props.transfer_map || '{}',
626
- discovery_method: props.discovery_method || 'hsi',
627
- });
628
-
629
- conn.prepare(
630
- 'INSERT INTO edges (source, target, type, properties) VALUES (?, ?, ?, ?) ON CONFLICT(source, target, type) DO UPDATE SET properties = excluded.properties'
631
- ).run(sourceId, targetId, 'ANALOGOUS_TO', edgeProps);
632
- return Promise.resolve(true);
633
- }
634
-
635
- /**
636
- * Create a STRUCTURALLY_ISOMORPHIC edge between two sections.
637
- * Records identical relational topology between room sections.
638
- * @param {import('node:sqlite').DatabaseSync} conn - node:sqlite DatabaseSync instance
639
- * @param {string} sectionA - Source section name
640
- * @param {string} sectionB - Target section name
641
- * @param {object} props - Edge properties
642
- * @param {number} [props.isomorphism_score=0.0] - 0-1 isomorphism score
643
- * @param {string} [props.mapped_elements='{}'] - JSON string of element mappings
644
- * @param {string} [props.source=''] - Source of the isomorphism detection
645
- * @returns {Promise<boolean>}
646
- */
647
- async function createIsomorphismEdge(conn, sectionA, sectionB, props = {}) {
648
- const edgeProps = JSON.stringify({
649
- isomorphism_score: props.isomorphism_score || 0.0,
650
- mapped_elements: props.mapped_elements || '{}',
651
- source: props.source || '',
652
- });
653
-
654
- conn.prepare(
655
- 'INSERT INTO edges (source, target, type, properties) VALUES (?, ?, ?, ?) ON CONFLICT(source, target, type) DO UPDATE SET properties = excluded.properties'
656
- ).run(sectionA, sectionB, 'STRUCTURALLY_ISOMORPHIC', edgeProps);
657
- return Promise.resolve(true);
658
- }
659
-
660
- /**
661
- * Create a RESOLVES_VIA edge linking a contradiction to its resolution.
662
- * Closes the loop: contradiction -> analogy/TRIZ -> resolution.
663
- * @param {import('node:sqlite').DatabaseSync} conn - node:sqlite DatabaseSync instance
664
- * @param {string} sourceId - Artifact ID (the contradicting artifact)
665
- * @param {string} targetId - Artifact ID (the resolution artifact)
666
- * @param {object} props - Edge properties
667
- * @param {string} [props.resolution_type='direct'] - analogy|triz_principle|direct
668
- * @param {string} [props.triz_principle=''] - TRIZ principle number/name if applicable
669
- * @param {string} [props.analogy_source=''] - Source analogy reference if applicable
670
- * @param {number} [props.confidence=0.0] - 0-1 confidence in resolution
671
- * @returns {Promise<boolean>}
672
- */
673
- async function createResolutionEdge(conn, sourceId, targetId, props = {}) {
674
- const edgeProps = JSON.stringify({
675
- resolution_type: props.resolution_type || 'direct',
676
- triz_principle: props.triz_principle || '',
677
- analogy_source: props.analogy_source || '',
678
- confidence: props.confidence || 0.0,
679
- });
680
-
681
- conn.prepare(
682
- 'INSERT INTO edges (source, target, type, properties) VALUES (?, ?, ?, ?) ON CONFLICT(source, target, type) DO UPDATE SET properties = excluded.properties'
683
- ).run(sourceId, targetId, 'RESOLVES_VIA', edgeProps);
684
- return Promise.resolve(true);
685
- }
686
-
687
- // --- Causal Extraction CRUD (Phase 53) ---
688
-
689
- /**
690
- * Create or update a CausalClaim node in SQLite.
691
- * Writes all 12 properties as JSON. Truncates cause/effect to 200 chars,
692
- * mechanism to 300 chars to prevent oversized nodes.
693
- * @param {import('node:sqlite').DatabaseSync} conn - node:sqlite DatabaseSync instance
694
- * @param {object} claim - CausalClaim properties
695
- * @param {string} claim.id - Unique claim ID
696
- * @param {string} claim.cause - Cause statement (truncated to 200 chars)
697
- * @param {string} claim.mechanism - Mechanism explanation (truncated to 300 chars)
698
- * @param {string} claim.effect - Effect statement (truncated to 200 chars)
699
- * @param {number} [claim.confidence=0.5] - Confidence score (0-1)
700
- * @param {string} [claim.evidence='[]'] - JSON array of evidence references
701
- * @param {string} [claim.source_artifact=''] - Source artifact ID
702
- * @param {string} [claim.domain='general'] - Domain classification
703
- * @param {string} [claim.falsifiable_prediction=''] - Testable prediction
704
- * @param {number} [claim.novelty_score=0.0] - Novelty score (0-1)
705
- * @param {string} [claim.extraction_method='inferred'] - observed|asserted|inferred
706
- * @param {string} [claim.created=''] - ISO date string
707
- * @returns {Promise<boolean>}
708
- */
709
- async function createCausalClaim(conn, claim) {
710
- const cause = (claim.cause || '').slice(0, 200);
711
- const mechanism = (claim.mechanism || '').slice(0, 300);
712
- const effect = (claim.effect || '').slice(0, 200);
713
- const confidence = typeof claim.confidence === 'number' ? claim.confidence : 0.5;
714
- const evidence = Array.isArray(claim.evidence) ? JSON.stringify(claim.evidence) : (claim.evidence || '[]');
715
- const sourceArtifact = claim.source_artifact || '';
716
- const domain = claim.domain || 'general';
717
- const prediction = claim.falsifiable_prediction || '';
718
- const novelty = typeof claim.novelty_score === 'number' ? claim.novelty_score : 0.0;
719
- const method = claim.extraction_method || 'inferred';
720
- const created = claim.created || '';
721
-
722
- const props = JSON.stringify({
723
- cause, mechanism, effect, confidence, evidence, source_artifact: sourceArtifact,
724
- domain, falsifiable_prediction: prediction, novelty_score: novelty,
725
- extraction_method: method, created,
726
- });
727
-
728
- conn.prepare(
729
- 'INSERT INTO nodes (id, type, properties) VALUES (?, ?, ?) ON CONFLICT(id) DO UPDATE SET type = excluded.type, properties = excluded.properties'
730
- ).run(claim.id, 'CausalClaim', props);
731
- return Promise.resolve(true);
732
- }
733
-
734
- /**
735
- * Create an EXTRACTED_FROM edge linking a CausalClaim to its source Artifact.
736
- * @param {import('node:sqlite').DatabaseSync} conn - node:sqlite DatabaseSync instance
737
- * @param {string} claimId - CausalClaim node ID
738
- * @param {string} artifactId - Artifact node ID
739
- * @returns {Promise<boolean>}
740
- */
741
- async function createExtractedFromEdge(conn, claimId, artifactId) {
742
- conn.prepare(
743
- 'INSERT INTO edges (source, target, type) VALUES (?, ?, ?) ON CONFLICT DO NOTHING'
744
- ).run(claimId, artifactId, 'EXTRACTED_FROM');
745
- return Promise.resolve(true);
746
- }
747
-
748
- // --- Causal Graph Engine (Phase 54) ---
749
-
750
- /**
751
- * Create a CASCADES_TO edge between two CausalClaim nodes.
752
- * Idempotent via ON CONFLICT. Records cascade type and severity.
753
- * @param {import('node:sqlite').DatabaseSync} conn - node:sqlite DatabaseSync instance
754
- * @param {string} fromClaimId - Source CausalClaim node ID
755
- * @param {string} toClaimId - Target CausalClaim node ID
756
- * @param {object} [opts] - Edge properties
757
- * @param {string} [opts.cascade_type='invalidation'] - invalidation|weakening|dependency
758
- * @param {string} [opts.severity='medium'] - high|medium|low
759
- * @param {number} [opts.path_length=1] - Hop distance
760
- * @returns {Promise<boolean>}
761
- */
762
- async function createCascadesToEdge(conn, fromClaimId, toClaimId, opts = {}) {
763
- const edgeProps = JSON.stringify({
764
- cascade_type: opts.cascade_type || 'invalidation',
765
- severity: opts.severity || 'medium',
766
- path_length: typeof opts.path_length === 'number' ? opts.path_length : 1,
767
- });
768
-
769
- conn.prepare(
770
- 'INSERT INTO edges (source, target, type, properties) VALUES (?, ?, ?, ?) ON CONFLICT(source, target, type) DO UPDATE SET properties = excluded.properties'
771
- ).run(fromClaimId, toClaimId, 'CASCADES_TO', edgeProps);
772
- return Promise.resolve(true);
773
- }
774
-
775
- /**
776
- * Export all CausalClaim nodes and CASCADES_TO edges as JSON.
777
- * Writes .lazygraph-causal-export.json to roomDir for Python engine consumption.
778
- * Handles empty graphs gracefully (writes JSON with empty arrays).
779
- * @param {string} roomDir - Path to room directory
780
- * @returns {Promise<{metadata: object, nodes: Array, edges: Array}>}
781
- */
782
- async function exportCausalGraph(roomDir) {
783
- const resolved = path.resolve(roomDir);
784
- const { db, conn } = await openGraph(resolved);
785
- try {
786
- // Query all CausalClaim nodes
787
- let nodes = [];
788
- try {
789
- nodes = conn.prepare(
790
- "SELECT id, json_extract(properties, '$.cause') AS cause, json_extract(properties, '$.mechanism') AS mechanism, json_extract(properties, '$.effect') AS effect, json_extract(properties, '$.confidence') AS confidence, json_extract(properties, '$.domain') AS domain, json_extract(properties, '$.source_artifact') AS source_artifact FROM nodes WHERE type = 'CausalClaim'"
791
- ).all();
792
- } catch (e) {
793
- // table may be empty or schema different
794
- }
795
-
796
- // Query all CASCADES_TO edges
797
- let edges = [];
798
- try {
799
- edges = conn.prepare(
800
- "SELECT source, target, json_extract(properties, '$.cascade_type') AS cascade_type, json_extract(properties, '$.severity') AS severity FROM edges WHERE type = 'CASCADES_TO'"
801
- ).all();
802
- } catch (e) {
803
- // no CASCADES_TO edges
804
- }
805
-
806
- const exportData = {
807
- metadata: {
808
- exported_at: new Date().toISOString(),
809
- node_count: nodes.length,
810
- edge_count: edges.length,
811
- },
812
- nodes,
813
- edges,
814
- };
815
-
816
- const exportPath = path.join(resolved, '.lazygraph-causal-export.json');
817
- fs.writeFileSync(exportPath, JSON.stringify(exportData, null, 2), 'utf-8');
818
- return exportData;
819
- } finally {
820
- await closeGraph(db);
821
- }
822
- }
823
-
824
- // --- TRIZ Contradiction Enrichment (DBA-09) ---
825
-
826
- /**
827
- * Enrich an existing CONTRADICTS edge with TRIZ parameter classification.
828
- * Looks up triz-matrix.json to suggest inventive principles for the contradiction.
829
- * @param {import('node:sqlite').DatabaseSync} conn - node:sqlite DatabaseSync instance
830
- * @param {string} artifactA - Source artifact ID
831
- * @param {string} artifactB - Target artifact ID
832
- * @param {string} improvingParam - TRIZ parameter being improved (one of 39)
833
- * @param {string} worseningParam - TRIZ parameter being worsened (one of 39)
834
- * @returns {Promise<{success: boolean, principles: number[], reason?: string}>}
835
- */
836
- async function enrichContradictionWithTRIZ(conn, artifactA, artifactB, improvingParam, worseningParam) {
837
- // Load TRIZ matrix
838
- const matrixPath = path.join(__dirname, '..', '..', 'references', 'methodology', 'triz-matrix.json');
839
- if (!fs.existsSync(matrixPath)) {
840
- return { success: false, principles: [], reason: 'triz-matrix.json not found' };
841
- }
842
-
843
- let matrix;
844
- try {
845
- matrix = JSON.parse(fs.readFileSync(matrixPath, 'utf-8'));
846
- } catch (e) {
847
- return { success: false, principles: [], reason: 'Failed to parse triz-matrix.json' };
848
- }
849
-
850
- // Look up principles
851
- const improvingEntry = matrix[improvingParam];
852
- if (!improvingEntry) {
853
- return { success: false, principles: [], reason: `Unknown improving parameter: ${improvingParam}` };
854
- }
855
-
856
- const principles = improvingEntry[worseningParam];
857
- if (!principles || !Array.isArray(principles) || principles.length === 0) {
858
- return { success: false, principles: [], reason: `No principles found for ${improvingParam} vs ${worseningParam}` };
859
- }
860
-
861
- const principlesStr = principles.join(',');
862
-
863
- // Create a RESOLVES_VIA edge capturing the TRIZ resolution direction
864
- const edgeProps = JSON.stringify({
865
- resolution_type: 'triz_principle',
866
- triz_principle: principlesStr,
867
- analogy_source: `${improvingParam} vs ${worseningParam}`,
868
- confidence: 0.7,
869
- });
870
-
871
- conn.prepare(
872
- 'INSERT INTO edges (source, target, type, properties) VALUES (?, ?, ?, ?) ON CONFLICT(source, target, type) DO UPDATE SET properties = excluded.properties'
873
- ).run(artifactA, artifactB, 'RESOLVES_VIA', edgeProps);
874
-
875
- return { success: true, principles };
876
- }
877
-
878
- // --- Whitespace Zone CRUD (Phase 61) ---
879
-
880
- /**
881
- * Create or update a WhitespaceZone node in SQLite.
882
- * Writes all properties as JSON. Idempotent.
883
- * @param {import('node:sqlite').DatabaseSync} conn - node:sqlite DatabaseSync instance
884
- * @param {object} zone - WhitespaceZone properties
885
- * @param {string} zone.id - Unique zone ID
886
- * @param {string} zone.brain_framework - Brain framework name this gap relates to
887
- * @param {number} [zone.density_score=0.0] - Embedding space density score
888
- * @param {number} [zone.knn_density=0.0] - KNN density from SemNovel algorithm
889
- * @param {string} [zone.nearest_frameworks='[]'] - JSON array of nearest framework names
890
- * @param {string} [zone.hypothesis=''] - Generated hypothesis about what should fill this gap
891
- * @param {number} [zone.strategic_rank=0.0] - Strategic importance ranking
892
- * @param {string} [zone.problem_type=''] - Problem type classification
893
- * @param {string} [zone.exploration_status='detected'] - detected|exploring|resolved|dismissed
894
- * @param {string} [zone.created=''] - ISO date string
895
- * @returns {Promise<boolean>}
896
- */
897
- async function addWhitespaceZone(conn, zone) {
898
- const props = JSON.stringify({
899
- brain_framework: zone.brain_framework || '',
900
- density_score: typeof zone.density_score === 'number' ? zone.density_score : 0.0,
901
- knn_density: typeof zone.knn_density === 'number' ? zone.knn_density : 0.0,
902
- nearest_frameworks: Array.isArray(zone.nearest_frameworks) ? JSON.stringify(zone.nearest_frameworks) : (zone.nearest_frameworks || '[]'),
903
- hypothesis: (zone.hypothesis || '').slice(0, 500),
904
- strategic_rank: typeof zone.strategic_rank === 'number' ? zone.strategic_rank : 0.0,
905
- problem_type: zone.problem_type || '',
906
- exploration_status: zone.exploration_status || 'detected',
907
- created: zone.created || '',
908
- });
909
-
910
- conn.prepare(
911
- 'INSERT INTO nodes (id, type, properties) VALUES (?, ?, ?) ON CONFLICT(id) DO UPDATE SET type = excluded.type, properties = excluded.properties'
912
- ).run(zone.id, 'WhitespaceZone', props);
913
- return Promise.resolve(true);
914
- }
915
-
916
- /**
917
- * Create a WHITESPACE_DETECTED edge from a WhitespaceZone to a nearby Artifact.
918
- * Records embedding distance. Idempotent.
919
- * @param {import('node:sqlite').DatabaseSync} conn - node:sqlite DatabaseSync instance
920
- * @param {string} zoneId - WhitespaceZone node ID
921
- * @param {string} artifactId - Artifact node ID
922
- * @param {number} [distance=0.0] - Embedding distance between zone centroid and artifact
923
- * @returns {Promise<boolean>}
924
- */
925
- async function linkWhitespaceToArtifact(conn, zoneId, artifactId, distance = 0.0) {
926
- const edgeProps = JSON.stringify({ distance });
927
- conn.prepare(
928
- 'INSERT INTO edges (source, target, type, properties) VALUES (?, ?, ?, ?) ON CONFLICT(source, target, type) DO UPDATE SET properties = excluded.properties'
929
- ).run(zoneId, artifactId, 'WHITESPACE_DETECTED', edgeProps);
930
- return Promise.resolve(true);
931
- }
932
-
933
- /**
934
- * Create a WHITESPACE_NEAR edge from a WhitespaceZone to a Section.
935
- * Records relevance score. Idempotent.
936
- * @param {import('node:sqlite').DatabaseSync} conn - node:sqlite DatabaseSync instance
937
- * @param {string} zoneId - WhitespaceZone node ID
938
- * @param {string} sectionName - Section node name
939
- * @param {number} [relevance=0.0] - Relevance score (0-1)
940
- * @returns {Promise<boolean>}
941
- */
942
- async function linkWhitespaceToSection(conn, zoneId, sectionName, relevance = 0.0) {
943
- const edgeProps = JSON.stringify({ relevance });
944
- conn.prepare(
945
- 'INSERT INTO edges (source, target, type, properties) VALUES (?, ?, ?, ?) ON CONFLICT(source, target, type) DO UPDATE SET properties = excluded.properties'
946
- ).run(zoneId, sectionName, 'WHITESPACE_NEAR', edgeProps);
947
- return Promise.resolve(true);
948
- }
949
-
950
- /**
951
- * Link a WhitespaceZone to an Artifact via DISCOVERY_CYCLE_SOURCE edge.
952
- * Records which discovery method (hsi, rs, analogy) found this zone.
953
- * @param {import('node:sqlite').DatabaseSync} conn - node:sqlite DatabaseSync instance
954
- * @param {string} zoneId - WhitespaceZone ID
955
- * @param {string} artifactId - Source Artifact ID
956
- * @param {string} discoveryMethod - 'hsi' | 'rs' | 'analogy'
957
- * @param {string} [cycleTimestamp] - ISO timestamp of discovery cycle run
958
- * @returns {Promise<boolean>}
959
- */
960
- async function linkDiscoveryCycleSource(conn, zoneId, artifactId, discoveryMethod, cycleTimestamp = '') {
961
- const ts = cycleTimestamp || new Date().toISOString();
962
- const edgeProps = JSON.stringify({ discovery_method: discoveryMethod, cycle_timestamp: ts });
963
- conn.prepare(
964
- 'INSERT INTO edges (source, target, type, properties) VALUES (?, ?, ?, ?) ON CONFLICT(source, target, type) DO UPDATE SET properties = excluded.properties'
965
- ).run(zoneId, artifactId, 'DISCOVERY_CYCLE_SOURCE', edgeProps);
966
- return Promise.resolve(true);
967
- }
968
-
969
- // --- Phase 89-07 Wave 1: generic typed-edge upsert primitive ---
970
- //
971
- // upsertEdge is the single chokepoint by which agentic surfaces (Phase 89-07
972
- // ReverseSalientAgent, Phase 116 tension hook, Phase 117 auto-explore, Phase
973
- // 118 MVA, Phase 120 breakthrough scan) emit typed cascade edges. It validates
974
- // the edge type against EDGE_TYPES and performs the same UPSERT pattern used
975
- // by every other edge writer in this module.
976
- //
977
- // Shape: upsertEdge(conn, { type, source, target, properties }) -> { ok, reason? }
978
- // - conn: node:sqlite DatabaseSync instance (or any object with .prepare).
979
- // - type: one of EDGE_TYPES (string).
980
- // - source: source node id (string).
981
- // - target: target node id (string).
982
- // - properties: optional object; serialized to JSON.
983
- //
984
- // Synchronous (no Promise wrapping); the underlying prepare/run is sync per
985
- // node:sqlite contract. Per-call shape mirrors the rest of this module.
986
- //
987
- // Canon Part 4: every choice is graph data; this primitive lets every agent
988
- // emit typed edges without bypassing EDGE_TYPES validation. Canon Part 7:
989
- // reuse-before-build; sibling agents reuse this instead of inlining SQL.
990
- function upsertEdge(conn, edge) {
991
- if (!edge || typeof edge !== 'object') {
992
- return { ok: false, reason: 'invalid_edge_object' };
993
- }
994
- const { type, source, target } = edge;
995
- if (typeof type !== 'string' || !EDGE_TYPES.includes(type)) {
996
- return { ok: false, reason: 'invalid_edge_type', detail: String(type).slice(0, 40) };
997
- }
998
- if (typeof source !== 'string' || source.length === 0) {
999
- return { ok: false, reason: 'invalid_source_id' };
1000
- }
1001
- if (typeof target !== 'string' || target.length === 0) {
1002
- return { ok: false, reason: 'invalid_target_id' };
1003
- }
1004
- const props = edge.properties && typeof edge.properties === 'object' ? edge.properties : {};
1005
- let propsJson;
1006
- try {
1007
- propsJson = JSON.stringify(props);
1008
- } catch (_e) {
1009
- return { ok: false, reason: 'properties_serialize_failed' };
1010
- }
1011
- try {
1012
- conn.prepare(
1013
- 'INSERT INTO edges (source, target, type, properties) VALUES (?, ?, ?, ?) ON CONFLICT(source, target, type) DO UPDATE SET properties = excluded.properties'
1014
- ).run(source, target, type, propsJson);
1015
- } catch (e) {
1016
- return { ok: false, reason: 'edge_write_failed', detail: String(e.message || '').slice(0, 80) };
1017
- }
1018
- return { ok: true, type, source, target };
1019
- }
1020
-
1021
- // --- Exports ---
1022
-
1023
- module.exports = {
1024
- EDGE_TYPES,
1025
- upsertEdge,
1026
- openGraph,
1027
- closeGraph,
1028
- initSchema,
1029
- indexArtifact,
1030
- rebuildGraph,
1031
- queryGraph,
1032
- graphStats,
1033
- embedArtifact,
1034
- // Design-by-Analogy (DBA-08, DBA-09)
1035
- createAnalogyEdge,
1036
- createIsomorphismEdge,
1037
- createResolutionEdge,
1038
- enrichContradictionWithTRIZ,
1039
- // Causal Extraction (Phase 53)
1040
- createCausalClaim,
1041
- createExtractedFromEdge,
1042
- // Causal Graph Engine (Phase 54)
1043
- createCascadesToEdge,
1044
- exportCausalGraph,
1045
- // Whitespace Zone Layer (Phase 61)
1046
- addWhitespaceZone,
1047
- linkWhitespaceToArtifact,
1048
- linkWhitespaceToSection,
1049
- // Discovery Cycle (Phase 64)
1050
- linkDiscoveryCycleSource,
1051
- // Stakeholder node type (Phase 84-05, SCOPE-NB-03 / SCOPE-NB-04)
1052
- STAKEHOLDER_TYPES,
1053
- createStakeholder,
1054
- getStakeholder,
1055
- upsertStakeholder,
1056
- findStakeholdersByClaim,
1057
- };