mindforge-cc 8.1.1 → 8.2.0

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 (1002) hide show
  1. package/.mindforge/celestial.db +0 -0
  2. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/CLAUDE.md +102 -0
  3. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/commands.cjs +959 -0
  4. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/config.cjs +421 -0
  5. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/core.cjs +1166 -0
  6. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/frontmatter.cjs +307 -0
  7. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/init.cjs +1336 -0
  8. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/milestone.cjs +252 -0
  9. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/model-profiles.cjs +68 -0
  10. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/phase.cjs +888 -0
  11. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/profile-output.cjs +952 -0
  12. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/profile-pipeline.cjs +539 -0
  13. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/roadmap.cjs +329 -0
  14. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/security.cjs +356 -0
  15. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/state.cjs +969 -0
  16. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/template.cjs +222 -0
  17. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/uat.cjs +189 -0
  18. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/verify.cjs +851 -0
  19. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/workstream.cjs +491 -0
  20. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/mindforge-tools.cjs +897 -0
  21. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/file-manifest.json +219 -0
  22. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/forge/help.md +11 -0
  23. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/forge/init-project.md +36 -0
  24. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/forge/plan-phase.md +34 -0
  25. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/hooks/mindforge-check-update.js +114 -0
  26. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/hooks/mindforge-context-monitor.js +156 -0
  27. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/hooks/mindforge-prompt-guard.js +96 -0
  28. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/hooks/mindforge-session-init_extended.js +42 -0
  29. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/hooks/mindforge-statusline.js +119 -0
  30. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/hooks/mindforge-workflow-guard.js +94 -0
  31. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/add-backlog.md +32 -0
  32. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/agent.md +31 -0
  33. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/approve.md +22 -0
  34. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/audit.md +34 -0
  35. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/auto.md +26 -0
  36. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/benchmark.md +37 -0
  37. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/browse.md +30 -0
  38. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/complete-milestone.md +22 -0
  39. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/costs.md +15 -0
  40. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/cross-review.md +21 -0
  41. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/dashboard.md +102 -0
  42. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/debug.md +133 -0
  43. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/discuss-phase.md +142 -0
  44. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/do.md +31 -0
  45. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/execute-phase.md +200 -0
  46. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/health.md +31 -0
  47. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/help.md +33 -0
  48. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/init-org.md +135 -0
  49. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/init-project.md +170 -0
  50. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/install-skill.md +28 -0
  51. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/learn.md +147 -0
  52. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/learning.md +20 -0
  53. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/map-codebase.md +302 -0
  54. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/marketplace.md +124 -0
  55. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/metrics.md +26 -0
  56. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/migrate.md +44 -0
  57. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/milestone.md +16 -0
  58. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/new-runtime.md +23 -0
  59. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/next.md +109 -0
  60. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/note.md +35 -0
  61. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/plan-phase.md +131 -0
  62. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/plant-seed.md +31 -0
  63. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/plugins.md +44 -0
  64. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/pr-review.md +45 -0
  65. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/profile-team.md +27 -0
  66. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/publish-skill.md +23 -0
  67. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/qa.md +20 -0
  68. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/quick.md +139 -0
  69. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/record-learning.md +22 -0
  70. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/release.md +14 -0
  71. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/remember.md +30 -0
  72. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/research.md +16 -0
  73. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/retrospective.md +31 -0
  74. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/review-backlog.md +34 -0
  75. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/review.md +161 -0
  76. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/security-scan.md +242 -0
  77. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/session-report.md +39 -0
  78. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/ship.md +111 -0
  79. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/skills.md +145 -0
  80. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/status.md +113 -0
  81. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/steer.md +17 -0
  82. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/sync-confluence.md +15 -0
  83. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/sync-jira.md +16 -0
  84. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/tokens.md +12 -0
  85. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/ui-phase.md +34 -0
  86. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/ui-review.md +36 -0
  87. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/update.md +46 -0
  88. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/validate-phase.md +31 -0
  89. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/verify-phase.md +66 -0
  90. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/workspace.md +33 -0
  91. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/workstreams.md +35 -0
  92. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/settings.json +42 -0
  93. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-add-backlog/SKILL.md +72 -0
  94. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-add-phase/SKILL.md +39 -0
  95. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-add-tests/SKILL.md +28 -0
  96. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-add-todo/SKILL.md +42 -0
  97. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-audit-milestone/SKILL.md +29 -0
  98. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-audit-uat/SKILL.md +20 -0
  99. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-autonomous/SKILL.md +33 -0
  100. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-brainstorming/SKILL.md +164 -0
  101. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-brainstorming/scripts/frame-template.html +214 -0
  102. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-brainstorming/scripts/helper.js +88 -0
  103. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-brainstorming/scripts/server.cjs +354 -0
  104. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-brainstorming/scripts/start-server.sh +148 -0
  105. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-brainstorming/scripts/stop-server.sh +56 -0
  106. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-brainstorming/spec-document-reviewer-prompt.md +49 -0
  107. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-brainstorming/visual-companion.md +287 -0
  108. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-check-todos/SKILL.md +40 -0
  109. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-cleanup/SKILL.md +19 -0
  110. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-complete-milestone/SKILL.md +131 -0
  111. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-debug/SKILL.md +163 -0
  112. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-debug_extended/CREATION-LOG.md +119 -0
  113. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-debug_extended/SKILL.md +296 -0
  114. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-debug_extended/condition-based-waiting-example.ts +158 -0
  115. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-debug_extended/condition-based-waiting.md +115 -0
  116. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-debug_extended/defense-in-depth.md +122 -0
  117. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-debug_extended/find-polluter.sh +63 -0
  118. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-debug_extended/root-cause-tracing.md +169 -0
  119. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-debug_extended/test-academic.md +14 -0
  120. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-debug_extended/test-pressure-1.md +58 -0
  121. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-debug_extended/test-pressure-2.md +68 -0
  122. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-debug_extended/test-pressure-3.md +69 -0
  123. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-discuss-phase/SKILL.md +54 -0
  124. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-do/SKILL.md +26 -0
  125. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-execute-phase/SKILL.md +49 -0
  126. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-execute-phase_extended/SKILL.md +70 -0
  127. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-fast/SKILL.md +23 -0
  128. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-forensics/SKILL.md +49 -0
  129. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-health/SKILL.md +17 -0
  130. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-help/SKILL.md +23 -0
  131. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-insert-phase/SKILL.md +28 -0
  132. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-join-discord/SKILL.md +19 -0
  133. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-list-phase-assumptions/SKILL.md +41 -0
  134. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-list-workspaces/SKILL.md +17 -0
  135. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-manager/SKILL.md +32 -0
  136. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-map-codebase/SKILL.md +64 -0
  137. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-milestone-summary/SKILL.md +44 -0
  138. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-neural-orchestrator/SKILL.md +115 -0
  139. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-neural-orchestrator/references/codex-tools.md +100 -0
  140. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-neural-orchestrator/references/gemini-tools.md +33 -0
  141. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-new-milestone/SKILL.md +38 -0
  142. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-new-project/SKILL.md +36 -0
  143. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-new-workspace/SKILL.md +39 -0
  144. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-next/SKILL.md +19 -0
  145. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-note/SKILL.md +29 -0
  146. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-parallel-mesh_extended/SKILL.md +182 -0
  147. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-pause-work/SKILL.md +35 -0
  148. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-plan-milestone-gaps/SKILL.md +28 -0
  149. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-plan-phase/SKILL.md +38 -0
  150. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-plan-phase_extended/SKILL.md +152 -0
  151. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-plan-phase_extended/plan-document-reviewer-prompt.md +49 -0
  152. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-plant-seed/SKILL.md +22 -0
  153. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-pr-branch/SKILL.md +21 -0
  154. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-profile-user/SKILL.md +38 -0
  155. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-progress/SKILL.md +19 -0
  156. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-quick/SKILL.md +38 -0
  157. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-reapply-patches/SKILL.md +124 -0
  158. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-remove-phase/SKILL.md +26 -0
  159. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-remove-workspace/SKILL.md +22 -0
  160. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-research-phase/SKILL.md +186 -0
  161. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-resume-work/SKILL.md +35 -0
  162. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-review/SKILL.md +31 -0
  163. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-review-backlog/SKILL.md +58 -0
  164. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-review-inbound/SKILL.md +213 -0
  165. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-review-request/SKILL.md +105 -0
  166. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-review-request/code-reviewer.md +146 -0
  167. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-session-report/SKILL.md +16 -0
  168. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-set-profile/SKILL.md +9 -0
  169. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-settings/SKILL.md +32 -0
  170. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-ship/SKILL.md +16 -0
  171. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-ship_extended/SKILL.md +200 -0
  172. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-skill-creation/SKILL.md +655 -0
  173. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-skill-creation/anthropic-best-practices.md +1150 -0
  174. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-skill-creation/examples/CLAUDE_MD_TESTING.md +189 -0
  175. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-skill-creation/graphviz-conventions.dot +172 -0
  176. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-skill-creation/persuasion-principles.md +187 -0
  177. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-skill-creation/render-graphs.js +168 -0
  178. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-skill-creation/testing-skills-with-subagents.md +384 -0
  179. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-stats/SKILL.md +16 -0
  180. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-swarm-execution/SKILL.md +277 -0
  181. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-swarm-execution/code-quality-reviewer-prompt.md +26 -0
  182. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-swarm-execution/implementer-prompt.md +113 -0
  183. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-swarm-execution/spec-reviewer-prompt.md +61 -0
  184. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-system-architecture/SKILL.md +136 -0
  185. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-system-architecture/examples.md +120 -0
  186. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-system-architecture/scaling-checklist.md +76 -0
  187. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-tdd/SKILL.md +112 -0
  188. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-tdd/deep-modules.md +21 -0
  189. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-tdd/interface-design.md +22 -0
  190. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-tdd/mocking.md +24 -0
  191. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-tdd/refactoring.md +21 -0
  192. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-tdd/tests.md +28 -0
  193. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-tdd_extended/SKILL.md +371 -0
  194. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-tdd_extended/testing-anti-patterns.md +299 -0
  195. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-thread/SKILL.md +123 -0
  196. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-ui-phase/SKILL.md +24 -0
  197. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-ui-review/SKILL.md +24 -0
  198. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-update/SKILL.md +35 -0
  199. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-validate-phase/SKILL.md +26 -0
  200. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-verify-work/SKILL.md +30 -0
  201. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-verify-work_extended/SKILL.md +139 -0
  202. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-workspace-isolated/SKILL.md +218 -0
  203. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-workstreams/SKILL.md +65 -0
  204. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/forge:help.md +10 -0
  205. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/forge:init-project.md +35 -0
  206. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/forge:plan-phase.md +33 -0
  207. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-add-phase.md +112 -0
  208. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-add-tests.md +351 -0
  209. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-add-todo.md +158 -0
  210. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-audit-milestone.md +332 -0
  211. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-audit-uat.md +109 -0
  212. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-autonomous.md +815 -0
  213. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-check-todos.md +177 -0
  214. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-cleanup.md +152 -0
  215. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-complete-milestone.md +766 -0
  216. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-diagnose-issues.md +220 -0
  217. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-discovery-phase.md +289 -0
  218. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-discuss-phase-assumptions.md +645 -0
  219. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-discuss-phase.md +1047 -0
  220. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-do.md +104 -0
  221. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-execute-phase.md +838 -0
  222. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-execute-plan.md +509 -0
  223. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-fast.md +105 -0
  224. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-forensics.md +265 -0
  225. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-health.md +181 -0
  226. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-help.md +606 -0
  227. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-insert-phase.md +130 -0
  228. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-list-phase-assumptions.md +178 -0
  229. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-list-workspaces.md +56 -0
  230. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-manager.md +360 -0
  231. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-map-codebase.md +370 -0
  232. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-milestone-summary.md +223 -0
  233. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-new-milestone.md +469 -0
  234. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-new-project.md +1226 -0
  235. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-new-workspace.md +237 -0
  236. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-next.md +97 -0
  237. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-node-repair.md +92 -0
  238. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-note.md +156 -0
  239. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-pause-work.md +176 -0
  240. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-plan-milestone-gaps.md +273 -0
  241. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-plan-phase.md +877 -0
  242. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-plant-seed.md +169 -0
  243. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-pr-branch.md +129 -0
  244. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-profile-user.md +450 -0
  245. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-progress.md +507 -0
  246. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-quick.md +732 -0
  247. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-remove-phase.md +155 -0
  248. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-remove-workspace.md +90 -0
  249. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-research-phase.md +74 -0
  250. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-resume-project.md +325 -0
  251. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-review.md +228 -0
  252. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-session-report.md +146 -0
  253. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-settings.md +283 -0
  254. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-ship.md +228 -0
  255. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-stats.md +60 -0
  256. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-transition.md +671 -0
  257. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-ui-phase.md +290 -0
  258. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-ui-review.md +157 -0
  259. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-update.md +323 -0
  260. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-validate-phase.md +167 -0
  261. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-verify-phase.md +254 -0
  262. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-verify-work.md +628 -0
  263. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:add-backlog.md +24 -0
  264. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:agent.md +25 -0
  265. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:approve.md +21 -0
  266. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:architecture.md +40 -0
  267. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:audit.md +33 -0
  268. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:auto.md +25 -0
  269. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:benchmark.md +36 -0
  270. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:brainstorming.md +16 -0
  271. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:browse.md +29 -0
  272. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:complete-milestone.md +21 -0
  273. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:costs.md +14 -0
  274. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:cross-review.md +20 -0
  275. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:dashboard.md +101 -0
  276. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:debug.md +131 -0
  277. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:discuss-phase.md +141 -0
  278. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:do.md +25 -0
  279. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:execute-phase.md +205 -0
  280. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:executor.md +18 -0
  281. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:health.md +24 -0
  282. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:help.md +26 -0
  283. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:identity.md +18 -0
  284. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:init-org.md +134 -0
  285. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:init-project.md +185 -0
  286. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:install-skill.md +27 -0
  287. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:learn.md +146 -0
  288. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:map-codebase.md +301 -0
  289. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:marketplace.md +123 -0
  290. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:memory.md +18 -0
  291. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:metrics.md +25 -0
  292. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:migrate.md +43 -0
  293. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:milestone.md +15 -0
  294. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:new-runtime.md +22 -0
  295. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:next.md +108 -0
  296. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:note.md +27 -0
  297. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:plan-phase.md +139 -0
  298. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:planner.md +18 -0
  299. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:plant-seed.md +24 -0
  300. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:plugins.md +43 -0
  301. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:pr-review.md +44 -0
  302. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:profile-team.md +26 -0
  303. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:publish-skill.md +22 -0
  304. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:qa.md +19 -0
  305. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:quick.md +138 -0
  306. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:release.md +13 -0
  307. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:remember.md +29 -0
  308. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:research.md +15 -0
  309. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:researcher.md +18 -0
  310. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:retrospective.md +29 -0
  311. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:review-backlog.md +26 -0
  312. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:review.md +160 -0
  313. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:reviewer.md +18 -0
  314. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:security-scan.md +236 -0
  315. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:session-report.md +31 -0
  316. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:ship.md +108 -0
  317. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:skills.md +144 -0
  318. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:soul.md +54 -0
  319. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:status.md +107 -0
  320. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:steer.md +16 -0
  321. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:sync-confluence.md +14 -0
  322. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:sync-jira.md +15 -0
  323. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:tdd.md +46 -0
  324. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:tokens.md +11 -0
  325. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:tool.md +18 -0
  326. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:ui-phase.md +27 -0
  327. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:ui-review.md +28 -0
  328. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:update.md +45 -0
  329. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:validate-phase.md +25 -0
  330. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:verify-phase.md +65 -0
  331. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:workspace.md +32 -0
  332. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:workstreams.md +27 -0
  333. package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/publish-release.md +36 -0
  334. package/.mindforge/mirrors/mirror-sre-776a1cf9/.czrc +3 -0
  335. package/.mindforge/mirrors/mirror-sre-776a1cf9/.github/pull_request_template.md +29 -0
  336. package/.mindforge/mirrors/mirror-sre-776a1cf9/.github/workflows/ai-intelligence.yml +55 -0
  337. package/.mindforge/mirrors/mirror-sre-776a1cf9/.github/workflows/auto-pr.yml +80 -0
  338. package/.mindforge/mirrors/mirror-sre-776a1cf9/.github/workflows/control-plane.yml +79 -0
  339. package/.mindforge/mirrors/mirror-sre-776a1cf9/.github/workflows/execution-plane.yml +52 -0
  340. package/.mindforge/mirrors/mirror-sre-776a1cf9/.github/workflows/mindforge-ai-review.yml +68 -0
  341. package/.mindforge/mirrors/mirror-sre-776a1cf9/.github/workflows/mindforge-autonomous.yml +70 -0
  342. package/.mindforge/mirrors/mirror-sre-776a1cf9/.github/workflows/mindforge-ci.yml +224 -0
  343. package/.mindforge/mirrors/mirror-sre-776a1cf9/.github/workflows/mindforge-observability.yml +71 -0
  344. package/.mindforge/mirrors/mirror-sre-776a1cf9/.github/workflows/mindforge-release.yml +55 -0
  345. package/.mindforge/mirrors/mirror-sre-776a1cf9/.github/workflows/observability-plane.yml +40 -0
  346. package/.mindforge/mirrors/mirror-sre-776a1cf9/.github/workflows/release-plane.yml +43 -0
  347. package/.mindforge/mirrors/mirror-sre-776a1cf9/.gitlab-ci-mindforge.yml +18 -0
  348. package/.mindforge/mirrors/mirror-sre-776a1cf9/.husky/pre-commit +1 -0
  349. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/MINDFORGE-SCHEMA.json +165 -0
  350. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/MINDFORGE-V2-SCHEMA.json +47 -0
  351. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/audit/AUDIT-SCHEMA.md +470 -0
  352. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/browser/daemon-protocol.md +24 -0
  353. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/browser/qa-engine.md +16 -0
  354. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/browser/session-manager.md +18 -0
  355. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/browser/visual-verify-spec.md +31 -0
  356. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/bypasses.json +8 -0
  357. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/ci/ci-config-schema.md +21 -0
  358. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/ci/ci-mode.md +179 -0
  359. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/ci/github-actions-adapter.md +224 -0
  360. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/ci/gitlab-ci-adapter.md +31 -0
  361. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/ci/jenkins-adapter.md +44 -0
  362. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/config.json +66 -0
  363. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/dashboard/api-reference.md +122 -0
  364. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/dashboard/dashboard-spec.md +96 -0
  365. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/distribution/marketplace.md +53 -0
  366. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/distribution/registry-client.md +166 -0
  367. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/distribution/registry-schema.md +96 -0
  368. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/distribution/skill-publisher.md +44 -0
  369. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/distribution/skill-validator.md +74 -0
  370. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/ads-protocol.md +54 -0
  371. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/autonomous/auto-executor.md +266 -0
  372. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/autonomous/headless-adapter.md +66 -0
  373. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/autonomous/node-repair.md +190 -0
  374. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/autonomous/progress-reporter.md +58 -0
  375. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/autonomous/steering-manager.md +64 -0
  376. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/autonomous/stuck-detector.md +89 -0
  377. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/compaction-protocol.md +167 -0
  378. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/context-injector.md +154 -0
  379. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/dependency-parser.md +113 -0
  380. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/integrity.json +12 -0
  381. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/knowledge-graph-protocol.md +125 -0
  382. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/nexus-tracer.js +11 -0
  383. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/persona-factory.md +45 -0
  384. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/shard-controller.md +53 -0
  385. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/skills/conflict-resolver.md +69 -0
  386. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/skills/loader.md +184 -0
  387. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/skills/registry.md +98 -0
  388. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/skills/versioning.md +75 -0
  389. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/swarm-controller.md +59 -0
  390. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/temporal-protocol.md +40 -0
  391. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/verification-pipeline.md +111 -0
  392. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/wave-executor.md +285 -0
  393. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/governance/GOVERNANCE-CONFIG.md +17 -0
  394. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/governance/approval-workflow.md +37 -0
  395. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/governance/change-classifier.md +63 -0
  396. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/governance/compliance-gates.md +31 -0
  397. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/governance/policies/sovereign-default.json +16 -0
  398. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/integrations/confluence.md +27 -0
  399. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/integrations/connection-manager.md +163 -0
  400. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/integrations/github.md +25 -0
  401. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/integrations/gitlab.md +13 -0
  402. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/integrations/jira.md +102 -0
  403. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/integrations/slack.md +41 -0
  404. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/intelligence/antipattern-detector.md +75 -0
  405. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/intelligence/difficulty-scorer.md +55 -0
  406. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/intelligence/health-engine.md +208 -0
  407. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/intelligence/skill-gap-analyser.md +40 -0
  408. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/intelligence/smart-compaction.md +71 -0
  409. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/memory/MEMORY-SCHEMA.md +155 -0
  410. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/memory/engine/capture-protocol.md +36 -0
  411. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/memory/engine/global-sync-spec.md +42 -0
  412. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/memory/engine/retrieval-spec.md +44 -0
  413. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/metrics/METRICS-SCHEMA.md +42 -0
  414. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/metrics/quality-tracker.md +32 -0
  415. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/models/model-registry.md +48 -0
  416. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/models/model-router.md +30 -0
  417. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/monorepo/cross-package-planner.md +114 -0
  418. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/monorepo/dependency-graph-builder.md +32 -0
  419. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/monorepo/workspace-detector.md +129 -0
  420. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/org/CONVENTIONS.md +62 -0
  421. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/org/ORG.md +51 -0
  422. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/org/SECURITY.md +50 -0
  423. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/org/TOOLS.md +53 -0
  424. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/org/integrations/INTEGRATIONS-CONFIG.md +58 -0
  425. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/org/skills/MANIFEST.md +15 -0
  426. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/advisor-researcher.md +89 -0
  427. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/analyst.md +112 -0
  428. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/architect.md +108 -0
  429. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/assumptions-analyzer-extend.md +87 -0
  430. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/assumptions-analyzer.md +109 -0
  431. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/codebase-mapper-extend.md +93 -0
  432. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/codebase-mapper.md +770 -0
  433. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/coverage-specialist.md +104 -0
  434. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/debug-specialist.md +118 -0
  435. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/debugger.md +97 -0
  436. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/decision-architect.md +102 -0
  437. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/developer.md +97 -0
  438. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/executor.md +88 -0
  439. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/integration-checker.md +92 -0
  440. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/mf-executor.md +40 -0
  441. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/mf-memory.md +33 -0
  442. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/mf-planner.md +45 -0
  443. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/mf-researcher.md +39 -0
  444. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/mf-reviewer.md +35 -0
  445. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/mf-tool.md +33 -0
  446. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/nyquist-auditor.md +84 -0
  447. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/overrides/README.md +85 -0
  448. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/phase-researcher.md +107 -0
  449. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/plan-checker.md +92 -0
  450. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/planner.md +105 -0
  451. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/project-researcher.md +99 -0
  452. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/qa-engineer.md +113 -0
  453. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/release-manager.md +114 -0
  454. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/research-agent.md +109 -0
  455. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/research-synthesizer.md +101 -0
  456. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/roadmapper-extend.md +100 -0
  457. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/roadmapper.md +103 -0
  458. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/security-reviewer.md +114 -0
  459. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/swarm-templates.json +118 -0
  460. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/tech-writer.md +118 -0
  461. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/ui-auditor.md +94 -0
  462. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/ui-checker.md +89 -0
  463. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/ui-researcher.md +99 -0
  464. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/user-profiler.md +93 -0
  465. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/verifier.md +101 -0
  466. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/plugins/PLUGINS-MANIFEST.md +23 -0
  467. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/plugins/plugin-loader.md +93 -0
  468. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/plugins/plugin-registry.md +44 -0
  469. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/plugins/plugin-schema.md +68 -0
  470. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/pr-review/ai-reviewer.md +266 -0
  471. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/pr-review/finding-formatter.md +46 -0
  472. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/pr-review/review-prompt-templates.md +44 -0
  473. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/production/compatibility-layer.md +39 -0
  474. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/production/migration-engine.md +52 -0
  475. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/production/production-checklist.md +76 -0
  476. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/production/token-optimiser.md +68 -0
  477. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/remediation-queue.json +47 -0
  478. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/skills/accessibility/SKILL.md +106 -0
  479. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/skills/api-design/SKILL.md +98 -0
  480. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/skills/code-quality/SKILL.md +88 -0
  481. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/skills/data-privacy/SKILL.md +126 -0
  482. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/skills/database-patterns/SKILL.md +192 -0
  483. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/skills/documentation/SKILL.md +91 -0
  484. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/skills/incident-response/SKILL.md +180 -0
  485. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/skills/performance/SKILL.md +120 -0
  486. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/skills/security-review/SKILL.md +83 -0
  487. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/skills/testing-standards/SKILL.md +97 -0
  488. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/skills-builder/auto-capture-protocol.md +88 -0
  489. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/skills-builder/learn-protocol.md +161 -0
  490. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/skills-builder/quality-scoring.md +120 -0
  491. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/team/TEAM-PROFILE.md +42 -0
  492. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/team/multi-handoff.md +23 -0
  493. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/team/profiles/README.md +13 -0
  494. package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/team/session-merger.md +18 -0
  495. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/ARCHITECTURE.md +0 -0
  496. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/AUDIT.jsonl +45 -0
  497. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/HANDOFF.json +8 -0
  498. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/PROJECT.md +33 -0
  499. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/RELEASE-CHECKLIST.md +68 -0
  500. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/REQUIREMENTS.md +23 -0
  501. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/ROADMAP.md +12 -0
  502. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/ROI.jsonl +2 -0
  503. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/STATE.md +31 -0
  504. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/approvals/.gitkeep +1 -0
  505. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/.gitkeep +1 -0
  506. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/org/CONVENTIONS.md +0 -0
  507. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/org/ORG.md +0 -0
  508. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/org/SECURITY.md +0 -0
  509. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/org/TOOLS.md +0 -0
  510. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/personas/analyst.md +0 -0
  511. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/personas/architect.md +0 -0
  512. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/personas/debug-specialist.md +0 -0
  513. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/personas/developer.md +26 -0
  514. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/personas/qa-engineer.md +0 -0
  515. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/personas/release-manager.md +0 -0
  516. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/personas/security-reviewer.md +33 -0
  517. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/personas/tech-writer.md +0 -0
  518. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/skills/api-design/SKILL.md +0 -0
  519. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/skills/code-quality/SKILL.md +0 -0
  520. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/skills/documentation/SKILL.md +0 -0
  521. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/skills/security-review/SKILL.md +23 -0
  522. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/skills/testing-standards/SKILL.md +27 -0
  523. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/ARCHITECTURE-AUDIT-REPORT.md +90 -0
  524. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/LOGS-BENCHMARKING.md +172 -0
  525. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/ROADMAP_V8.md +49 -0
  526. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/github-actions-logs.md +88 -0
  527. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-1-imp/DAY1-HARDEN.md +823 -0
  528. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-1-imp/DAY1-IMPLEMENT.md +2459 -0
  529. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-1-imp/DAY1-REVIEW.md +288 -0
  530. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-2-imp/DAY2-HARDEN.md +954 -0
  531. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-2-imp/DAY2-IMPLEMENT.md +2347 -0
  532. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-2-imp/DAY2-REVIEW.md +422 -0
  533. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-3-imp/DAY3-HARDEN.md +870 -0
  534. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-3-imp/DAY3-IMPLEMENT.md +2798 -0
  535. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-3-imp/DAY3-REVIEW.md +484 -0
  536. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-4-imp/DAY4-HARDEN.md +1087 -0
  537. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-4-imp/DAY4-IMPLEMENT.md +2874 -0
  538. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-4-imp/DAY4-REVIEW.md +386 -0
  539. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-5-imp/DAY5-HARDEN.md +1078 -0
  540. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-5-imp/DAY5-IMPLEMENT.md +3151 -0
  541. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-5-imp/DAY5-REVIEW.md +345 -0
  542. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-6-imp/DAY6-COMPLETE.md +3919 -0
  543. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-7-imp-prod/DAY7-PRODUCTION-FINAL.md +4513 -0
  544. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/ci-actions/github-workflows-v2.md +421 -0
  545. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/ci-actions/v2-ci-actions.md +292 -0
  546. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/day-10-imp/DAY10-MULTI-MODEL.md +3402 -0
  547. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/day-11-imp/DAY11-PERSISTENT-MEMORY.md +3237 -0
  548. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/day-12-imp/DAY12-REALTIME-DASHBOARD.md +3301 -0
  549. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/day-13-imp/DAY13-SELF-BUILDING-SKILLS.md +3798 -0
  550. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/day-14-prod-v2/DAY14-V2-PRODUCTION-RELEASE.md +2255 -0
  551. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/day-8-imp/DAY8-AUTONOMOUS-ENGINE.md +3400 -0
  552. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/day-9-imp/DAY9-BROWSER-RUNTIME.md +3293 -0
  553. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/audit-archive/.gitkeep +1 -0
  554. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/decisions/.gitkeep +0 -0
  555. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/jira-sync.json +5 -0
  556. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/milestones/.gitkeep +1 -0
  557. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/phases/.gitkeep +0 -0
  558. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/research/.gitkeep +0 -0
  559. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/screenshots/.gitkeep +0 -0
  560. package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/slack-threads.json +3 -0
  561. package/.mindforge/mirrors/mirror-sre-776a1cf9/AGENTS_LEARNING.md +112 -0
  562. package/.mindforge/mirrors/mirror-sre-776a1cf9/CHANGELOG.md +1116 -0
  563. package/.mindforge/mirrors/mirror-sre-776a1cf9/LICENSE +21 -0
  564. package/.mindforge/mirrors/mirror-sre-776a1cf9/MINDFORGE.md +91 -0
  565. package/.mindforge/mirrors/mirror-sre-776a1cf9/README.md +424 -0
  566. package/.mindforge/mirrors/mirror-sre-776a1cf9/RELEASENOTES.md +199 -0
  567. package/.mindforge/mirrors/mirror-sre-776a1cf9/REPLICATION.json +12 -0
  568. package/.mindforge/mirrors/mirror-sre-776a1cf9/SECURITY.md +4 -0
  569. package/.mindforge/mirrors/mirror-sre-776a1cf9/SOUL.md +52 -0
  570. package/.mindforge/mirrors/mirror-sre-776a1cf9/agents/executor/IDENTITY.md +31 -0
  571. package/.mindforge/mirrors/mirror-sre-776a1cf9/agents/memory/IDENTITY.md +27 -0
  572. package/.mindforge/mirrors/mirror-sre-776a1cf9/agents/planner/IDENTITY.md +35 -0
  573. package/.mindforge/mirrors/mirror-sre-776a1cf9/agents/researcher/IDENTITY.md +29 -0
  574. package/.mindforge/mirrors/mirror-sre-776a1cf9/agents/reviewer/IDENTITY.md +31 -0
  575. package/.mindforge/mirrors/mirror-sre-776a1cf9/agents/tool/IDENTITY.md +27 -0
  576. package/.mindforge/mirrors/mirror-sre-776a1cf9/auto-pr.yml +74 -0
  577. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/autonomous/auto-runner.js +378 -0
  578. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/autonomous/context-refactorer.js +64 -0
  579. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/autonomous/headless.js +36 -0
  580. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/autonomous/intent-harvester.js +80 -0
  581. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/autonomous/mesh-self-healer.js +67 -0
  582. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/autonomous/progress-stream.js +49 -0
  583. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/autonomous/repair-operator.js +213 -0
  584. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/autonomous/steer.js +89 -0
  585. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/autonomous/stuck-monitor.js +120 -0
  586. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/browser/browser-daemon.js +139 -0
  587. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/browser/daemon-manager.js +91 -0
  588. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/browser/qa-engine.js +47 -0
  589. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/browser/qa-report-writer.js +32 -0
  590. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/browser/regression-writer.js +27 -0
  591. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/browser/screenshot-store.js +49 -0
  592. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/browser/session-manager.js +93 -0
  593. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/browser/visual-verify-executor.js +89 -0
  594. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/change-classifier.js +86 -0
  595. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/dashboard/api-router.js +198 -0
  596. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/dashboard/approval-handler.js +134 -0
  597. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/dashboard/frontend/index.html +751 -0
  598. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/dashboard/metrics-aggregator.js +296 -0
  599. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/dashboard/revops-api.js +47 -0
  600. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/dashboard/server.js +138 -0
  601. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/dashboard/sse-bridge.js +178 -0
  602. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/dashboard/team-tracker.js +0 -0
  603. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/dashboard/temporal-api.js +82 -0
  604. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/context-entropy-guard.js +94 -0
  605. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/feedback-loop.js +106 -0
  606. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/handover-manager.js +71 -0
  607. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/intelligence-interlock.js +39 -0
  608. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/learning-manager.js +181 -0
  609. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/logic-drift-detector.js +100 -0
  610. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/logic-validator.js +74 -0
  611. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/mesh-syncer.js +129 -0
  612. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/nexus-tracer.js +356 -0
  613. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/orbital-guardian.js +84 -0
  614. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/reason-source-aligner.js +111 -0
  615. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/remediation-engine.js +81 -0
  616. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/self-corrective-synthesizer.js +65 -0
  617. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/skill-evolver.js +105 -0
  618. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/sre-manager.js +117 -0
  619. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/temporal-cli.js +52 -0
  620. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/temporal-hindsight.js +115 -0
  621. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/temporal-hub.js +138 -0
  622. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/test-ceg.js +59 -0
  623. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/test-interlock.js +40 -0
  624. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/test-remediation.js +61 -0
  625. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/test-rsa.js +64 -0
  626. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/test-scs.js +57 -0
  627. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/test-v7-blueprint.js +44 -0
  628. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/gov-audit.js +38 -0
  629. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/approve.js +60 -0
  630. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/config-manager.js +85 -0
  631. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/impact-analyzer.js +141 -0
  632. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/policies/critical-data.json +1 -0
  633. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/policies/default-policies.jsonl +33 -0
  634. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/policy-engine.js +210 -0
  635. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/policy-gate-hardened.js +59 -0
  636. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/quantum-crypto.js +111 -0
  637. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/rbac-manager.js +109 -0
  638. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/test-config.js +40 -0
  639. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/test-crypto-pluggable.js +50 -0
  640. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/test-hardened-gate.js +71 -0
  641. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/trust-verifier.js +81 -0
  642. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/ztai-archiver.js +104 -0
  643. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/ztai-manager.js +239 -0
  644. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/hindsight-injector.js +59 -0
  645. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/install.js +129 -0
  646. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/installer-core.js +805 -0
  647. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/auto-shadow.js +274 -0
  648. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/cli.js +99 -0
  649. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/eis-client.js +95 -0
  650. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/embedding-engine.js +326 -0
  651. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/federated-sync.js +293 -0
  652. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/ghost-pattern-detector.js +69 -0
  653. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/global-sync.js +107 -0
  654. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/identity-synthesizer.js +146 -0
  655. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/knowledge-capture.js +442 -0
  656. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/knowledge-graph.js +609 -0
  657. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/knowledge-indexer.js +172 -0
  658. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/knowledge-store.js +337 -0
  659. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/pillar-health-tracker.js +63 -0
  660. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/semantic-hub.js +211 -0
  661. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/session-memory-loader.js +137 -0
  662. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/vector-hub.js +170 -0
  663. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/migrations/0.1.0-to-0.5.0.js +36 -0
  664. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/migrations/0.5.0-to-0.6.0.js +17 -0
  665. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/migrations/0.6.0-to-1.0.0.js +100 -0
  666. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/migrations/1.0.0-to-2.0.0.js +115 -0
  667. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/migrations/migrate.js +155 -0
  668. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/migrations/schema-versions.js +76 -0
  669. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/migrations/v8-sqlite-migration.js +85 -0
  670. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/mindforge-cc.sh +5 -0
  671. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/mindforge-cli.js +180 -0
  672. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/models/anthropic-provider.js +77 -0
  673. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/models/cloud-broker.js +161 -0
  674. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/models/cost-tracker.js +118 -0
  675. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/models/finops-hub.js +79 -0
  676. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/models/gemini-provider.js +79 -0
  677. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/models/model-broker.js +129 -0
  678. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/models/model-client.js +98 -0
  679. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/models/model-router.js +112 -0
  680. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/models/openai-provider.js +78 -0
  681. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/models/performance-stats.json +22 -0
  682. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/research/research-engine.js +115 -0
  683. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/review/ads-engine.js +126 -0
  684. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/review/ads-synthesizer.js +117 -0
  685. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/review/cross-review-engine.js +92 -0
  686. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/review/finding-synthesizer.js +116 -0
  687. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/review/review-report-writer.js +49 -0
  688. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/revops/debt-monitor.js +60 -0
  689. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/revops/market-evaluator.js +73 -0
  690. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/revops/remediation-queue.js +107 -0
  691. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/revops/roi-engine.js +65 -0
  692. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/revops/router-steering-v2.js +73 -0
  693. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/revops/velocity-forecaster.js +59 -0
  694. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/shard-helper.js +134 -0
  695. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/skill-registry.js +232 -0
  696. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/skill-validator.js +211 -0
  697. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/skills-builder/learn-cli.js +57 -0
  698. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/skills-builder/marketplace-cli.js +54 -0
  699. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/skills-builder/marketplace-client.js +198 -0
  700. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/skills-builder/pattern-detector.js +144 -0
  701. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/skills-builder/skill-generator.js +258 -0
  702. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/skills-builder/skill-registrar.js +107 -0
  703. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/skills-builder/skill-scorer.js +263 -0
  704. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/skills-builder/source-loader.js +268 -0
  705. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/spawn-agent.js +61 -0
  706. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/updater/changelog-fetcher.js +62 -0
  707. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/updater/self-update.js +169 -0
  708. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/updater/version-comparator.js +68 -0
  709. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/validate-config.js +92 -0
  710. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/wizard/config-generator.js +112 -0
  711. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/wizard/environment-detector.js +83 -0
  712. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/wizard/setup-wizard.js +240 -0
  713. package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/wizard/theme.js +184 -0
  714. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/CAPABILITIES-MANIFEST.md +64 -0
  715. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Context/Master-Context.md +694 -0
  716. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/INTELLIGENCE-MESH.md +37 -0
  717. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/MIND-FORGE-REFERENCE-V6.md +96 -0
  718. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/PERSONAS.md +920 -0
  719. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/audit-events.md +59 -0
  720. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/checkpoints.md +778 -0
  721. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/commands.md +107 -0
  722. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/config-reference.md +81 -0
  723. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/continuation-format.md +249 -0
  724. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/decimal-phase-calculation.md +64 -0
  725. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/git-integration.md +295 -0
  726. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/git-planning-commit.md +38 -0
  727. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/model-profile-resolution.md +36 -0
  728. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/model-profiles.md +139 -0
  729. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/phase-argument-parsing.md +61 -0
  730. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/planning-config.md +202 -0
  731. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/questioning.md +162 -0
  732. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/sdk-api.md +53 -0
  733. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/skills-api.md +57 -0
  734. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/tdd.md +263 -0
  735. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/ui-brand.md +160 -0
  736. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/user-profiling.md +681 -0
  737. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/verification-patterns.md +612 -0
  738. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/workstream-flag.md +58 -0
  739. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Agents/CLAUDE-MD.md +122 -0
  740. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Agents/COPILOT-INSTRUCTIONS.md +7 -0
  741. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Agents/DEBUGGER-PROMPT.md +91 -0
  742. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Agents/PLANNER-PROMPT.md +117 -0
  743. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Codebase/architecture.md +255 -0
  744. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Codebase/concerns.md +310 -0
  745. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Codebase/conventions.md +307 -0
  746. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Codebase/integrations.md +280 -0
  747. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Codebase/stack.md +186 -0
  748. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Codebase/structure.md +285 -0
  749. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Codebase/testing.md +480 -0
  750. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Execution/CONTINUE-HERE.md +78 -0
  751. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Execution/DISCUSSION-LOG.md +63 -0
  752. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Execution/PHASE-PROMPT.md +610 -0
  753. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Execution/STATE.md +176 -0
  754. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Execution/SUMMARY-COMPLEX.md +59 -0
  755. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Execution/SUMMARY-MINIMAL.md +41 -0
  756. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Execution/SUMMARY-STANDARD.md +48 -0
  757. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Execution/SUMMARY.md +248 -0
  758. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Profile/DEV-PREFERENCES.md +21 -0
  759. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Profile/USER-PROFILE.md +146 -0
  760. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Profile/USER-SETUP.md +311 -0
  761. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Project/AGENTS_LEARNING.md +88 -0
  762. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Project/DISCOVERY.md +146 -0
  763. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Project/MILESTONE-ARCHIVE.md +123 -0
  764. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Project/MILESTONE.md +115 -0
  765. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Project/PROJECT.md +206 -0
  766. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Project/REQUIREMENTS.md +231 -0
  767. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Project/RETROSPECTIVE.md +54 -0
  768. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Project/ROADMAP.md +202 -0
  769. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Quality/DEBUG.md +164 -0
  770. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Quality/UAT.md +280 -0
  771. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Quality/UI-SPEC.md +100 -0
  772. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Quality/VALIDATION.md +76 -0
  773. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Quality/VERIFICATION-REPORT.md +322 -0
  774. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Research/ARCHITECTURE.md +204 -0
  775. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Research/FEATURES.md +147 -0
  776. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Research/PITFALLS.md +200 -0
  777. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Research/STACK.md +120 -0
  778. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Research/SUMMARY.md +170 -0
  779. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/System/CONFIG.json +43 -0
  780. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/System/CONTEXT.md +352 -0
  781. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/adr/ADR-024-browser-localhost-only.md +17 -0
  782. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/adr/ADR-025-visual-verify-failure-treatment.md +19 -0
  783. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/adr/ADR-026-session-persistence-security.md +20 -0
  784. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/adr/ADR-042-ads-protocol.md +30 -0
  785. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/architecture/NEXUS-DASHBOARD.md +35 -0
  786. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/architecture/PAR-ZTS-SURVEY.md +43 -0
  787. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/architecture/README.md +78 -0
  788. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/architecture/V3-CORE.md +52 -0
  789. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/architecture/V4-SWARM-MESH.md +77 -0
  790. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/architecture/V5-ENTERPRISE.md +131 -0
  791. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/architecture/V6-SOVEREIGN.md +43 -0
  792. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/architecture/adr-039-multi-runtime-support.md +20 -0
  793. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/architecture/adr-040-additive-schema-migration.md +21 -0
  794. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/architecture/adr-041-stable-runtime-interface-contract.md +20 -0
  795. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/architecture/decision-records-index.md +29 -0
  796. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/ci-cd-integration.md +30 -0
  797. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/ci-cd.md +92 -0
  798. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/ci-quickstart.md +78 -0
  799. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/commands-reference.md +144 -0
  800. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/commands-skills/DISCOVERED_SKILLS.md +21 -0
  801. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/contributing/CONTRIBUTING.md +38 -0
  802. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/contributing/plugin-authoring.md +50 -0
  803. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/contributing/skill-authoring.md +41 -0
  804. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/enterprise-setup.md +25 -0
  805. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/faq.md +38 -0
  806. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/feature-dashboard.md +63 -0
  807. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/getting-started.md +44 -0
  808. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/governance-guide.md +99 -0
  809. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/monorepo-guide.md +26 -0
  810. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/persona-customisation.md +56 -0
  811. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/publishing-guide.md +43 -0
  812. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/quick-verify.md +33 -0
  813. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/registry/AGENTS.md +37 -0
  814. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/registry/COMMANDS.md +87 -0
  815. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/registry/HOOKS.md +38 -0
  816. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/registry/PERSONAS.md +64 -0
  817. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/registry/README.md +27 -0
  818. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/registry/SKILLS.md +142 -0
  819. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/registry/WORKFLOWS.md +72 -0
  820. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/release-checklist-guide.md +37 -0
  821. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/requirements.md +29 -0
  822. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/sdk-reference.md +27 -0
  823. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/security/SECURITY.md +55 -0
  824. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/security/ZTAI-OVERVIEW.md +37 -0
  825. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/security/penetration-test-results.md +31 -0
  826. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/security/threat-model.md +142 -0
  827. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/skills-authoring-guide.md +176 -0
  828. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/skills-publishing-guide.md +22 -0
  829. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/team-setup-guide.md +21 -0
  830. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/testing-current-version.md +130 -0
  831. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/troubleshooting.md +139 -0
  832. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/tutorial.md +162 -0
  833. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/upgrade.md +58 -0
  834. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/user-guide.md +244 -0
  835. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/usp-features.md +102 -0
  836. package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/workflow-atlas.md +57 -0
  837. package/.mindforge/mirrors/mirror-sre-776a1cf9/eslint.config.mjs +31 -0
  838. package/.mindforge/mirrors/mirror-sre-776a1cf9/examples/starter-project/.planning/AUDIT.jsonl +1 -0
  839. package/.mindforge/mirrors/mirror-sre-776a1cf9/examples/starter-project/.planning/HANDOFF.json +23 -0
  840. package/.mindforge/mirrors/mirror-sre-776a1cf9/examples/starter-project/.planning/PROJECT.md +27 -0
  841. package/.mindforge/mirrors/mirror-sre-776a1cf9/examples/starter-project/.planning/STATE.md +10 -0
  842. package/.mindforge/mirrors/mirror-sre-776a1cf9/examples/starter-project/MINDFORGE.md +40 -0
  843. package/.mindforge/mirrors/mirror-sre-776a1cf9/examples/starter-project/README.md +14 -0
  844. package/.mindforge/mirrors/mirror-sre-776a1cf9/package-lock.json +3882 -0
  845. package/.mindforge/mirrors/mirror-sre-776a1cf9/package.json +66 -0
  846. package/.mindforge/mirrors/mirror-sre-776a1cf9/sdk/README.md +69 -0
  847. package/.mindforge/mirrors/mirror-sre-776a1cf9/sdk/eslint.config.mjs +34 -0
  848. package/.mindforge/mirrors/mirror-sre-776a1cf9/sdk/package-lock.json +1507 -0
  849. package/.mindforge/mirrors/mirror-sre-776a1cf9/sdk/package.json +30 -0
  850. package/.mindforge/mirrors/mirror-sre-776a1cf9/sdk/src/client.ts +133 -0
  851. package/.mindforge/mirrors/mirror-sre-776a1cf9/sdk/src/commands.ts +63 -0
  852. package/.mindforge/mirrors/mirror-sre-776a1cf9/sdk/src/events.ts +166 -0
  853. package/.mindforge/mirrors/mirror-sre-776a1cf9/sdk/src/index.ts +23 -0
  854. package/.mindforge/mirrors/mirror-sre-776a1cf9/sdk/src/memory.ts +257 -0
  855. package/.mindforge/mirrors/mirror-sre-776a1cf9/sdk/src/types.ts +87 -0
  856. package/.mindforge/mirrors/mirror-sre-776a1cf9/sdk/tsconfig.json +13 -0
  857. package/.mindforge/mirrors/mirror-sre-776a1cf9/skills-lock.json +30 -0
  858. package/.mindforge/mirrors/mirror-sre-776a1cf9/test/sovereign-status.test.js +18 -0
  859. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/ads.test.js +121 -0
  860. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/audit.test.js +206 -0
  861. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/autonomous.test.js +53 -0
  862. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/browser.test.js +61 -0
  863. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/ci-mode.test.js +162 -0
  864. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/compaction.test.js +161 -0
  865. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/dashboard.test.js +327 -0
  866. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/distribution.test.js +205 -0
  867. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/e2e.test.js +618 -0
  868. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/entropy-test.js +47 -0
  869. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/feedback-loop.test.js +62 -0
  870. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/governance/test-cadia-optimizer.js +112 -0
  871. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/governance/test-policies/deny-security.json +9 -0
  872. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/governance/test-policies/permit-t2.json +10 -0
  873. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/governance.test.js +130 -0
  874. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/install.test.js +209 -0
  875. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/integrations.test.js +128 -0
  876. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/intelligence.test.js +117 -0
  877. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/knowledge-graph.test.js +593 -0
  878. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/learning-engine.test.js +69 -0
  879. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/mca-routing-test.js +37 -0
  880. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/memory.test.js +166 -0
  881. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/metrics.test.js +96 -0
  882. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/migration.test.js +308 -0
  883. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/model-broker.test.js +55 -0
  884. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/model-routing.test.js +111 -0
  885. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/nexus-tracing.test.js +49 -0
  886. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/production.test.js +416 -0
  887. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/release.test.js +99 -0
  888. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/revops-roi.test.js +52 -0
  889. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/run-nexus-tests.js +84 -0
  890. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/sdk.test.js +200 -0
  891. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/security-audit.test.js +67 -0
  892. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/self-building-skills.test.js +285 -0
  893. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/semantic-hub.test.js +91 -0
  894. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/sharding.test.js +87 -0
  895. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/skills-platform.test.js +389 -0
  896. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/sre-zk-proof-test.js +76 -0
  897. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/swarms.test.md +21 -0
  898. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/temporal-vision.test.js +68 -0
  899. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/v7-pillar-integration.test.js +73 -0
  900. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/v7-proactive-homing.test.js +53 -0
  901. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/v7-sovereign-security.test.js +64 -0
  902. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/v8-mesh-sync.test.js +76 -0
  903. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/v8-orbital-governance.test.js +74 -0
  904. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/v8-persistence.test.js +86 -0
  905. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/v8-skill-evolution.test.js +74 -0
  906. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/wave-engine.test.js +336 -0
  907. package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/ztai-enterprise.test.js +103 -0
  908. package/.planning/archive/v8-cleanup/.agents/skills/ai-image-generation/SKILL.md +147 -0
  909. package/.planning/archive/v8-cleanup/.agents/skills/ai-video-generation/SKILL.md +185 -0
  910. package/.planning/archive/v8-cleanup/.agents/skills/critique/SKILL.md +201 -0
  911. package/.planning/archive/v8-cleanup/.agents/skills/critique/reference/cognitive-load.md +106 -0
  912. package/.planning/archive/v8-cleanup/.agents/skills/critique/reference/heuristics-scoring.md +234 -0
  913. package/.planning/archive/v8-cleanup/.agents/skills/critique/reference/personas.md +178 -0
  914. package/.planning/archive/v8-cleanup/.agents/skills/elevenlabs-music/SKILL.md +191 -0
  915. package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/SKILL.md +659 -0
  916. package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/_sync_all.py +414 -0
  917. package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/app-interface.csv +31 -0
  918. package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/charts.csv +26 -0
  919. package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/colors.csv +162 -0
  920. package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/design.csv +1776 -0
  921. package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/draft.csv +1779 -0
  922. package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/google-fonts.csv +1924 -0
  923. package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/icons.csv +106 -0
  924. package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/landing.csv +35 -0
  925. package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/products.csv +162 -0
  926. package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
  927. package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  928. package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/styles.csv +85 -0
  929. package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/typography.csv +74 -0
  930. package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/ui-reasoning.csv +162 -0
  931. package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  932. package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/scripts/core.py +247 -0
  933. package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/scripts/design_system.py +1067 -0
  934. package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/scripts/search.py +114 -0
  935. package/.planning/archive/v8-cleanup/.forge/org/CONVENTIONS.md +0 -0
  936. package/.planning/archive/v8-cleanup/.forge/org/ORG.md +0 -0
  937. package/.planning/archive/v8-cleanup/.forge/org/SECURITY.md +0 -0
  938. package/.planning/archive/v8-cleanup/.forge/org/TOOLS.md +0 -0
  939. package/.planning/archive/v8-cleanup/.forge/personas/analyst.md +0 -0
  940. package/.planning/archive/v8-cleanup/.forge/personas/architect.md +0 -0
  941. package/.planning/archive/v8-cleanup/.forge/personas/debug-specialist.md +0 -0
  942. package/.planning/archive/v8-cleanup/.forge/personas/developer.md +26 -0
  943. package/.planning/archive/v8-cleanup/.forge/personas/qa-engineer.md +0 -0
  944. package/.planning/archive/v8-cleanup/.forge/personas/release-manager.md +0 -0
  945. package/.planning/archive/v8-cleanup/.forge/personas/security-reviewer.md +33 -0
  946. package/.planning/archive/v8-cleanup/.forge/personas/tech-writer.md +0 -0
  947. package/.planning/archive/v8-cleanup/.forge/skills/api-design/SKILL.md +0 -0
  948. package/.planning/archive/v8-cleanup/.forge/skills/code-quality/SKILL.md +0 -0
  949. package/.planning/archive/v8-cleanup/.forge/skills/documentation/SKILL.md +0 -0
  950. package/.planning/archive/v8-cleanup/.forge/skills/security-review/SKILL.md +23 -0
  951. package/.planning/archive/v8-cleanup/.forge/skills/testing-standards/SKILL.md +27 -0
  952. package/.planning/archive/v8-cleanup/ARCHITECTURE-AUDIT-REPORT.md +90 -0
  953. package/.planning/archive/v8-cleanup/LOGS-BENCHMARKING.md +172 -0
  954. package/.planning/archive/v8-cleanup/MIND-FORGE-V6-ENTERPRISE-PROPOSAL.md +79 -0
  955. package/.planning/archive/v8-cleanup/ROADMAP_V7.md +67 -0
  956. package/.planning/archive/v8-cleanup/ROADMAP_V8.md +49 -0
  957. package/.planning/archive/v8-cleanup/github-actions-logs.md +88 -0
  958. package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-1-imp/DAY1-HARDEN.md +823 -0
  959. package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-1-imp/DAY1-IMPLEMENT.md +2459 -0
  960. package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-1-imp/DAY1-REVIEW.md +288 -0
  961. package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-2-imp/DAY2-HARDEN.md +954 -0
  962. package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-2-imp/DAY2-IMPLEMENT.md +2347 -0
  963. package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-2-imp/DAY2-REVIEW.md +422 -0
  964. package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-3-imp/DAY3-HARDEN.md +870 -0
  965. package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-3-imp/DAY3-IMPLEMENT.md +2798 -0
  966. package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-3-imp/DAY3-REVIEW.md +484 -0
  967. package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-4-imp/DAY4-HARDEN.md +1087 -0
  968. package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-4-imp/DAY4-IMPLEMENT.md +2874 -0
  969. package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-4-imp/DAY4-REVIEW.md +386 -0
  970. package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-5-imp/DAY5-HARDEN.md +1078 -0
  971. package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-5-imp/DAY5-IMPLEMENT.md +3151 -0
  972. package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-5-imp/DAY5-REVIEW.md +345 -0
  973. package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-6-imp/DAY6-COMPLETE.md +3919 -0
  974. package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-7-imp-prod/DAY7-PRODUCTION-FINAL.md +4513 -0
  975. package/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/ci-actions/github-workflows-v2.md +421 -0
  976. package/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/ci-actions/v2-ci-actions.md +292 -0
  977. package/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/day-10-imp/DAY10-MULTI-MODEL.md +3402 -0
  978. package/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/day-11-imp/DAY11-PERSISTENT-MEMORY.md +3237 -0
  979. package/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/day-12-imp/DAY12-REALTIME-DASHBOARD.md +3301 -0
  980. package/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/day-13-imp/DAY13-SELF-BUILDING-SKILLS.md +3798 -0
  981. package/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/day-14-prod-v2/DAY14-V2-PRODUCTION-RELEASE.md +2255 -0
  982. package/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/day-8-imp/DAY8-AUTONOMOUS-ENGINE.md +3400 -0
  983. package/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/day-9-imp/DAY9-BROWSER-RUNTIME.md +3293 -0
  984. package/.planning/decisions/SRE-4e54a061.md +19 -0
  985. package/CHANGELOG.md +14 -0
  986. package/MINDFORGE.md +5 -4
  987. package/README.md +3 -2
  988. package/RELEASENOTES.md +17 -0
  989. package/bin/autonomous/auto-runner.js +64 -0
  990. package/bin/engine/learning-manager.js +4 -2
  991. package/bin/governance/impact-analyzer.js +4 -2
  992. package/bin/installer-core.js +18 -2
  993. package/bin/models/model-router.js +3 -1
  994. package/bin/sre/adversarial-sre.js +109 -0
  995. package/bin/sre/sentinel.js +128 -0
  996. package/bin/sre/shadow-mirror.js +122 -0
  997. package/bin/sre/sli-verifier.js +81 -0
  998. package/docs/Context/Master-Context.md +22 -2
  999. package/docs/PERSONAS.md +40 -0
  1000. package/docs/architecture/V8-SRE.md +88 -0
  1001. package/docs/governance-guide.md +43 -17
  1002. package/package.json +2 -2
@@ -0,0 +1,3301 @@
1
+ # MindForge v2 — Day 12: Real-Time Web Observability Dashboard
2
+ # Branch: `feat/mindforge-v2-realtime-dashboard`
3
+ # Prerequisite: `feat/mindforge-v2-persistent-memory` merged to `main`
4
+ # Version target: v2.0.0-alpha.5
5
+ # Theme: "The Entire Team Sees What MindForge Is Doing."
6
+
7
+ ---
8
+
9
+ ## BRANCH SETUP
10
+
11
+ ```bash
12
+ git checkout main
13
+ git pull origin main
14
+
15
+ # Verify Day 11 baseline
16
+ node -e "console.log(require('./package.json').version)" # Must be 2.0.0-alpha.4
17
+
18
+ # All 19 test suites must pass before starting Day 12
19
+ SUITES=(install wave-engine audit compaction skills-platform \
20
+ integrations governance intelligence metrics \
21
+ distribution ci-mode sdk production migration e2e \
22
+ autonomous browser model-routing memory)
23
+
24
+ for suite in "${SUITES[@]}"; do
25
+ printf " %-30s" "${suite}..."
26
+ node tests/${suite}.test.js 2>&1 | tail -1
27
+ done
28
+ # ALL 19 must pass — zero failures before Day 12 begins.
29
+
30
+ git checkout -b feat/mindforge-v2-realtime-dashboard
31
+ ```
32
+
33
+ ---
34
+
35
+ ## DAY 12 SCOPE
36
+
37
+ Day 12 builds the **Real-Time Web Observability Dashboard** — the feature that
38
+ takes MindForge from a CLI-only tool to a team-visible platform. When
39
+ `/mindforge:auto` is running in one terminal, anyone on the team can open
40
+ `http://localhost:7339` and see exactly what is happening: tasks completing,
41
+ security findings, approval requests, cost accumulation, knowledge graph entries —
42
+ all updating live without page refresh.
43
+
44
+ **The competitive advantage:** No other agentic framework has an integrated
45
+ web dashboard. Teams currently track progress via CLI output in a shared terminal
46
+ or by looking at git commits. The MindForge dashboard makes the agent's work
47
+ as visible as a Jira board.
48
+
49
+ **Architecture decisions:**
50
+ - **Express.js** — battle-tested, zero-config HTTP server with SSE support
51
+ - **Server-Sent Events** (SSE, not WebSocket) — one-way push from server, no client lib needed
52
+ - **Single-file HTML frontend** — no build step, no bundler, no framework dependency
53
+ - **localhost:7339** — adjacent to SDK SSE (7337) and browser daemon (7338)
54
+ - **Localhost-only** — consistent with ADR-017 (never expose on network interface)
55
+ - **No authentication** — local dev tool; security via binding address only
56
+
57
+ **Day 12 components:**
58
+
59
+ | Component | Description |
60
+ |---|---|
61
+ | Dashboard server | Express.js HTTP server, localhost:7339, SSE push |
62
+ | SSE event bridge | Tails AUDIT.jsonl, auto-state.json → SSE stream |
63
+ | REST API | 10 endpoints: status, audit, metrics, approvals, team, memory, costs, steer |
64
+ | Approval API | POST /api/approve/:id — approve/reject from browser |
65
+ | Frontend: Activity Feed | Live AUDIT event stream, wave progress bar, phase status |
66
+ | Frontend: Quality Metrics | Charts: session score trend, verify rate, cost trend |
67
+ | Frontend: Pending Approvals | Tier 2/3 approval UI with approve/reject buttons |
68
+ | Frontend: Knowledge Graph | Visual nodes/edges of knowledge base entries |
69
+ | Frontend: Team Activity | Active developers, last-seen, conflict detection |
70
+ | `/mindforge:dashboard` command | Start/stop/status/open |
71
+ | `tests/dashboard.test.js` | 20th test suite |
72
+
73
+ **New commands today: 45 total (44 + dashboard)**
74
+
75
+ ---
76
+
77
+ # ═══════════════════════════════════════════════════════════════════════
78
+ # PART 1 — IMPLEMENTATION PROMPT
79
+ # ═══════════════════════════════════════════════════════════════════════
80
+
81
+ ---
82
+
83
+ ## TASK 1 — Scaffold Day 12 directory structure
84
+
85
+ ```bash
86
+ # Dashboard server
87
+ mkdir -p bin/dashboard
88
+ touch bin/dashboard/server.js
89
+ touch bin/dashboard/sse-bridge.js
90
+ touch bin/dashboard/api-router.js
91
+ touch bin/dashboard/approval-handler.js
92
+ touch bin/dashboard/team-tracker.js
93
+ touch bin/dashboard/metrics-aggregator.js
94
+
95
+ # Dashboard frontend (single-file HTML, no build step)
96
+ mkdir -p bin/dashboard/frontend
97
+ touch bin/dashboard/frontend/index.html
98
+
99
+ # Dashboard specs
100
+ mkdir -p .mindforge/dashboard
101
+ touch .mindforge/dashboard/dashboard-spec.md
102
+ touch .mindforge/dashboard/api-reference.md
103
+
104
+ # New command
105
+ touch .claude/commands/mindforge/dashboard.md
106
+ cp .claude/commands/mindforge/dashboard.md .agent/mindforge/dashboard.md
107
+
108
+ # Test suite
109
+ touch tests/dashboard.test.js
110
+
111
+ # PID file location
112
+ # .planning/dashboard-server.pid — created at runtime, gitignored
113
+ cat >> .gitignore << 'EOF'
114
+
115
+ # MindForge v2 — dashboard runtime files
116
+ .planning/dashboard-server.pid
117
+ EOF
118
+ ```
119
+
120
+ **Add Express.js dependency:**
121
+ ```bash
122
+ node -e "
123
+ const fs = require('fs');
124
+ const p = JSON.parse(fs.readFileSync('package.json','utf8'));
125
+ p.dependencies = p.dependencies || {};
126
+ p.dependencies['express'] = '^4.19.2';
127
+ fs.writeFileSync('package.json', JSON.stringify(p, null, 2) + '\n');
128
+ console.log('Added express dependency');
129
+ "
130
+ ```
131
+
132
+ **Commit:**
133
+ ```bash
134
+ git add .
135
+ git commit -m "chore(v2-day12): scaffold real-time dashboard directory structure"
136
+ ```
137
+
138
+ ---
139
+
140
+ ## TASK 2 — Write the Dashboard Specification
141
+
142
+ ### `.mindforge/dashboard/dashboard-spec.md`
143
+
144
+ ```markdown
145
+ # MindForge v2 — Dashboard Specification
146
+
147
+ ## Overview
148
+
149
+ The MindForge dashboard is a real-time web UI that reflects the live state of
150
+ the MindForge agent and all project artifacts. It serves as the team's window
151
+ into what the agent is doing — designed for standup visibility, not agent control
152
+ (though it does support approval actions for Tier 2/3 governance).
153
+
154
+ ## Architecture
155
+
156
+ ```
157
+ Browser clients
158
+ ↑ SSE (push) ↑ REST (pull on load)
159
+ │ │
160
+ bin/dashboard/server.js (Express.js, localhost:7339)
161
+ │ │
162
+ sse-bridge.js api-router.js
163
+ │ (tails files) │ (reads files)
164
+ │ │
165
+ AUDIT.jsonl HANDOFF.json
166
+ auto-state.json session-quality.jsonl
167
+ APPROVAL-*.json token-usage.jsonl
168
+ HANDOFF.json knowledge-base.jsonl
169
+ TEAM-STATE.jsonl .planning/phases/
170
+ ```
171
+
172
+ ## Port and binding
173
+
174
+ - **Port:** 7339 (Dashboard = 7337+2, after SSE at 7337 and Browser Daemon at 7338)
175
+ - **Binding:** 127.0.0.1 ONLY — never 0.0.0.0 (ADR-017 policy)
176
+ - **Protocol:** HTTP/1.1 with SSE for live events
177
+ - **Process lifecycle:**
178
+ - Started by: `/mindforge:dashboard` command or `bin/dashboard/server.js`
179
+ - Stopped by: `CTRL+C`, `/mindforge:dashboard --stop`, or SIGTERM
180
+ - Auto-stop: when MindForge session ends (watches for HANDOFF.json inactivity)
181
+
182
+ ## Dashboard pages (5 tabs)
183
+
184
+ ### Page 1 — Live Activity (default view)
185
+ Shows real-time execution state:
186
+ - Project name and current phase description
187
+ - Auto mode status indicator (RUNNING/PAUSED/ESCALATED/IDLE)
188
+ - Wave progress bar (current wave / total waves)
189
+ - Current task name and elapsed time
190
+ - Live AUDIT event feed (last 50 events, newest at top)
191
+ - Steering input box (sends to steering queue if auto mode active)
192
+
193
+ ### Page 2 — Quality Metrics
194
+ Charts powered by session-quality.jsonl and token-usage.jsonl:
195
+ - Session quality score trend (last 20 sessions, sparkline)
196
+ - Verify pass rate over time (last 20 sessions)
197
+ - Security findings by severity (bar chart: CRITICAL/HIGH/MEDIUM/LOW)
198
+ - Token cost per session trend
199
+ - Node repair frequency (auto mode health signal)
200
+
201
+ ### Page 3 — Pending Approvals
202
+ Governance queue visible to the whole team:
203
+ - Shows all APPROVAL-*.json files with status: pending
204
+ - For each: tier, phase/plan, change description, time since requested, expiry
205
+ - [Approve] and [Reject] buttons that call POST /api/approve/:id
206
+ - Expired approvals shown separately with red indicator
207
+
208
+ ### Page 4 — Knowledge Graph
209
+ Visual representation of the knowledge base:
210
+ - Force-directed graph: nodes = knowledge entries, edges = ADR links
211
+ - Color by type: blue=decision, green=preference, red=bug_pattern, yellow=domain
212
+ - Node size = confidence × 30px radius
213
+ - Click node → side panel with full content
214
+ - Filter by type, tags, or confidence threshold
215
+
216
+ ### Page 5 — Team Activity
217
+ Multi-developer visibility:
218
+ - Active developers (git email → last AUDIT event timestamp)
219
+ - What each developer is working on (last task from AUDIT.jsonl)
220
+ - File conflict detection (two developers recently touching the same file)
221
+ - Session history (list of sessions, quality scores, costs)
222
+
223
+ ## Security model
224
+
225
+ 1. Localhost-only binding (127.0.0.1) — consistent with all MindForge servers
226
+ 2. No authentication — local dev tool, not exposed to network
227
+ 3. CORS policy: only allow requests from localhost
228
+ 4. Approval actions (POST /api/approve/:id) require the approval file to exist
229
+ in `.planning/approvals/` — cannot fabricate approvals from browser
230
+ 5. Steering (POST /api/steer) only works when auto-state.json shows `status: running`
231
+ 6. All file reads are restricted to `.planning/` and `.mindforge/` directories —
232
+ no arbitrary filesystem access from the API
233
+
234
+ ## SCREENSHARE MODE (recommended team use)
235
+ The dashboard is designed to be screenshared during standups:
236
+ - Product managers see live progress without CLI access
237
+ - Designers see when their UI implementation tasks are running
238
+ - Stakeholders see real estimates of completion time
239
+ - On-call engineers see security findings as they're detected
240
+ Never expose the dashboard URL externally — it contains project details.
241
+ ```
242
+
243
+ ### `.mindforge/dashboard/api-reference.md`
244
+
245
+ ```markdown
246
+ # MindForge Dashboard API Reference
247
+
248
+ ## Base URL: http://localhost:7339
249
+
250
+ ## GET /api/status
251
+ Current execution state.
252
+ ```json
253
+ {
254
+ "project_name": "saas-app",
255
+ "phase": 3,
256
+ "phase_description": "Authentication System",
257
+ "auto_mode": true,
258
+ "auto_status": "running|paused|escalated|idle",
259
+ "current_task": "Plan 3-05 — JWT middleware",
260
+ "wave_current": 2,
261
+ "wave_total": 3,
262
+ "tasks_completed": 5,
263
+ "tasks_total": 8,
264
+ "elapsed_ms": 1083000,
265
+ "node_repairs": 1,
266
+ "escalations": 0,
267
+ "last_commit": "abc1234",
268
+ "last_event_at": "ISO-8601"
269
+ }
270
+ ```
271
+
272
+ ## GET /api/audit?limit=50&offset=0&event=task_completed
273
+ Recent AUDIT.jsonl entries (newest first).
274
+ Query params: limit (default 50, max 200), offset, event (filter by event type)
275
+
276
+ ## GET /api/metrics
277
+ Session quality and cost summary.
278
+ ```json
279
+ {
280
+ "sessions": [{ "id": "...", "quality_score": 0.87, "cost_usd": 0.42, "verify_pass_rate": 0.95 }],
281
+ "avg_quality": 0.85,
282
+ "avg_cost_usd": 0.38,
283
+ "security_findings": { "CRITICAL": 0, "HIGH": 2, "MEDIUM": 5, "LOW": 8 },
284
+ "node_repair_rate": 0.08
285
+ }
286
+ ```
287
+
288
+ ## GET /api/approvals
289
+ Pending governance approvals.
290
+ ```json
291
+ {
292
+ "pending": [
293
+ {
294
+ "id": "uuid",
295
+ "tier": 2,
296
+ "phase": 3,
297
+ "plan": "04",
298
+ "description": "Add user RBAC model",
299
+ "requested_at": "ISO-8601",
300
+ "expires_at": "ISO-8601",
301
+ "hours_remaining": 21.3,
302
+ "diff_preview": "src/models/user.ts +48 lines..."
303
+ }
304
+ ],
305
+ "approved": [...],
306
+ "rejected": [...],
307
+ "expired": [...]
308
+ }
309
+ ```
310
+
311
+ ## POST /api/approve/:id
312
+ ```json
313
+ Request: { "decision": "approve|reject", "comment": "optional", "approver": "email" }
314
+ Response: { "success": true, "decision": "approve", "approval_id": "uuid" }
315
+ ```
316
+
317
+ ## GET /api/team
318
+ Active developer activity.
319
+ ```json
320
+ {
321
+ "active": [
322
+ { "email": "john@company.com", "current_task": "Plan 3-05", "last_seen_mins": 0 }
323
+ ],
324
+ "conflicts": [
325
+ { "file": "src/auth/session.ts", "developers": ["john@...", "jane@..."] }
326
+ ]
327
+ }
328
+ ```
329
+
330
+ ## GET /api/memory?q=jwt&limit=10
331
+ Knowledge base query.
332
+ ```json
333
+ {
334
+ "entries": [
335
+ { "id": "kb-uuid", "type": "architectural_decision", "topic": "JWT tokens", "confidence": 0.90 }
336
+ ],
337
+ "total": 47
338
+ }
339
+ ```
340
+
341
+ ## GET /api/costs?window=7d
342
+ Cost summary from token-usage.jsonl.
343
+ ```json
344
+ {
345
+ "total_usd": 3.84,
346
+ "today_usd": 1.21,
347
+ "by_model": { "claude-sonnet-4-6": 1.92, "gpt-4o": 0.98 },
348
+ "daily_limit_usd": 10.00,
349
+ "limit_used_pct": 12.1
350
+ }
351
+ ```
352
+
353
+ ## POST /api/steer
354
+ Inject steering guidance (requires auto mode running).
355
+ ```json
356
+ Request: { "instruction": "Use Redis for session storage", "priority": "normal" }
357
+ Response: { "success": true, "queued": true }
358
+ ```
359
+
360
+ ## GET /events
361
+ SSE stream. Events emitted:
362
+ - `audit:new` — new AUDIT.jsonl entry
363
+ - `status:update` — auto-state.json changed
364
+ - `approval:new` — new approval request
365
+ - `approval:resolved` — approval approved or rejected
366
+ - `conflict:detected` — two developers touching same file
367
+ - `ping` — keepalive every 15 seconds
368
+ ```
369
+
370
+ **Commit:**
371
+ ```bash
372
+ git add .mindforge/dashboard/
373
+ git commit -m "feat(v2-dashboard): write dashboard specification and API reference"
374
+ ```
375
+
376
+ ---
377
+
378
+ ## TASK 3 — Implement the SSE Bridge
379
+
380
+ ### `bin/dashboard/sse-bridge.js`
381
+
382
+ ```javascript
383
+ /**
384
+ * MindForge v2 — SSE Event Bridge
385
+ * Tails AUDIT.jsonl and auto-state.json and pushes changes
386
+ * to all connected SSE clients.
387
+ *
388
+ * Design:
389
+ * - Uses fs.watchFile() for cross-platform file watching (not fs.watch)
390
+ * - Each connected client gets a Response object stored in a Set
391
+ * - Events are broadcast to ALL connected clients on every file change
392
+ * - Keepalive ping every 15 seconds to detect disconnected clients
393
+ */
394
+ 'use strict';
395
+
396
+ const fs = require('fs');
397
+ const path = require('path');
398
+
399
+ const AUDIT_PATH = path.join(process.cwd(), '.planning', 'AUDIT.jsonl');
400
+ const AUTO_STATE_PATH = path.join(process.cwd(), '.planning', 'auto-state.json');
401
+ const APPROVAL_DIR = path.join(process.cwd(), '.planning', 'approvals');
402
+
403
+ const clients = new Set(); // Connected SSE response objects
404
+
405
+ let _lastAuditSize = 0;
406
+ let _lastAutoState = '';
407
+ let _lastApprovals = '';
408
+
409
+ // ── Client management ─────────────────────────────────────────────────────────
410
+
411
+ function addClient(res) {
412
+ clients.add(res);
413
+ res.on('close', () => {
414
+ clients.delete(res);
415
+ });
416
+ }
417
+
418
+ function broadcast(eventName, data) {
419
+ const message = `event: ${eventName}\ndata: ${JSON.stringify(data)}\n\n`;
420
+ for (const res of clients) {
421
+ try {
422
+ res.write(message);
423
+ } catch {
424
+ clients.delete(res);
425
+ }
426
+ }
427
+ }
428
+
429
+ function broadcastRaw(message) {
430
+ for (const res of clients) {
431
+ try {
432
+ res.write(message);
433
+ } catch {
434
+ clients.delete(res);
435
+ }
436
+ }
437
+ }
438
+
439
+ // ── File tail: AUDIT.jsonl ────────────────────────────────────────────────────
440
+
441
+ function pollAuditLog() {
442
+ if (!fs.existsSync(AUDIT_PATH)) return;
443
+
444
+ try {
445
+ const stat = fs.statSync(AUDIT_PATH);
446
+ const newSize = stat.size;
447
+
448
+ if (newSize <= _lastAuditSize) return; // No new data
449
+
450
+ // Read only the new bytes appended since last poll
451
+ const fd = fs.openSync(AUDIT_PATH, 'r');
452
+ const chunk = Buffer.alloc(newSize - _lastAuditSize);
453
+ fs.readSync(fd, chunk, 0, chunk.length, _lastAuditSize);
454
+ fs.closeSync(fd);
455
+ _lastAuditSize = newSize;
456
+
457
+ // Parse new lines
458
+ const newLines = chunk.toString().split('\n').filter(Boolean);
459
+ for (const line of newLines) {
460
+ try {
461
+ const entry = JSON.parse(line);
462
+ broadcast('audit:new', entry);
463
+ } catch { /* skip malformed */ }
464
+ }
465
+ } catch { /* ignore read errors — file may be locked */ }
466
+ }
467
+
468
+ // ── File poll: auto-state.json ────────────────────────────────────────────────
469
+
470
+ function pollAutoState() {
471
+ if (!fs.existsSync(AUTO_STATE_PATH)) return;
472
+
473
+ try {
474
+ const raw = fs.readFileSync(AUTO_STATE_PATH, 'utf8');
475
+ if (raw === _lastAutoState) return;
476
+ _lastAutoState = raw;
477
+ const state = JSON.parse(raw);
478
+ broadcast('status:update', state);
479
+ } catch { /* ignore */ }
480
+ }
481
+
482
+ // ── File poll: approval directory ─────────────────────────────────────────────
483
+
484
+ function pollApprovals() {
485
+ if (!fs.existsSync(APPROVAL_DIR)) return;
486
+
487
+ try {
488
+ const files = fs.readdirSync(APPROVAL_DIR)
489
+ .filter(f => f.startsWith('APPROVAL-') && f.endsWith('.json'))
490
+ .sort();
491
+ const key = files.join(',');
492
+ if (key === _lastApprovals) return;
493
+ _lastApprovals = key;
494
+
495
+ // Find new pending approvals
496
+ for (const f of files) {
497
+ try {
498
+ const data = JSON.parse(fs.readFileSync(path.join(APPROVAL_DIR, f), 'utf8'));
499
+ if (data.status === 'pending') {
500
+ broadcast('approval:new', data);
501
+ }
502
+ } catch { /* skip */ }
503
+ }
504
+ } catch { /* ignore */ }
505
+ }
506
+
507
+ // ── Keepalive ─────────────────────────────────────────────────────────────────
508
+
509
+ let _pollInterval = null;
510
+ let _pingInterval = null;
511
+
512
+ function start() {
513
+ // Initialize AUDIT position
514
+ if (fs.existsSync(AUDIT_PATH)) {
515
+ _lastAuditSize = fs.statSync(AUDIT_PATH).size;
516
+ }
517
+
518
+ // Poll every 2 seconds
519
+ _pollInterval = setInterval(() => {
520
+ pollAuditLog();
521
+ pollAutoState();
522
+ pollApprovals();
523
+ }, 2000);
524
+
525
+ // Keepalive ping every 15 seconds
526
+ _pingInterval = setInterval(() => {
527
+ broadcastRaw(`: ping\n\n`);
528
+ }, 15_000);
529
+
530
+ _pollInterval.unref();
531
+ _pingInterval.unref();
532
+ }
533
+
534
+ function stop() {
535
+ if (_pollInterval) { clearInterval(_pollInterval); _pollInterval = null; }
536
+ if (_pingInterval) { clearInterval(_pingInterval); _pingInterval = null; }
537
+ }
538
+
539
+ function getClientCount() { return clients.size; }
540
+
541
+ module.exports = { addClient, broadcast, start, stop, getClientCount };
542
+ ```
543
+
544
+ **Commit:**
545
+ ```bash
546
+ git add bin/dashboard/sse-bridge.js
547
+ git commit -m "feat(v2-dashboard): implement SSE event bridge with AUDIT/state/approval tailing"
548
+ ```
549
+
550
+ ---
551
+
552
+ ## TASK 4 — Implement the Metrics Aggregator
553
+
554
+ ### `bin/dashboard/metrics-aggregator.js`
555
+
556
+ ```javascript
557
+ /**
558
+ * MindForge v2 — Metrics Aggregator
559
+ * Reads .mindforge/metrics/ and .planning/ files and produces
560
+ * structured metrics for the dashboard API.
561
+ */
562
+ 'use strict';
563
+
564
+ const fs = require('fs');
565
+ const path = require('path');
566
+
567
+ const QUALITY_LOG = path.join(process.cwd(), '.mindforge', 'metrics', 'session-quality.jsonl');
568
+ const USAGE_LOG = path.join(process.cwd(), '.mindforge', 'metrics', 'token-usage.jsonl');
569
+ const AUDIT_PATH = path.join(process.cwd(), '.planning', 'AUDIT.jsonl');
570
+ const HANDOFF_PATH = path.join(process.cwd(), '.planning', 'HANDOFF.json');
571
+ const AUTO_STATE = path.join(process.cwd(), '.planning', 'auto-state.json');
572
+ const APPROVAL_DIR = path.join(process.cwd(), '.planning', 'approvals');
573
+ const TEAM_STATE = path.join(process.cwd(), '.planning', 'TEAM-STATE.jsonl');
574
+ const KB_PATH = path.join(process.cwd(), '.mindforge', 'memory', 'knowledge-base.jsonl');
575
+
576
+ function readJSONL(filePath, limit = 500) {
577
+ if (!fs.existsSync(filePath)) return [];
578
+ return fs.readFileSync(filePath, 'utf8')
579
+ .split('\n').filter(Boolean).slice(-limit)
580
+ .map(l => { try { return JSON.parse(l); } catch { return null; } })
581
+ .filter(Boolean);
582
+ }
583
+
584
+ function readJSON(filePath) {
585
+ if (!fs.existsSync(filePath)) return null;
586
+ try { return JSON.parse(fs.readFileSync(filePath, 'utf8')); } catch { return null; }
587
+ }
588
+
589
+ // ── Status ────────────────────────────────────────────────────────────────────
590
+ function getStatus() {
591
+ const handoff = readJSON(HANDOFF_PATH);
592
+ const autoState = readJSON(AUTO_STATE);
593
+
594
+ // Read project name from PROJECT.md
595
+ let projectName = 'MindForge Project';
596
+ const projectMd = path.join(process.cwd(), '.planning', 'PROJECT.md');
597
+ if (fs.existsSync(projectMd)) {
598
+ const m = fs.readFileSync(projectMd, 'utf8').match(/^# (.+)/m);
599
+ if (m) projectName = m[1].trim();
600
+ }
601
+
602
+ return {
603
+ project_name: projectName,
604
+ phase: handoff?.current_phase ?? null,
605
+ phase_description: handoff?.phase_description ?? null,
606
+ auto_mode: autoState?.auto_mode_active ?? false,
607
+ auto_status: autoState?.status ?? 'idle',
608
+ current_task: autoState?.current_task ?? handoff?.next_task ?? null,
609
+ wave_current: autoState?.wave_current ?? null,
610
+ wave_total: autoState?.wave_total ?? null,
611
+ tasks_completed: autoState?.tasks_completed ?? null,
612
+ tasks_total: autoState?.tasks_total ?? null,
613
+ elapsed_ms: autoState?.elapsed_ms ?? null,
614
+ node_repairs: autoState?.node_repairs ?? 0,
615
+ escalations: autoState?.escalations ?? 0,
616
+ last_commit: autoState?.last_commit ?? null,
617
+ last_event_at: handoff?.last_updated ?? null,
618
+ schema_version: handoff?.schema_version ?? null,
619
+ };
620
+ }
621
+
622
+ // ── Audit ─────────────────────────────────────────────────────────────────────
623
+ function getAuditEntries(limit = 50, offset = 0, eventFilter = null) {
624
+ const all = readJSONL(AUDIT_PATH, 1000);
625
+ const reversed = all.reverse(); // Newest first
626
+
627
+ const filtered = eventFilter
628
+ ? reversed.filter(e => e.event === eventFilter)
629
+ : reversed;
630
+
631
+ return {
632
+ entries: filtered.slice(offset, offset + limit),
633
+ total: filtered.length,
634
+ limit,
635
+ offset,
636
+ };
637
+ }
638
+
639
+ // ── Metrics ───────────────────────────────────────────────────────────────────
640
+ function getMetrics() {
641
+ const qualityEntries = readJSONL(QUALITY_LOG, 20);
642
+ const usageEntries = readJSONL(USAGE_LOG, 200);
643
+ const auditEntries = readJSONL(AUDIT_PATH, 500);
644
+
645
+ // Quality scores (last 20 sessions)
646
+ const sessions = qualityEntries.map(e => ({
647
+ id: e.session_id,
648
+ timestamp: e.timestamp,
649
+ quality_score: e.quality_score ?? 0,
650
+ verify_pass_rate: e.verify_pass_rate ?? 0,
651
+ cost_usd: e.total_cost_usd ?? 0,
652
+ node_repairs: e.node_repairs ?? 0,
653
+ }));
654
+
655
+ const avg_quality = sessions.length
656
+ ? sessions.reduce((s, e) => s + e.quality_score, 0) / sessions.length : 0;
657
+ const avg_cost_usd = sessions.length
658
+ ? sessions.reduce((s, e) => s + e.cost_usd, 0) / sessions.length : 0;
659
+
660
+ // Security findings from AUDIT
661
+ const securityFindings = { CRITICAL: 0, HIGH: 0, MEDIUM: 0, LOW: 0 };
662
+ auditEntries
663
+ .filter(e => e.event === 'security_finding')
664
+ .forEach(e => {
665
+ const sev = e.severity || 'LOW';
666
+ securityFindings[sev] = (securityFindings[sev] || 0) + 1;
667
+ });
668
+
669
+ // Node repair rate
670
+ const taskEvents = auditEntries.filter(e => e.event === 'task_completed' || e.event === 'task_failed');
671
+ const repairEvents = auditEntries.filter(e => e.event === 'node_repair');
672
+ const node_repair_rate = taskEvents.length
673
+ ? repairEvents.length / taskEvents.length : 0;
674
+
675
+ return {
676
+ sessions,
677
+ avg_quality: Math.round(avg_quality * 100) / 100,
678
+ avg_cost_usd: Math.round(avg_cost_usd * 10000) / 10000,
679
+ security_findings: securityFindings,
680
+ node_repair_rate: Math.round(node_repair_rate * 100) / 100,
681
+ total_tasks: taskEvents.filter(e => e.event === 'task_completed').length,
682
+ };
683
+ }
684
+
685
+ // ── Approvals ─────────────────────────────────────────────────────────────────
686
+ function getApprovals() {
687
+ if (!fs.existsSync(APPROVAL_DIR)) return { pending: [], approved: [], rejected: [], expired: [] };
688
+
689
+ const now = Date.now();
690
+ const files = fs.readdirSync(APPROVAL_DIR)
691
+ .filter(f => f.startsWith('APPROVAL-') && f.endsWith('.json'))
692
+ .sort();
693
+
694
+ const pending = [];
695
+ const approved = [];
696
+ const rejected = [];
697
+ const expired = [];
698
+
699
+ for (const f of files) {
700
+ try {
701
+ const data = JSON.parse(fs.readFileSync(path.join(APPROVAL_DIR, f), 'utf8'));
702
+ const expiry = data.expires_at ? new Date(data.expires_at).getTime() : Infinity;
703
+ const hoursRemaining = expiry === Infinity ? null : (expiry - now) / 3_600_000;
704
+
705
+ const enriched = { ...data, hours_remaining: hoursRemaining };
706
+
707
+ if (data.status === 'approved') approved.push(enriched);
708
+ else if (data.status === 'rejected') rejected.push(enriched);
709
+ else if (expiry < now) expired.push({ ...enriched, status: 'expired' });
710
+ else pending.push(enriched);
711
+ } catch { /* skip corrupt files */ }
712
+ }
713
+
714
+ return { pending, approved, rejected, expired };
715
+ }
716
+
717
+ // ── Team activity ─────────────────────────────────────────────────────────────
718
+ function getTeamActivity() {
719
+ const auditEntries = readJSONL(AUDIT_PATH, 200);
720
+
721
+ // Group by author (git email from session_id or authored_by field)
722
+ const byAuthor = {};
723
+ for (const entry of auditEntries) {
724
+ const author = entry.authored_by || entry.session_id || 'unknown';
725
+ if (!byAuthor[author] || entry.timestamp > byAuthor[author].last_seen) {
726
+ byAuthor[author] = {
727
+ email: author,
728
+ last_seen: entry.timestamp,
729
+ current_task: entry.plan ? `Plan ${entry.phase}-${entry.plan}` : null,
730
+ event: entry.event,
731
+ };
732
+ }
733
+ }
734
+
735
+ const now = Date.now();
736
+ const active = Object.values(byAuthor)
737
+ .map(a => ({
738
+ ...a,
739
+ last_seen_mins: Math.round((now - new Date(a.last_seen).getTime()) / 60_000),
740
+ }))
741
+ .filter(a => a.last_seen_mins < 120) // Active in last 2 hours
742
+ .sort((a, b) => a.last_seen_mins - b.last_seen_mins);
743
+
744
+ // Conflict detection — two authors recently touching same file
745
+ const conflicts = detectFileConflicts(auditEntries);
746
+
747
+ return { active, conflicts };
748
+ }
749
+
750
+ function detectFileConflicts(auditEntries) {
751
+ const fileToAuthors = {};
752
+
753
+ for (const entry of auditEntries.slice(-100)) {
754
+ if (!entry.files_modified) continue;
755
+ const author = entry.authored_by || entry.session_id;
756
+ if (!author) continue;
757
+
758
+ const files = Array.isArray(entry.files_modified) ? entry.files_modified : [entry.files_modified];
759
+ for (const f of files) {
760
+ if (!fileToAuthors[f]) fileToAuthors[f] = new Set();
761
+ fileToAuthors[f].add(author);
762
+ }
763
+ }
764
+
765
+ return Object.entries(fileToAuthors)
766
+ .filter(([, authors]) => authors.size > 1)
767
+ .map(([file, authors]) => ({ file, developers: [...authors] }));
768
+ }
769
+
770
+ // ── Memory ────────────────────────────────────────────────────────────────────
771
+ function getMemory(query = '', limit = 20) {
772
+ if (!fs.existsSync(KB_PATH)) return { entries: [], total: 0 };
773
+
774
+ const lines = fs.readFileSync(KB_PATH, 'utf8').split('\n').filter(Boolean);
775
+ const byId = new Map();
776
+ for (const l of lines) {
777
+ try { const e = JSON.parse(l); byId.set(e.id, e); } catch { /* skip */ }
778
+ }
779
+
780
+ let entries = [...byId.values()].filter(e => !e.deprecated);
781
+
782
+ if (query) {
783
+ const q = query.toLowerCase();
784
+ entries = entries.filter(e =>
785
+ e.topic.toLowerCase().includes(q) ||
786
+ e.content.toLowerCase().includes(q) ||
787
+ (e.tags || []).some(t => t.toLowerCase().includes(q))
788
+ );
789
+ }
790
+
791
+ entries.sort((a, b) => b.confidence - a.confidence);
792
+
793
+ return { entries: entries.slice(0, limit), total: entries.length };
794
+ }
795
+
796
+ // ── Costs ─────────────────────────────────────────────────────────────────────
797
+ function getCosts(windowDays = 7) {
798
+ const entries = readJSONL(USAGE_LOG, 1000);
799
+ const cutoff = new Date(Date.now() - windowDays * 86_400_000).toISOString().slice(0, 10);
800
+ const today = new Date().toISOString().slice(0, 10);
801
+
802
+ const filtered = entries.filter(e => e.date >= cutoff);
803
+ const todayItems = entries.filter(e => e.date === today);
804
+
805
+ const total_usd = filtered.reduce((s, e) => s + (e.cost_usd || 0), 0);
806
+ const today_usd = todayItems.reduce((s, e) => s + (e.cost_usd || 0), 0);
807
+
808
+ const by_model = {};
809
+ for (const e of filtered) {
810
+ const m = e.model || 'unknown';
811
+ by_model[m] = (by_model[m] || 0) + (e.cost_usd || 0);
812
+ }
813
+
814
+ // Read daily limit from MINDFORGE.md
815
+ let daily_limit = 0;
816
+ const mmPath = path.join(process.cwd(), 'MINDFORGE.md');
817
+ if (fs.existsSync(mmPath)) {
818
+ const match = fs.readFileSync(mmPath, 'utf8').match(/^MODEL_COST_HARD_LIMIT_USD=(.+)$/m);
819
+ if (match) daily_limit = parseFloat(match[1]);
820
+ }
821
+
822
+ return {
823
+ total_usd: Math.round(total_usd * 10000) / 10000,
824
+ today_usd: Math.round(today_usd * 10000) / 10000,
825
+ by_model,
826
+ window_days: windowDays,
827
+ daily_limit_usd: daily_limit,
828
+ limit_used_pct: daily_limit > 0 ? Math.round((today_usd / daily_limit) * 100) : null,
829
+ };
830
+ }
831
+
832
+ module.exports = { getStatus, getAuditEntries, getMetrics, getApprovals, getTeamActivity, getMemory, getCosts };
833
+ ```
834
+
835
+ **Commit:**
836
+ ```bash
837
+ git add bin/dashboard/metrics-aggregator.js
838
+ git commit -m "feat(v2-dashboard): implement metrics aggregator for all 7 API data sources"
839
+ ```
840
+
841
+ ---
842
+
843
+ ## TASK 5 — Implement the Approval Handler
844
+
845
+ ### `bin/dashboard/approval-handler.js`
846
+
847
+ ```javascript
848
+ /**
849
+ * MindForge v2 — Approval Handler
850
+ * Handles POST /api/approve/:id — approve or reject governance requests.
851
+ * Reads/writes APPROVAL-*.json files in .planning/approvals/
852
+ */
853
+ 'use strict';
854
+
855
+ const fs = require('fs');
856
+ const path = require('path');
857
+
858
+ const APPROVAL_DIR = path.join(process.cwd(), '.planning', 'approvals');
859
+ const AUDIT_PATH = path.join(process.cwd(), '.planning', 'AUDIT.jsonl');
860
+
861
+ /**
862
+ * Process an approval decision from the dashboard.
863
+ * @param {string} approvalId - The APPROVAL UUID
864
+ * @param {string} decision - 'approve' or 'reject'
865
+ * @param {string} comment - Optional comment
866
+ * @param {string} approver - Approver identifier (email or name)
867
+ * @returns {{ success, decision, message }}
868
+ */
869
+ function processDecision(approvalId, decision, comment, approver) {
870
+ // Input validation
871
+ if (!approvalId || typeof approvalId !== 'string') {
872
+ return { success: false, error: 'Invalid approval ID' };
873
+ }
874
+
875
+ // Sanitize approvalId — only allow UUID characters
876
+ if (!/^[a-f0-9-]{36}$/.test(approvalId)) {
877
+ return { success: false, error: 'Malformed approval ID format' };
878
+ }
879
+
880
+ if (!['approve', 'reject'].includes(decision)) {
881
+ return { success: false, error: 'Decision must be "approve" or "reject"' };
882
+ }
883
+
884
+ // Find the approval file
885
+ const filePath = path.join(APPROVAL_DIR, `APPROVAL-${approvalId}.json`);
886
+ if (!fs.existsSync(filePath)) {
887
+ return { success: false, error: `Approval not found: ${approvalId}` };
888
+ }
889
+
890
+ let approval;
891
+ try {
892
+ approval = JSON.parse(fs.readFileSync(filePath, 'utf8'));
893
+ } catch {
894
+ return { success: false, error: 'Cannot parse approval file' };
895
+ }
896
+
897
+ // Validate approval is still pending
898
+ if (approval.status !== 'pending') {
899
+ return { success: false, error: `Approval already ${approval.status}` };
900
+ }
901
+
902
+ // Check expiry
903
+ if (approval.expires_at && new Date(approval.expires_at) < new Date()) {
904
+ return { success: false, error: 'Approval has expired' };
905
+ }
906
+
907
+ // Update approval file
908
+ const updated = {
909
+ ...approval,
910
+ status: decision === 'approve' ? 'approved' : 'rejected',
911
+ resolved_at: new Date().toISOString(),
912
+ resolved_by: approver || 'dashboard',
913
+ comment: comment || null,
914
+ resolution_channel: 'mindforge-dashboard',
915
+ };
916
+
917
+ fs.writeFileSync(filePath, JSON.stringify(updated, null, 2));
918
+
919
+ // Write AUDIT entry
920
+ writeAuditEntry({
921
+ id: require('crypto').randomBytes(8).toString('hex'),
922
+ timestamp: new Date().toISOString(),
923
+ event: decision === 'approve' ? 'approval_granted' : 'approval_rejected',
924
+ approval_id: approvalId,
925
+ tier: approval.tier,
926
+ phase: approval.phase,
927
+ plan: approval.plan,
928
+ resolved_by: approver || 'dashboard',
929
+ comment: comment || null,
930
+ agent: 'mindforge-dashboard',
931
+ session_id: 'dashboard',
932
+ });
933
+
934
+ return {
935
+ success: true,
936
+ decision,
937
+ approval_id: approvalId,
938
+ tier: approval.tier,
939
+ message: `${approval.tier === 3 ? 'Tier 3' : 'Tier 2'} approval ${decision}d for Plan ${approval.phase}-${approval.plan}`,
940
+ };
941
+ }
942
+
943
+ function writeAuditEntry(entry) {
944
+ try {
945
+ if (!fs.existsSync(path.dirname(AUDIT_PATH))) return;
946
+ fs.appendFileSync(AUDIT_PATH, JSON.stringify(entry) + '\n');
947
+ } catch { /* ignore AUDIT write failures */ }
948
+ }
949
+
950
+ function listApprovals() {
951
+ if (!fs.existsSync(APPROVAL_DIR)) return [];
952
+ return fs.readdirSync(APPROVAL_DIR)
953
+ .filter(f => f.startsWith('APPROVAL-') && f.endsWith('.json'))
954
+ .map(f => {
955
+ try { return JSON.parse(fs.readFileSync(path.join(APPROVAL_DIR, f), 'utf8')); }
956
+ catch { return null; }
957
+ })
958
+ .filter(Boolean);
959
+ }
960
+
961
+ module.exports = { processDecision, listApprovals };
962
+ ```
963
+
964
+ **Commit:**
965
+ ```bash
966
+ git add bin/dashboard/approval-handler.js
967
+ git commit -m "feat(v2-dashboard): implement approval handler with UUID validation and AUDIT trail"
968
+ ```
969
+
970
+ ---
971
+
972
+ ## TASK 6 — Implement the Dashboard API Router
973
+
974
+ ### `bin/dashboard/api-router.js`
975
+
976
+ ```javascript
977
+ /**
978
+ * MindForge v2 — Dashboard API Router
979
+ * All REST endpoints for the dashboard.
980
+ */
981
+ 'use strict';
982
+
983
+ const path = require('path');
984
+ const fs = require('fs');
985
+ const Metrics = require('./metrics-aggregator');
986
+ const Approval = require('./approval-handler');
987
+ const SSE = require('./sse-bridge');
988
+
989
+ // Steering queue path (from Day 8 auto-executor)
990
+ const STEERING_QUEUE = path.join(process.cwd(), '.planning', 'steering-queue.jsonl');
991
+ const AUTO_STATE_PATH = path.join(process.cwd(), '.planning', 'auto-state.json');
992
+
993
+ function register(app) {
994
+
995
+ // ── SSE stream ──────────────────────────────────────────────────────────────
996
+ app.get('/events', (req, res) => {
997
+ res.setHeader('Content-Type', 'text/event-stream');
998
+ res.setHeader('Cache-Control', 'no-cache');
999
+ res.setHeader('Connection', 'keep-alive');
1000
+ res.setHeader('X-Accel-Buffering', 'no'); // Disable Nginx buffering
1001
+ res.flushHeaders();
1002
+
1003
+ // Send current status immediately on connect
1004
+ try {
1005
+ const status = Metrics.getStatus();
1006
+ res.write(`event: status:update\ndata: ${JSON.stringify(status)}\n\n`);
1007
+ } catch { /* ignore */ }
1008
+
1009
+ SSE.addClient(res);
1010
+ });
1011
+
1012
+ // ── Status ──────────────────────────────────────────────────────────────────
1013
+ app.get('/api/status', (req, res) => {
1014
+ try {
1015
+ res.json(Metrics.getStatus());
1016
+ } catch (err) {
1017
+ res.status(500).json({ error: err.message });
1018
+ }
1019
+ });
1020
+
1021
+ // ── Audit entries ───────────────────────────────────────────────────────────
1022
+ app.get('/api/audit', (req, res) => {
1023
+ try {
1024
+ const limit = Math.min(parseInt(req.query.limit || '50', 10), 200);
1025
+ const offset = Math.max(parseInt(req.query.offset || '0', 10), 0);
1026
+ const event = typeof req.query.event === 'string' ? req.query.event : null;
1027
+ res.json(Metrics.getAuditEntries(limit, offset, event));
1028
+ } catch (err) {
1029
+ res.status(500).json({ error: err.message });
1030
+ }
1031
+ });
1032
+
1033
+ // ── Quality metrics ─────────────────────────────────────────────────────────
1034
+ app.get('/api/metrics', (req, res) => {
1035
+ try {
1036
+ res.json(Metrics.getMetrics());
1037
+ } catch (err) {
1038
+ res.status(500).json({ error: err.message });
1039
+ }
1040
+ });
1041
+
1042
+ // ── Approvals ───────────────────────────────────────────────────────────────
1043
+ app.get('/api/approvals', (req, res) => {
1044
+ try {
1045
+ res.json(Metrics.getApprovals());
1046
+ } catch (err) {
1047
+ res.status(500).json({ error: err.message });
1048
+ }
1049
+ });
1050
+
1051
+ app.post('/api/approve/:id', (req, res) => {
1052
+ try {
1053
+ const { id } = req.params;
1054
+ const { decision, comment, approver } = req.body || {};
1055
+
1056
+ if (!decision) {
1057
+ return res.status(400).json({ error: 'Missing "decision" field (approve|reject)' });
1058
+ }
1059
+
1060
+ const result = Approval.processDecision(id, decision, comment, approver);
1061
+
1062
+ if (!result.success) {
1063
+ return res.status(400).json(result);
1064
+ }
1065
+
1066
+ // Broadcast approval event to all SSE clients
1067
+ SSE.broadcast(
1068
+ decision === 'approve' ? 'approval:resolved' : 'approval:resolved',
1069
+ { approval_id: id, decision, message: result.message }
1070
+ );
1071
+
1072
+ res.json(result);
1073
+ } catch (err) {
1074
+ res.status(500).json({ error: err.message });
1075
+ }
1076
+ });
1077
+
1078
+ // ── Team activity ───────────────────────────────────────────────────────────
1079
+ app.get('/api/team', (req, res) => {
1080
+ try {
1081
+ res.json(Metrics.getTeamActivity());
1082
+ } catch (err) {
1083
+ res.status(500).json({ error: err.message });
1084
+ }
1085
+ });
1086
+
1087
+ // ── Knowledge base query ────────────────────────────────────────────────────
1088
+ app.get('/api/memory', (req, res) => {
1089
+ try {
1090
+ const q = typeof req.query.q === 'string' ? req.query.q.slice(0, 100) : '';
1091
+ const limit = Math.min(parseInt(req.query.limit || '20', 10), 100);
1092
+ res.json(Metrics.getMemory(q, limit));
1093
+ } catch (err) {
1094
+ res.status(500).json({ error: err.message });
1095
+ }
1096
+ });
1097
+
1098
+ // ── Costs ───────────────────────────────────────────────────────────────────
1099
+ app.get('/api/costs', (req, res) => {
1100
+ try {
1101
+ const window = Math.min(parseInt(req.query.window || '7', 10), 90);
1102
+ res.json(Metrics.getCosts(window));
1103
+ } catch (err) {
1104
+ res.status(500).json({ error: err.message });
1105
+ }
1106
+ });
1107
+
1108
+ // ── Steering (requires auto mode running) ───────────────────────────────────
1109
+ app.post('/api/steer', (req, res) => {
1110
+ try {
1111
+ const { instruction, priority = 'normal' } = req.body || {};
1112
+
1113
+ if (!instruction || typeof instruction !== 'string') {
1114
+ return res.status(400).json({ error: 'Missing "instruction" field' });
1115
+ }
1116
+ if (instruction.length > 500) {
1117
+ return res.status(400).json({ error: 'Instruction too long (max 500 chars)' });
1118
+ }
1119
+ if (!['normal', 'urgent', 'stop'].includes(priority)) {
1120
+ return res.status(400).json({ error: 'Invalid priority. Use: normal|urgent|stop' });
1121
+ }
1122
+
1123
+ // Check auto mode is running
1124
+ const autoState = fs.existsSync(AUTO_STATE_PATH)
1125
+ ? JSON.parse(fs.readFileSync(AUTO_STATE_PATH, 'utf8'))
1126
+ : null;
1127
+
1128
+ if (!autoState || autoState.status !== 'running') {
1129
+ return res.status(409).json({ error: 'Auto mode is not running. Steering has no effect.' });
1130
+ }
1131
+
1132
+ // Run injection guard
1133
+ const INJECTION_PATTERNS = [
1134
+ /IGNORE ALL PREVIOUS INSTRUCTIONS/i,
1135
+ /DISREGARD YOUR INSTRUCTIONS/i,
1136
+ /FORGET YOUR TRAINING/i,
1137
+ /YOUR NEW INSTRUCTIONS ARE/i,
1138
+ /OVERRIDE:/i,
1139
+ ];
1140
+ if (INJECTION_PATTERNS.some(p => p.test(instruction))) {
1141
+ return res.status(400).json({ error: 'Instruction rejected: contains prohibited patterns' });
1142
+ }
1143
+
1144
+ // Write to steering queue
1145
+ const entry = {
1146
+ id: require('crypto').randomBytes(8).toString('hex'),
1147
+ timestamp: new Date().toISOString(),
1148
+ instruction: instruction.trim(),
1149
+ priority,
1150
+ authored_by: 'dashboard',
1151
+ applies_to: 'all',
1152
+ status: 'queued',
1153
+ applied_at: null,
1154
+ applied_to_plan: null,
1155
+ };
1156
+
1157
+ if (!fs.existsSync(path.dirname(STEERING_QUEUE))) {
1158
+ fs.mkdirSync(path.dirname(STEERING_QUEUE), { recursive: true });
1159
+ }
1160
+ fs.appendFileSync(STEERING_QUEUE, JSON.stringify(entry) + '\n');
1161
+
1162
+ res.json({ success: true, queued: true, id: entry.id, priority });
1163
+ } catch (err) {
1164
+ res.status(500).json({ error: err.message });
1165
+ }
1166
+ });
1167
+
1168
+ // ── Client count (for dashboard connection indicator) ───────────────────────
1169
+ app.get('/api/connections', (req, res) => {
1170
+ res.json({ clients: SSE.getClientCount() });
1171
+ });
1172
+ }
1173
+
1174
+ module.exports = { register };
1175
+ ```
1176
+
1177
+ **Commit:**
1178
+ ```bash
1179
+ git add bin/dashboard/api-router.js
1180
+ git commit -m "feat(v2-dashboard): implement dashboard API router with all 10 endpoints"
1181
+ ```
1182
+
1183
+ ---
1184
+
1185
+ ## TASK 7 — Implement the Dashboard Server
1186
+
1187
+ ### `bin/dashboard/server.js`
1188
+
1189
+ ```javascript
1190
+ #!/usr/bin/env node
1191
+ /**
1192
+ * MindForge v2 — Dashboard Server
1193
+ * Real-time web observability at localhost:7339.
1194
+ *
1195
+ * Usage:
1196
+ * node bin/dashboard/server.js [--port 7339] [--open]
1197
+ * /mindforge:dashboard [--port 7339] [--open] [--stop]
1198
+ *
1199
+ * Security: binds to 127.0.0.1 only (ADR-017 policy).
1200
+ * No authentication — localhost-only access is the security model.
1201
+ */
1202
+ 'use strict';
1203
+
1204
+ const http = require('http');
1205
+ const path = require('path');
1206
+ const fs = require('fs');
1207
+ const ARGS = process.argv.slice(2);
1208
+
1209
+ const PORT = parseInt(ARGS.find((_, i, a) => a[i-1] === '--port') || '7339', 10);
1210
+ const OPEN_BROWSER = ARGS.includes('--open');
1211
+ const PID_FILE = path.join(process.cwd(), '.planning', 'dashboard-server.pid');
1212
+ const FRONTEND = path.join(__dirname, 'frontend', 'index.html');
1213
+
1214
+ // ── Load dependencies gracefully ──────────────────────────────────────────────
1215
+ let express;
1216
+ try {
1217
+ express = require('express');
1218
+ } catch {
1219
+ console.error('[dashboard] express not installed. Run: npm install express');
1220
+ process.exit(1);
1221
+ }
1222
+
1223
+ const SSE = require('./sse-bridge');
1224
+ const API = require('./api-router');
1225
+
1226
+ // ── Express app ───────────────────────────────────────────────────────────────
1227
+ const app = express();
1228
+
1229
+ // Security middleware
1230
+ app.use((req, res, next) => {
1231
+ const addr = req.socket.remoteAddress;
1232
+ const isLocal = addr === '127.0.0.1' || addr === '::1' || addr === '::ffff:127.0.0.1';
1233
+ if (!isLocal) {
1234
+ return res.status(403).json({ error: 'Dashboard is localhost-only' });
1235
+ }
1236
+ next();
1237
+ });
1238
+
1239
+ // CORS — only allow requests from localhost origins
1240
+ app.use((req, res, next) => {
1241
+ const origin = req.headers.origin;
1242
+ if (!origin || /^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/.test(origin)) {
1243
+ res.setHeader('Access-Control-Allow-Origin', origin || '*');
1244
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
1245
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
1246
+ }
1247
+ if (req.method === 'OPTIONS') return res.status(204).end();
1248
+ next();
1249
+ });
1250
+
1251
+ app.use(express.json({ limit: '64kb' })); // Limit request body size
1252
+
1253
+ // Security headers
1254
+ app.use((req, res, next) => {
1255
+ res.setHeader('X-Content-Type-Options', 'nosniff');
1256
+ res.setHeader('X-Frame-Options', 'SAMEORIGIN');
1257
+ res.setHeader('Cache-Control', 'no-store'); // Never cache dashboard responses
1258
+ next();
1259
+ });
1260
+
1261
+ // ── Static frontend ───────────────────────────────────────────────────────────
1262
+ app.get('/', (req, res) => {
1263
+ if (!fs.existsSync(FRONTEND)) {
1264
+ return res.status(503).send('<h1>Dashboard frontend not found</h1><p>Run: npm run build:dashboard</p>');
1265
+ }
1266
+ res.sendFile(FRONTEND);
1267
+ });
1268
+
1269
+ // ── Register API routes ───────────────────────────────────────────────────────
1270
+ API.register(app);
1271
+
1272
+ // ── Start SSE bridge ──────────────────────────────────────────────────────────
1273
+ SSE.start();
1274
+
1275
+ // ── HTTP server ───────────────────────────────────────────────────────────────
1276
+ const server = http.createServer(app);
1277
+
1278
+ server.listen(PORT, '127.0.0.1', () => {
1279
+ fs.mkdirSync(path.dirname(PID_FILE), { recursive: true });
1280
+ fs.writeFileSync(PID_FILE, String(process.pid));
1281
+
1282
+ console.log(`\n⚡ MindForge Dashboard`);
1283
+ console.log(` URL: http://localhost:${PORT}`);
1284
+ console.log(` Status: http://localhost:${PORT}/api/status`);
1285
+ console.log(` Events: http://localhost:${PORT}/events`);
1286
+ console.log(` PID: ${process.pid}`);
1287
+ console.log(`\n Press CTRL+C to stop\n`);
1288
+
1289
+ if (OPEN_BROWSER) {
1290
+ const open = process.platform === 'darwin' ? 'open'
1291
+ : process.platform === 'win32' ? 'start'
1292
+ : 'xdg-open';
1293
+ require('child_process').spawn(open, [`http://localhost:${PORT}`], { detached: true, stdio: 'ignore' });
1294
+ }
1295
+ });
1296
+
1297
+ server.on('error', err => {
1298
+ if (err.code === 'EADDRINUSE') {
1299
+ console.error(`[dashboard] Port ${PORT} already in use.`);
1300
+ console.error(`[dashboard] Stop it: /mindforge:dashboard --stop`);
1301
+ console.error(`[dashboard] Or use a different port: /mindforge:dashboard --port 7340`);
1302
+ }
1303
+ process.exit(1);
1304
+ });
1305
+
1306
+ // ── Graceful shutdown ─────────────────────────────────────────────────────────
1307
+ function shutdown(signal) {
1308
+ console.log(`\n[dashboard] ${signal} received — shutting down`);
1309
+ SSE.stop();
1310
+ server.close(() => {
1311
+ if (fs.existsSync(PID_FILE)) fs.unlinkSync(PID_FILE);
1312
+ process.exit(0);
1313
+ });
1314
+ setTimeout(() => process.exit(0), 3000);
1315
+ }
1316
+
1317
+ process.on('SIGTERM', () => shutdown('SIGTERM'));
1318
+ process.on('SIGINT', () => shutdown('SIGINT'));
1319
+ ```
1320
+
1321
+ **Commit:**
1322
+ ```bash
1323
+ git add bin/dashboard/server.js
1324
+ git commit -m "feat(v2-dashboard): implement Express dashboard server with security middleware and graceful shutdown"
1325
+ ```
1326
+
1327
+ ---
1328
+
1329
+ ## TASK 8 — Build the Single-File HTML Frontend
1330
+
1331
+ ### `bin/dashboard/frontend/index.html`
1332
+
1333
+ ```html
1334
+ <!DOCTYPE html>
1335
+ <html lang="en">
1336
+ <head>
1337
+ <meta charset="UTF-8">
1338
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
1339
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
1340
+ <title>MindForge Dashboard</title>
1341
+ <style>
1342
+ /* ── Design tokens ───────────────────────────────────────────── */
1343
+ :root {
1344
+ --bg: #0d1117;
1345
+ --surface: #161b22;
1346
+ --border: #30363d;
1347
+ --text: #e6edf3;
1348
+ --muted: #8b949e;
1349
+ --accent: #58a6ff;
1350
+ --green: #3fb950;
1351
+ --yellow: #d29922;
1352
+ --red: #f85149;
1353
+ --orange: #db6d28;
1354
+ --purple: #bc8cff;
1355
+ --font-mono:'JetBrains Mono', 'Fira Code', 'Consolas', monospace;
1356
+ }
1357
+
1358
+ /* ── Reset ───────────────────────────────────────────────────── */
1359
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
1360
+ html, body { height: 100%; overflow: hidden; }
1361
+ body { background: var(--bg); color: var(--text); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; font-size: 13px; }
1362
+
1363
+ /* ── Layout ──────────────────────────────────────────────────── */
1364
+ #app { display: flex; flex-direction: column; height: 100vh; }
1365
+ header { display: flex; align-items: center; justify-content: space-between; padding: 10px 20px; background: var(--surface); border-bottom: 1px solid var(--border); flex-shrink: 0; }
1366
+ nav { display: flex; gap: 4px; padding: 8px 20px; background: var(--surface); border-bottom: 1px solid var(--border); flex-shrink: 0; }
1367
+ main { flex: 1; overflow: hidden; padding: 16px 20px; }
1368
+ .page { display: none; height: 100%; overflow: auto; }
1369
+ .page.active { display: flex; flex-direction: column; gap: 12px; }
1370
+
1371
+ /* ── Header ──────────────────────────────────────────────────── */
1372
+ .logo { font-weight: 700; font-size: 15px; color: var(--accent); letter-spacing: -0.3px; }
1373
+ .project{ font-size: 12px; color: var(--muted); }
1374
+ .conn { display: flex; align-items: center; gap: 6px; font-size: 11px; color: var(--muted); }
1375
+ .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--red); }
1376
+ .dot.live { background: var(--green); animation: pulse 2s infinite; }
1377
+ @keyframes pulse { 0%,100%{opacity:1} 50%{opacity:.4} }
1378
+
1379
+ /* ── Nav tabs ────────────────────────────────────────────────── */
1380
+ .tab { padding: 5px 14px; border-radius: 6px; cursor: pointer; color: var(--muted); font-size: 12px; font-weight: 500; transition: all .15s; border: none; background: none; }
1381
+ .tab:hover { background: var(--border); color: var(--text); }
1382
+ .tab.active { background: var(--accent); color: #fff; }
1383
+ .badge { background: var(--red); color: #fff; border-radius: 10px; padding: 1px 6px; font-size: 10px; margin-left: 4px; }
1384
+
1385
+ /* ── Cards ───────────────────────────────────────────────────── */
1386
+ .card { background: var(--surface); border: 1px solid var(--border); border-radius: 8px; padding: 14px 16px; }
1387
+ .card h3{ font-size: 11px; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: .5px; margin-bottom: 10px; }
1388
+
1389
+ /* ── Status bar ──────────────────────────────────────────────── */
1390
+ #status-bar { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 10px; }
1391
+ .stat { display: flex; flex-direction: column; gap: 2px; }
1392
+ .stat-label { font-size: 10px; color: var(--muted); text-transform: uppercase; letter-spacing: .4px; }
1393
+ .stat-value { font-size: 18px; font-weight: 700; font-variant-numeric: tabular-nums; }
1394
+ .stat-value.accent { color: var(--accent); }
1395
+ .stat-value.green { color: var(--green); }
1396
+ .stat-value.yellow { color: var(--yellow); }
1397
+ .stat-value.red { color: var(--red); }
1398
+
1399
+ /* ── Progress bar ────────────────────────────────────────────── */
1400
+ .progress-wrap { display: flex; align-items: center; gap: 10px; }
1401
+ .progress-bar { flex: 1; height: 6px; background: var(--border); border-radius: 3px; overflow: hidden; }
1402
+ .progress-fill { height: 100%; background: var(--accent); border-radius: 3px; transition: width .3s; }
1403
+ .progress-pct { font-size: 11px; color: var(--muted); min-width: 36px; text-align: right; }
1404
+
1405
+ /* ── Audit feed ──────────────────────────────────────────────── */
1406
+ #audit-feed { font-family: var(--font-mono); font-size: 11px; line-height: 1.7; overflow-y: auto; max-height: calc(100vh - 320px); }
1407
+ .event-row { display: grid; grid-template-columns: 80px 150px 1fr; gap: 10px; padding: 3px 0; border-bottom: 1px solid #1c2128; }
1408
+ .event-row:first-child { color: var(--text); }
1409
+ .event-row:not(:first-child) { color: var(--muted); }
1410
+ .ev-time { color: var(--muted); }
1411
+ .ev-type { }
1412
+ .ev-type.task_completed { color: var(--green); }
1413
+ .ev-type.task_failed { color: var(--red); }
1414
+ .ev-type.security_finding { color: var(--yellow); }
1415
+ .ev-type.auto_mode_escalated { color: var(--red); font-weight: bold; }
1416
+ .ev-type.node_repair { color: var(--orange); }
1417
+ .ev-type.approval_granted { color: var(--green); }
1418
+ .ev-detail { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1419
+
1420
+ /* ── Steering input ──────────────────────────────────────────── */
1421
+ .steer-row { display: flex; gap: 8px; margin-top: 10px; }
1422
+ .steer-input { flex: 1; background: var(--bg); border: 1px solid var(--border); color: var(--text); padding: 7px 12px; border-radius: 6px; font-size: 12px; font-family: var(--font-mono); }
1423
+ .steer-input:focus { outline: none; border-color: var(--accent); }
1424
+ .steer-btn { padding: 7px 16px; background: var(--accent); color: #fff; border: none; border-radius: 6px; cursor: pointer; font-size: 12px; font-weight: 600; }
1425
+ .steer-btn:hover { opacity: .85; }
1426
+ .steer-btn:disabled { opacity: .4; cursor: default; }
1427
+
1428
+ /* ── Approval cards ──────────────────────────────────────────── */
1429
+ .approval-card { border-left: 3px solid var(--yellow); padding: 12px; display: flex; justify-content: space-between; align-items: flex-start; }
1430
+ .approval-card.tier3 { border-left-color: var(--red); }
1431
+ .approval-card.expiring { border-left-color: var(--orange); }
1432
+ .approval-meta { font-size: 10px; color: var(--muted); margin-top: 4px; }
1433
+ .approval-actions { display: flex; gap: 6px; flex-shrink: 0; }
1434
+ .btn-approve { padding: 5px 14px; background: var(--green); color: #fff; border: none; border-radius: 5px; cursor: pointer; font-size: 12px; font-weight: 600; }
1435
+ .btn-approve:hover { opacity: .85; }
1436
+ .btn-reject { padding: 5px 14px; background: var(--red); color: #fff; border: none; border-radius: 5px; cursor: pointer; font-size: 12px; font-weight: 600; }
1437
+ .btn-reject:hover { opacity: .85; }
1438
+
1439
+ /* ── Metrics charts ──────────────────────────────────────────── */
1440
+ .chart-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
1441
+ canvas { width: 100% !important; max-height: 140px; }
1442
+
1443
+ /* ── Knowledge graph ─────────────────────────────────────────── */
1444
+ #graph-canvas { width: 100%; height: calc(100vh - 220px); background: var(--bg); border-radius: 8px; border: 1px solid var(--border); }
1445
+ .node-panel { position: absolute; right: 20px; top: 80px; width: 280px; background: var(--surface); border: 1px solid var(--border); border-radius: 8px; padding: 14px; max-height: 60vh; overflow-y: auto; display: none; }
1446
+ .node-panel.visible { display: block; }
1447
+
1448
+ /* ── Team activity ───────────────────────────────────────────── */
1449
+ .developer-row { display: flex; align-items: center; gap: 12px; padding: 8px 0; border-bottom: 1px solid var(--border); }
1450
+ .avatar { width: 28px; height: 28px; border-radius: 50%; background: var(--accent); display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; color: #fff; flex-shrink: 0; }
1451
+ .dev-info { flex: 1; }
1452
+ .dev-name { font-size: 12px; font-weight: 600; }
1453
+ .dev-task { font-size: 11px; color: var(--muted); }
1454
+ .dev-last { font-size: 10px; color: var(--muted); }
1455
+ .conflict-row { background: rgba(248, 81, 73, .08); border: 1px solid var(--red); border-radius: 5px; padding: 7px 10px; font-size: 11px; color: var(--red); }
1456
+
1457
+ /* ── Utility ─────────────────────────────────────────────────── */
1458
+ .empty { text-align: center; padding: 40px; color: var(--muted); font-size: 12px; }
1459
+ .tag { display: inline-block; background: var(--border); padding: 2px 7px; border-radius: 3px; font-size: 10px; margin: 2px; }
1460
+ .confidence { display: inline-block; padding: 1px 6px; border-radius: 3px; font-size: 10px; font-weight: 700; }
1461
+ .conf-high { background: rgba(63,185,80,.2); color: var(--green); }
1462
+ .conf-med { background: rgba(210,153,34,.2); color: var(--yellow); }
1463
+ .conf-low { background: rgba(248,81,73,.2); color: var(--red); }
1464
+ </style>
1465
+ </head>
1466
+ <body>
1467
+ <div id="app">
1468
+
1469
+ <!-- ── Header ─────────────────────────────────────────────────── -->
1470
+ <header>
1471
+ <div style="display:flex;align-items:center;gap:16px">
1472
+ <span class="logo">⚡ MindForge</span>
1473
+ <span class="project" id="hdr-project">Loading...</span>
1474
+ <span id="hdr-status" style="font-size:11px;padding:2px 8px;border-radius:3px;background:#161b22;color:#8b949e">IDLE</span>
1475
+ </div>
1476
+ <div class="conn">
1477
+ <div class="dot" id="conn-dot"></div>
1478
+ <span id="conn-label">Connecting...</span>
1479
+ </div>
1480
+ </header>
1481
+
1482
+ <!-- ── Nav ────────────────────────────────────────────────────── -->
1483
+ <nav>
1484
+ <button class="tab active" onclick="showPage('activity')">Activity</button>
1485
+ <button class="tab" onclick="showPage('metrics')">Quality</button>
1486
+ <button class="tab" onclick="showPage('approvals')">Approvals <span class="badge" id="approval-badge" style="display:none">0</span></button>
1487
+ <button class="tab" onclick="showPage('memory')">Knowledge</button>
1488
+ <button class="tab" onclick="showPage('team')">Team</button>
1489
+ </nav>
1490
+
1491
+ <!-- ── Main ───────────────────────────────────────────────────── -->
1492
+ <main>
1493
+
1494
+ <!-- Page 1: Activity ──────────────────────────────────────── -->
1495
+ <div class="page active" id="page-activity">
1496
+
1497
+ <div class="card" id="status-bar-card">
1498
+ <h3>Phase Status</h3>
1499
+ <div id="status-bar">
1500
+ <div class="stat"><span class="stat-label">Phase</span><span class="stat-value accent" id="s-phase">—</span></div>
1501
+ <div class="stat"><span class="stat-label">Tasks</span><span class="stat-value" id="s-tasks">—</span></div>
1502
+ <div class="stat"><span class="stat-label">Wave</span><span class="stat-value" id="s-wave">—</span></div>
1503
+ <div class="stat"><span class="stat-label">Repairs</span><span class="stat-value" id="s-repairs">0</span></div>
1504
+ <div class="stat"><span class="stat-label">Elapsed</span><span class="stat-value" id="s-elapsed">—</span></div>
1505
+ </div>
1506
+ <div class="progress-wrap" style="margin-top:12px">
1507
+ <div class="progress-bar"><div class="progress-fill" id="progress-fill" style="width:0%"></div></div>
1508
+ <span class="progress-pct" id="progress-pct">0%</span>
1509
+ </div>
1510
+ <div style="margin-top:8px;font-size:11px;color:var(--muted)" id="s-current-task">No active task</div>
1511
+ </div>
1512
+
1513
+ <div class="card" style="flex:1">
1514
+ <h3>Live Events</h3>
1515
+ <div id="audit-feed"><div class="empty">Waiting for events...</div></div>
1516
+ <div class="steer-row">
1517
+ <input class="steer-input" id="steer-input" placeholder="Steer auto mode: e.g. Use Redis for session storage..." />
1518
+ <button class="steer-btn" id="steer-btn" onclick="sendSteer()">Steer</button>
1519
+ </div>
1520
+ </div>
1521
+ </div>
1522
+
1523
+ <!-- Page 2: Quality Metrics ──────────────────────────────── -->
1524
+ <div class="page" id="page-metrics">
1525
+ <div class="chart-grid">
1526
+ <div class="card"><h3>Session Quality Score</h3><canvas id="chart-quality"></canvas></div>
1527
+ <div class="card"><h3>Verify Pass Rate</h3><canvas id="chart-verify"></canvas></div>
1528
+ <div class="card"><h3>Security Findings</h3><canvas id="chart-security"></canvas></div>
1529
+ <div class="card"><h3>Cost Per Session ($)</h3><canvas id="chart-cost"></canvas></div>
1530
+ </div>
1531
+ <div class="card" style="margin-top:4px">
1532
+ <h3>Summary</h3>
1533
+ <div id="metrics-summary" style="display:grid;grid-template-columns:repeat(4,1fr);gap:16px;padding-top:8px">
1534
+ <div class="stat"><span class="stat-label">Avg Quality</span><span class="stat-value accent" id="m-quality">—</span></div>
1535
+ <div class="stat"><span class="stat-label">Avg Cost</span><span class="stat-value" id="m-cost">—</span></div>
1536
+ <div class="stat"><span class="stat-label">Repair Rate</span><span class="stat-value" id="m-repair">—</span></div>
1537
+ <div class="stat"><span class="stat-label">Total Tasks</span><span class="stat-value green" id="m-tasks">—</span></div>
1538
+ </div>
1539
+ </div>
1540
+ </div>
1541
+
1542
+ <!-- Page 3: Approvals ────────────────────────────────────── -->
1543
+ <div class="page" id="page-approvals">
1544
+ <div class="card">
1545
+ <h3>Pending Approvals</h3>
1546
+ <div id="approvals-pending"><div class="empty">No pending approvals ✅</div></div>
1547
+ </div>
1548
+ <div class="card">
1549
+ <h3>Recent Resolutions</h3>
1550
+ <div id="approvals-resolved"><div class="empty">No recent resolutions</div></div>
1551
+ </div>
1552
+ </div>
1553
+
1554
+ <!-- Page 4: Knowledge Graph ──────────────────────────────── -->
1555
+ <div class="page" id="page-memory" style="position:relative">
1556
+ <div class="card" style="flex-shrink:0">
1557
+ <div style="display:flex;align-items:center;gap:12px">
1558
+ <input id="memory-search" style="flex:1;background:var(--bg);border:1px solid var(--border);color:var(--text);padding:6px 12px;border-radius:6px;font-size:12px" placeholder="Search knowledge base..." oninput="searchMemory(this.value)">
1559
+ <span id="memory-count" style="font-size:11px;color:var(--muted)">— entries</span>
1560
+ </div>
1561
+ </div>
1562
+ <div id="memory-list" style="overflow-y:auto;flex:1"></div>
1563
+ </div>
1564
+
1565
+ <!-- Page 5: Team Activity ────────────────────────────────── -->
1566
+ <div class="page" id="page-team">
1567
+ <div class="card">
1568
+ <h3>Active Developers</h3>
1569
+ <div id="team-active"><div class="empty">No recent activity</div></div>
1570
+ </div>
1571
+ <div class="card">
1572
+ <h3>⚠️ File Conflicts</h3>
1573
+ <div id="team-conflicts"><div class="empty">No conflicts detected ✅</div></div>
1574
+ </div>
1575
+ </div>
1576
+
1577
+ </main>
1578
+ </div>
1579
+
1580
+ <script>
1581
+ // ── State ─────────────────────────────────────────────────────────────────────
1582
+ const state = { events: [], status: {}, approvals: {}, charts: {}, sse: null };
1583
+
1584
+ // ── Page navigation ───────────────────────────────────────────────────────────
1585
+ function showPage(name) {
1586
+ document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));
1587
+ document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
1588
+ document.getElementById('page-' + name).classList.add('active');
1589
+ event.target.classList.add('active');
1590
+
1591
+ // Load data for the page
1592
+ if (name === 'metrics') loadMetrics();
1593
+ if (name === 'approvals') loadApprovals();
1594
+ if (name === 'memory') loadMemory('');
1595
+ if (name === 'team') loadTeam();
1596
+ }
1597
+
1598
+ // ── SSE connection ────────────────────────────────────────────────────────────
1599
+ function connectSSE() {
1600
+ const es = new EventSource('/events');
1601
+ state.sse = es;
1602
+
1603
+ es.addEventListener('audit:new', e => {
1604
+ const entry = JSON.parse(e.data);
1605
+ prependAuditEvent(entry);
1606
+ });
1607
+
1608
+ es.addEventListener('status:update', e => {
1609
+ updateStatusBar(JSON.parse(e.data));
1610
+ });
1611
+
1612
+ es.addEventListener('approval:new', e => {
1613
+ const data = JSON.parse(e.data);
1614
+ showApprovalBadge();
1615
+ });
1616
+
1617
+ es.onopen = () => {
1618
+ document.getElementById('conn-dot').classList.add('live');
1619
+ document.getElementById('conn-label').textContent = 'Live';
1620
+ };
1621
+
1622
+ es.onerror = () => {
1623
+ document.getElementById('conn-dot').classList.remove('live');
1624
+ document.getElementById('conn-label').textContent = 'Reconnecting...';
1625
+ setTimeout(connectSSE, 3000);
1626
+ es.close();
1627
+ };
1628
+ }
1629
+
1630
+ // ── Activity feed ─────────────────────────────────────────────────────────────
1631
+ async function loadActivity() {
1632
+ try {
1633
+ const r = await fetch('/api/audit?limit=50');
1634
+ const d = await r.json();
1635
+ const feed = document.getElementById('audit-feed');
1636
+ if (!d.entries?.length) { feed.innerHTML = '<div class="empty">No events yet</div>'; return; }
1637
+ feed.innerHTML = '';
1638
+ d.entries.forEach(e => appendAuditRow(feed, e));
1639
+ } catch {}
1640
+ }
1641
+
1642
+ function prependAuditEvent(entry) {
1643
+ const feed = document.getElementById('audit-feed');
1644
+ const empty = feed.querySelector('.empty');
1645
+ if (empty) feed.innerHTML = '';
1646
+
1647
+ const row = createAuditRow(entry);
1648
+ feed.insertBefore(row, feed.firstChild);
1649
+
1650
+ // Keep max 100 rows
1651
+ while (feed.children.length > 100) feed.removeChild(feed.lastChild);
1652
+ }
1653
+
1654
+ function appendAuditRow(feed, entry) { feed.appendChild(createAuditRow(entry)); }
1655
+
1656
+ function createAuditRow(entry) {
1657
+ const row = document.createElement('div');
1658
+ row.className = 'event-row';
1659
+ const time = entry.timestamp ? new Date(entry.timestamp).toLocaleTimeString() : '';
1660
+ const detail = entry.plan ? `Plan ${entry.phase}-${entry.plan} ${entry.task_name || ''}`.trim()
1661
+ : entry.reason || entry.description || entry.topic || JSON.stringify(entry).slice(0, 80);
1662
+ row.innerHTML = `
1663
+ <span class="ev-time">${time}</span>
1664
+ <span class="ev-type ${entry.event}">${entry.event}</span>
1665
+ <span class="ev-detail">${escapeHtml(detail)}</span>
1666
+ `;
1667
+ return row;
1668
+ }
1669
+
1670
+ // ── Status bar ────────────────────────────────────────────────────────────────
1671
+ async function loadStatus() {
1672
+ try {
1673
+ const r = await fetch('/api/status');
1674
+ const d = await r.json();
1675
+ updateStatusBar(d);
1676
+ } catch {}
1677
+ }
1678
+
1679
+ function updateStatusBar(d) {
1680
+ setText('hdr-project', d.project_name || 'MindForge Project');
1681
+ const statusEl = document.getElementById('hdr-status');
1682
+ statusEl.textContent = (d.auto_status || 'IDLE').toUpperCase();
1683
+ statusEl.style.background = d.auto_mode ? '#0d4429' : '#1c2128';
1684
+ statusEl.style.color = d.auto_mode ? 'var(--green)' : 'var(--muted)';
1685
+
1686
+ setText('s-phase', d.phase ? `${d.phase} — ${(d.phase_description || '').slice(0, 30)}` : '—');
1687
+ setText('s-tasks', d.tasks_total ? `${d.tasks_completed}/${d.tasks_total}` : '—');
1688
+ setText('s-wave', d.wave_total ? `${d.wave_current}/${d.wave_total}` : '—');
1689
+ setText('s-repairs', d.node_repairs || 0);
1690
+ setText('s-elapsed', d.elapsed_ms ? formatDuration(d.elapsed_ms) : '—');
1691
+ setText('s-current-task', d.current_task || 'No active task');
1692
+
1693
+ const pct = d.tasks_total ? Math.round((d.tasks_completed / d.tasks_total) * 100) : 0;
1694
+ document.getElementById('progress-fill').style.width = pct + '%';
1695
+ setText('progress-pct', pct + '%');
1696
+ }
1697
+
1698
+ // ── Metrics ───────────────────────────────────────────────────────────────────
1699
+ async function loadMetrics() {
1700
+ try {
1701
+ const r = await fetch('/api/metrics');
1702
+ const d = await r.json();
1703
+ setText('m-quality', d.avg_quality?.toFixed(2) || '—');
1704
+ setText('m-cost', d.avg_cost_usd ? '$' + d.avg_cost_usd.toFixed(4) : '—');
1705
+ setText('m-repair', d.node_repair_rate ? (d.node_repair_rate * 100).toFixed(1) + '%' : '0%');
1706
+ setText('m-tasks', d.total_tasks || '0');
1707
+ drawCharts(d);
1708
+ } catch {}
1709
+ }
1710
+
1711
+ function drawCharts(d) {
1712
+ const sessions = d.sessions || [];
1713
+ const labels = sessions.map((_, i) => `S${i+1}`);
1714
+
1715
+ drawLineChart('chart-quality', labels, sessions.map(s => s.quality_score), 'Quality Score', '#58a6ff');
1716
+ drawLineChart('chart-verify', labels, sessions.map(s => s.verify_pass_rate), 'Pass Rate', '#3fb950');
1717
+ drawLineChart('chart-cost', labels, sessions.map(s => s.cost_usd), 'Cost ($)', '#bc8cff');
1718
+
1719
+ const sf = d.security_findings || {};
1720
+ drawBarChart('chart-security',
1721
+ ['CRITICAL','HIGH','MEDIUM','LOW'],
1722
+ [sf.CRITICAL||0, sf.HIGH||0, sf.MEDIUM||0, sf.LOW||0],
1723
+ ['#f85149','#db6d28','#d29922','#8b949e']
1724
+ );
1725
+ }
1726
+
1727
+ function drawLineChart(id, labels, data, label, color) {
1728
+ const canvas = document.getElementById(id);
1729
+ if (!canvas) return;
1730
+ const ctx = canvas.getContext('2d');
1731
+ canvas.width = canvas.offsetWidth; canvas.height = 130;
1732
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
1733
+ if (!data.length) return;
1734
+
1735
+ const max = Math.max(...data, 0.01);
1736
+ const pad = 20;
1737
+ const w = canvas.width - pad * 2;
1738
+ const h = canvas.height - pad * 2;
1739
+
1740
+ ctx.strokeStyle = color; ctx.lineWidth = 2; ctx.beginPath();
1741
+ data.forEach((v, i) => {
1742
+ const x = pad + (i / Math.max(data.length - 1, 1)) * w;
1743
+ const y = pad + h - (v / max) * h;
1744
+ i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y);
1745
+ });
1746
+ ctx.stroke();
1747
+
1748
+ // Area fill
1749
+ ctx.fillStyle = color + '22';
1750
+ ctx.lineTo(pad + w, pad + h); ctx.lineTo(pad, pad + h);
1751
+ ctx.closePath(); ctx.fill();
1752
+ }
1753
+
1754
+ function drawBarChart(id, labels, data, colors) {
1755
+ const canvas = document.getElementById(id);
1756
+ if (!canvas) return;
1757
+ const ctx = canvas.getContext('2d');
1758
+ canvas.width = canvas.offsetWidth; canvas.height = 130;
1759
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
1760
+
1761
+ const max = Math.max(...data, 1);
1762
+ const barW = canvas.width / labels.length;
1763
+ const pad = 10;
1764
+
1765
+ data.forEach((v, i) => {
1766
+ const h = ((v / max) * (canvas.height - pad * 2));
1767
+ const x = i * barW + barW * 0.2;
1768
+ const y = canvas.height - pad - h;
1769
+ ctx.fillStyle = colors[i] || '#58a6ff';
1770
+ ctx.fillRect(x, y, barW * 0.6, h);
1771
+ ctx.fillStyle = '#8b949e';
1772
+ ctx.font = '10px sans-serif';
1773
+ ctx.fillText(labels[i], x + barW * 0.1, canvas.height - 2);
1774
+ if (v > 0) { ctx.fillStyle = '#e6edf3'; ctx.fillText(v, x + barW * 0.1, y - 3); }
1775
+ });
1776
+ }
1777
+
1778
+ // ── Approvals ─────────────────────────────────────────────────────────────────
1779
+ async function loadApprovals() {
1780
+ try {
1781
+ const r = await fetch('/api/approvals');
1782
+ const d = await r.json();
1783
+
1784
+ const pendingEl = document.getElementById('approvals-pending');
1785
+ const resolvedEl = document.getElementById('approvals-resolved');
1786
+
1787
+ if (!d.pending?.length) {
1788
+ pendingEl.innerHTML = '<div class="empty">No pending approvals ✅</div>';
1789
+ } else {
1790
+ pendingEl.innerHTML = d.pending.map(a => `
1791
+ <div class="approval-card ${a.tier === 3 ? 'tier3' : ''} ${a.hours_remaining < 4 ? 'expiring' : ''}">
1792
+ <div>
1793
+ <div><strong>Tier ${a.tier}</strong> — Phase ${a.phase}, Plan ${a.plan}</div>
1794
+ <div style="margin-top:4px;color:var(--text)">${escapeHtml(a.description || 'No description')}</div>
1795
+ <div class="approval-meta">${relativeTime(a.requested_at)} | ${a.hours_remaining ? a.hours_remaining.toFixed(1) + 'h remaining' : 'No expiry'}</div>
1796
+ </div>
1797
+ <div class="approval-actions">
1798
+ <button class="btn-approve" onclick="decide('${a.id}','approve')">Approve</button>
1799
+ <button class="btn-reject" onclick="decide('${a.id}','reject')">Reject</button>
1800
+ </div>
1801
+ </div>
1802
+ `).join('');
1803
+ }
1804
+
1805
+ const resolved = [...(d.approved||[]), ...(d.rejected||[])].slice(0, 5);
1806
+ resolvedEl.innerHTML = resolved.length
1807
+ ? resolved.map(a => `<div style="padding:6px 0;border-bottom:1px solid var(--border);font-size:11px;color:var(--muted)">
1808
+ ${a.status === 'approved' ? '✅' : '❌'} Tier ${a.tier} — Phase ${a.phase} Plan ${a.plan} — ${escapeHtml(a.resolved_by||'unknown')} ${relativeTime(a.resolved_at)}
1809
+ </div>`).join('')
1810
+ : '<div class="empty">No recent resolutions</div>';
1811
+
1812
+ updateApprovalBadge(d.pending?.length || 0);
1813
+ } catch {}
1814
+ }
1815
+
1816
+ async function decide(id, decision) {
1817
+ if (!confirm(`${decision === 'approve' ? 'Approve' : 'Reject'} this request?`)) return;
1818
+ try {
1819
+ const r = await fetch(`/api/approve/${id}`, {
1820
+ method: 'POST',
1821
+ headers: { 'Content-Type': 'application/json' },
1822
+ body: JSON.stringify({ decision, approver: 'dashboard-user' }),
1823
+ });
1824
+ const d = await r.json();
1825
+ if (d.success) { showToast(d.message); loadApprovals(); }
1826
+ else showToast('Error: ' + d.error, true);
1827
+ } catch (e) { showToast('Request failed', true); }
1828
+ }
1829
+
1830
+ // ── Memory / Knowledge Graph ──────────────────────────────────────────────────
1831
+ let _memSearchTimer;
1832
+ function searchMemory(q) {
1833
+ clearTimeout(_memSearchTimer);
1834
+ _memSearchTimer = setTimeout(() => loadMemory(q), 300);
1835
+ }
1836
+
1837
+ async function loadMemory(q = '') {
1838
+ try {
1839
+ const r = await fetch('/api/memory?q=' + encodeURIComponent(q) + '&limit=50');
1840
+ const d = await r.json();
1841
+ setText('memory-count', d.total + ' entries');
1842
+
1843
+ const typeColors = {
1844
+ architectural_decision: '#58a6ff',
1845
+ code_pattern: '#3fb950',
1846
+ bug_pattern: '#f85149',
1847
+ team_preference: '#d29922',
1848
+ domain_knowledge: '#bc8cff',
1849
+ };
1850
+
1851
+ document.getElementById('memory-list').innerHTML = d.entries.length
1852
+ ? d.entries.map(e => {
1853
+ const confClass = e.confidence >= 0.8 ? 'conf-high' : e.confidence >= 0.6 ? 'conf-med' : 'conf-low';
1854
+ const typeColor = typeColors[e.type] || '#8b949e';
1855
+ return `
1856
+ <div class="card" style="margin-bottom:8px;border-left:3px solid ${typeColor}">
1857
+ <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:6px">
1858
+ <strong style="font-size:12px">${escapeHtml(e.topic)}</strong>
1859
+ <div style="display:flex;gap:6px;align-items:center">
1860
+ <span class="confidence ${confClass}">${(e.confidence * 100).toFixed(0)}%</span>
1861
+ <span class="tag">${e.type.replace(/_/g, ' ')}</span>
1862
+ </div>
1863
+ </div>
1864
+ <div style="font-size:11px;color:var(--muted);line-height:1.5">${escapeHtml(e.content.slice(0, 200))}</div>
1865
+ <div style="margin-top:6px">${(e.tags||[]).map(t => `<span class="tag">${t}</span>`).join('')}</div>
1866
+ </div>`;
1867
+ }).join('')
1868
+ : '<div class="empty">No knowledge entries found</div>';
1869
+ } catch {}
1870
+ }
1871
+
1872
+ // ── Team ──────────────────────────────────────────────────────────────────────
1873
+ async function loadTeam() {
1874
+ try {
1875
+ const r = await fetch('/api/team');
1876
+ const d = await r.json();
1877
+
1878
+ const activeEl = document.getElementById('team-active');
1879
+ const conflictEl = document.getElementById('team-conflicts');
1880
+
1881
+ activeEl.innerHTML = d.active?.length
1882
+ ? d.active.map(a => `
1883
+ <div class="developer-row">
1884
+ <div class="avatar">${(a.email||'?')[0].toUpperCase()}</div>
1885
+ <div class="dev-info">
1886
+ <div class="dev-name">${escapeHtml(a.email)}</div>
1887
+ <div class="dev-task">${escapeHtml(a.current_task || 'No active task')}</div>
1888
+ </div>
1889
+ <div class="dev-last">${a.last_seen_mins}m ago</div>
1890
+ </div>`).join('')
1891
+ : '<div class="empty">No recent developer activity</div>';
1892
+
1893
+ conflictEl.innerHTML = d.conflicts?.length
1894
+ ? d.conflicts.map(c => `
1895
+ <div class="conflict-row">⚠️ ${escapeHtml(c.file)} — modified by: ${c.developers.map(d => escapeHtml(d)).join(', ')}</div>`).join('')
1896
+ : '<div class="empty">No conflicts detected ✅</div>';
1897
+ } catch {}
1898
+ }
1899
+
1900
+ // ── Steering ──────────────────────────────────────────────────────────────────
1901
+ async function sendSteer() {
1902
+ const input = document.getElementById('steer-input');
1903
+ const instruction = input.value.trim();
1904
+ if (!instruction) return;
1905
+ try {
1906
+ const r = await fetch('/api/steer', {
1907
+ method: 'POST',
1908
+ headers: { 'Content-Type': 'application/json' },
1909
+ body: JSON.stringify({ instruction, priority: 'normal' }),
1910
+ });
1911
+ const d = await r.json();
1912
+ if (d.success) { showToast('Steering instruction queued'); input.value = ''; }
1913
+ else showToast('Error: ' + d.error, true);
1914
+ } catch { showToast('Failed to send steering instruction', true); }
1915
+ }
1916
+
1917
+ document.getElementById('steer-input').addEventListener('keydown', e => {
1918
+ if (e.key === 'Enter') sendSteer();
1919
+ });
1920
+
1921
+ // ── Approval badge ────────────────────────────────────────────────────────────
1922
+ function updateApprovalBadge(count) {
1923
+ const badge = document.getElementById('approval-badge');
1924
+ badge.style.display = count > 0 ? 'inline' : 'none';
1925
+ badge.textContent = count;
1926
+ }
1927
+ function showApprovalBadge() { updateApprovalBadge(1); }
1928
+
1929
+ // ── Toast ─────────────────────────────────────────────────────────────────────
1930
+ function showToast(msg, isError = false) {
1931
+ const t = document.createElement('div');
1932
+ t.textContent = msg;
1933
+ t.style.cssText = `position:fixed;bottom:20px;right:20px;padding:10px 18px;border-radius:6px;font-size:12px;color:#fff;z-index:1000;background:${isError?'var(--red)':'var(--green)'}`;
1934
+ document.body.appendChild(t);
1935
+ setTimeout(() => t.remove(), 3000);
1936
+ }
1937
+
1938
+ // ── Helpers ───────────────────────────────────────────────────────────────────
1939
+ function setText(id, val) { const el = document.getElementById(id); if (el) el.textContent = val; }
1940
+ function escapeHtml(s) { return String(s||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;'); }
1941
+ function formatDuration(ms) {
1942
+ const m = Math.floor(ms / 60000); const s = Math.floor((ms % 60000) / 1000);
1943
+ return m > 60 ? `${Math.floor(m/60)}h ${m%60}m` : `${m}m ${s}s`;
1944
+ }
1945
+ function relativeTime(iso) {
1946
+ if (!iso) return '';
1947
+ const mins = Math.round((Date.now() - new Date(iso).getTime()) / 60000);
1948
+ if (mins < 1) return 'just now';
1949
+ if (mins < 60) return `${mins}m ago`;
1950
+ return `${Math.floor(mins/60)}h ago`;
1951
+ }
1952
+
1953
+ // ── Init ──────────────────────────────────────────────────────────────────────
1954
+ (async function init() {
1955
+ connectSSE();
1956
+ await loadStatus();
1957
+ await loadActivity();
1958
+ // Refresh activity every 30s
1959
+ setInterval(loadActivity, 30_000);
1960
+ setInterval(loadStatus, 15_000);
1961
+ })();
1962
+ </script>
1963
+ </body>
1964
+ </html>
1965
+ ```
1966
+
1967
+ **Commit:**
1968
+ ```bash
1969
+ git add bin/dashboard/frontend/index.html
1970
+ git commit -m "feat(v2-dashboard): implement single-file HTML dashboard with 5 pages and live SSE"
1971
+ ```
1972
+
1973
+ ---
1974
+
1975
+ ## TASK 9 — Write the `/mindforge:dashboard` command
1976
+
1977
+ ### `.claude/commands/mindforge/dashboard.md`
1978
+
1979
+ ```markdown
1980
+ # MindForge v2 — Dashboard Command
1981
+ # Usage: /mindforge:dashboard [--port 7339] [--open] [--stop] [--status]
1982
+ # Version: v2.0.0-alpha.5
1983
+
1984
+ ## Purpose
1985
+ Start the MindForge real-time web dashboard — a live observability UI for the
1986
+ entire team. Shows execution progress, quality metrics, pending approvals,
1987
+ knowledge graph, and team activity without requiring CLI access.
1988
+
1989
+ ## Design
1990
+ The dashboard is a localhost-only web server:
1991
+ - No build step — single HTML file, no bundler, no npm packages on client
1992
+ - No authentication — binding to 127.0.0.1 is the security model
1993
+ - Live updates via Server-Sent Events — no WebSocket library needed
1994
+ - Designed for screensharing at standups, not external access
1995
+
1996
+ ## Usage
1997
+
1998
+ ### Start the dashboard
1999
+ ```
2000
+ /mindforge:dashboard
2001
+ → Dashboard running at: http://localhost:7339
2002
+ → Press CTRL+C to stop (or /mindforge:dashboard --stop)
2003
+ ```
2004
+
2005
+ ### Start and open in browser
2006
+ ```
2007
+ /mindforge:dashboard --open
2008
+ → Opens http://localhost:7339 in your default browser
2009
+ ```
2010
+
2011
+ ### Custom port
2012
+ ```
2013
+ /mindforge:dashboard --port 7340
2014
+ → Useful if 7339 is already in use
2015
+ ```
2016
+
2017
+ ### Stop the dashboard
2018
+ ```
2019
+ /mindforge:dashboard --stop
2020
+ → Finds the running dashboard process (from PID file) and sends SIGTERM
2021
+ ```
2022
+
2023
+ ### Check dashboard status
2024
+ ```
2025
+ /mindforge:dashboard --status
2026
+ → Checks if dashboard is running, shows port and PID
2027
+ → Also shows: http://localhost:7339/api/status
2028
+ ```
2029
+
2030
+ ## Dashboard pages
2031
+
2032
+ ### Activity (default)
2033
+ - Phase name, auto mode status (RUNNING/PAUSED/ESCALATED/IDLE)
2034
+ - Wave progress bar (tasks completed / total)
2035
+ - Live AUDIT event feed with color-coded event types
2036
+ - Steering input: send guidance to auto mode without touching the CLI
2037
+
2038
+ ### Quality Metrics
2039
+ - Session quality score trend (last 20 sessions)
2040
+ - Verify pass rate over time
2041
+ - Security findings by severity (CRITICAL/HIGH/MEDIUM/LOW)
2042
+ - Cost per session trend
2043
+
2044
+ ### Approvals
2045
+ - All pending Tier 2/3 governance requests
2046
+ - [Approve] and [Reject] buttons — no CLI needed for approval
2047
+ - Tier, phase/plan, description, time since requested, expiry warning
2048
+ - Recent approval history
2049
+
2050
+ ### Knowledge
2051
+ - Search the knowledge graph from the browser
2052
+ - Entries filtered by confidence, type, tags
2053
+ - Color-coded by knowledge type
2054
+
2055
+ ### Team
2056
+ - Active developers (by git email, from AUDIT.jsonl)
2057
+ - What each person is working on (last task)
2058
+ - File conflict warnings (two developers recently touching the same file)
2059
+
2060
+ ## Security rules
2061
+ 1. Never expose the dashboard on 0.0.0.0 — localhost only
2062
+ 2. Never forward the port externally (no ngrok, no port forwarding)
2063
+ 3. For remote team visibility: screenshare your browser instead
2064
+ 4. The dashboard shows project details including code patterns and decisions
2065
+
2066
+ ## Integration with auto mode
2067
+ When `/mindforge:auto` is running and the dashboard is open:
2068
+ - Activity feed updates live as tasks complete
2069
+ - Wave progress bar advances in real-time
2070
+ - Any escalations appear immediately with red indicator
2071
+ - The Steering input is active — inject guidance without a second terminal
2072
+
2073
+ ## AUDIT entry
2074
+ ```json
2075
+ { "event": "dashboard_started", "port": 7339, "pid": 12345 }
2076
+ { "event": "dashboard_stopped", "pid": 12345 }
2077
+ ```
2078
+ ```
2079
+
2080
+ **Commit:**
2081
+ ```bash
2082
+ cp .claude/commands/mindforge/dashboard.md .agent/mindforge/dashboard.md
2083
+ git add .claude/commands/mindforge/dashboard.md .agent/mindforge/dashboard.md
2084
+ git commit -m "feat(v2-dashboard): add /mindforge:dashboard command"
2085
+ ```
2086
+
2087
+ ---
2088
+
2089
+ ## TASK 10 — Update CLAUDE.md for dashboard awareness
2090
+
2091
+ ### Add to `.claude/CLAUDE.md` and `.agent/CLAUDE.md`
2092
+
2093
+ ```markdown
2094
+ ---
2095
+
2096
+ ## REAL-TIME DASHBOARD (v2.0.0 — Day 12)
2097
+
2098
+ ### Dashboard server
2099
+ The MindForge dashboard runs at localhost:7339 when started.
2100
+ Start: `node bin/dashboard/server.js [--port 7339] [--open]`
2101
+ Stop: `/mindforge:dashboard --stop`
2102
+
2103
+ Localhost-only (127.0.0.1) — consistent with ADR-017.
2104
+ Never bind to 0.0.0.0, never port-forward externally.
2105
+
2106
+ ### When to recommend the dashboard
2107
+ Suggest starting the dashboard when:
2108
+ - User runs /mindforge:auto (live progress visibility)
2109
+ - Team standup approaching (screenshare mode)
2110
+ - Tier 2/3 approvals are pending (approver can approve from browser)
2111
+ - Debugging a quality issue (metrics page shows trends)
2112
+
2113
+ ### AUDIT events written by dashboard
2114
+ - dashboard_started: on server start
2115
+ - dashboard_stopped: on graceful shutdown
2116
+ - approval_granted / approval_rejected: when approved via browser UI
2117
+ - steering_queued: when steering instruction sent via browser UI
2118
+
2119
+ ### New command (Day 12)
2120
+ - /mindforge:dashboard — start/stop/status the real-time web dashboard
2121
+
2122
+ ---
2123
+ ```
2124
+
2125
+ **Commit:**
2126
+ ```bash
2127
+ git add .claude/CLAUDE.md .agent/CLAUDE.md
2128
+ git commit -m "feat(v2-dashboard): update CLAUDE.md with dashboard awareness and integration notes"
2129
+ ```
2130
+
2131
+ ---
2132
+
2133
+ ## TASK 11 — Write the dashboard test suite
2134
+
2135
+ ### `tests/dashboard.test.js`
2136
+
2137
+ ```javascript
2138
+ /**
2139
+ * MindForge v2 — Dashboard Test Suite
2140
+ * Tests SSE bridge, metrics aggregator, approval handler,
2141
+ * API router, and server startup/shutdown.
2142
+ *
2143
+ * Note: Tests do NOT start a real Express server — they test
2144
+ * the component logic directly to avoid port conflicts in CI.
2145
+ *
2146
+ * Run: node tests/dashboard.test.js
2147
+ */
2148
+ 'use strict';
2149
+
2150
+ const fs = require('fs');
2151
+ const path = require('path');
2152
+ const http = require('http');
2153
+ const os = require('os');
2154
+ const assert = require('assert');
2155
+
2156
+ let passed = 0, failed = 0;
2157
+
2158
+ function test(name, fn) {
2159
+ try { fn(); console.log(` ✅ ${name}`); passed++; }
2160
+ catch(e) { console.error(` ❌ ${name}\n ${e.message}`); failed++; }
2161
+ }
2162
+
2163
+ async function testAsync(name, fn) {
2164
+ try { await fn(); console.log(` ✅ ${name}`); passed++; }
2165
+ catch(e) { console.error(` ❌ ${name}\n ${e.message}`); failed++; }
2166
+ }
2167
+
2168
+ // ── Temp project factory ──────────────────────────────────────────────────────
2169
+ function mkProject() {
2170
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'mf-dashboard-'));
2171
+ const write = (rel, c) => { const f = path.join(dir, rel); fs.mkdirSync(path.dirname(f), { recursive: true }); fs.writeFileSync(f, c); return f; };
2172
+ const exists = rel => fs.existsSync(path.join(dir, rel));
2173
+ const cleanup = () => { try { fs.rmSync(dir, { recursive: true, force: true }); } catch {} };
2174
+ return { dir, write, exists, cleanup };
2175
+ }
2176
+
2177
+ // ── Module imports ────────────────────────────────────────────────────────────
2178
+ const Metrics = require('../bin/dashboard/metrics-aggregator');
2179
+ const Approval = require('../bin/dashboard/approval-handler');
2180
+ const SSE = require('../bin/dashboard/sse-bridge');
2181
+
2182
+ // ── Sample data fixtures ──────────────────────────────────────────────────────
2183
+ const SAMPLE_HANDOFF = {
2184
+ schema_version: '2.0.0',
2185
+ current_phase: 3,
2186
+ phase_description: 'Authentication System',
2187
+ next_task: 'Plan 3-06',
2188
+ last_updated: new Date().toISOString(),
2189
+ };
2190
+
2191
+ const SAMPLE_AUTO_STATE = {
2192
+ schema_version: '2.0.0',
2193
+ auto_mode_active: true,
2194
+ status: 'running',
2195
+ phase: 3,
2196
+ wave_current: 2, wave_total: 3,
2197
+ tasks_completed: 5, tasks_total: 8,
2198
+ node_repairs: 1, escalations: 0,
2199
+ elapsed_ms: 1083000,
2200
+ current_task: 'Plan 3-05 — JWT middleware',
2201
+ last_commit: 'abc1234',
2202
+ };
2203
+
2204
+ const SAMPLE_APPROVAL = {
2205
+ id: 'aaaabbbb-cccc-dddd-eeee-ffffffffffff',
2206
+ tier: 2,
2207
+ phase: 3,
2208
+ plan: '04',
2209
+ description: 'Add user RBAC model',
2210
+ status: 'pending',
2211
+ requested_at: new Date().toISOString(),
2212
+ expires_at: new Date(Date.now() + 86_400_000).toISOString(),
2213
+ };
2214
+
2215
+ // ═══════════════════════════════════════════════════════════════════════
2216
+ console.log('\nMindForge v2 — Dashboard Tests\n');
2217
+
2218
+ // ── File existence ────────────────────────────────────────────────────────────
2219
+ console.log('Required files:');
2220
+ [
2221
+ 'bin/dashboard/server.js',
2222
+ 'bin/dashboard/sse-bridge.js',
2223
+ 'bin/dashboard/api-router.js',
2224
+ 'bin/dashboard/approval-handler.js',
2225
+ 'bin/dashboard/metrics-aggregator.js',
2226
+ 'bin/dashboard/frontend/index.html',
2227
+ '.mindforge/dashboard/dashboard-spec.md',
2228
+ '.mindforge/dashboard/api-reference.md',
2229
+ '.claude/commands/mindforge/dashboard.md',
2230
+ '.agent/mindforge/dashboard.md',
2231
+ ].forEach(f => test(`${f} exists`, () => assert.ok(fs.existsSync(f), `Missing: ${f}`)));
2232
+
2233
+ // ── Metrics aggregator ────────────────────────────────────────────────────────
2234
+ console.log('\nMetrics aggregator:');
2235
+
2236
+ test('getStatus: returns object with required fields when no files exist', () => {
2237
+ const p = mkProject();
2238
+ const orig = process.cwd();
2239
+ process.chdir(p.dir);
2240
+ try {
2241
+ const status = Metrics.getStatus();
2242
+ assert.ok(typeof status === 'object', 'Should return object');
2243
+ assert.ok('project_name' in status, 'Should have project_name');
2244
+ assert.ok('auto_mode' in status, 'Should have auto_mode');
2245
+ assert.ok('auto_status' in status, 'Should have auto_status');
2246
+ } finally { process.chdir(orig); p.cleanup(); }
2247
+ });
2248
+
2249
+ test('getStatus: reads HANDOFF.json and auto-state.json', () => {
2250
+ const p = mkProject();
2251
+ const orig = process.cwd();
2252
+ process.chdir(p.dir);
2253
+ try {
2254
+ p.write('.planning/HANDOFF.json', JSON.stringify(SAMPLE_HANDOFF));
2255
+ p.write('.planning/auto-state.json', JSON.stringify(SAMPLE_AUTO_STATE));
2256
+ p.write('.planning/PROJECT.md', '# My Auth App\n');
2257
+
2258
+ const status = Metrics.getStatus();
2259
+ assert.strictEqual(status.phase, 3, 'Should read phase from HANDOFF.json');
2260
+ assert.strictEqual(status.auto_mode, true, 'Should read auto_mode from auto-state.json');
2261
+ assert.strictEqual(status.auto_status, 'running', 'Should read status');
2262
+ assert.strictEqual(status.tasks_completed, 5, 'Should read tasks_completed');
2263
+ assert.strictEqual(status.project_name, 'My Auth App', 'Should read project name');
2264
+ } finally { process.chdir(orig); p.cleanup(); }
2265
+ });
2266
+
2267
+ test('getAuditEntries: returns newest first with limit', () => {
2268
+ const p = mkProject();
2269
+ const orig = process.cwd();
2270
+ process.chdir(p.dir);
2271
+ try {
2272
+ const entries = [
2273
+ { id: '1', timestamp: '2026-01-01T10:00:00Z', event: 'task_completed', phase: 3, plan: '01' },
2274
+ { id: '2', timestamp: '2026-01-01T10:05:00Z', event: 'task_completed', phase: 3, plan: '02' },
2275
+ { id: '3', timestamp: '2026-01-01T10:10:00Z', event: 'security_finding', phase: 3 },
2276
+ ];
2277
+ p.write('.planning/AUDIT.jsonl', entries.map(e => JSON.stringify(e)).join('\n') + '\n');
2278
+
2279
+ const result = Metrics.getAuditEntries(2, 0, null);
2280
+ assert.strictEqual(result.entries.length, 2, 'Should respect limit');
2281
+ assert.strictEqual(result.entries[0].id, '3', 'Newest should be first (id=3)');
2282
+ assert.strictEqual(result.total, 3, 'Should report total count');
2283
+ } finally { process.chdir(orig); p.cleanup(); }
2284
+ });
2285
+
2286
+ test('getAuditEntries: filters by event type', () => {
2287
+ const p = mkProject();
2288
+ const orig = process.cwd();
2289
+ process.chdir(p.dir);
2290
+ try {
2291
+ const entries = [
2292
+ { id: '1', timestamp: '2026-01-01T10:00:00Z', event: 'task_completed' },
2293
+ { id: '2', timestamp: '2026-01-01T10:05:00Z', event: 'security_finding' },
2294
+ ];
2295
+ p.write('.planning/AUDIT.jsonl', entries.map(e => JSON.stringify(e)).join('\n') + '\n');
2296
+
2297
+ const result = Metrics.getAuditEntries(50, 0, 'security_finding');
2298
+ assert.ok(result.entries.every(e => e.event === 'security_finding'), 'Should only return filtered event type');
2299
+ assert.strictEqual(result.entries.length, 1, 'Should return 1 security_finding');
2300
+ } finally { process.chdir(orig); p.cleanup(); }
2301
+ });
2302
+
2303
+ test('getApprovals: returns categorized approvals', () => {
2304
+ const p = mkProject();
2305
+ const orig = process.cwd();
2306
+ process.chdir(p.dir);
2307
+ try {
2308
+ p.write(`.planning/approvals/APPROVAL-${SAMPLE_APPROVAL.id}.json`, JSON.stringify(SAMPLE_APPROVAL));
2309
+
2310
+ const result = Metrics.getApprovals();
2311
+ assert.ok(Array.isArray(result.pending), 'Should have pending array');
2312
+ assert.ok(Array.isArray(result.approved), 'Should have approved array');
2313
+ assert.ok(Array.isArray(result.rejected), 'Should have rejected array');
2314
+ assert.ok(Array.isArray(result.expired), 'Should have expired array');
2315
+ assert.strictEqual(result.pending.length, 1, 'Should have 1 pending approval');
2316
+ assert.strictEqual(result.pending[0].id, SAMPLE_APPROVAL.id);
2317
+ } finally { process.chdir(orig); p.cleanup(); }
2318
+ });
2319
+
2320
+ test('getApprovals: classifies expired approval correctly', () => {
2321
+ const p = mkProject();
2322
+ const orig = process.cwd();
2323
+ process.chdir(p.dir);
2324
+ try {
2325
+ const expired = {
2326
+ ...SAMPLE_APPROVAL,
2327
+ id: 'expired-uuid-1234-5678-abcd-ef0123456789',
2328
+ status: 'pending',
2329
+ expires_at: new Date(Date.now() - 3600_000).toISOString(), // 1 hour ago
2330
+ };
2331
+ p.write(`.planning/approvals/APPROVAL-${expired.id}.json`, JSON.stringify(expired));
2332
+
2333
+ const result = Metrics.getApprovals();
2334
+ assert.strictEqual(result.expired.length, 1, 'Should classify as expired');
2335
+ assert.strictEqual(result.pending.length, 0, 'Should not be in pending');
2336
+ } finally { process.chdir(orig); p.cleanup(); }
2337
+ });
2338
+
2339
+ test('getCosts: returns correct total', () => {
2340
+ const p = mkProject();
2341
+ const orig = process.cwd();
2342
+ process.chdir(p.dir);
2343
+ try {
2344
+ const today = new Date().toISOString().slice(0, 10);
2345
+ p.write('.mindforge/metrics/token-usage.jsonl',
2346
+ JSON.stringify({ date: today, model: 'claude-sonnet-4-6', cost_usd: 0.05 }) + '\n' +
2347
+ JSON.stringify({ date: today, model: 'gpt-4o', cost_usd: 0.12 }) + '\n'
2348
+ );
2349
+
2350
+ const costs = Metrics.getCosts(7);
2351
+ assert.ok(Math.abs(costs.total_usd - 0.17) < 0.001, `Expected ~0.17, got ${costs.total_usd}`);
2352
+ assert.ok(costs.by_model['claude-sonnet-4-6'], 'Should break down by model');
2353
+ assert.ok(costs.by_model['gpt-4o'], 'Should have gpt-4o');
2354
+ } finally { process.chdir(orig); p.cleanup(); }
2355
+ });
2356
+
2357
+ test('getTeamActivity: returns active developers from AUDIT', () => {
2358
+ const p = mkProject();
2359
+ const orig = process.cwd();
2360
+ process.chdir(p.dir);
2361
+ try {
2362
+ const now = new Date().toISOString();
2363
+ p.write('.planning/AUDIT.jsonl',
2364
+ JSON.stringify({ id: '1', timestamp: now, event: 'task_completed', authored_by: 'alice@team.com', phase: 3, plan: '04' }) + '\n' +
2365
+ JSON.stringify({ id: '2', timestamp: now, event: 'task_started', authored_by: 'bob@team.com', phase: 3, plan: '05' }) + '\n'
2366
+ );
2367
+
2368
+ const team = Metrics.getTeamActivity();
2369
+ assert.ok(Array.isArray(team.active), 'Should have active array');
2370
+ assert.ok(Array.isArray(team.conflicts), 'Should have conflicts array');
2371
+ assert.ok(team.active.some(a => a.email === 'alice@team.com'), 'Should include alice');
2372
+ assert.ok(team.active.some(a => a.email === 'bob@team.com'), 'Should include bob');
2373
+ } finally { process.chdir(orig); p.cleanup(); }
2374
+ });
2375
+
2376
+ // ── Approval handler ──────────────────────────────────────────────────────────
2377
+ console.log('\nApproval handler:');
2378
+
2379
+ test('processDecision: approves a valid pending approval', () => {
2380
+ const p = mkProject();
2381
+ const orig = process.cwd();
2382
+ process.chdir(p.dir);
2383
+ try {
2384
+ p.write(`.planning/approvals/APPROVAL-${SAMPLE_APPROVAL.id}.json`, JSON.stringify(SAMPLE_APPROVAL));
2385
+ p.write('.planning/AUDIT.jsonl', ''); // Create AUDIT file
2386
+
2387
+ const result = Approval.processDecision(SAMPLE_APPROVAL.id, 'approve', 'Looks good', 'reviewer@team.com');
2388
+ assert.strictEqual(result.success, true, 'Should succeed');
2389
+ assert.strictEqual(result.decision, 'approve', 'Should record approve decision');
2390
+
2391
+ const updated = JSON.parse(fs.readFileSync(path.join(p.dir, `.planning/approvals/APPROVAL-${SAMPLE_APPROVAL.id}.json`), 'utf8'));
2392
+ assert.strictEqual(updated.status, 'approved', 'File should be updated to approved');
2393
+ assert.strictEqual(updated.resolved_by, 'reviewer@team.com', 'Should record resolver');
2394
+ } finally { process.chdir(orig); p.cleanup(); }
2395
+ });
2396
+
2397
+ test('processDecision: rejects a valid pending approval', () => {
2398
+ const p = mkProject();
2399
+ const orig = process.cwd();
2400
+ process.chdir(p.dir);
2401
+ try {
2402
+ p.write(`.planning/approvals/APPROVAL-${SAMPLE_APPROVAL.id}.json`, JSON.stringify(SAMPLE_APPROVAL));
2403
+ p.write('.planning/AUDIT.jsonl', '');
2404
+
2405
+ const result = Approval.processDecision(SAMPLE_APPROVAL.id, 'reject', 'Not ready', 'reviewer@team.com');
2406
+ assert.strictEqual(result.success, true);
2407
+ assert.strictEqual(result.decision, 'reject');
2408
+ } finally { process.chdir(orig); p.cleanup(); }
2409
+ });
2410
+
2411
+ test('processDecision: rejects malformed approval ID', () => {
2412
+ const result = Approval.processDecision('../../evil/path', 'approve', '', '');
2413
+ assert.strictEqual(result.success, false, 'Should reject path traversal in ID');
2414
+ assert.ok(result.error, 'Should have error message');
2415
+ });
2416
+
2417
+ test('processDecision: rejects already-resolved approval', () => {
2418
+ const p = mkProject();
2419
+ const orig = process.cwd();
2420
+ process.chdir(p.dir);
2421
+ try {
2422
+ const alreadyApproved = { ...SAMPLE_APPROVAL, status: 'approved' };
2423
+ p.write(`.planning/approvals/APPROVAL-${SAMPLE_APPROVAL.id}.json`, JSON.stringify(alreadyApproved));
2424
+
2425
+ const result = Approval.processDecision(SAMPLE_APPROVAL.id, 'reject', '', '');
2426
+ assert.strictEqual(result.success, false, 'Should not allow re-resolving');
2427
+ assert.ok(result.error.includes('already'), 'Should explain why');
2428
+ } finally { process.chdir(orig); p.cleanup(); }
2429
+ });
2430
+
2431
+ test('processDecision: rejects invalid decision value', () => {
2432
+ const result = Approval.processDecision(SAMPLE_APPROVAL.id, 'maybe', '', '');
2433
+ assert.strictEqual(result.success, false);
2434
+ assert.ok(result.error, 'Should have error message');
2435
+ });
2436
+
2437
+ test('processDecision: rejects expired approval', () => {
2438
+ const p = mkProject();
2439
+ const orig = process.cwd();
2440
+ process.chdir(p.dir);
2441
+ try {
2442
+ const expired = { ...SAMPLE_APPROVAL, expires_at: new Date(Date.now() - 3600_000).toISOString() };
2443
+ p.write(`.planning/approvals/APPROVAL-${SAMPLE_APPROVAL.id}.json`, JSON.stringify(expired));
2444
+
2445
+ const result = Approval.processDecision(SAMPLE_APPROVAL.id, 'approve', '', '');
2446
+ assert.strictEqual(result.success, false, 'Should reject expired approval');
2447
+ assert.ok(result.error.includes('expired'), 'Should mention expiry');
2448
+ } finally { process.chdir(orig); p.cleanup(); }
2449
+ });
2450
+
2451
+ // ── SSE bridge ────────────────────────────────────────────────────────────────
2452
+ console.log('\nSSE bridge:');
2453
+
2454
+ test('addClient / getClientCount: tracks connected clients', () => {
2455
+ const initial = SSE.getClientCount();
2456
+ // Simulate a client (mock res object)
2457
+ const mockRes = { write: () => {}, on: (evt, cb) => {} };
2458
+ SSE.addClient(mockRes);
2459
+ assert.strictEqual(SSE.getClientCount(), initial + 1, 'Count should increase by 1');
2460
+ // Simulate disconnect
2461
+ const mockRes2 = { write: () => {}, on: (evt, cb) => { if (evt === 'close') setTimeout(cb, 0); } };
2462
+ SSE.addClient(mockRes2);
2463
+ });
2464
+
2465
+ test('broadcast: sends formatted SSE message', () => {
2466
+ const received = [];
2467
+ const mockRes = {
2468
+ write: msg => received.push(msg),
2469
+ on: () => {},
2470
+ };
2471
+ SSE.addClient(mockRes);
2472
+ SSE.broadcast('test:event', { hello: 'world' });
2473
+ const found = received.find(m => m.includes('test:event') && m.includes('hello'));
2474
+ assert.ok(found, 'Client should receive the broadcast message');
2475
+ assert.ok(found.includes('"hello":"world"'), 'Message should contain JSON data');
2476
+ });
2477
+
2478
+ // ── Frontend HTML integrity ───────────────────────────────────────────────────
2479
+ console.log('\nFrontend HTML:');
2480
+
2481
+ test('index.html: has all 5 page sections', () => {
2482
+ const html = fs.readFileSync('bin/dashboard/frontend/index.html', 'utf8');
2483
+ ['page-activity','page-metrics','page-approvals','page-memory','page-team']
2484
+ .forEach(id => assert.ok(html.includes(`id="${id}"`), `Missing page: ${id}`));
2485
+ });
2486
+
2487
+ test('index.html: has SSE EventSource connection', () => {
2488
+ const html = fs.readFileSync('bin/dashboard/frontend/index.html', 'utf8');
2489
+ assert.ok(html.includes('EventSource'), 'Should create EventSource for SSE');
2490
+ assert.ok(html.includes('/events'), 'Should connect to /events endpoint');
2491
+ });
2492
+
2493
+ test('index.html: has security-safe HTML escaping', () => {
2494
+ const html = fs.readFileSync('bin/dashboard/frontend/index.html', 'utf8');
2495
+ assert.ok(html.includes('escapeHtml'), 'Should have HTML escaping function');
2496
+ assert.ok(html.includes('replace(/&/g'), 'Should escape ampersands');
2497
+ });
2498
+
2499
+ test('index.html: has approval action buttons', () => {
2500
+ const html = fs.readFileSync('bin/dashboard/frontend/index.html', 'utf8');
2501
+ assert.ok(html.includes('decide('), 'Should have decide() function for approvals');
2502
+ assert.ok(html.includes('/api/approve/'), 'Should call approval API endpoint');
2503
+ });
2504
+
2505
+ // ── Security validations ──────────────────────────────────────────────────────
2506
+ console.log('\nSecurity properties:');
2507
+
2508
+ test('server.js binds to 127.0.0.1 not 0.0.0.0', () => {
2509
+ const c = fs.readFileSync('bin/dashboard/server.js', 'utf8');
2510
+ assert.ok(c.includes("'127.0.0.1'"), 'Should bind to 127.0.0.1');
2511
+ assert.ok(!c.includes("'0.0.0.0'"), 'Must NOT bind to 0.0.0.0');
2512
+ });
2513
+
2514
+ test('api-router.js has injection guard on steering endpoint', () => {
2515
+ const c = fs.readFileSync('bin/dashboard/api-router.js', 'utf8');
2516
+ assert.ok(c.includes('INJECTION_PATTERNS'), 'Should have injection patterns array');
2517
+ assert.ok(c.includes('prohibited'), 'Should reject prohibited patterns');
2518
+ });
2519
+
2520
+ test('approval-handler.js validates UUID format before file access', () => {
2521
+ const c = fs.readFileSync('bin/dashboard/approval-handler.js', 'utf8');
2522
+ assert.ok(c.includes('[a-f0-9-]'), 'Should validate UUID format');
2523
+ });
2524
+
2525
+ test('server.js has request body size limit', () => {
2526
+ const c = fs.readFileSync('bin/dashboard/server.js', 'utf8');
2527
+ assert.ok(c.includes('limit') && c.includes('64kb'), 'Should limit request body to 64kb');
2528
+ });
2529
+
2530
+ test('server.js rejects non-localhost connections with 403', () => {
2531
+ const c = fs.readFileSync('bin/dashboard/server.js', 'utf8');
2532
+ assert.ok(c.includes('403'), 'Should return 403 for non-localhost');
2533
+ assert.ok(c.includes('isLocal'), 'Should check if request is local');
2534
+ });
2535
+
2536
+ // ── All 45 commands ───────────────────────────────────────────────────────────
2537
+ console.log('\nAll 45 commands (44 + 1 Day 12):');
2538
+
2539
+ const ALL_COMMANDS = [
2540
+ 'help','init-project','plan-phase','execute-phase','verify-phase','ship',
2541
+ 'next','quick','status','debug',
2542
+ 'skills','review','security-scan','map-codebase','discuss-phase',
2543
+ 'audit','milestone','complete-milestone','approve','sync-jira','sync-confluence',
2544
+ 'health','retrospective','profile-team','metrics',
2545
+ 'init-org','install-skill','publish-skill','pr-review','workspace','benchmark',
2546
+ 'update','migrate','plugins','tokens','release',
2547
+ 'auto','steer',
2548
+ 'browse','qa',
2549
+ 'cross-review','research','costs',
2550
+ 'remember',
2551
+ 'dashboard',
2552
+ ];
2553
+ assert.strictEqual(ALL_COMMANDS.length, 45);
2554
+
2555
+ test('all 45 commands in .claude/commands/mindforge/', () => {
2556
+ const missing = ALL_COMMANDS.filter(c => !fs.existsSync(`.claude/commands/mindforge/${c}.md`));
2557
+ assert.strictEqual(missing.length, 0, `Missing: ${missing.join(', ')}`);
2558
+ });
2559
+
2560
+ test('all 45 commands mirrored in .agent/mindforge/', () => {
2561
+ const missing = ALL_COMMANDS.filter(c => !fs.existsSync(`.agent/mindforge/${c}.md`));
2562
+ assert.strictEqual(missing.length, 0, `Missing agent: ${missing.join(', ')}`);
2563
+ });
2564
+
2565
+ // ── Version ───────────────────────────────────────────────────────────────────
2566
+ console.log('\nVersion:');
2567
+
2568
+ test('package.json is v2.0.0-alpha.5', () => {
2569
+ const v = JSON.parse(fs.readFileSync('package.json', 'utf8')).version;
2570
+ assert.ok(v === '2.0.0-alpha.5' || v.startsWith('2.'), `Expected v2.x, got ${v}`);
2571
+ });
2572
+
2573
+ // ── Results ───────────────────────────────────────────────────────────────────
2574
+ console.log(`\n${'─'.repeat(55)}`);
2575
+ console.log(`Results: ${passed} passed, ${failed} failed`);
2576
+ if (failed > 0) { console.error(`\n❌ ${failed} test(s) failed.\n`); process.exit(1); }
2577
+ else { console.log(`\n✅ All dashboard tests passed.\n`); }
2578
+ ```
2579
+
2580
+ **Commit:**
2581
+ ```bash
2582
+ git add tests/dashboard.test.js
2583
+ git commit -m "test(v2-dashboard): add comprehensive dashboard test suite (20th suite)"
2584
+ ```
2585
+
2586
+ ---
2587
+
2588
+ ## TASK 12 — Bump version, update CHANGELOG, push
2589
+
2590
+ ```bash
2591
+ node -e "
2592
+ const fs = require('fs');
2593
+ const p = JSON.parse(fs.readFileSync('package.json','utf8'));
2594
+ p.version = '2.0.0-alpha.5';
2595
+ fs.writeFileSync('package.json', JSON.stringify(p, null, 2) + '\n');
2596
+ console.log('Bumped to v2.0.0-alpha.5');
2597
+ "
2598
+ ```
2599
+
2600
+ Update `CHANGELOG.md`:
2601
+
2602
+ ```markdown
2603
+ ## [2.0.0-alpha.5] — Day 12: Real-Time Web Observability Dashboard
2604
+
2605
+ ### Added
2606
+
2607
+ **Dashboard Server:**
2608
+ - bin/dashboard/server.js — Express.js HTTP server at localhost:7339
2609
+ - Localhost-only binding (127.0.0.1) — consistent with ADR-017
2610
+ - Security middleware: IP check, CORS (localhost-only), body limit (64kb)
2611
+ - Security headers: X-Content-Type-Options, X-Frame-Options, no-cache
2612
+ - Graceful shutdown on SIGTERM/SIGINT with PID file cleanup
2613
+ - --open flag opens default browser automatically
2614
+
2615
+ **SSE Event Bridge:**
2616
+ - bin/dashboard/sse-bridge.js — tails AUDIT.jsonl, auto-state.json, approvals/
2617
+ - 2-second poll interval for live event delivery
2618
+ - 15-second keepalive ping to detect disconnected clients
2619
+ - Client tracking via Set (auto-removes on close)
2620
+
2621
+ **Metrics Aggregator:**
2622
+ - bin/dashboard/metrics-aggregator.js — 7 data source readers
2623
+ - getStatus(): HANDOFF.json + auto-state.json → current execution state
2624
+ - getAuditEntries(): newest-first with limit/offset/event-filter
2625
+ - getMetrics(): quality trends, security findings, repair rate
2626
+ - getApprovals(): categorized (pending/approved/rejected/expired)
2627
+ - getTeamActivity(): active developers + file conflict detection
2628
+ - getMemory(): knowledge base search
2629
+ - getCosts(): per-model cost summary with daily limit %
2630
+
2631
+ **Approval Handler:**
2632
+ - bin/dashboard/approval-handler.js — approve/reject from browser
2633
+ - UUID format validation (prevents path traversal in approval ID)
2634
+ - Expiry enforcement (rejects expired approvals)
2635
+ - Writes AUDIT entry for every approval decision
2636
+ - resolution_channel: 'mindforge-dashboard' for traceability
2637
+
2638
+ **API Router (10 endpoints):**
2639
+ - GET /events — SSE stream with initial status push
2640
+ - GET /api/status, /api/audit, /api/metrics, /api/approvals
2641
+ - GET /api/team, /api/memory, /api/costs, /api/connections
2642
+ - POST /api/approve/:id — with UUID validation
2643
+ - POST /api/steer — with injection guard + auto-mode check
2644
+
2645
+ **Frontend (single-file HTML, no build step):**
2646
+ - bin/dashboard/frontend/index.html — dark theme, 5-page dashboard
2647
+ - Page 1 Activity: live event feed, wave progress, steering input
2648
+ - Page 2 Quality: 4 charts (quality, verify, security, cost)
2649
+ - Page 3 Approvals: approve/reject from browser with confirmation
2650
+ - Page 4 Knowledge: searchable knowledge graph display
2651
+ - Page 5 Team: active developers, last-seen, file conflicts
2652
+ - Charts: canvas-based line and bar charts (no external lib)
2653
+ - HTML escaping: escapeHtml() on all user-derived content
2654
+
2655
+ **New Command (total: 45):**
2656
+ - /mindforge:dashboard — start/stop/status/open the web dashboard
2657
+
2658
+ **Tests:**
2659
+ - tests/dashboard.test.js — 20th suite (all aggregator functions,
2660
+ approval handler CRUD, SSE client management, frontend integrity,
2661
+ security property validation)
2662
+ ```
2663
+
2664
+ ```bash
2665
+ git add CHANGELOG.md package.json
2666
+ git commit -m "chore(v2-alpha5): Day 12 complete — real-time web dashboard, v2.0.0-alpha.5"
2667
+ git push origin feat/mindforge-v2-realtime-dashboard
2668
+ ```
2669
+
2670
+ ---
2671
+
2672
+ # ═══════════════════════════════════════════════════════════════════════
2673
+ # PART 2 — REVIEW PROMPT
2674
+ # ═══════════════════════════════════════════════════════════════════════
2675
+
2676
+ ---
2677
+
2678
+ ## DAY 12 REVIEW
2679
+
2680
+ Activate **`architect.md` + `security-reviewer.md` + `qa-engineer.js`** simultaneously.
2681
+
2682
+ Day 12 risk profile:
2683
+ 1. **Approval ID path traversal** — POST /api/approve/:id with crafted ID
2684
+ 2. **Steering injection via dashboard** — browser UI sends instructions to agent context
2685
+ 3. **SSE client accumulation** — disconnected clients never cleaned up = memory leak
2686
+ 4. **Chart data XSS** — knowledge topics/content rendered to canvas or innerHTML
2687
+ 5. **CORS bypass** — misconfigured CORS allows cross-origin approval actions
2688
+ 6. **Approval without auth** — any localhost process can approve Tier 3 changes via API
2689
+
2690
+ ---
2691
+
2692
+ ## REVIEW PASS 1 — Approval Security
2693
+
2694
+ Read `approval-handler.js` and `api-router.js` completely.
2695
+
2696
+ - [ ] **UUID validation in `processDecision` is correct but `api-router.js` uses `req.params.id` directly** without its own validation layer. Express route params are strings — a carefully crafted URL like `/api/approve/../../../../.planning/approvals/APPROVAL-real-uuid` could bypass the UUID check if path normalization behaves unexpectedly. Fix: "Add a second validation in `api-router.js` before calling `processDecision`: `if (!/^[a-f0-9-]{36}$/.test(req.params.id)) return res.status(400).json({ error: 'Invalid ID format' })`."
2697
+
2698
+ - [ ] **Tier 3 approvals can be approved via the dashboard without CLI verification.** The approval handler writes `approved` to the file — the same mechanism that CLI approval uses. But Tier 3 governance was designed to require a human with CLI access. Dashboard approval means a stakeholder who can access the dashboard (any localhost process) can approve Tier 3 (payment/PII/auth) changes without ever seeing the code diff. Fix: "Add a Tier 3 browser confirmation: require the approver to type the plan ID to confirm (not just click Approve). Add `confirmation_required: true` flag for Tier 3. The frontend shows: 'Type the plan ID to confirm Tier 3 approval:' input field."
2699
+
2700
+ - [ ] **Approval handler writes the approval file in-place after validation.** If the process crashes between writing `status: approved` and writing the AUDIT entry, the approval is recorded but the AUDIT trail is missing. Fix: "Write the AUDIT entry FIRST (before updating the approval file). If the AUDIT write succeeds but the file update fails: the state is slightly inconsistent (AUDIT says approved, file says pending) but the human reviewer can reconcile. If the file update succeeds but AUDIT write fails: approval happens silently — this is the worse case. Write AUDIT first."
2701
+
2702
+ ---
2703
+
2704
+ ## REVIEW PASS 2 — SSE Bridge: Memory Leaks
2705
+
2706
+ Read `sse-bridge.js` completely.
2707
+
2708
+ - [ ] **`clients` Set grows without cleanup when clients disconnect ungracefully.** The `res.on('close')` handler removes the client correctly — but only for graceful TCP closures. If the client connection dies without a TCP close (NAT timeout, process kill), the client stays in the Set forever. Fix: "Add a write-error cleanup: wrap `res.write()` in a try-catch. If writing throws (EPIPE, ECONNRESET), remove the client from the Set immediately. The existing try-catch does call `clients.delete(res)` — verify this is working by testing with a simulated write failure."
2709
+
2710
+ - [ ] **`pollAuditLog` reads file bytes by position assuming no file rotation.** If AUDIT.jsonl is rotated (renamed, new file created), `_lastAuditSize` will be wrong. The new file will have size < `_lastAuditSize`, but the condition `newSize <= _lastAuditSize` would return early and miss all new events. Fix: "On each poll: check if the file's inode has changed (compare `stat.ino`). If the inode changed: the file was rotated. Reset `_lastAuditSize = 0` and re-read from start."
2711
+
2712
+ ---
2713
+
2714
+ ## REVIEW PASS 3 — Frontend: XSS Risk
2715
+
2716
+ Read `bin/dashboard/frontend/index.html` completely.
2717
+
2718
+ - [ ] **`escapeHtml` is defined but not consistently applied.** Several `innerHTML` assignments use `escapeHtml()` correctly (`approval-card`, `memory-list`, `developer-row`). But `createAuditRow` uses `escapeHtml(detail)` — the `detail` variable is built from `entry.plan`, `entry.phase`, `entry.task_name`, etc. If any AUDIT.jsonl entry contains `<script>` in a task name (possible if a steering instruction is used as a task name), it would execute. Fix: "Verify every `innerHTML` assignment with dynamic content calls `escapeHtml()`. Add a note: 'All user-derived content MUST go through escapeHtml() before setting innerHTML. Never trust AUDIT.jsonl content.'"
2719
+
2720
+ - [ ] **Chart data could contain XSS if rendered to text.** The chart drawing uses `ctx.fillText(labels[i], ...)` for label text. Canvas `fillText` does not execute HTML/JS — it's safe. But `setText()` uses `textContent` (safe). The issue would only arise if chart labels were ever put into `innerHTML` — verify they are not.
2721
+
2722
+ ---
2723
+
2724
+ ## REVIEW PASS 4 — API Router: Input Validation
2725
+
2726
+ Read `api-router.js` completely.
2727
+
2728
+ - [ ] **`/api/memory?q=` query parameter is truncated to 100 chars but not sanitized.** The query is passed to `Metrics.getMemory(q, limit)` which does `entry.topic.toLowerCase().includes(q)`. This is safe (string comparison only). But if the knowledge base content were ever rendered into innerHTML without escaping, the query value could be used for injection. This is already guarded by `escapeHtml()` in the frontend — document this dependency explicitly.
2729
+
2730
+ - [ ] **`/api/steer` validation checks auto-mode running but reads auto-state.json directly.** If auto-state.json is stale (e.g., auto mode crashed without updating it), the check passes (`status: running`) even though no auto-mode loop is actually reading the steering queue. This is a minor issue — the queued instruction just gets ignored. Document: "Steer queue is best-effort — if auto mode has crashed, queued instructions will be picked up when auto mode resumes."
2731
+
2732
+ ---
2733
+
2734
+ ## REVIEW PASS 5 — Server Security
2735
+
2736
+ Read `server.js` completely.
2737
+
2738
+ - [ ] **CORS `Access-Control-Allow-Origin: *` fallback when no `origin` header.** The CORS middleware sets `*` when `origin` is absent. This happens with same-origin requests (correct) but also with curl, Postman, and scripted API calls. Since the dashboard is localhost-only, this is acceptable — but should be tightened. Fix: "When `origin` is absent, don't set CORS header at all (same-origin requests don't need it). Only set CORS headers when an origin header is present and it's localhost."
2739
+
2740
+ - [ ] **`--open` flag spawns a child process using `require('child_process').spawn`.** The `open`/`start`/`xdg-open` command is selected based on `process.platform`. On Linux, `xdg-open` opens a URL in the default browser. But the URL is hardcoded as `http://localhost:${PORT}` — no user input. This is safe (no injection possible). However, `detached: true` without `stdio: 'inherit'` means errors from the browser open command are silently ignored. This is the correct behaviour for this use case.
2741
+
2742
+ ---
2743
+
2744
+ ## REVIEW PASS 6 — Test Suite
2745
+
2746
+ Read `tests/dashboard.test.js` completely.
2747
+
2748
+ - [ ] **Missing test: Tier 3 approval confirmation requirement.** After hardening Pass 1 (Tier 3 requires typing plan ID), add a test that verifies the backend rejects a Tier 3 approval without the confirmation.
2749
+
2750
+ - [ ] **Missing test: SSE inode rotation.** After hardening Pass 2 (inode-based rotation detection), add a test that simulates file rotation and verifies new events are not missed.
2751
+
2752
+ - [ ] **`broadcast` test: the mock client stays in the `clients` Set.** After calling `SSE.addClient(mockRes)` in the test, the mockRes remains in the Set for subsequent tests. This could cause `broadcast` tests to fail in non-isolated order. Fix: "After the broadcast test, remove the mock client from the Set by simulating a close event."
2753
+
2754
+ ---
2755
+
2756
+ ## REVIEW SUMMARY TABLE
2757
+
2758
+ ```
2759
+ ## Day 12 Review Summary
2760
+
2761
+ | Category | BLOCKING | MAJOR | MINOR | SUGGESTION |
2762
+ |--------------------|----------|-------|-------|------------|
2763
+ | Approval Security | | | | |
2764
+ | SSE Bridge | | | | |
2765
+ | Frontend XSS | | | | |
2766
+ | API Router | | | | |
2767
+ | Server Security | | | | |
2768
+ | Test Suite | | | | |
2769
+ | **TOTAL** | | | | |
2770
+
2771
+ ## Verdict
2772
+ [ ] ✅ APPROVED — Proceed to HARDEN section
2773
+ [ ] ⚠️ APPROVED WITH CONDITIONS
2774
+ [ ] ❌ NOT APPROVED
2775
+ ```
2776
+
2777
+ ---
2778
+
2779
+ # ═══════════════════════════════════════════════════════════════════════
2780
+ # PART 3 — HARDENING PROMPT
2781
+ # ═══════════════════════════════════════════════════════════════════════
2782
+
2783
+ ---
2784
+
2785
+ ## DAY 12 HARDENING
2786
+
2787
+ Activate **`security-reviewer.md` + `architect.md`** simultaneously.
2788
+
2789
+ Confirm all test suites pass before hardening:
2790
+ ```bash
2791
+ for suite in install wave-engine audit compaction skills-platform \
2792
+ integrations governance intelligence metrics \
2793
+ distribution ci-mode sdk production migration e2e \
2794
+ autonomous browser model-routing memory dashboard; do
2795
+ printf " %-30s" "${suite}..."
2796
+ node tests/${suite}.test.js 2>&1 | tail -1
2797
+ done
2798
+ ```
2799
+
2800
+ ---
2801
+
2802
+ ## HARDEN 1 — Add Tier 3 confirmation requirement
2803
+
2804
+ Update `bin/dashboard/approval-handler.js`:
2805
+
2806
+ ```javascript
2807
+ /**
2808
+ * Updated processDecision — Tier 3 requires plan ID confirmation
2809
+ */
2810
+ function processDecision(approvalId, decision, comment, approver, confirmationId = null) {
2811
+ // Existing validation...
2812
+ if (!/^[a-f0-9-]{36}$/.test(approvalId)) {
2813
+ return { success: false, error: 'Malformed approval ID format' };
2814
+ }
2815
+ // ... file read and pending check ...
2816
+
2817
+ // TIER 3 CONFIRMATION — require typing the plan ID
2818
+ if (approval.tier === 3 && decision === 'approve') {
2819
+ const expectedConfirmation = `${approval.phase}-${approval.plan}`;
2820
+ if (!confirmationId || confirmationId.trim() !== expectedConfirmation) {
2821
+ return {
2822
+ success: false,
2823
+ error: `Tier 3 approval requires typing the plan ID to confirm.`,
2824
+ confirmation_required: true,
2825
+ expected: expectedConfirmation,
2826
+ tier3_warning: 'This is a Tier 3 change (auth/payment/PII). Review the code diff before approving.',
2827
+ };
2828
+ }
2829
+ }
2830
+
2831
+ // ... rest of function unchanged ...
2832
+ }
2833
+ ```
2834
+
2835
+ Update `bin/dashboard/frontend/index.html` — `decide()` function:
2836
+
2837
+ ```javascript
2838
+ async function decide(id, decision, tier) {
2839
+ let confirmationId = null;
2840
+
2841
+ if (decision === 'approve' && tier === 3) {
2842
+ confirmationId = prompt(
2843
+ '⚠️ TIER 3 APPROVAL (auth/payment/PII)\n\n' +
2844
+ 'Review the code diff before approving.\n\n' +
2845
+ 'Type the plan ID (e.g., "3-04") to confirm:'
2846
+ );
2847
+ if (!confirmationId) return; // User cancelled
2848
+ } else {
2849
+ if (!confirm(`${decision === 'approve' ? 'Approve' : 'Reject'} this request?`)) return;
2850
+ }
2851
+
2852
+ try {
2853
+ const r = await fetch(`/api/approve/${id}`, {
2854
+ method: 'POST',
2855
+ headers: { 'Content-Type': 'application/json' },
2856
+ body: JSON.stringify({ decision, approver: 'dashboard-user', confirmation_id: confirmationId }),
2857
+ });
2858
+ const d = await r.json();
2859
+ if (d.success) { showToast(d.message); loadApprovals(); }
2860
+ else if (d.confirmation_required) {
2861
+ showToast('Confirmation required: type the plan ID exactly', true);
2862
+ } else {
2863
+ showToast('Error: ' + d.error, true);
2864
+ }
2865
+ } catch { showToast('Request failed', true); }
2866
+ }
2867
+ ```
2868
+
2869
+ Also update `/api/approve/:id` in `api-router.js` to pass `confirmation_id`:
2870
+
2871
+ ```javascript
2872
+ app.post('/api/approve/:id', (req, res) => {
2873
+ // ... existing validation ...
2874
+ const { decision, comment, approver, confirmation_id } = req.body || {};
2875
+ const result = Approval.processDecision(id, decision, comment, approver, confirmation_id);
2876
+ // ...
2877
+ });
2878
+ ```
2879
+
2880
+ **Commit:**
2881
+ ```bash
2882
+ git add bin/dashboard/approval-handler.js \
2883
+ bin/dashboard/frontend/index.html \
2884
+ bin/dashboard/api-router.js
2885
+ git commit -m "harden(v2-dashboard): add Tier 3 confirmation — must type plan ID to approve"
2886
+ ```
2887
+
2888
+ ---
2889
+
2890
+ ## HARDEN 2 — Fix SSE inode rotation detection
2891
+
2892
+ Update `bin/dashboard/sse-bridge.js`:
2893
+
2894
+ ```javascript
2895
+ let _auditInode = 0; // Track file inode for rotation detection
2896
+
2897
+ function pollAuditLog() {
2898
+ if (!fs.existsSync(AUDIT_PATH)) return;
2899
+
2900
+ try {
2901
+ const stat = fs.statSync(AUDIT_PATH);
2902
+ const newSize = stat.size;
2903
+ const newIno = stat.ino;
2904
+
2905
+ // File rotation detected: inode changed or new file is smaller
2906
+ if (newIno !== _auditInode && _auditInode !== 0) {
2907
+ process.stderr.write('[sse-bridge] AUDIT.jsonl rotation detected — resetting position\n');
2908
+ _lastAuditSize = 0;
2909
+ }
2910
+ _auditInode = newIno;
2911
+
2912
+ if (newSize <= _lastAuditSize) return;
2913
+
2914
+ // ... rest of poll logic unchanged ...
2915
+ } catch { /* ignore */ }
2916
+ }
2917
+ ```
2918
+
2919
+ Also fix SSE `broadcast` to handle write errors more robustly:
2920
+
2921
+ ```javascript
2922
+ function broadcast(eventName, data) {
2923
+ const message = `event: ${eventName}\ndata: ${JSON.stringify(data)}\n\n`;
2924
+ const toRemove = [];
2925
+ for (const res of clients) {
2926
+ try {
2927
+ res.write(message);
2928
+ } catch (err) {
2929
+ // Connection died ungracefully (EPIPE, ECONNRESET, etc.)
2930
+ toRemove.push(res);
2931
+ }
2932
+ }
2933
+ // Remove dead clients outside the iteration
2934
+ toRemove.forEach(res => clients.delete(res));
2935
+ }
2936
+ ```
2937
+
2938
+ **Commit:**
2939
+ ```bash
2940
+ git add bin/dashboard/sse-bridge.js
2941
+ git commit -m "harden(v2-dashboard): fix SSE inode rotation detection and dead client cleanup"
2942
+ ```
2943
+
2944
+ ---
2945
+
2946
+ ## HARDEN 3 — Fix CORS header for requests without Origin
2947
+
2948
+ Update `server.js` CORS middleware:
2949
+
2950
+ ```javascript
2951
+ // CORS — only allow requests from localhost origins
2952
+ app.use((req, res, next) => {
2953
+ const origin = req.headers.origin;
2954
+
2955
+ if (origin && /^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/.test(origin)) {
2956
+ // Explicit localhost origin — set CORS headers
2957
+ res.setHeader('Access-Control-Allow-Origin', origin);
2958
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
2959
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
2960
+ res.setHeader('Vary', 'Origin'); // Important: vary by origin for caching
2961
+ }
2962
+ // No origin header (same-origin/curl/postman): don't set CORS headers
2963
+ // This is correct — same-origin requests don't need CORS headers
2964
+
2965
+ if (req.method === 'OPTIONS') return res.status(204).end();
2966
+ next();
2967
+ });
2968
+ ```
2969
+
2970
+ **Commit:**
2971
+ ```bash
2972
+ git add bin/dashboard/server.js
2973
+ git commit -m "harden(v2-dashboard): fix CORS — don't set wildcard for requests without Origin header"
2974
+ ```
2975
+
2976
+ ---
2977
+
2978
+ ## HARDEN 4 — Write AUDIT entry before updating approval file
2979
+
2980
+ Update `bin/dashboard/approval-handler.js`:
2981
+
2982
+ ```javascript
2983
+ function processDecision(approvalId, decision, comment, approver, confirmationId = null) {
2984
+ // ... existing validation ...
2985
+
2986
+ const updated = {
2987
+ ...approval,
2988
+ status: decision === 'approve' ? 'approved' : 'rejected',
2989
+ resolved_at: new Date().toISOString(),
2990
+ resolved_by: approver || 'dashboard',
2991
+ comment: comment || null,
2992
+ resolution_channel: 'mindforge-dashboard',
2993
+ };
2994
+
2995
+ const auditEntry = {
2996
+ id: require('crypto').randomBytes(8).toString('hex'),
2997
+ timestamp: new Date().toISOString(),
2998
+ event: decision === 'approve' ? 'approval_granted' : 'approval_rejected',
2999
+ approval_id: approvalId,
3000
+ tier: approval.tier,
3001
+ phase: approval.phase,
3002
+ plan: approval.plan,
3003
+ resolved_by: approver || 'dashboard',
3004
+ comment: comment || null,
3005
+ agent: 'mindforge-dashboard',
3006
+ session_id: 'dashboard',
3007
+ };
3008
+
3009
+ // WRITE AUDIT FIRST — then update the approval file
3010
+ // If AUDIT write fails: don't update approval (safer — approval can be retried)
3011
+ // If approval write fails: AUDIT says approved but file says pending (reconcilable)
3012
+ try {
3013
+ writeAuditEntry(auditEntry);
3014
+ } catch (auditErr) {
3015
+ process.stderr.write(`[approval-handler] AUDIT write failed — aborting approval: ${auditErr.message}\n`);
3016
+ return { success: false, error: 'AUDIT write failed — approval not processed. Retry.' };
3017
+ }
3018
+
3019
+ // Now update the approval file
3020
+ fs.writeFileSync(filePath, JSON.stringify(updated, null, 2));
3021
+
3022
+ return {
3023
+ success: true,
3024
+ decision,
3025
+ approval_id: approvalId,
3026
+ tier: approval.tier,
3027
+ message: `${approval.tier === 3 ? 'Tier 3' : 'Tier 2'} approval ${decision}d for Plan ${approval.phase}-${approval.plan}`,
3028
+ };
3029
+ }
3030
+ ```
3031
+
3032
+ **Commit:**
3033
+ ```bash
3034
+ git add bin/dashboard/approval-handler.js
3035
+ git commit -m "harden(v2-dashboard): write AUDIT entry before approval file update (fail-safe ordering)"
3036
+ ```
3037
+
3038
+ ---
3039
+
3040
+ ## HARDEN 5 — Write 3 ADRs for Day 12 decisions
3041
+
3042
+ ### `.planning/decisions/ADR-033-dashboard-localhost-only.md`
3043
+
3044
+ ```markdown
3045
+ # ADR-033: Dashboard binds to localhost only (127.0.0.1)
3046
+
3047
+ **Status:** Accepted | **Date:** v2.0.0 | **Day:** 12
3048
+
3049
+ ## Context
3050
+ The dashboard shows live project state including security findings, code decisions,
3051
+ and team activity. Should it be accessible on the network?
3052
+
3053
+ ## Decision
3054
+ Dashboard binds to 127.0.0.1 only. Same policy as SDK SSE (ADR-017) and
3055
+ Browser Daemon (ADR-024).
3056
+
3057
+ ## Rationale
3058
+ The dashboard contains sensitive project information:
3059
+ - Security findings with vulnerability details
3060
+ - Knowledge graph with architectural decisions
3061
+ - Team member email addresses
3062
+ - Cost tracking and token usage
3063
+ - Approval requests with code diffs
3064
+
3065
+ Exposing this on a network interface would require authentication, TLS, and
3066
+ access control — adding significant complexity. The use case (team visibility)
3067
+ is better served by screensharing the developer's browser than exposing an
3068
+ unauthenticated server.
3069
+
3070
+ ## Consequences
3071
+ Remote team members: screenshare or SSH tunnel.
3072
+ CI environments: dashboard not started in headless mode.
3073
+ ```
3074
+
3075
+ ### `.planning/decisions/ADR-034-tier3-approval-confirmation.md`
3076
+
3077
+ ```markdown
3078
+ # ADR-034: Tier 3 dashboard approvals require typing the plan ID
3079
+
3080
+ **Status:** Accepted | **Date:** v2.0.0 | **Day:** 12
3081
+
3082
+ ## Context
3083
+ The dashboard allows approving governance requests via a button click.
3084
+ Tier 3 changes (auth/payment/PII) are high-stakes. Should they be
3085
+ approachable from the dashboard the same way as Tier 2?
3086
+
3087
+ ## Decision
3088
+ Tier 3 dashboard approvals require the approver to type the plan ID
3089
+ (e.g., "3-04") into a confirmation input field before the approval is processed.
3090
+
3091
+ ## Rationale
3092
+ A mis-click or accidental browser interaction should not approve a Tier 3 change.
3093
+ The type-to-confirm pattern (used by GitHub for repository deletion) creates a
3094
+ deliberate speed bump that prevents accidental approval.
3095
+ The plan ID is specific enough to require intent but simple enough to not be burdensome.
3096
+
3097
+ ## Consequences
3098
+ Tier 2 approvals: single click + confirm dialog.
3099
+ Tier 3 approvals: single click + type plan ID.
3100
+ Tier 3 rejections: single click + confirm dialog (no typing required to reject).
3101
+ ```
3102
+
3103
+ ### `.planning/decisions/ADR-035-audit-before-approval-file.md`
3104
+
3105
+ ```markdown
3106
+ # ADR-035: AUDIT entry written before approval file update
3107
+
3108
+ **Status:** Accepted | **Date:** v2.0.0 | **Day:** 12
3109
+
3110
+ ## Context
3111
+ When approving a governance request, two writes are required:
3112
+ 1. AUDIT.jsonl entry (compliance trail)
3113
+ 2. APPROVAL-*.json file update (status: approved)
3114
+
3115
+ In which order should these writes occur?
3116
+
3117
+ ## Decision
3118
+ AUDIT entry is written first. If AUDIT write fails, the approval is aborted.
3119
+ If AUDIT succeeds but APPROVAL file write fails: AUDIT shows approved but
3120
+ APPROVAL file still shows pending. This is reconcilable by retrying.
3121
+
3122
+ ## Rationale
3123
+ The AUDIT trail is the compliance record. An approval without an AUDIT entry
3124
+ is a silent approval — undetectable in compliance audits.
3125
+
3126
+ The reverse (APPROVAL file updated but no AUDIT) is worse because:
3127
+ 1. The governance gate would pass (approval file says approved)
3128
+ 2. The audit trail would show no approval event
3129
+ 3. This would be a compliance violation
3130
+
3131
+ By writing AUDIT first: if anything fails, the approval is either fully
3132
+ recorded (both written) or not recorded at all (AUDIT write failed = abort).
3133
+
3134
+ ## Consequences
3135
+ AUDIT write failure = approval not processed (retry required).
3136
+ This is the correct fail-safe: prefer no approval over silent approval.
3137
+ ```
3138
+
3139
+ **Commit:**
3140
+ ```bash
3141
+ git add .planning/decisions/ADR-033*.md \
3142
+ .planning/decisions/ADR-034*.md \
3143
+ .planning/decisions/ADR-035*.md
3144
+ git commit -m "docs(adr): add ADR-033 dashboard localhost, ADR-034 Tier 3 confirm, ADR-035 audit-before-approval"
3145
+ ```
3146
+
3147
+ ---
3148
+
3149
+ ## HARDEN 6 — Add hardening tests
3150
+
3151
+ ```javascript
3152
+ // Add to tests/dashboard.test.js:
3153
+
3154
+ console.log('\nHardening tests:');
3155
+
3156
+ test('Tier 3 approval without confirmation is rejected', () => {
3157
+ const p = mkProject();
3158
+ const orig = process.cwd();
3159
+ process.chdir(p.dir);
3160
+ try {
3161
+ const tier3Approval = { ...SAMPLE_APPROVAL, tier: 3 };
3162
+ p.write(`.planning/approvals/APPROVAL-${SAMPLE_APPROVAL.id}.json`, JSON.stringify(tier3Approval));
3163
+
3164
+ // No confirmationId provided
3165
+ const result = Approval.processDecision(SAMPLE_APPROVAL.id, 'approve', '', 'approver@test.com', null);
3166
+ assert.strictEqual(result.success, false, 'Should fail without confirmation');
3167
+ assert.ok(result.confirmation_required, 'Should indicate confirmation is required');
3168
+ assert.ok(result.tier3_warning, 'Should include tier3 warning');
3169
+ } finally { process.chdir(orig); p.cleanup(); }
3170
+ });
3171
+
3172
+ test('Tier 3 approval with correct plan ID succeeds', () => {
3173
+ const p = mkProject();
3174
+ const orig = process.cwd();
3175
+ process.chdir(p.dir);
3176
+ try {
3177
+ const tier3Approval = { ...SAMPLE_APPROVAL, tier: 3 };
3178
+ p.write(`.planning/approvals/APPROVAL-${SAMPLE_APPROVAL.id}.json`, JSON.stringify(tier3Approval));
3179
+ p.write('.planning/AUDIT.jsonl', '');
3180
+
3181
+ const result = Approval.processDecision(SAMPLE_APPROVAL.id, 'approve', '', 'approver@test.com', `${SAMPLE_APPROVAL.phase}-${SAMPLE_APPROVAL.plan}`);
3182
+ assert.strictEqual(result.success, true, 'Should succeed with correct plan ID');
3183
+ } finally { process.chdir(orig); p.cleanup(); }
3184
+ });
3185
+
3186
+ test('Tier 3 approval with WRONG plan ID is rejected', () => {
3187
+ const p = mkProject();
3188
+ const orig = process.cwd();
3189
+ process.chdir(p.dir);
3190
+ try {
3191
+ const tier3Approval = { ...SAMPLE_APPROVAL, tier: 3 };
3192
+ p.write(`.planning/approvals/APPROVAL-${SAMPLE_APPROVAL.id}.json`, JSON.stringify(tier3Approval));
3193
+
3194
+ const result = Approval.processDecision(SAMPLE_APPROVAL.id, 'approve', '', 'approver@test.com', '3-99'); // Wrong plan
3195
+ assert.strictEqual(result.success, false, 'Should reject wrong plan ID');
3196
+ } finally { process.chdir(orig); p.cleanup(); }
3197
+ });
3198
+
3199
+ test('SSE broadcast handles dead clients without crashing', () => {
3200
+ let writeCount = 0;
3201
+ let errorClient = { write: () => { throw new Error('EPIPE'); }, on: () => {} };
3202
+ let goodClient = { write: msg => { writeCount++; }, on: () => {} };
3203
+
3204
+ SSE.addClient(errorClient);
3205
+ SSE.addClient(goodClient);
3206
+
3207
+ // Broadcast should not throw even with a dead client
3208
+ assert.doesNotThrow(() => SSE.broadcast('test:event', { data: 'test' }), 'Should handle dead client gracefully');
3209
+ assert.ok(writeCount >= 1, 'Good client should receive the broadcast');
3210
+ });
3211
+
3212
+ test('server.js does not set CORS wildcard for missing Origin header', () => {
3213
+ const c = fs.readFileSync('bin/dashboard/server.js', 'utf8');
3214
+ // The CORS handler should only set headers when origin is present AND localhost
3215
+ assert.ok(c.includes('if (origin &&'), 'CORS should be conditional on origin presence');
3216
+ // Should NOT have unconditional Access-Control-Allow-Origin: *
3217
+ const unconditional = c.match(/setHeader\('Access-Control-Allow-Origin',\s*'\*'\)/);
3218
+ assert.ok(!unconditional, 'Should NOT set unconditional wildcard CORS');
3219
+ });
3220
+ ```
3221
+
3222
+ **Commit:**
3223
+ ```bash
3224
+ git add tests/dashboard.test.js
3225
+ git commit -m "test(v2-dashboard): add hardening tests — Tier 3 confirmation, dead client SSE, CORS wildcard"
3226
+ ```
3227
+
3228
+ ---
3229
+
3230
+ ## HARDEN 7 — Final pre-merge verification
3231
+
3232
+ ```bash
3233
+ #!/usr/bin/env bash
3234
+ echo "MindForge v2 Day 12 — Pre-Merge Verification"
3235
+ echo "═════════════════════════════════════════════"
3236
+ PASS=true
3237
+
3238
+ V=$(node -e "console.log(require('./package.json').version)")
3239
+ [[ "${V}" == "2.0.0-alpha.5" ]] && echo " Version: ${V} ✅" || { echo " ❌ ${V}"; PASS=false; }
3240
+
3241
+ echo ""
3242
+ FAIL=0
3243
+ for s in install wave-engine audit compaction skills-platform \
3244
+ integrations governance intelligence metrics \
3245
+ distribution ci-mode sdk production migration e2e \
3246
+ autonomous browser model-routing memory dashboard; do
3247
+ printf " %-30s" "${s}..."
3248
+ node tests/${s}.test.js 2>&1 | tail -1 | grep -q "passed" && echo "✅" || { echo "❌"; ((FAIL++)); PASS=false; }
3249
+ done
3250
+
3251
+ CMDS=$(ls .claude/commands/mindforge/ | wc -l | tr -d ' ')
3252
+ [ "$CMDS" -ge 45 ] && echo " Commands: ${CMDS} ✅" || { echo " ❌ Commands: ${CMDS}"; PASS=false; }
3253
+
3254
+ ADRS=$(ls .planning/decisions/ADR-*.md 2>/dev/null | wc -l | tr -d ' ')
3255
+ [ "$ADRS" -ge 35 ] && echo " ADRs: ${ADRS} ✅" || { echo " ❌ ADRs: ${ADRS}"; PASS=false; }
3256
+
3257
+ # Dashboard should never bind to 0.0.0.0
3258
+ UNSAFE=$(grep -r "0\.0\.0\.0" bin/dashboard/ 2>/dev/null || true)
3259
+ [ -z "$UNSAFE" ] && echo " Binding: localhost-only ✅" || { echo " ❌ 0.0.0.0 binding found"; PASS=false; }
3260
+
3261
+ # No hardcoded credentials in dashboard
3262
+ CREDS=$(grep -rE "(password|secret|api_key)\s*=\s*['\"][^'\"]{8,}" bin/dashboard/ 2>/dev/null | \
3263
+ grep -v "placeholder\|TEST_ONLY" || true)
3264
+ [ -z "$CREDS" ] && echo " Credentials: clean ✅" || { echo " ❌ Credentials in dashboard"; PASS=false; }
3265
+
3266
+ echo ""
3267
+ $PASS && echo "✅ ALL CHECKS PASSED — Day 12 complete" || { echo "❌ FAILURES"; exit 1; }
3268
+ ```
3269
+
3270
+ **Final commit:**
3271
+ ```bash
3272
+ git add .
3273
+ git commit -m "harden(v2-day12): all hardening complete — Tier 3 confirm, inode rotation, CORS, AUDIT ordering"
3274
+ git push origin feat/mindforge-v2-realtime-dashboard
3275
+ ```
3276
+
3277
+ ---
3278
+
3279
+ ## DAY 12 COMPLETE
3280
+
3281
+ | Component | Status |
3282
+ |---|---|
3283
+ | Dashboard server (Express.js, localhost:7339, security middleware) | ✅ |
3284
+ | SSE Event Bridge (AUDIT tail, inode rotation, dead client cleanup) | ✅ |
3285
+ | Metrics Aggregator (7 data sources: status, audit, metrics, approvals, team, memory, costs) | ✅ |
3286
+ | Approval Handler (UUID validation, Tier 3 confirmation, AUDIT-first write) | ✅ |
3287
+ | API Router (10 endpoints, injection guard on steer, approval validation) | ✅ |
3288
+ | Frontend: Activity Feed (live SSE, wave progress, steering input) | ✅ |
3289
+ | Frontend: Quality Metrics (4 canvas charts) | ✅ |
3290
+ | Frontend: Pending Approvals (approve/reject with Tier 3 confirm) | ✅ |
3291
+ | Frontend: Knowledge Graph (searchable entry list) | ✅ |
3292
+ | Frontend: Team Activity (developers, last-seen, conflict detection) | ✅ |
3293
+ | `/mindforge:dashboard` command (45th) | ✅ |
3294
+ | CLAUDE.md dashboard awareness | ✅ |
3295
+ | `tests/dashboard.test.js` (20th test suite) | ✅ |
3296
+ | ADR-033 (localhost), ADR-034 (Tier 3 confirm), ADR-035 (audit ordering) | ✅ |
3297
+ | CHANGELOG v2.0.0-alpha.5 | ✅ |
3298
+
3299
+ **MindForge v2.0.0-alpha.5: 45 commands · 20 test suites · 35 ADRs**
3300
+ **Branch:** `feat/mindforge-v2-realtime-dashboard`
3301
+ **Day 12 complete. Open PR → merge → start Day 13 (Self-Building Skills)**