@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,646 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /*
5
+ * Copyright (c) 2026 Mindrian. BSL 1.1.
6
+ * Phase 89.3 Plan 03 -- 5-branch Cytoscape mind map fixture suite.
7
+ *
8
+ * renderMindMap(query_filter, opts) is the read-side companion to the
9
+ * dual-tier writers (rs-neo4j-writer.cjs Plan 89.3-01 and
10
+ * rs-sqlite-mirror.cjs Plan 89.3-02). It reads from the active tier
11
+ * (Aura via opts.driver OR room.db via opts.roomDir) and emits a
12
+ * Cytoscape-compatible JSON payload split into 5 branches plus a
13
+ * standalone HTML wrapper that uses the existing dashboard cytoscape
14
+ * CDN (Canon Part 7 reuse; zero new runtime deps).
15
+ *
16
+ * The 5 branches (per kickoff section 5):
17
+ * 1. Direct Intersections lsa > 0.6 AND bert > 0.6
18
+ * 2. Structural Transfer classification = structural_transfer
19
+ * 3. Semantic Implementation classification = semantic_implementation
20
+ * 4. Discovered RS ReverseSalient nodes
21
+ * 5. Innovation Ecosystem Innovation + Paper + Author + Institution slice
22
+ *
23
+ * 10 scenarios + A1 end-of-suite sweep:
24
+ * 1 Happy path (Tier 0; all 5 branches populated from seeded fixtures)
25
+ * 2 Tier 0 read path (empty room.db; graceful 5-branch render with empty arrays)
26
+ * 3 Tier 1 read path (mocked driver; verify Cypher dispatch + populated branches)
27
+ * 4 Single-node edge case (1 hybrid RSDiscovery; lsa/bert below threshold; not in any branch)
28
+ * 5 All 5 branches present in JSON regardless of data sparsity
29
+ * 6 HTML wrapper has cytoscape@3.33.1 CDN script tag (Canon Part 7 reuse)
30
+ * 7 Canon Part 8 audit on rendered HTML (clean fixture; no forbidden patterns)
31
+ * 8 query_filter applied correctly (filters by branch name)
32
+ * 9 CANON PART 8 adversarial -- forbidden in node properties read from sqlite
33
+ * 10 CANON PART 8 adversarial -- forbidden in classification field returned by aura mock
34
+ *
35
+ * End-of-suite sweep:
36
+ * A1: walk every captured result.html_wrapper from passing scenarios;
37
+ * JSON.stringify and scan against FORBIDDEN_PATTERNS; assert ZERO
38
+ * hits across all clean scenarios. Throw scenarios verify undefined
39
+ * result so no html_wrapper to scan.
40
+ *
41
+ * Pure CJS, zero npm deps, node built-ins only (assert, fs, path, os, crypto).
42
+ */
43
+
44
+ const assert = require('node:assert/strict');
45
+ const fs = require('node:fs');
46
+ const path = require('node:path');
47
+ const os = require('node:os');
48
+ const crypto = require('node:crypto');
49
+
50
+ const REPO_ROOT = path.resolve(__dirname, '..', '..');
51
+
52
+ // Source of truth for parity gate.
53
+ const crossRoomAggregator = require('../core/cross-room-aggregator.cjs');
54
+ const FORBIDDEN_PATTERNS = crossRoomAggregator.FORBIDDEN_PATTERNS;
55
+
56
+ // Lazy-required (so RED commit can prove module-not-found before GREEN).
57
+ const lazygraph = require('../core/lazygraph-ops.cjs');
58
+
59
+ // Track every tmp room dir for cleanup.
60
+ const tmpRooms = [];
61
+
62
+ // Capture result.html_wrapper from every clean scenario for the A1 sweep.
63
+ const capturedHtmlWrappers = [];
64
+
65
+ let passed = 0;
66
+ let failed = 0;
67
+ const failures = [];
68
+
69
+ function resetRequireCache() {
70
+ const targets = [
71
+ '../core/rs-egress-violations.cjs',
72
+ '../core/rs-egress-prompts.cjs',
73
+ '../core/cross-room-aggregator.cjs',
74
+ '../core/rs-mind-map.cjs',
75
+ ];
76
+ for (const t of targets) {
77
+ try {
78
+ const p = require.resolve(t);
79
+ delete require.cache[p];
80
+ } catch (_e) { /* best effort */ }
81
+ }
82
+ }
83
+
84
+ async function runScenario(name, fn) {
85
+ const start = Date.now();
86
+ try {
87
+ await fn();
88
+ passed += 1;
89
+ process.stdout.write(' ok ' + name + ' (' + (Date.now() - start) + 'ms)\n');
90
+ } catch (err) {
91
+ failed += 1;
92
+ failures.push({ name: name, err: err });
93
+ process.stderr.write(' FAIL ' + name + '\n');
94
+ process.stderr.write(' ' + (err && err.stack ? err.stack : err) + '\n');
95
+ } finally {
96
+ resetRequireCache();
97
+ }
98
+ }
99
+
100
+ // ---------- Tmp room helper ----------
101
+
102
+ function makeTmpRoom() {
103
+ const slug = crypto.randomUUID();
104
+ const roomDir = path.join(os.tmpdir(), 'mos-89-3-03-' + slug);
105
+ fs.mkdirSync(roomDir, { recursive: true });
106
+ tmpRooms.push(roomDir);
107
+ return {
108
+ roomDir: roomDir,
109
+ cleanup: function () {
110
+ try {
111
+ fs.rmSync(roomDir, { recursive: true, force: true });
112
+ } catch (_e) { /* best effort */ }
113
+ },
114
+ };
115
+ }
116
+
117
+ // ---------- Direct INSERT seed helpers ----------
118
+ //
119
+ // Tests inject raw rows directly via lazygraph.openGraph + INSERT.
120
+ // We do NOT call rs-sqlite-mirror.writeDiscovery in seeds (that would
121
+ // create a circular test dependency between Plan 89.3-02 and this plan).
122
+
123
+ async function seedNode(roomDir, id, type, properties) {
124
+ const handle = await lazygraph.openGraph(roomDir);
125
+ try {
126
+ handle.conn.prepare(
127
+ 'INSERT OR REPLACE INTO nodes (id, type, properties) VALUES (?, ?, ?)'
128
+ ).run(id, type, JSON.stringify(properties || {}));
129
+ } finally {
130
+ await lazygraph.closeGraph(handle.db);
131
+ }
132
+ }
133
+
134
+ async function seedEdge(roomDir, source, target, type, properties) {
135
+ const handle = await lazygraph.openGraph(roomDir);
136
+ try {
137
+ handle.conn.prepare(
138
+ 'INSERT OR REPLACE INTO edges (source, target, type, properties) VALUES (?, ?, ?, ?)'
139
+ ).run(source, target, type, JSON.stringify(properties || {}));
140
+ } finally {
141
+ await lazygraph.closeGraph(handle.db);
142
+ }
143
+ }
144
+
145
+ // ---------- Aura mock driver factory ----------
146
+ //
147
+ // Returns a {session: () => ({run, close})} object that responds to the
148
+ // 5 Cypher MATCH queries renderMindMap dispatches in Tier 1 mode. The
149
+ // shape of records mirrors the neo4j-driver Result shape (each record
150
+ // has a .get(name) method that returns the matched node value with
151
+ // .properties).
152
+
153
+ function makeAuraMock(perBranchRecords) {
154
+ // perBranchRecords: { 'Direct Intersections': [...node objects...], ... }
155
+ const sessionRunCalls = [];
156
+
157
+ // Map node.type to the Cypher key the readAuraBranches loop asks for.
158
+ // Returning null for non-matching keys mirrors the real neo4j-driver
159
+ // behavior on OPTIONAL MATCH where the un-matched bind is null. This
160
+ // keeps the multi-hop branch (Innovation Ecosystem) from spuriously
161
+ // duplicating the same row's node across all keys.
162
+ const TYPE_TO_KEY = {
163
+ 'RSDiscovery': 'd',
164
+ 'ReverseSalient': 'rs',
165
+ 'Innovation': 'i',
166
+ 'Paper': 'p',
167
+ 'Author': 'a',
168
+ 'Institution': 'inst',
169
+ };
170
+ function recordFromNode(nodeObj) {
171
+ const matchKey = TYPE_TO_KEY[nodeObj.type] || 'd';
172
+ return {
173
+ get: function (key) {
174
+ if (key !== matchKey) return null;
175
+ return {
176
+ properties: nodeObj.properties || {},
177
+ labels: nodeObj.labels || [nodeObj.type || 'Unknown'],
178
+ identity: { low: nodeObj.id ? hashToInt(nodeObj.id) : 0, high: 0 },
179
+ };
180
+ },
181
+ keys: [matchKey],
182
+ _node: nodeObj,
183
+ };
184
+ }
185
+
186
+ function hashToInt(s) {
187
+ // Mod 9999 keeps the integer to <= 4 digits so the resulting
188
+ // 'aura-NNNN' id cannot accidentally trigger the phone-like
189
+ // FORBIDDEN_PATTERNS regex (which matches \d{3}-\d{4} sequences).
190
+ // The mock identity space is small enough that 9999 has zero
191
+ // collision risk for the per-scenario fixtures.
192
+ let h = 0;
193
+ for (let i = 0; i < s.length; i += 1) {
194
+ h = ((h << 5) - h) + s.charCodeAt(i);
195
+ h |= 0;
196
+ }
197
+ return Math.abs(h) % 9999;
198
+ }
199
+
200
+ return {
201
+ session: function () {
202
+ return {
203
+ run: function (cypher, params) {
204
+ sessionRunCalls.push({ cypher: cypher, params: params || {} });
205
+ // Heuristic: choose branch based on cypher substring.
206
+ let records = [];
207
+ if (/lsa.*0\.6.*bert.*0\.6/i.test(cypher) || /Direct Intersections/i.test(cypher)) {
208
+ records = (perBranchRecords['Direct Intersections'] || []).map(recordFromNode);
209
+ } else if (/structural_transfer/i.test(cypher) || /Structural Transfer/i.test(cypher)) {
210
+ records = (perBranchRecords['Structural Transfer'] || []).map(recordFromNode);
211
+ } else if (/semantic_implementation/i.test(cypher) || /Semantic Implementation/i.test(cypher)) {
212
+ records = (perBranchRecords['Semantic Implementation'] || []).map(recordFromNode);
213
+ } else if (/ReverseSalient/i.test(cypher) || /Discovered RS/i.test(cypher)) {
214
+ records = (perBranchRecords['Discovered RS'] || []).map(recordFromNode);
215
+ } else if (/Innovation/i.test(cypher) || /Paper/i.test(cypher) || /Author/i.test(cypher)) {
216
+ records = (perBranchRecords['Innovation Ecosystem'] || []).map(recordFromNode);
217
+ }
218
+ return Promise.resolve({ records: records });
219
+ },
220
+ close: function () { return Promise.resolve(); },
221
+ };
222
+ },
223
+ _calls: sessionRunCalls,
224
+ close: function () { return Promise.resolve(); },
225
+ };
226
+ }
227
+
228
+ // ---------- Scenarios ----------
229
+
230
+ async function scenario1HappyPathTier0() {
231
+ // Pre-seed a tmp room.db with the 5 branches' worth of fixtures, then
232
+ // call renderMindMap; assert all 5 branches populated with the right
233
+ // counts.
234
+ const m = require('../core/rs-mind-map.cjs');
235
+ const tmp = makeTmpRoom();
236
+ try {
237
+ // 2 RSDiscovery nodes for Direct Intersections (lsa>0.6 AND bert>0.6)
238
+ await seedNode(tmp.roomDir, 'rsd-di-001', 'RSDiscovery', {
239
+ classification: 'hybrid', lsa: 0.85, bert: 0.78, thesis: 'A safe thesis.',
240
+ });
241
+ await seedNode(tmp.roomDir, 'rsd-di-002', 'RSDiscovery', {
242
+ classification: 'hybrid', lsa: 0.71, bert: 0.69, thesis: 'Another safe thesis.',
243
+ });
244
+
245
+ // 1 RSDiscovery for Structural Transfer
246
+ await seedNode(tmp.roomDir, 'rsd-st-001', 'RSDiscovery', {
247
+ classification: 'structural_transfer', lsa: 0.55, bert: 0.20, thesis: 'Structural thesis.',
248
+ });
249
+
250
+ // 1 RSDiscovery for Semantic Implementation
251
+ await seedNode(tmp.roomDir, 'rsd-si-001', 'RSDiscovery', {
252
+ classification: 'semantic_implementation', lsa: 0.20, bert: 0.55, thesis: 'Semantic thesis.',
253
+ });
254
+
255
+ // 1 hybrid (counts in metadata.total_nodes but does not match branches 2-3)
256
+ await seedNode(tmp.roomDir, 'rsd-hy-001', 'RSDiscovery', {
257
+ classification: 'hybrid', lsa: 0.5, bert: 0.5,
258
+ });
259
+
260
+ // 2 ReverseSalient nodes
261
+ await seedNode(tmp.roomDir, 'rs-001', 'ReverseSalient', { query_concept: 'qc1', doc_concept: 'dc1' });
262
+ await seedNode(tmp.roomDir, 'rs-002', 'ReverseSalient', { query_concept: 'qc2', doc_concept: 'dc2' });
263
+
264
+ // 1 Innovation + 1 Paper + 1 Author + 1 Institution + 3 edges
265
+ await seedNode(tmp.roomDir, 'inn-001', 'Innovation', { thesis: 'Innovation thesis.', breakthrough_score: 7.5 });
266
+ await seedNode(tmp.roomDir, 'paper-001', 'Paper', { title: 'A paper title', source: 'openalex' });
267
+ await seedNode(tmp.roomDir, 'auth-001', 'Author', { name: 'Smith, Jane', orcid: '0000-0001-2345-6789' });
268
+ await seedNode(tmp.roomDir, 'inst-001', 'Institution', { name: 'Stanford' });
269
+ await seedEdge(tmp.roomDir, 'paper-001', 'auth-001', 'AUTHORED_BY', {});
270
+ await seedEdge(tmp.roomDir, 'auth-001', 'inst-001', 'AFFILIATED_WITH', {});
271
+ await seedEdge(tmp.roomDir, 'rsd-di-001', 'paper-001', 'DERIVED_FROM', {});
272
+
273
+ const result = await m.renderMindMap({}, { tier: 'sqlite', roomDir: tmp.roomDir });
274
+ capturedHtmlWrappers.push({ scenario: '1-happy-path-tier0', html: result.html_wrapper });
275
+
276
+ // Branch shape assertions.
277
+ assert.ok(result.branches, 'result.branches must be present');
278
+ assert.equal(Object.keys(result.branches).length, 5, 'must have exactly 5 branches');
279
+ assert.equal(result.branches['Direct Intersections'].nodes.length, 2,
280
+ 'Direct Intersections must have 2 nodes (lsa>0.6 AND bert>0.6); got ' +
281
+ result.branches['Direct Intersections'].nodes.length);
282
+ assert.equal(result.branches['Structural Transfer'].nodes.length, 1,
283
+ 'Structural Transfer must have 1 node');
284
+ assert.equal(result.branches['Semantic Implementation'].nodes.length, 1,
285
+ 'Semantic Implementation must have 1 node');
286
+ assert.equal(result.branches['Discovered RS'].nodes.length, 2,
287
+ 'Discovered RS must have 2 ReverseSalient nodes');
288
+ assert.equal(result.branches['Innovation Ecosystem'].nodes.length, 4,
289
+ 'Innovation Ecosystem must have 4 nodes (Innovation + Paper + Author + Institution); got ' +
290
+ result.branches['Innovation Ecosystem'].nodes.length);
291
+
292
+ // Metadata.
293
+ assert.equal(result.metadata.tier, 'sqlite', 'metadata.tier must be sqlite');
294
+ assert.ok(result.metadata.total_nodes >= 9,
295
+ 'total_nodes must be >= 9 (5 RSDiscovery + 2 RS + 4 ecosystem); got ' + result.metadata.total_nodes);
296
+ assert.equal(result.metadata.schema_version, '1.0', 'schema_version must be 1.0');
297
+ assert.ok(typeof result.metadata.branch_counts === 'object', 'branch_counts must be object');
298
+
299
+ // HTML wrapper.
300
+ assert.ok(typeof result.html_wrapper === 'string', 'html_wrapper must be string');
301
+ assert.ok(result.html_wrapper.length > 0, 'html_wrapper must be non-empty');
302
+ assert.ok(result.html_wrapper.startsWith('<!DOCTYPE html>'),
303
+ 'html_wrapper must start with <!DOCTYPE html>');
304
+ assert.ok(result.html_wrapper.indexOf('cytoscape@3.33.1') !== -1,
305
+ 'html_wrapper must reference cytoscape@3.33.1 CDN');
306
+ } finally {
307
+ tmp.cleanup();
308
+ }
309
+ }
310
+
311
+ async function scenario2Tier0EmptyGraceful() {
312
+ // Empty room.db (initSchema runs but no data); renderMindMap must
313
+ // return all 5 branches with empty arrays and a non-empty HTML wrapper.
314
+ const m = require('../core/rs-mind-map.cjs');
315
+ const tmp = makeTmpRoom();
316
+ try {
317
+ // Open + close once just to ensure the schema initializes (mimics a
318
+ // fresh room).
319
+ const handle = await lazygraph.openGraph(tmp.roomDir);
320
+ await lazygraph.closeGraph(handle.db);
321
+
322
+ const result = await m.renderMindMap({}, { tier: 'sqlite', roomDir: tmp.roomDir });
323
+ capturedHtmlWrappers.push({ scenario: '2-tier0-empty', html: result.html_wrapper });
324
+
325
+ assert.equal(Object.keys(result.branches).length, 5, 'must always have 5 branches');
326
+ for (const branch of Object.keys(result.branches)) {
327
+ assert.deepEqual(result.branches[branch].nodes, [],
328
+ 'branch ' + branch + ' must have empty nodes on empty room');
329
+ assert.deepEqual(result.branches[branch].edges, [],
330
+ 'branch ' + branch + ' must have empty edges on empty room');
331
+ }
332
+ assert.equal(result.metadata.total_nodes, 0, 'total_nodes must be 0');
333
+ assert.equal(result.metadata.total_edges, 0, 'total_edges must be 0');
334
+ assert.ok(result.html_wrapper.length > 0,
335
+ 'html_wrapper must still render on empty room (legend + empty cytoscape)');
336
+ } finally {
337
+ tmp.cleanup();
338
+ }
339
+ }
340
+
341
+ async function scenario3Tier1MockedDriver() {
342
+ // Construct a mock driver that returns matching records for the 5
343
+ // branch Cypher queries. Verify driver dispatched + branches populated.
344
+ const m = require('../core/rs-mind-map.cjs');
345
+ const mock = makeAuraMock({
346
+ 'Direct Intersections': [
347
+ { id: 'rsd-di-1', type: 'RSDiscovery', properties: { classification: 'hybrid', lsa: 0.9, bert: 0.85, thesis: 'Safe one.' } },
348
+ ],
349
+ 'Structural Transfer': [
350
+ { id: 'rsd-st-1', type: 'RSDiscovery', properties: { classification: 'structural_transfer', thesis: 'Safe two.' } },
351
+ ],
352
+ 'Semantic Implementation': [
353
+ { id: 'rsd-si-1', type: 'RSDiscovery', properties: { classification: 'semantic_implementation', thesis: 'Safe three.' } },
354
+ ],
355
+ 'Discovered RS': [
356
+ { id: 'rs-1', type: 'ReverseSalient', properties: { query_concept: 'safe-query', doc_concept: 'safe-doc' } },
357
+ ],
358
+ 'Innovation Ecosystem': [
359
+ { id: 'inn-1', type: 'Innovation', properties: { thesis: 'Safe innovation.', breakthrough_score: 5.5 } },
360
+ { id: 'paper-1', type: 'Paper', properties: { title: 'A safe paper title.' } },
361
+ ],
362
+ });
363
+
364
+ const result = await m.renderMindMap({}, { tier: 'aura', driver: mock });
365
+ capturedHtmlWrappers.push({ scenario: '3-tier1-mocked', html: result.html_wrapper });
366
+
367
+ assert.equal(result.metadata.tier, 'aura', 'metadata.tier must be aura');
368
+ assert.ok(mock._calls.length >= 5,
369
+ 'driver session.run must be called >= 5 times (one per branch); got ' + mock._calls.length);
370
+ assert.equal(result.branches['Direct Intersections'].nodes.length, 1,
371
+ 'Direct Intersections must have 1 node');
372
+ assert.equal(result.branches['Discovered RS'].nodes.length, 1,
373
+ 'Discovered RS must have 1 node');
374
+ assert.equal(result.branches['Innovation Ecosystem'].nodes.length, 2,
375
+ 'Innovation Ecosystem must have 2 nodes; got ' + result.branches['Innovation Ecosystem'].nodes.length);
376
+ }
377
+
378
+ async function scenario4SingleNodeEdgeCase() {
379
+ // Pre-seed a single hybrid RSDiscovery with lsa=0.5, bert=0.5 (below
380
+ // both thresholds AND classification not structural/semantic). It
381
+ // should NOT appear in branches 1-3 but counts in metadata.total_nodes.
382
+ const m = require('../core/rs-mind-map.cjs');
383
+ const tmp = makeTmpRoom();
384
+ try {
385
+ await seedNode(tmp.roomDir, 'rsd-hyb-001', 'RSDiscovery', {
386
+ classification: 'hybrid', lsa: 0.5, bert: 0.5, thesis: 'Below thresholds.',
387
+ });
388
+
389
+ const result = await m.renderMindMap({}, { tier: 'sqlite', roomDir: tmp.roomDir });
390
+ capturedHtmlWrappers.push({ scenario: '4-single-node', html: result.html_wrapper });
391
+
392
+ assert.equal(result.branches['Direct Intersections'].nodes.length, 0,
393
+ 'Direct Intersections must be empty (lsa/bert both 0.5)');
394
+ assert.equal(result.branches['Structural Transfer'].nodes.length, 0,
395
+ 'Structural Transfer must be empty (no matching classification)');
396
+ assert.equal(result.branches['Semantic Implementation'].nodes.length, 0,
397
+ 'Semantic Implementation must be empty (no matching classification)');
398
+ assert.equal(result.metadata.total_nodes, 1, 'total_nodes must be 1');
399
+ // HTML still renders without JS error in the embedded JSON.
400
+ assert.ok(result.html_wrapper.indexOf('elements') !== -1,
401
+ 'html_wrapper must contain the elements JSON marker');
402
+ } finally {
403
+ tmp.cleanup();
404
+ }
405
+ }
406
+
407
+ async function scenario5AllFiveBranchesPresent() {
408
+ // Empty room; assert exactly 5 branch keys with the expected names.
409
+ const m = require('../core/rs-mind-map.cjs');
410
+ const tmp = makeTmpRoom();
411
+ try {
412
+ const result = await m.renderMindMap({}, { tier: 'sqlite', roomDir: tmp.roomDir });
413
+ capturedHtmlWrappers.push({ scenario: '5-five-branches', html: result.html_wrapper });
414
+
415
+ const expected = ['Direct Intersections', 'Structural Transfer',
416
+ 'Semantic Implementation', 'Discovered RS', 'Innovation Ecosystem'];
417
+ assert.equal(Object.keys(result.branches).length, 5, 'must have exactly 5 branches');
418
+ for (const name of expected) {
419
+ assert.ok(name in result.branches,
420
+ 'branch ' + name + ' must be present in result.branches keys');
421
+ }
422
+ } finally {
423
+ tmp.cleanup();
424
+ }
425
+ }
426
+
427
+ async function scenario6HtmlHasCytoscapeCdn() {
428
+ // result.html_wrapper.includes('https://unpkg.com/cytoscape@3.33.1...').
429
+ // Same CDN URL as dashboard/index.html line 22 (Canon Part 7 reuse).
430
+ const m = require('../core/rs-mind-map.cjs');
431
+ const tmp = makeTmpRoom();
432
+ try {
433
+ const result = await m.renderMindMap({}, { tier: 'sqlite', roomDir: tmp.roomDir });
434
+ capturedHtmlWrappers.push({ scenario: '6-html-cdn', html: result.html_wrapper });
435
+
436
+ assert.ok(result.html_wrapper.indexOf('https://unpkg.com/cytoscape@3.33.1/dist/cytoscape.min.js') !== -1,
437
+ 'html_wrapper must include the exact cytoscape@3.33.1 CDN URL (Canon Part 7 reuse of dashboard pattern)');
438
+ } finally {
439
+ tmp.cleanup();
440
+ }
441
+ }
442
+
443
+ async function scenario7AuditOnRenderedHtmlClean() {
444
+ // Run the happy-path fixture (Test 1 style); assert result.html_wrapper
445
+ // does NOT contain any FORBIDDEN_PATTERNS substrings (the function ran
446
+ // auditQueryObject internally and returned successfully).
447
+ const m = require('../core/rs-mind-map.cjs');
448
+ const tmp = makeTmpRoom();
449
+ try {
450
+ await seedNode(tmp.roomDir, 'rsd-clean-001', 'RSDiscovery', {
451
+ classification: 'hybrid', lsa: 0.9, bert: 0.85, thesis: 'A clean thesis with no PII.',
452
+ });
453
+ const result = await m.renderMindMap({}, { tier: 'sqlite', roomDir: tmp.roomDir });
454
+ capturedHtmlWrappers.push({ scenario: '7-audit-clean', html: result.html_wrapper });
455
+
456
+ for (const re of FORBIDDEN_PATTERNS) {
457
+ assert.ok(!re.test(result.html_wrapper),
458
+ 'html_wrapper must not match FORBIDDEN_PATTERNS regex ' + re.source);
459
+ }
460
+ } finally {
461
+ tmp.cleanup();
462
+ }
463
+ }
464
+
465
+ async function scenario8QueryFilterApplied() {
466
+ // 4 RSDiscovery rows (2 structural + 2 semantic). renderMindMap
467
+ // ({branch: 'Structural Transfer'}, ...) must populate ONLY the
468
+ // requested branch.
469
+ const m = require('../core/rs-mind-map.cjs');
470
+ const tmp = makeTmpRoom();
471
+ try {
472
+ await seedNode(tmp.roomDir, 'rsd-st-001', 'RSDiscovery', {
473
+ classification: 'structural_transfer', lsa: 0.5, bert: 0.2, thesis: 'Safe one.',
474
+ });
475
+ await seedNode(tmp.roomDir, 'rsd-st-002', 'RSDiscovery', {
476
+ classification: 'structural_transfer', lsa: 0.6, bert: 0.1, thesis: 'Safe two.',
477
+ });
478
+ await seedNode(tmp.roomDir, 'rsd-si-001', 'RSDiscovery', {
479
+ classification: 'semantic_implementation', lsa: 0.1, bert: 0.5, thesis: 'Safe three.',
480
+ });
481
+ await seedNode(tmp.roomDir, 'rsd-si-002', 'RSDiscovery', {
482
+ classification: 'semantic_implementation', lsa: 0.2, bert: 0.6, thesis: 'Safe four.',
483
+ });
484
+
485
+ const result = await m.renderMindMap({ branch: 'Structural Transfer' },
486
+ { tier: 'sqlite', roomDir: tmp.roomDir });
487
+ capturedHtmlWrappers.push({ scenario: '8-query-filter', html: result.html_wrapper });
488
+
489
+ assert.equal(result.branches['Structural Transfer'].nodes.length, 2,
490
+ 'Structural Transfer must have 2 nodes after filter');
491
+ assert.equal(result.branches['Semantic Implementation'].nodes.length, 0,
492
+ 'Semantic Implementation must be empty when filter selects Structural Transfer');
493
+ assert.equal(result.branches['Direct Intersections'].nodes.length, 0,
494
+ 'Direct Intersections must be empty under filter');
495
+ assert.equal(result.branches['Discovered RS'].nodes.length, 0,
496
+ 'Discovered RS must be empty under filter');
497
+ assert.equal(result.branches['Innovation Ecosystem'].nodes.length, 0,
498
+ 'Innovation Ecosystem must be empty under filter');
499
+
500
+ assert.equal(result.metadata.branch_counts['Structural Transfer'], 2,
501
+ 'branch_counts.Structural Transfer must be 2');
502
+ assert.equal(result.metadata.branch_counts['Semantic Implementation'], 0,
503
+ 'branch_counts.Semantic Implementation must be 0');
504
+ } finally {
505
+ tmp.cleanup();
506
+ }
507
+ }
508
+
509
+ async function scenario9AdvForbiddenInSqliteProperties() {
510
+ // CANON PART 8 adversarial #1: forbidden bytes in node.properties read
511
+ // from sqlite. The audit on the rendered HTML must catch the leak and
512
+ // throw ExternalEgressViolation.
513
+ const m = require('../core/rs-mind-map.cjs');
514
+ const tmp = makeTmpRoom();
515
+ try {
516
+ // FORBIDDEN_PATTERNS[3] matches /\bmeeting with\b/i.
517
+ await seedNode(tmp.roomDir, 'rsd-leak-001', 'RSDiscovery', {
518
+ classification: 'structural_transfer',
519
+ lsa: 0.5,
520
+ bert: 0.2,
521
+ thesis: 'A thesis that leaks via meeting with the team.',
522
+ });
523
+
524
+ let threw = null;
525
+ let result = undefined;
526
+ try {
527
+ result = await m.renderMindMap({}, { tier: 'sqlite', roomDir: tmp.roomDir });
528
+ } catch (err) {
529
+ threw = err;
530
+ }
531
+
532
+ assert.ok(threw, 'must throw on forbidden in sqlite properties');
533
+ assert.equal(threw.name, 'ExternalEgressViolation',
534
+ 'must throw ExternalEgressViolation, got ' + (threw && threw.name));
535
+ assert.equal(threw.meta.surface, 'rs-mind-map-html',
536
+ 'meta.surface must be rs-mind-map-html, got ' + (threw && threw.meta && threw.meta.surface));
537
+ assert.ok(threw.meta.matched_pattern, 'meta.matched_pattern must be present');
538
+ assert.equal(result, undefined, 'result must NOT be returned on audit fail');
539
+ } finally {
540
+ tmp.cleanup();
541
+ }
542
+ }
543
+
544
+ async function scenario10AdvForbiddenInAuraClassification() {
545
+ // CANON PART 8 adversarial #2: forbidden bytes in classification field
546
+ // returned by aura mock. The audit on the rendered HTML must catch the
547
+ // leak and throw ExternalEgressViolation.
548
+ const m = require('../core/rs-mind-map.cjs');
549
+ // FORBIDDEN_PATTERNS[2] matches /\b(Lawrence|Jonathan|...)\s+(said|...)\b/i.
550
+ const mock = makeAuraMock({
551
+ 'Direct Intersections': [],
552
+ 'Structural Transfer': [
553
+ { id: 'rsd-leak-001', type: 'RSDiscovery', properties: { classification: 'structural_transfer', thesis: 'Lawrence said this is the answer.' } },
554
+ ],
555
+ 'Semantic Implementation': [],
556
+ 'Discovered RS': [],
557
+ 'Innovation Ecosystem': [],
558
+ });
559
+
560
+ let threw = null;
561
+ let result = undefined;
562
+ try {
563
+ result = await m.renderMindMap({}, { tier: 'aura', driver: mock });
564
+ } catch (err) {
565
+ threw = err;
566
+ }
567
+
568
+ assert.ok(threw, 'must throw on forbidden in aura classification');
569
+ assert.equal(threw.name, 'ExternalEgressViolation',
570
+ 'must throw ExternalEgressViolation, got ' + (threw && threw.name));
571
+ assert.equal(threw.meta.surface, 'rs-mind-map-html',
572
+ 'meta.surface must be rs-mind-map-html');
573
+ assert.ok(threw.meta.matched_pattern, 'meta.matched_pattern must be present');
574
+ assert.equal(result, undefined, 'result must NOT be returned on audit fail');
575
+ }
576
+
577
+ // ---------- A1 end-of-suite sweep ----------
578
+
579
+ function a1Sweep() {
580
+ let hits = 0;
581
+ for (const rec of capturedHtmlWrappers) {
582
+ if (typeof rec.html !== 'string') continue;
583
+ for (const re of FORBIDDEN_PATTERNS) {
584
+ if (re.test(rec.html)) {
585
+ hits += 1;
586
+ process.stderr.write(
587
+ ' A1 HIT scenario=' + rec.scenario +
588
+ ' pattern=' + re.source + '\n'
589
+ );
590
+ }
591
+ }
592
+ }
593
+ return hits;
594
+ }
595
+
596
+ // ---------- Main ----------
597
+
598
+ (async function main() {
599
+ process.stdout.write('=== 89.3-03 rs-mind-map suite (REPO_ROOT=' +
600
+ REPO_ROOT + ') ===\n');
601
+
602
+ await runScenario('1-happy-path-tier0', scenario1HappyPathTier0);
603
+ await runScenario('2-tier0-empty-graceful', scenario2Tier0EmptyGraceful);
604
+ await runScenario('3-tier1-mocked-driver', scenario3Tier1MockedDriver);
605
+ await runScenario('4-single-node-edge-case', scenario4SingleNodeEdgeCase);
606
+ await runScenario('5-all-five-branches-present', scenario5AllFiveBranchesPresent);
607
+ await runScenario('6-html-cytoscape-cdn', scenario6HtmlHasCytoscapeCdn);
608
+ await runScenario('7-audit-rendered-html-clean', scenario7AuditOnRenderedHtmlClean);
609
+ await runScenario('8-query-filter-applied', scenario8QueryFilterApplied);
610
+ await runScenario('9-adv-CANON-PART-8-sqlite-properties', scenario9AdvForbiddenInSqliteProperties);
611
+ await runScenario('10-adv-CANON-PART-8-aura-classification', scenario10AdvForbiddenInAuraClassification);
612
+
613
+ const sweepHits = a1Sweep();
614
+ if (sweepHits > 0) {
615
+ failed += 1;
616
+ failures.push({
617
+ name: 'A1-sweep',
618
+ err: new Error('A1 sweep found ' + sweepHits + ' forbidden-pattern hits'),
619
+ });
620
+ process.stderr.write(' FAIL A1-sweep (' + sweepHits + ' hits)\n');
621
+ } else {
622
+ process.stdout.write(' ok A1-sweep (zero forbidden-pattern hits across captured html_wrappers)\n');
623
+ }
624
+
625
+ // Cleanup any tmp rooms that survived.
626
+ for (const dir of tmpRooms) {
627
+ try { fs.rmSync(dir, { recursive: true, force: true }); } catch (_e) { /* best effort */ }
628
+ }
629
+
630
+ if (failed > 0) {
631
+ process.stdout.write('=== 89.3-03 rs-mind-map suite: ' +
632
+ passed + '/10 passed' +
633
+ ' (' + failed + ' failed) ===\n');
634
+ for (const f of failures) {
635
+ process.stderr.write(' FAILURE: ' + f.name + ': ' +
636
+ (f.err && f.err.message ? f.err.message : String(f.err)) + '\n');
637
+ }
638
+ process.exit(1);
639
+ }
640
+
641
+ process.stdout.write('=== 89.3-03 rs-mind-map suite: 10/10 passed ===\n');
642
+ process.exit(0);
643
+ })().catch(function (err) {
644
+ process.stderr.write('FATAL: ' + (err && err.stack ? err.stack : err) + '\n');
645
+ process.exit(2);
646
+ });