@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,229 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Phase 80 Stage 02 -- Person Detector (pure function).
5
+ *
6
+ * detectPeople(fileEntries, opts) runs a 5-tier detection ladder against
7
+ * vault-scanner file entries and returns a deduplicated array of detected
8
+ * people matching the MANIFEST.json people[] schema subset.
9
+ *
10
+ * Detection tiers (highest to lowest confidence):
11
+ * 1. frontmatter -- attendees/author/team/contributors YAML
12
+ * 2. attendees_header -- "## Attendees" or "## Participants" list
13
+ * 3. mentions -- "@Name" style mentions
14
+ * 4. first_last_repeated -- First Last capitalized pair >= 3 distinct files
15
+ * 5. ner -- LLM NER sweep (STUB, returns nothing)
16
+ *
17
+ * Role detection is keyword-based against a sliding window around each name
18
+ * occurrence. See references/import-config.md for the role bucket keywords.
19
+ *
20
+ * Pure: no fs writes, no child_process, no AI calls. Body access goes
21
+ * through opts.bodyLoader (default is fs.readFileSync(source_abs_path)) so
22
+ * tests can pass synthetic content.
23
+ */
24
+
25
+ const fs = require('node:fs');
26
+
27
+ // Keyword order matters: longer/more-specific keywords MUST come before their
28
+ // substrings so "co-founder" beats "founder", "board member" beats "board".
29
+ const ROLE_BUCKETS = {
30
+ 'core-team': ['co-founder', 'cofounder', 'founder', 'ceo', 'cto', 'coo', 'cfo', 'head of', 'vp', 'our team', 'we built', 'team lead'],
31
+ 'consultants': ['consultant', 'contractor', 'freelance', 'hired', 'retained', 'engaged'],
32
+ 'advisors': ['advisor', 'mentor', 'guidance', 'advised us', 'coach'],
33
+ 'investors': ['investor', 'vc', 'fund', 'angel', 'seed round', 'series a', 'series b', 'series c', 'cap table', 'term sheet'],
34
+ 'board': ['board member', 'chairman', 'director', 'sits on the board', 'board seat']
35
+ };
36
+
37
+ const STOPWORDS_2WORD = new Set([
38
+ 'new york', 'los angeles', 'san francisco', 'project plan', 'action items',
39
+ 'next steps', 'key insights', 'data room', 'team sync', 'team meeting',
40
+ 'problem definition', 'solution design', 'business model'
41
+ ]);
42
+
43
+ const TIER_RANK = {
44
+ frontmatter: 5,
45
+ attendees_header: 4,
46
+ mentions: 3,
47
+ first_last_repeated: 2,
48
+ ner: 1
49
+ };
50
+
51
+ const TIER_CONFIDENCE = {
52
+ frontmatter: 0.97,
53
+ attendees_header: 0.88,
54
+ mentions: 0.75,
55
+ first_last_repeated: 0.60,
56
+ ner: 0.45
57
+ };
58
+
59
+ const ATTENDEES_HEADER_RE = /##\s*(?:Attendees|Participants)\s*\n((?:\s*[-*]\s*.+\n?)+)/i;
60
+ const MENTION_RE = /(?:^|\s)@([A-Z][a-z]+(?:\s+[A-Z][a-z]+)?)/g;
61
+ // Use lookahead so overlapping pairs like "Today Eli Zarchin" yield both
62
+ // "Today Eli" AND "Eli Zarchin" -- the stopword filter discards common
63
+ // false-positives like "Today Morning".
64
+ const FIRST_LAST_RE = /\b([A-Z][a-z]+)(?=\s+([A-Z][a-z]+)\b)/g;
65
+
66
+ function slugify(name) {
67
+ return String(name || '')
68
+ .toLowerCase()
69
+ .normalize('NFD')
70
+ .replace(/[\u0300-\u036f]/g, '')
71
+ .replace(/[^a-z0-9\s-]/g, '')
72
+ .trim()
73
+ .replace(/\s+/g, '-');
74
+ }
75
+
76
+ function inferRole(name, content) {
77
+ const haystack = String(content || '').toLowerCase();
78
+ const needle = name.toLowerCase();
79
+ const idx = haystack.indexOf(needle);
80
+ if (idx === -1) return { bucket: 'unassigned', evidence: 'no match' };
81
+ const window = haystack.slice(Math.max(0, idx - 80), idx + needle.length + 80);
82
+ for (const bucket of Object.keys(ROLE_BUCKETS)) {
83
+ for (const kw of ROLE_BUCKETS[bucket]) {
84
+ if (window.indexOf(kw) !== -1) {
85
+ return { bucket: bucket, evidence: kw };
86
+ }
87
+ }
88
+ }
89
+ return { bucket: 'unassigned', evidence: 'no match' };
90
+ }
91
+
92
+ function detectPeople(fileEntries, opts) {
93
+ opts = opts || {};
94
+ const loader = opts.bodyLoader || function (f) {
95
+ try { return fs.readFileSync(f.source_abs_path, 'utf8'); } catch (e) { return ''; }
96
+ };
97
+ const exclude = new Set((opts.excludeNames || []).map(slugify));
98
+ const registry = new Map();
99
+
100
+ function record(name, fileId, tier, content) {
101
+ if (!name || typeof name !== 'string') return;
102
+ const trimmed = name.trim();
103
+ if (!trimmed) return;
104
+ if (STOPWORDS_2WORD.has(trimmed.toLowerCase())) return;
105
+ const slug = slugify(trimmed);
106
+ if (!slug || exclude.has(slug)) return;
107
+
108
+ const existing = registry.get(slug);
109
+ const role = inferRole(trimmed, content);
110
+
111
+ if (!existing) {
112
+ registry.set(slug, {
113
+ name: trimmed,
114
+ slug: slug,
115
+ detection_tier: tier,
116
+ detection_confidence: TIER_CONFIDENCE[tier],
117
+ role_guess: role.bucket,
118
+ role_evidence: role.evidence,
119
+ mention_files: [fileId]
120
+ });
121
+ return;
122
+ }
123
+
124
+ // merge mention_files
125
+ if (existing.mention_files.indexOf(fileId) === -1) {
126
+ existing.mention_files.push(fileId);
127
+ }
128
+ // upgrade to higher tier if applicable
129
+ if (TIER_RANK[tier] > TIER_RANK[existing.detection_tier]) {
130
+ existing.detection_tier = tier;
131
+ existing.detection_confidence = TIER_CONFIDENCE[tier];
132
+ }
133
+ // upgrade role if existing was unassigned and new finding has real role
134
+ if (existing.role_guess === 'unassigned' && role.bucket !== 'unassigned') {
135
+ existing.role_guess = role.bucket;
136
+ existing.role_evidence = role.evidence;
137
+ }
138
+ }
139
+
140
+ // First pass: gather bodies + run tiers 1, 2, 3 per file
141
+ const bodies = new Map(); // fileId -> body string
142
+ for (const f of fileEntries) {
143
+ let body = '';
144
+ try { body = loader(f) || ''; } catch (e) { body = ''; }
145
+ bodies.set(f.id, body);
146
+
147
+ // Tier 1: frontmatter
148
+ const fm = f.source_frontmatter || {};
149
+ const fmKeys = ['attendees', 'author', 'team', 'contributors'];
150
+ for (const key of fmKeys) {
151
+ const v = fm[key];
152
+ if (!v) continue;
153
+ if (Array.isArray(v)) {
154
+ for (const n of v) record(String(n), f.id, 'frontmatter', body);
155
+ } else if (typeof v === 'string') {
156
+ record(v, f.id, 'frontmatter', body);
157
+ }
158
+ }
159
+
160
+ // Tier 2: ## Attendees / ## Participants header
161
+ const am = body.match(ATTENDEES_HEADER_RE);
162
+ if (am) {
163
+ const lines = am[1].split('\n');
164
+ for (const line of lines) {
165
+ const m = line.match(/^\s*[-*]\s*(.+?)\s*$/);
166
+ if (m && m[1]) record(m[1], f.id, 'attendees_header', body);
167
+ }
168
+ }
169
+
170
+ // Tier 3: @mentions
171
+ MENTION_RE.lastIndex = 0;
172
+ let mm;
173
+ while ((mm = MENTION_RE.exec(body)) !== null) {
174
+ record(mm[1], f.id, 'mentions', body);
175
+ }
176
+ }
177
+
178
+ // Tier 4: first_last_repeated -- capitalized pair across >= 3 distinct files
179
+ const candidateFiles = new Map(); // "First Last" -> Set(fileId)
180
+ for (const f of fileEntries) {
181
+ const body = bodies.get(f.id) || '';
182
+ FIRST_LAST_RE.lastIndex = 0;
183
+ const seenInFile = new Set();
184
+ let m;
185
+ while ((m = FIRST_LAST_RE.exec(body)) !== null) {
186
+ const full = m[1] + ' ' + m[2];
187
+ // advance at least one char to avoid infinite loop on zero-width match
188
+ if (FIRST_LAST_RE.lastIndex === m.index) FIRST_LAST_RE.lastIndex += 1;
189
+ if (STOPWORDS_2WORD.has(full.toLowerCase())) continue;
190
+ if (seenInFile.has(full)) continue;
191
+ seenInFile.add(full);
192
+ if (!candidateFiles.has(full)) candidateFiles.set(full, new Set());
193
+ candidateFiles.get(full).add(f.id);
194
+ }
195
+ }
196
+ for (const entry of candidateFiles.entries()) {
197
+ const full = entry[0];
198
+ const fileSet = entry[1];
199
+ if (fileSet.size < 3) continue;
200
+ const slug = slugify(full);
201
+ // If already in registry via a higher tier, just merge mention_files
202
+ if (registry.has(slug)) {
203
+ const existing = registry.get(slug);
204
+ for (const fid of fileSet) {
205
+ if (existing.mention_files.indexOf(fid) === -1) existing.mention_files.push(fid);
206
+ }
207
+ continue;
208
+ }
209
+ // Record once per file so mention_files captures all
210
+ for (const fid of fileSet) {
211
+ const body = bodies.get(fid) || '';
212
+ record(full, fid, 'first_last_repeated', body);
213
+ }
214
+ }
215
+
216
+ // Tier 5: NER stub -- intentionally empty. Deferred to a future LLM pass.
217
+
218
+ return Array.from(registry.values());
219
+ }
220
+
221
+ module.exports = {
222
+ detectPeople: detectPeople,
223
+ slugify: slugify,
224
+ inferRole: inferRole,
225
+ ROLE_BUCKETS: ROLE_BUCKETS,
226
+ STOPWORDS_2WORD: STOPWORDS_2WORD,
227
+ TIER_RANK: TIER_RANK,
228
+ TIER_CONFIDENCE: TIER_CONFIDENCE
229
+ };
@@ -0,0 +1,149 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * Unit tests for lib/import/person-detector.cjs
6
+ * Run: node lib/import/person-detector.test.cjs
7
+ */
8
+
9
+ const assert = require('node:assert/strict');
10
+ const { detectPeople, slugify } = require('./person-detector.cjs');
11
+
12
+ let passed = 0;
13
+ let failed = 0;
14
+ function test(name, fn) {
15
+ try {
16
+ fn();
17
+ passed += 1;
18
+ process.stdout.write(' ok ' + name + '\n');
19
+ } catch (err) {
20
+ failed += 1;
21
+ process.stdout.write(' FAIL ' + name + '\n ' + err.message + '\n');
22
+ }
23
+ }
24
+
25
+ function fakeFile(id, frontmatter, body) {
26
+ return {
27
+ id: id,
28
+ source_path: 'notes/' + id + '.md',
29
+ source_abs_path: '/tmp/fake/' + id + '.md',
30
+ source_frontmatter: frontmatter || {},
31
+ source_wikilinks: [],
32
+ parent_folder: 'notes',
33
+ __body: body || ''
34
+ };
35
+ }
36
+
37
+ function makeLoader() {
38
+ return function (f) { return f.__body || ''; };
39
+ }
40
+
41
+ test('Test 1: frontmatter tier detects attendees with confidence >= 0.95', function () {
42
+ const files = [fakeFile('f_1', { attendees: ['Jane Doe', 'John Roe'] }, 'body text')];
43
+ const r = detectPeople(files, { bodyLoader: makeLoader() });
44
+ assert.equal(r.length, 2, 'expected 2 people');
45
+ const jane = r.find(function (p) { return p.slug === 'jane-doe'; });
46
+ assert.ok(jane, 'jane present');
47
+ assert.equal(jane.detection_tier, 'frontmatter');
48
+ assert.ok(jane.detection_confidence >= 0.95, 'confidence >= 0.95 got ' + jane.detection_confidence);
49
+ });
50
+
51
+ test('Test 2: attendees header tier confidence >= 0.85', function () {
52
+ const body = '## Attendees\n- Jane Doe\n- John Roe\n\nDiscussion...';
53
+ const files = [fakeFile('f_1', {}, body)];
54
+ const r = detectPeople(files, { bodyLoader: makeLoader() });
55
+ assert.equal(r.length, 2);
56
+ const jane = r.find(function (p) { return p.slug === 'jane-doe'; });
57
+ assert.ok(jane);
58
+ assert.equal(jane.detection_tier, 'attendees_header');
59
+ assert.ok(jane.detection_confidence >= 0.85, 'confidence >= 0.85');
60
+ });
61
+
62
+ test('Test 3: first_last_repeated tier across 3 files', function () {
63
+ const files = [
64
+ fakeFile('f_1', {}, 'Today Eli Zarchin spoke about plans.'),
65
+ fakeFile('f_2', {}, 'Eli Zarchin reviewed the deck.'),
66
+ fakeFile('f_3', {}, 'Note from Eli Zarchin on budget.')
67
+ ];
68
+ const r = detectPeople(files, { bodyLoader: makeLoader() });
69
+ const eli = r.find(function (p) { return p.slug === 'eli-zarchin'; });
70
+ assert.ok(eli, 'eli detected');
71
+ assert.equal(eli.detection_tier, 'first_last_repeated');
72
+ assert.equal(eli.mention_files.length, 3);
73
+ });
74
+
75
+ test('Test 4: slug normalization handles punctuation and unicode', function () {
76
+ assert.equal(slugify('Jane Doe'), 'jane-doe');
77
+ assert.equal(slugify("O'Brien"), 'obrien');
78
+ assert.equal(slugify('Zoë Müller'), 'zoe-muller');
79
+ assert.equal(slugify(' Alice Smith '), 'alice-smith');
80
+ });
81
+
82
+ test('Test 5: role bucket fires on co-founder keyword near name', function () {
83
+ const body = 'Team sync notes. Jane Doe, co-founder, opened the meeting.';
84
+ const files = [fakeFile('f_1', { attendees: ['Jane Doe'] }, body)];
85
+ const r = detectPeople(files, { bodyLoader: makeLoader() });
86
+ const jane = r.find(function (p) { return p.slug === 'jane-doe'; });
87
+ assert.ok(jane);
88
+ assert.equal(jane.role_guess, 'core-team');
89
+ assert.equal(jane.role_evidence, 'co-founder');
90
+ });
91
+
92
+ test('Test 6: role bucket fallthrough to unassigned', function () {
93
+ const files = [fakeFile('f_1', { attendees: ['Bob Random'] }, 'Bob Random joined.')];
94
+ const r = detectPeople(files, { bodyLoader: makeLoader() });
95
+ const bob = r.find(function (p) { return p.slug === 'bob-random'; });
96
+ assert.ok(bob);
97
+ assert.equal(bob.role_guess, 'unassigned');
98
+ assert.equal(bob.role_evidence, 'no match');
99
+ });
100
+
101
+ test('Test 7: dedup across tiers keeps highest tier and merges mention_files', function () {
102
+ const files = [
103
+ fakeFile('f_1', { attendees: ['Jane Doe'] }, 'Jane Doe frontmatter'),
104
+ fakeFile('f_2', {}, '## Attendees\n- Jane Doe\n'),
105
+ fakeFile('f_3', {}, 'Jane Doe appears here too.')
106
+ ];
107
+ const r = detectPeople(files, { bodyLoader: makeLoader() });
108
+ const janeEntries = r.filter(function (p) { return p.slug === 'jane-doe'; });
109
+ assert.equal(janeEntries.length, 1, 'one jane only');
110
+ assert.equal(janeEntries[0].detection_tier, 'frontmatter', 'highest tier kept');
111
+ assert.ok(janeEntries[0].mention_files.indexOf('f_1') !== -1);
112
+ assert.ok(janeEntries[0].mention_files.indexOf('f_2') !== -1);
113
+ });
114
+
115
+ test('Test 8: stopword filter blocks "New York" and "Project Plan"', function () {
116
+ const files = [
117
+ fakeFile('f_1', {}, 'New York New York New York'),
118
+ fakeFile('f_2', {}, 'New York update'),
119
+ fakeFile('f_3', {}, 'Project Plan Project Plan Project Plan'),
120
+ fakeFile('f_4', {}, 'Project Plan notes')
121
+ ];
122
+ const r = detectPeople(files, { bodyLoader: makeLoader() });
123
+ const ny = r.find(function (p) { return p.slug === 'new-york'; });
124
+ const pp = r.find(function (p) { return p.slug === 'project-plan'; });
125
+ assert.equal(ny, undefined, 'New York should not be a person');
126
+ assert.equal(pp, undefined, 'Project Plan should not be a person');
127
+ });
128
+
129
+ test('Test 9: excludeNames filters self-references', function () {
130
+ const files = [fakeFile('f_1', { attendees: ['Jonathan Sagir', 'Jane Doe'] }, 'body')];
131
+ const r = detectPeople(files, { bodyLoader: makeLoader(), excludeNames: ['Jonathan Sagir'] });
132
+ assert.equal(r.length, 1);
133
+ assert.equal(r[0].slug, 'jane-doe');
134
+ });
135
+
136
+ test('Test 10: purity -- no fs writes, result is array', function () {
137
+ const files = [fakeFile('f_1', { attendees: ['Jane Doe'] }, 'Jane Doe, co-founder.')];
138
+ const r = detectPeople(files, { bodyLoader: makeLoader() });
139
+ assert.ok(Array.isArray(r));
140
+ // shape matches manifest people[] subset
141
+ const p = r[0];
142
+ assert.ok('name' in p && 'slug' in p && 'detection_tier' in p);
143
+ assert.ok('detection_confidence' in p && 'role_guess' in p);
144
+ assert.ok('role_evidence' in p && Array.isArray(p.mention_files));
145
+ });
146
+
147
+ process.stdout.write('\n' + passed + ' passed, ' + failed + ' failed\n');
148
+ if (failed > 0) process.exit(1);
149
+ process.stdout.write('PASS\n');
@@ -0,0 +1,186 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Phase 80 Plan 80-05 -- IMPORT-REPORT.md renderer.
5
+ *
6
+ * Consumed by scripts/vault-import.cjs at the end of the 4-stage pipeline
7
+ * (and by the --undo branch to re-render with UNDONE: true). Shape verbatim
8
+ * from 80-CONTEXT.md gray area #10.
9
+ *
10
+ * Sections (in order): frontmatter, H1, Summary, Routing Table,
11
+ * People Detected, Meetings Detected, Warnings, /mos: Usability Check
12
+ * (placeholder populated by 80-06), Manifest Reference.
13
+ *
14
+ * Main-topic-slug extraction: top-2 destination sections by count. If a
15
+ * single section dominates (> 60%), use that section alone. --topic flag
16
+ * override is applied upstream in scripts/vault-import.cjs via pickMainTopic.
17
+ */
18
+
19
+ const { readManifest } = require('./manifest.cjs');
20
+
21
+ function slugifyTopic(s) {
22
+ return String(s || '').toLowerCase().replace(/[^a-z0-9-]+/g, '-').replace(/^-+|-+$/g, '');
23
+ }
24
+
25
+ function extractMainTopicSlug(manifest, override) {
26
+ if (override) return slugifyTopic(override);
27
+ const counts = new Map();
28
+ for (const f of manifest.files || []) {
29
+ const sec = f.classification && f.classification.section;
30
+ if (!sec) continue;
31
+ counts.set(sec, (counts.get(sec) || 0) + 1);
32
+ }
33
+ const sorted = Array.from(counts.entries()).sort(function (a, b) { return b[1] - a[1]; });
34
+ if (sorted.length === 0) return 'unclassified';
35
+ const total = sorted.reduce(function (s, e) { return s + e[1]; }, 0);
36
+ const top = sorted[0];
37
+ if (top[1] / total > 0.6) return slugifyTopic(top[0]);
38
+ if (sorted.length === 1) return slugifyTopic(top[0]);
39
+ return slugifyTopic(top[0]) + '-' + slugifyTopic(sorted[1][0]);
40
+ }
41
+
42
+ function countDecisions(files) {
43
+ let auto = 0, sugg = 0, inbox = 0;
44
+ for (const f of files || []) {
45
+ const d = f.classification && f.classification.decision;
46
+ if (d === 'AUTO') auto++;
47
+ else if (d === 'SUGGEST') sugg++;
48
+ else if (d === 'INBOX') inbox++;
49
+ }
50
+ return { auto: auto, sugg: sugg, inbox: inbox };
51
+ }
52
+
53
+ function escapeCell(s) {
54
+ return String(s == null ? '' : s).replace(/\|/g, '\\|').replace(/\r?\n/g, ' ');
55
+ }
56
+
57
+ function generateImportReport(manifest, opts) {
58
+ opts = opts || {};
59
+ const date = (manifest.import_id || '').slice(0, 10);
60
+ const counts = countDecisions(manifest.files || []);
61
+ const mainTopic = manifest.main_topic || extractMainTopicSlug(manifest, opts.topic);
62
+ const isUndone = !!(manifest.undo && manifest.undo.is_undone);
63
+
64
+ const lines = [];
65
+ lines.push('---');
66
+ if (isUndone) lines.push('UNDONE: true');
67
+ lines.push('date: ' + date);
68
+ lines.push('main_topic: ' + mainTopic);
69
+ lines.push('source_vault: ' + (manifest.source_vault || ''));
70
+ lines.push('total_files: ' + (manifest.files || []).length);
71
+ lines.push('status: ' + (manifest.status || 'in_progress'));
72
+ lines.push('import_id: ' + (manifest.import_id || ''));
73
+ lines.push('---');
74
+ lines.push('');
75
+
76
+ const titleTopic = mainTopic.replace(/-/g, ' ').replace(/\b\w/g, function (c) { return c.toUpperCase(); });
77
+ lines.push('# Import Report -- ' + date + ' ' + titleTopic);
78
+ lines.push('');
79
+
80
+ // Summary
81
+ lines.push('## Summary');
82
+ lines.push('- ' + (manifest.files || []).length + ' files ingested');
83
+ lines.push('- ' + counts.auto + ' auto-routed (confidence >= 0.75)');
84
+ lines.push('- ' + counts.sugg + ' in inbox/suggested (0.45 - 0.74)');
85
+ lines.push('- ' + counts.inbox + ' in inbox/unclassified (< 0.45)');
86
+ lines.push('- ' + (manifest.people || []).length + ' people detected');
87
+ lines.push('- ' + (manifest.meetings || []).length + ' meetings detected');
88
+ if (isUndone) {
89
+ lines.push('');
90
+ lines.push('> This import has been UNDONE. Files were moved to `imports/' + (manifest.import_id || '') + '/undone/`. ROOM.md and MINTO.md scaffolds scoped to this import were removed. The source vault was never touched.');
91
+ }
92
+ lines.push('');
93
+
94
+ // Routing Table
95
+ lines.push('## Routing Table');
96
+ lines.push('');
97
+ lines.push('| Source | Destination | Confidence | Decision |');
98
+ lines.push('|--------|-------------|------------|----------|');
99
+ for (const f of manifest.files || []) {
100
+ const c = f.classification || {};
101
+ lines.push(
102
+ '| ' + escapeCell(f.source_path) +
103
+ ' | ' + escapeCell(f.destination_path || '(skipped)') +
104
+ ' | ' + (c.confidence != null ? c.confidence : '') +
105
+ ' | ' + escapeCell(c.decision || '') + ' |'
106
+ );
107
+ }
108
+ lines.push('');
109
+
110
+ // People Detected
111
+ lines.push('## People Detected');
112
+ lines.push('');
113
+ if (!(manifest.people || []).length) {
114
+ lines.push('(none)');
115
+ } else {
116
+ lines.push('| Name | Role Guess | Mentions | Profile |');
117
+ lines.push('|------|------------|----------|---------|');
118
+ for (const p of manifest.people) {
119
+ lines.push(
120
+ '| ' + escapeCell(p.name) +
121
+ ' | ' + escapeCell(p.role_guess || p.role_bucket || 'unassigned') +
122
+ ' | ' + ((p.mention_files || []).length) +
123
+ ' | ' + escapeCell(p.profile_path || '') + ' |'
124
+ );
125
+ }
126
+ }
127
+ lines.push('');
128
+
129
+ // Meetings Detected
130
+ lines.push('## Meetings Detected');
131
+ lines.push('');
132
+ if (!(manifest.meetings || []).length) {
133
+ lines.push('(none)');
134
+ } else {
135
+ lines.push('| Date | Signals | Routed To |');
136
+ lines.push('|------|---------|-----------|');
137
+ for (const m of manifest.meetings) {
138
+ lines.push(
139
+ '| ' + escapeCell(m.detected_date || '') +
140
+ ' | ' + escapeCell((m.detection_signals || []).join(', ')) +
141
+ ' | ' + escapeCell(m.routed_to || m.filed_via || '(pending)') + ' |'
142
+ );
143
+ }
144
+ }
145
+ lines.push('');
146
+
147
+ // Warnings
148
+ lines.push('## Warnings');
149
+ lines.push('');
150
+ if (!(manifest.warnings || []).length) {
151
+ lines.push('(none)');
152
+ } else {
153
+ for (const w of manifest.warnings) {
154
+ lines.push('- ' + escapeCell(w.type) + ': ' + escapeCell(w.context || ''));
155
+ }
156
+ }
157
+ lines.push('');
158
+
159
+ // /mos: Usability Check (placeholder for 80-06)
160
+ lines.push('## /mos: Usability Check');
161
+ lines.push('');
162
+ if (opts.smokeTestResult) {
163
+ lines.push('- status: ' + escapeCell(opts.smokeTestResult.status || 'unknown'));
164
+ if (opts.smokeTestResult.details) {
165
+ lines.push('- details: ' + escapeCell(opts.smokeTestResult.details));
166
+ }
167
+ } else {
168
+ lines.push('_Placeholder -- populated by Phase 80 Plan 06 (branding + smoke test)._');
169
+ }
170
+ lines.push('');
171
+
172
+ // Manifest Reference
173
+ lines.push('## Manifest Reference');
174
+ lines.push('');
175
+ lines.push('See `01-ingest/output/MANIFEST.json` for the full source -> destination mapping (undo support).');
176
+ lines.push('');
177
+
178
+ return lines.join('\n');
179
+ }
180
+
181
+ module.exports = {
182
+ generateImportReport: generateImportReport,
183
+ extractMainTopicSlug: extractMainTopicSlug,
184
+ slugifyTopic: slugifyTopic,
185
+ countDecisions: countDecisions
186
+ };