@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,618 @@
1
+ /*
2
+ * Copyright (c) 2026 Mindrian. BSL 1.1.
3
+ *
4
+ * Phase 88-10 -- decision-capture persistence module
5
+ * ===================================================
6
+ * Per-section decision persistence. Writes APPROVE/REJECT/DEFER
7
+ * decisions to the owning section's Feynman-MINTO.md frontmatter
8
+ * decision_log field. When the log exceeds 20 entries, older entries
9
+ * archive to .mindrian/decision-archive/YYYY-MM/<section>.jsonl
10
+ * (partitioned by the ARCHIVED entry's timestamp, not the current
11
+ * time). Read-optimized path for 88-07 session-start TRIPLE_CONTEXT
12
+ * injection (paired with Phase 88-01 folder-memory.readDecisionLog).
13
+ *
14
+ * Usage example:
15
+ * const { recordDecision, readDecisionLog } = require('./decision-capture.cjs');
16
+ * const r = recordDecision(roomPath, 'market-analysis', {
17
+ * session_id: 'sess-2026-04-19-xyz',
18
+ * timestamp: new Date().toISOString(),
19
+ * action: 'flag_tam_staleness',
20
+ * user_response: 'defer',
21
+ * reason: 'Q3 refresh required',
22
+ * });
23
+ * // r: { success, violations?, archived? }
24
+ *
25
+ * Composes with:
26
+ * - Phase 87-02 (lib/core/write-lock.cjs) -- acquireLock around the
27
+ * MINTO mutation so cross-producer renames serialize cleanly.
28
+ * - Phase 88-00 (lib/memory/narrative-schema.cjs) --
29
+ * validateDecisionLogEntry is the single chokepoint for per-entry
30
+ * schema enforcement before we append.
31
+ * - Phase 88-00-B (lib/core/feynman-minto-invariants.cjs) -- post-write
32
+ * validation; critical severity aborts and restores the previous
33
+ * MINTO.md byte-for-byte.
34
+ * - Phase 88-04-B (scripts/vault-section-minto-generator.cjs) --
35
+ * atomic openSync 'wx' + fsync + rename pattern reused here.
36
+ *
37
+ * The decision_log field is preserved across regen via the 88-00 schema
38
+ * contract (read-before-write preservation inside the generator). That
39
+ * contract is tested independently in Test 11 of the acceptance suite.
40
+ *
41
+ * Pure CJS, node built-ins only, zero npm dependencies. Three-surface
42
+ * compatible (CLI hook, Desktop MCP handler, Cowork shared runner).
43
+ *
44
+ * License: BSL 1.1.
45
+ */
46
+
47
+ 'use strict';
48
+
49
+ const fs = require('node:fs');
50
+ const path = require('node:path');
51
+
52
+ const narrativeSchema = require('../memory/narrative-schema.cjs');
53
+ const writeLock = require('./write-lock.cjs');
54
+ const feynmanMintoInvariants = require('./feynman-minto-invariants.cjs');
55
+
56
+ const MAX_DECISION_LOG = 20;
57
+
58
+ // ---------- Helpers ----------
59
+
60
+ function safeReadSync(p) {
61
+ try {
62
+ return fs.readFileSync(p, 'utf8');
63
+ } catch (_e) {
64
+ return null;
65
+ }
66
+ }
67
+
68
+ function stripQuote(s) {
69
+ if (typeof s !== 'string') return s;
70
+ const t = s.trim();
71
+ if (
72
+ (t.startsWith('"') && t.endsWith('"')) ||
73
+ (t.startsWith("'") && t.endsWith("'"))
74
+ ) return t.slice(1, -1);
75
+ return t;
76
+ }
77
+
78
+ function quote(v) {
79
+ // Minimal safe YAML double-quote: escape backslashes + inner quotes.
80
+ const s = String(v).replace(/\\/g, '\\\\').replace(/"/g, '\\"');
81
+ return '"' + s + '"';
82
+ }
83
+
84
+ // Narrow-dialect frontmatter parser scoped to this module: pulls every
85
+ // top-level key + the decision_log block-style object array. Copy of the
86
+ // 88-00 generator readPreservedV88Fields() approach with enough surface
87
+ // to rebuild the full frontmatter back (we need to preserve unknown
88
+ // keys byte-for-byte when we re-emit). Zero new deps.
89
+ function parseFrontmatter(fmText) {
90
+ const lines = fmText.split(/\r?\n/);
91
+ // We return an ordered list of "items": either {kind:'scalar', key, raw}
92
+ // or {kind:'emptyArray', key} or {kind:'decisionLog', entries} or
93
+ // {kind:'blockList', key, items[]} or {kind:'blank', raw}.
94
+ // On re-emit we preserve the exact raw line for scalar items so unknown
95
+ // keys (schema_version, status, etc.) survive mutation byte-for-byte.
96
+ const items = [];
97
+ let i = 0;
98
+ while (i < lines.length) {
99
+ const line = lines[i];
100
+ if (/^\s*$/.test(line)) {
101
+ items.push({ kind: 'blank', raw: line });
102
+ i += 1;
103
+ continue;
104
+ }
105
+ const scalarM = line.match(/^([A-Za-z_][A-Za-z0-9_-]*):\s*(.*)$/);
106
+ if (!scalarM) {
107
+ // Non-conforming line -- preserve verbatim.
108
+ items.push({ kind: 'blank', raw: line });
109
+ i += 1;
110
+ continue;
111
+ }
112
+ const key = scalarM[1];
113
+ const rest = scalarM[2];
114
+
115
+ if (rest.trim().length > 0) {
116
+ // Inline scalar or flow-style array.
117
+ items.push({ kind: 'scalar', key: key, raw: line });
118
+ i += 1;
119
+ continue;
120
+ }
121
+
122
+ // Block follows -- either string-list or object-list.
123
+ // Look ahead: peek at next non-blank line.
124
+ let j = i + 1;
125
+ while (j < lines.length && /^\s*$/.test(lines[j])) j += 1;
126
+ if (j >= lines.length) {
127
+ items.push({ kind: 'emptyBlock', key: key, raw: line });
128
+ i = j;
129
+ continue;
130
+ }
131
+ const peek = lines[j];
132
+ if (!/^\s+-\s/.test(peek)) {
133
+ // Not a list -- treat as orphan empty.
134
+ items.push({ kind: 'emptyBlock', key: key, raw: line });
135
+ i = j;
136
+ continue;
137
+ }
138
+
139
+ // Block list. Determine string-list vs object-list from first item.
140
+ const objHead = peek.match(
141
+ /^\s+-\s+([A-Za-z_][A-Za-z0-9_-]*):\s*(.*)$/
142
+ );
143
+ const strItem = peek.match(/^\s+-\s+(.*)$/);
144
+ const isObjectList = !!objHead;
145
+ if (isObjectList) {
146
+ // Consume object list.
147
+ const entries = [];
148
+ i = j;
149
+ let current = null;
150
+ while (i < lines.length) {
151
+ const row = lines[i];
152
+ if (/^\s*$/.test(row)) { i += 1; continue; }
153
+ if (/^[A-Za-z_]/.test(row)) break;
154
+ const head = row.match(
155
+ /^\s+-\s+([A-Za-z_][A-Za-z0-9_-]*):\s*(.*)$/
156
+ );
157
+ if (head) {
158
+ if (current) entries.push(current);
159
+ current = {};
160
+ current[head[1]] = stripQuote(head[2]);
161
+ i += 1;
162
+ continue;
163
+ }
164
+ const cont = row.match(
165
+ /^\s+([A-Za-z_][A-Za-z0-9_-]*):\s*(.*)$/
166
+ );
167
+ if (cont && current) {
168
+ current[cont[1]] = stripQuote(cont[2]);
169
+ i += 1;
170
+ continue;
171
+ }
172
+ break;
173
+ }
174
+ if (current) entries.push(current);
175
+ items.push({ kind: 'objectList', key: key, entries: entries });
176
+ continue;
177
+ }
178
+ // String list.
179
+ const strItems = [];
180
+ i = j;
181
+ while (i < lines.length) {
182
+ const row = lines[i];
183
+ if (/^\s*$/.test(row)) { i += 1; continue; }
184
+ if (/^[A-Za-z_]/.test(row)) break;
185
+ const s = row.match(/^\s+-\s+(.*)$/);
186
+ if (s) {
187
+ strItems.push(stripQuote(s[1]));
188
+ i += 1;
189
+ continue;
190
+ }
191
+ break;
192
+ }
193
+ items.push({ kind: 'stringList', key: key, items: strItems });
194
+ }
195
+ return items;
196
+ }
197
+
198
+ function emitFrontmatter(items) {
199
+ const out = [];
200
+ for (const it of items) {
201
+ if (it.kind === 'blank') {
202
+ out.push(it.raw);
203
+ continue;
204
+ }
205
+ if (it.kind === 'scalar' || it.kind === 'emptyBlock') {
206
+ out.push(it.raw);
207
+ continue;
208
+ }
209
+ if (it.kind === 'stringList') {
210
+ if (it.items.length === 0) {
211
+ out.push(it.key + ': []');
212
+ } else {
213
+ out.push(it.key + ':');
214
+ for (const v of it.items) out.push(' - ' + quote(v));
215
+ }
216
+ continue;
217
+ }
218
+ if (it.kind === 'objectList') {
219
+ if (it.entries.length === 0) {
220
+ out.push(it.key + ': []');
221
+ } else {
222
+ out.push(it.key + ':');
223
+ for (const entry of it.entries) {
224
+ const keys = Object.keys(entry);
225
+ if (keys.length === 0) continue;
226
+ // session_id first if present (canonical ordering mirrors the
227
+ // 88-00 generator renderV88FrontmatterLines decision_log shape).
228
+ const ordered = [];
229
+ if ('session_id' in entry) ordered.push('session_id');
230
+ for (const k of keys) {
231
+ if (k !== 'session_id') ordered.push(k);
232
+ }
233
+ ordered.forEach(function (k, idx) {
234
+ const prefix = idx === 0 ? ' - ' : ' ';
235
+ out.push(prefix + k + ': ' + quote(entry[k]));
236
+ });
237
+ }
238
+ }
239
+ continue;
240
+ }
241
+ }
242
+ return out.join('\n');
243
+ }
244
+
245
+ // Extract the decision_log entries from a parsed frontmatter items array.
246
+ // Returns the current array + index (so we can replace it in place).
247
+ function findDecisionLog(items) {
248
+ for (let i = 0; i < items.length; i++) {
249
+ const it = items[i];
250
+ if ((it.kind === 'objectList' || it.kind === 'stringList') && it.key === 'decision_log') {
251
+ return { idx: i, entries: Array.isArray(it.entries) ? it.entries.slice() : [] };
252
+ }
253
+ if ((it.kind === 'scalar' || it.kind === 'emptyBlock') && it.key === 'decision_log') {
254
+ // Inline empty array: `decision_log: []`
255
+ return { idx: i, entries: [] };
256
+ }
257
+ }
258
+ return { idx: -1, entries: [] };
259
+ }
260
+
261
+ // Replace (or insert) the decision_log block in the items array.
262
+ function setDecisionLog(items, idx, entries) {
263
+ const newItem = { kind: 'objectList', key: 'decision_log', entries: entries };
264
+ if (idx === -1) {
265
+ // Not present: insert before the last blank-at-end (if any) so the
266
+ // output trails cleanly. Simplest: append.
267
+ items.push(newItem);
268
+ } else {
269
+ items[idx] = newItem;
270
+ }
271
+ return items;
272
+ }
273
+
274
+ // ---------- Archive helpers ----------
275
+
276
+ // Derive YYYY-MM partition from an ISO-8601 timestamp. Returns null if the
277
+ // timestamp is malformed (should never happen: entries are validated
278
+ // before they enter the decision_log).
279
+ function archiveMonth(isoTimestamp) {
280
+ if (typeof isoTimestamp !== 'string' || isoTimestamp.length < 7) return null;
281
+ return isoTimestamp.slice(0, 7);
282
+ }
283
+
284
+ // Archive filename from a section. URL-encode every character that is
285
+ // unsafe across Linux, macOS, Windows filesystems so special-char
286
+ // sections (spaces, unicode, slashes) still work. We keep it simple:
287
+ // encodeURIComponent covers all known hazards.
288
+ function archiveBasename(section) {
289
+ // Preserve dashes, which are filesystem-safe and readable.
290
+ return encodeURIComponent(section).replace(/%2D/gi, '-') + '.jsonl';
291
+ }
292
+
293
+ function archiveEntry(roomPath, section, entry) {
294
+ const yyyyMM = archiveMonth(entry.timestamp);
295
+ if (!yyyyMM) {
296
+ throw new Error(
297
+ 'decision-capture: cannot derive archive partition from timestamp ' +
298
+ JSON.stringify(entry.timestamp)
299
+ );
300
+ }
301
+ const archiveDir = path.join(
302
+ roomPath,
303
+ '.mindrian',
304
+ 'decision-archive',
305
+ yyyyMM
306
+ );
307
+ fs.mkdirSync(archiveDir, { recursive: true });
308
+ const archivePath = path.join(archiveDir, archiveBasename(section));
309
+ // appendFileSync is atomic for small lines per POSIX for O_APPEND writes;
310
+ // we still wrap in try/catch to surface filesystem errors cleanly.
311
+ fs.appendFileSync(archivePath, JSON.stringify(entry) + '\n');
312
+ return archivePath;
313
+ }
314
+
315
+ // ---------- Atomic MINTO mutation ----------
316
+
317
+ // Rewrite MINTO.md with the updated decision_log, preserving all other
318
+ // frontmatter keys and the body byte-for-byte. Uses the openSync('wx') +
319
+ // fsync + rename pattern from Phase 88-04-B (same atomic-write contract,
320
+ // scoped locally to this module to avoid cross-requiring the generator).
321
+ function atomicRewriteMintoWithDecisionLog(mintoPath, updatedEntries, roomPath) {
322
+ const raw = safeReadSync(mintoPath);
323
+ if (raw === null) {
324
+ return {
325
+ success: false,
326
+ violations: [{
327
+ category: 'existence',
328
+ severity: 'error',
329
+ message: 'no_minto',
330
+ }],
331
+ };
332
+ }
333
+ const fm = raw.match(/^(---\r?\n)([\s\S]*?)(\r?\n---\r?\n)([\s\S]*)$/);
334
+ if (!fm) {
335
+ return {
336
+ success: false,
337
+ violations: [{
338
+ category: 'schema',
339
+ severity: 'error',
340
+ message: 'frontmatter-parse-failed',
341
+ }],
342
+ };
343
+ }
344
+ const header = fm[1];
345
+ const fmText = fm[2];
346
+ const tail = fm[3];
347
+ const body = fm[4];
348
+
349
+ const items = parseFrontmatter(fmText);
350
+ const cur = findDecisionLog(items);
351
+ setDecisionLog(items, cur.idx, updatedEntries);
352
+ const newFmText = emitFrontmatter(items);
353
+ const newContent = header + newFmText + tail + body;
354
+
355
+ // Atomic write sequence (Phase 88-04-B pattern):
356
+ // openSync('wx') + writeSync + fsyncSync + closeSync
357
+ // + invariants.validate(tmp) (warning-tolerant, critical-blocks)
358
+ // + acquireLock + renameSync + releaseLock
359
+ const tmpPath = mintoPath + '.tmp.' + process.pid + '.minto';
360
+ let fd;
361
+ try {
362
+ fd = fs.openSync(tmpPath, 'wx');
363
+ } catch (e) {
364
+ if (e.code === 'EEXIST') {
365
+ // Stale tmp from a prior mid-write crash owned by the same pid
366
+ // slot. Clean and retry once.
367
+ try { fs.unlinkSync(tmpPath); } catch (_) {}
368
+ fd = fs.openSync(tmpPath, 'wx');
369
+ } else {
370
+ throw e;
371
+ }
372
+ }
373
+ try {
374
+ fs.writeSync(fd, newContent);
375
+ fs.fsyncSync(fd);
376
+ } finally {
377
+ try { fs.closeSync(fd); } catch (_) {}
378
+ }
379
+
380
+ // Post-write invariants validation. Critical severity aborts and
381
+ // restores the previous MINTO.md byte-for-byte (by unlinking the tmp).
382
+ let validation;
383
+ try {
384
+ validation = feynmanMintoInvariants.validate(tmpPath);
385
+ } catch (_e) {
386
+ validation = { valid: true, violations: [], severity: null };
387
+ }
388
+ const SEV = feynmanMintoInvariants.SEVERITY;
389
+ const isCritical = validation.violations.some(function (v) {
390
+ return v.severity === SEV.CRITICAL;
391
+ });
392
+ if (isCritical) {
393
+ try { fs.unlinkSync(tmpPath); } catch (_) {}
394
+ return {
395
+ success: false,
396
+ violations: validation.violations,
397
+ };
398
+ }
399
+
400
+ // Atomic publish under the Phase 87-02 write-lock. Retry on contention
401
+ // with exponential backoff + half-jitter (mirrors 88-04-B pattern).
402
+ const LOCK_RETRIES = 12;
403
+ const LOCK_BASE_MS = 25;
404
+ const LOCK_CAP_MS = 1600;
405
+ let locked = false;
406
+ let lockErr = null;
407
+ for (let attempt = 0; attempt < LOCK_RETRIES; attempt++) {
408
+ try {
409
+ writeLock.acquireLock(roomPath);
410
+ locked = true;
411
+ lockErr = null;
412
+ break;
413
+ } catch (e) {
414
+ lockErr = e;
415
+ const backoff = Math.min(
416
+ LOCK_CAP_MS,
417
+ LOCK_BASE_MS * Math.pow(2, attempt)
418
+ );
419
+ const sleep = Math.floor(backoff / 2 + Math.random() * (backoff / 2));
420
+ const end = Date.now() + sleep;
421
+ while (Date.now() < end) { /* busy-wait */ }
422
+ }
423
+ }
424
+ if (!locked) {
425
+ try { fs.unlinkSync(tmpPath); } catch (_) {}
426
+ return {
427
+ success: false,
428
+ violations: [{
429
+ category: 'atomicity',
430
+ severity: 'error',
431
+ message: 'write-lock acquire failed after ' + LOCK_RETRIES +
432
+ ' retries: ' + (lockErr && lockErr.message || lockErr),
433
+ }],
434
+ };
435
+ }
436
+
437
+ try {
438
+ fs.renameSync(tmpPath, mintoPath);
439
+ } finally {
440
+ try { writeLock.releaseLock(roomPath); } catch (_) {}
441
+ }
442
+
443
+ return { success: true, violations: validation.violations };
444
+ }
445
+
446
+ // ---------- Public API ----------
447
+
448
+ /**
449
+ * recordDecision(roomPath, section, decision)
450
+ *
451
+ * Append a decision to the section's MINTO.md frontmatter decision_log.
452
+ * Enforces the 20-entry cap; older entries archive to
453
+ * `<roomPath>/.mindrian/decision-archive/YYYY-MM/<section>.jsonl`
454
+ * partitioned by the ARCHIVED entry's timestamp (not the current time).
455
+ *
456
+ * Returns:
457
+ * { success: true, violations: [], archived: {count, archivePaths[]} | null }
458
+ * { success: false, violations: [...] }
459
+ */
460
+ function recordDecision(roomPath, section, decision) {
461
+ // --- Validate entry shape ---
462
+ const v = narrativeSchema.validateDecisionLogEntry(decision);
463
+ if (!v.valid) {
464
+ return {
465
+ success: false,
466
+ violations: v.errors.map(function (msg) {
467
+ return { category: 'schema', severity: 'error', message: msg };
468
+ }),
469
+ };
470
+ }
471
+
472
+ const mintoPath = path.join(roomPath, section, 'MINTO.md');
473
+ if (!fs.existsSync(mintoPath)) {
474
+ // This plan does NOT create MINTO.md from scratch. 88-13 guardian
475
+ // will enqueue regen when it sees an empty section with a decision
476
+ // request. Surface the gap so the caller can route to the debouncer.
477
+ return {
478
+ success: false,
479
+ violations: [{
480
+ category: 'existence',
481
+ severity: 'error',
482
+ message: 'no_minto',
483
+ }],
484
+ };
485
+ }
486
+
487
+ // --- Acquire write-lock around the read-modify-write cycle ---
488
+ // The atomic rewriter acquires its own lock around the rename. We also
489
+ // hold a SEPARATE lock around the read-modify-write so two processes
490
+ // cannot both read the same decision_log, append disjoint entries, and
491
+ // then race their writes (last-writer-wins would lose one entry).
492
+ //
493
+ // Retry with exponential backoff so concurrent producers converge
494
+ // without starvation (Phase 88-02/88-04-B backoff pattern).
495
+ const LOCK_RETRIES = 12;
496
+ const LOCK_BASE_MS = 25;
497
+ const LOCK_CAP_MS = 1600;
498
+ let outerLocked = false;
499
+ let outerErr = null;
500
+ for (let attempt = 0; attempt < LOCK_RETRIES; attempt++) {
501
+ try {
502
+ writeLock.acquireLock(roomPath);
503
+ outerLocked = true;
504
+ outerErr = null;
505
+ break;
506
+ } catch (e) {
507
+ outerErr = e;
508
+ const backoff = Math.min(
509
+ LOCK_CAP_MS,
510
+ LOCK_BASE_MS * Math.pow(2, attempt)
511
+ );
512
+ const sleep = Math.floor(backoff / 2 + Math.random() * (backoff / 2));
513
+ const end = Date.now() + sleep;
514
+ while (Date.now() < end) { /* busy-wait */ }
515
+ }
516
+ }
517
+ if (!outerLocked) {
518
+ return {
519
+ success: false,
520
+ violations: [{
521
+ category: 'atomicity',
522
+ severity: 'error',
523
+ message: 'decision-capture: outer write-lock acquire failed: ' +
524
+ (outerErr && outerErr.message || outerErr),
525
+ }],
526
+ };
527
+ }
528
+
529
+ try {
530
+ // --- Read current decision_log ---
531
+ const currentLog = readDecisionLogInternal(mintoPath);
532
+ const newLog = currentLog.concat([decision]);
533
+
534
+ // --- Cap + archive ---
535
+ let archivedCount = 0;
536
+ const archivePaths = [];
537
+ while (newLog.length > MAX_DECISION_LOG) {
538
+ const oldest = newLog.shift();
539
+ try {
540
+ const ap = archiveEntry(roomPath, section, oldest);
541
+ archivedCount += 1;
542
+ archivePaths.push(ap);
543
+ } catch (e) {
544
+ return {
545
+ success: false,
546
+ violations: [{
547
+ category: 'atomicity',
548
+ severity: 'error',
549
+ message: 'archive write failed: ' + (e && e.message || e),
550
+ }],
551
+ };
552
+ }
553
+ }
554
+
555
+ // --- Atomic MINTO rewrite ---
556
+ // The rewriter acquires its OWN lock around the rename; our outer
557
+ // lock guarantees atomic read-modify-write but the acquireLock call
558
+ // inside atomicRewriteMintoWithDecisionLog sees we already own the
559
+ // lock (same PID) and re-acquires cleanly (write-lock.cjs same-pid
560
+ // re-acquire is an overwrite, not a throw).
561
+ const writeResult = atomicRewriteMintoWithDecisionLog(
562
+ mintoPath,
563
+ newLog,
564
+ roomPath
565
+ );
566
+ if (!writeResult.success) {
567
+ // Atomic rewrite failed -- the archived entries are already on
568
+ // disk. That is acceptable: archival is append-only (JSONL) and
569
+ // the caller retries the write. The MINTO decision_log will
570
+ // re-converge on next successful call.
571
+ return writeResult;
572
+ }
573
+
574
+ return {
575
+ success: true,
576
+ violations: writeResult.violations || [],
577
+ archived: archivedCount > 0
578
+ ? { count: archivedCount, archivePaths: archivePaths }
579
+ : null,
580
+ };
581
+ } finally {
582
+ try { writeLock.releaseLock(roomPath); } catch (_) {}
583
+ }
584
+ }
585
+
586
+ // Internal helper: read decision_log directly from a MINTO path without
587
+ // going through folder-memory (avoids cross-require + lets us parse the
588
+ // exact block-style dialect we emit).
589
+ function readDecisionLogInternal(mintoPath) {
590
+ const raw = safeReadSync(mintoPath);
591
+ if (raw === null) return [];
592
+ const fm = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n/);
593
+ if (!fm) return [];
594
+ const items = parseFrontmatter(fm[1]);
595
+ const found = findDecisionLog(items);
596
+ return found.entries;
597
+ }
598
+
599
+ /**
600
+ * readDecisionLog(roomPath, section)
601
+ *
602
+ * Returns the current decision_log (Array) from the section's MINTO.md
603
+ * frontmatter. Never throws. Returns [] when MINTO is missing or lacks
604
+ * the field (pre-88-00 file not yet migrated).
605
+ *
606
+ * Does NOT read the archive. The archive is for dedicated full-history
607
+ * consumers (not needed for 88-07 session-start injection, which only
608
+ * consumes the current-section window).
609
+ */
610
+ function readDecisionLog(roomPath, section) {
611
+ const mintoPath = path.join(roomPath, section, 'MINTO.md');
612
+ return readDecisionLogInternal(mintoPath);
613
+ }
614
+
615
+ module.exports = {
616
+ recordDecision: recordDecision,
617
+ readDecisionLog: readDecisionLog,
618
+ };
@@ -0,0 +1,82 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * deep-links.cjs -- Deep Link Protocol for MindrianOS
5
+ *
6
+ * Generates claude-cli:// URLs for room-to-room navigation,
7
+ * dashboard-to-CLI handoff, and section-specific deep links.
8
+ *
9
+ * Protocol: claude-cli://open?cwd={path}&q={command}
10
+ * Security: ASCII control char rejection, path <=4096 chars, query <=5000 chars
11
+ */
12
+
13
+ const path = require('path');
14
+
15
+ /**
16
+ * Generate a deep link URL for a room path and optional command.
17
+ * @param {string} roomPath - Absolute path to room directory
18
+ * @param {string} [command] - Optional /mos: command to execute on open
19
+ * @returns {string} claude-cli:// URL
20
+ */
21
+ function generateDeepLink(roomPath, command) {
22
+ const cwd = path.resolve(roomPath);
23
+ if (cwd.length > 4096) {
24
+ throw new Error('Room path exceeds 4096 character limit');
25
+ }
26
+
27
+ const encodedCwd = encodeURIComponent(cwd);
28
+
29
+ if (!command) {
30
+ return `claude-cli://open?cwd=${encodedCwd}`;
31
+ }
32
+
33
+ const q = command.length > 5000 ? command.slice(0, 5000) : command;
34
+ const encodedQ = encodeURIComponent(q);
35
+ return `claude-cli://open?cwd=${encodedCwd}&q=${encodedQ}`;
36
+ }
37
+
38
+ /**
39
+ * Generate a deep link to a specific room section.
40
+ * @param {string} roomPath - Absolute path to room directory
41
+ * @param {string} section - Section name (e.g., 'problem-definition')
42
+ * @returns {string} claude-cli:// URL that opens the room and navigates to section
43
+ */
44
+ function generateSectionLink(roomPath, section) {
45
+ return generateDeepLink(roomPath, `/mos:room ${section}`);
46
+ }
47
+
48
+ /**
49
+ * Generate a deep link to the room dashboard.
50
+ * @param {string} roomPath - Absolute path to room directory
51
+ * @returns {string} claude-cli:// URL that opens the dashboard
52
+ */
53
+ function generateDashboardLink(roomPath) {
54
+ return generateDeepLink(roomPath, '/mos:dashboard');
55
+ }
56
+
57
+ /**
58
+ * Generate a deep link to the room wiki.
59
+ * @param {string} roomPath - Absolute path to room directory
60
+ * @returns {string} claude-cli:// URL that opens the wiki
61
+ */
62
+ function generateWikiLink(roomPath) {
63
+ return generateDeepLink(roomPath, '/mos:wiki');
64
+ }
65
+
66
+ /**
67
+ * Generate a deep link for a specific methodology command.
68
+ * @param {string} roomPath - Absolute path to room directory
69
+ * @param {string} methodology - Methodology name (e.g., 'find-analogies')
70
+ * @returns {string} claude-cli:// URL
71
+ */
72
+ function generateMethodologyLink(roomPath, methodology) {
73
+ return generateDeepLink(roomPath, `/mos:${methodology}`);
74
+ }
75
+
76
+ module.exports = {
77
+ generateDeepLink,
78
+ generateSectionLink,
79
+ generateDashboardLink,
80
+ generateWikiLink,
81
+ generateMethodologyLink,
82
+ };