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.
- package/.mindforge/celestial.db +0 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/CLAUDE.md +102 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/commands.cjs +959 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/config.cjs +421 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/core.cjs +1166 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/frontmatter.cjs +307 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/init.cjs +1336 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/milestone.cjs +252 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/model-profiles.cjs +68 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/phase.cjs +888 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/profile-output.cjs +952 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/profile-pipeline.cjs +539 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/roadmap.cjs +329 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/security.cjs +356 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/state.cjs +969 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/template.cjs +222 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/uat.cjs +189 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/verify.cjs +851 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/lib/workstream.cjs +491 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/bin/mindforge-tools.cjs +897 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/file-manifest.json +219 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/forge/help.md +11 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/forge/init-project.md +36 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/forge/plan-phase.md +34 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/hooks/mindforge-check-update.js +114 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/hooks/mindforge-context-monitor.js +156 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/hooks/mindforge-prompt-guard.js +96 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/hooks/mindforge-session-init_extended.js +42 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/hooks/mindforge-statusline.js +119 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/hooks/mindforge-workflow-guard.js +94 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/add-backlog.md +32 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/agent.md +31 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/approve.md +22 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/audit.md +34 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/auto.md +26 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/benchmark.md +37 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/browse.md +30 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/complete-milestone.md +22 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/costs.md +15 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/cross-review.md +21 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/dashboard.md +102 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/debug.md +133 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/discuss-phase.md +142 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/do.md +31 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/execute-phase.md +200 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/health.md +31 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/help.md +33 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/init-org.md +135 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/init-project.md +170 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/install-skill.md +28 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/learn.md +147 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/learning.md +20 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/map-codebase.md +302 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/marketplace.md +124 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/metrics.md +26 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/migrate.md +44 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/milestone.md +16 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/new-runtime.md +23 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/next.md +109 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/note.md +35 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/plan-phase.md +131 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/plant-seed.md +31 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/plugins.md +44 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/pr-review.md +45 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/profile-team.md +27 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/publish-skill.md +23 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/qa.md +20 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/quick.md +139 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/record-learning.md +22 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/release.md +14 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/remember.md +30 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/research.md +16 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/retrospective.md +31 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/review-backlog.md +34 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/review.md +161 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/security-scan.md +242 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/session-report.md +39 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/ship.md +111 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/skills.md +145 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/status.md +113 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/steer.md +17 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/sync-confluence.md +15 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/sync-jira.md +16 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/tokens.md +12 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/ui-phase.md +34 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/ui-review.md +36 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/update.md +46 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/validate-phase.md +31 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/verify-phase.md +66 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/workspace.md +33 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/mindforge/workstreams.md +35 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/settings.json +42 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-add-backlog/SKILL.md +72 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-add-phase/SKILL.md +39 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-add-tests/SKILL.md +28 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-add-todo/SKILL.md +42 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-audit-milestone/SKILL.md +29 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-audit-uat/SKILL.md +20 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-autonomous/SKILL.md +33 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-brainstorming/SKILL.md +164 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-brainstorming/scripts/frame-template.html +214 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-brainstorming/scripts/helper.js +88 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-brainstorming/scripts/server.cjs +354 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-brainstorming/scripts/start-server.sh +148 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-brainstorming/scripts/stop-server.sh +56 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-brainstorming/spec-document-reviewer-prompt.md +49 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-brainstorming/visual-companion.md +287 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-check-todos/SKILL.md +40 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-cleanup/SKILL.md +19 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-complete-milestone/SKILL.md +131 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-debug/SKILL.md +163 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-debug_extended/CREATION-LOG.md +119 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-debug_extended/SKILL.md +296 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-debug_extended/condition-based-waiting-example.ts +158 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-debug_extended/condition-based-waiting.md +115 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-debug_extended/defense-in-depth.md +122 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-debug_extended/find-polluter.sh +63 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-debug_extended/root-cause-tracing.md +169 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-debug_extended/test-academic.md +14 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-debug_extended/test-pressure-1.md +58 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-debug_extended/test-pressure-2.md +68 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-debug_extended/test-pressure-3.md +69 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-discuss-phase/SKILL.md +54 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-do/SKILL.md +26 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-execute-phase/SKILL.md +49 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-execute-phase_extended/SKILL.md +70 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-fast/SKILL.md +23 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-forensics/SKILL.md +49 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-health/SKILL.md +17 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-help/SKILL.md +23 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-insert-phase/SKILL.md +28 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-join-discord/SKILL.md +19 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-list-phase-assumptions/SKILL.md +41 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-list-workspaces/SKILL.md +17 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-manager/SKILL.md +32 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-map-codebase/SKILL.md +64 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-milestone-summary/SKILL.md +44 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-neural-orchestrator/SKILL.md +115 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-neural-orchestrator/references/codex-tools.md +100 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-neural-orchestrator/references/gemini-tools.md +33 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-new-milestone/SKILL.md +38 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-new-project/SKILL.md +36 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-new-workspace/SKILL.md +39 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-next/SKILL.md +19 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-note/SKILL.md +29 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-parallel-mesh_extended/SKILL.md +182 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-pause-work/SKILL.md +35 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-plan-milestone-gaps/SKILL.md +28 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-plan-phase/SKILL.md +38 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-plan-phase_extended/SKILL.md +152 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-plan-phase_extended/plan-document-reviewer-prompt.md +49 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-plant-seed/SKILL.md +22 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-pr-branch/SKILL.md +21 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-profile-user/SKILL.md +38 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-progress/SKILL.md +19 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-quick/SKILL.md +38 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-reapply-patches/SKILL.md +124 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-remove-phase/SKILL.md +26 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-remove-workspace/SKILL.md +22 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-research-phase/SKILL.md +186 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-resume-work/SKILL.md +35 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-review/SKILL.md +31 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-review-backlog/SKILL.md +58 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-review-inbound/SKILL.md +213 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-review-request/SKILL.md +105 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-review-request/code-reviewer.md +146 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-session-report/SKILL.md +16 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-set-profile/SKILL.md +9 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-settings/SKILL.md +32 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-ship/SKILL.md +16 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-ship_extended/SKILL.md +200 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-skill-creation/SKILL.md +655 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-skill-creation/anthropic-best-practices.md +1150 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-skill-creation/examples/CLAUDE_MD_TESTING.md +189 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-skill-creation/graphviz-conventions.dot +172 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-skill-creation/persuasion-principles.md +187 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-skill-creation/render-graphs.js +168 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-skill-creation/testing-skills-with-subagents.md +384 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-stats/SKILL.md +16 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-swarm-execution/SKILL.md +277 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-swarm-execution/code-quality-reviewer-prompt.md +26 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-swarm-execution/implementer-prompt.md +113 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-swarm-execution/spec-reviewer-prompt.md +61 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-system-architecture/SKILL.md +136 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-system-architecture/examples.md +120 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-system-architecture/scaling-checklist.md +76 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-tdd/SKILL.md +112 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-tdd/deep-modules.md +21 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-tdd/interface-design.md +22 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-tdd/mocking.md +24 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-tdd/refactoring.md +21 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-tdd/tests.md +28 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-tdd_extended/SKILL.md +371 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-tdd_extended/testing-anti-patterns.md +299 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-thread/SKILL.md +123 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-ui-phase/SKILL.md +24 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-ui-review/SKILL.md +24 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-update/SKILL.md +35 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-validate-phase/SKILL.md +26 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-verify-work/SKILL.md +30 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-verify-work_extended/SKILL.md +139 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-workspace-isolated/SKILL.md +218 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/skills/mindforge-workstreams/SKILL.md +65 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/forge:help.md +10 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/forge:init-project.md +35 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/forge:plan-phase.md +33 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-add-phase.md +112 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-add-tests.md +351 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-add-todo.md +158 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-audit-milestone.md +332 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-audit-uat.md +109 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-autonomous.md +815 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-check-todos.md +177 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-cleanup.md +152 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-complete-milestone.md +766 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-diagnose-issues.md +220 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-discovery-phase.md +289 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-discuss-phase-assumptions.md +645 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-discuss-phase.md +1047 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-do.md +104 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-execute-phase.md +838 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-execute-plan.md +509 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-fast.md +105 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-forensics.md +265 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-health.md +181 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-help.md +606 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-insert-phase.md +130 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-list-phase-assumptions.md +178 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-list-workspaces.md +56 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-manager.md +360 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-map-codebase.md +370 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-milestone-summary.md +223 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-new-milestone.md +469 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-new-project.md +1226 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-new-workspace.md +237 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-next.md +97 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-node-repair.md +92 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-note.md +156 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-pause-work.md +176 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-plan-milestone-gaps.md +273 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-plan-phase.md +877 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-plant-seed.md +169 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-pr-branch.md +129 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-profile-user.md +450 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-progress.md +507 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-quick.md +732 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-remove-phase.md +155 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-remove-workspace.md +90 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-research-phase.md +74 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-resume-project.md +325 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-review.md +228 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-session-report.md +146 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-settings.md +283 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-ship.md +228 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-stats.md +60 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-transition.md +671 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-ui-phase.md +290 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-ui-review.md +157 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-update.md +323 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-validate-phase.md +167 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-verify-phase.md +254 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge-verify-work.md +628 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:add-backlog.md +24 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:agent.md +25 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:approve.md +21 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:architecture.md +40 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:audit.md +33 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:auto.md +25 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:benchmark.md +36 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:brainstorming.md +16 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:browse.md +29 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:complete-milestone.md +21 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:costs.md +14 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:cross-review.md +20 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:dashboard.md +101 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:debug.md +131 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:discuss-phase.md +141 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:do.md +25 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:execute-phase.md +205 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:executor.md +18 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:health.md +24 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:help.md +26 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:identity.md +18 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:init-org.md +134 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:init-project.md +185 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:install-skill.md +27 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:learn.md +146 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:map-codebase.md +301 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:marketplace.md +123 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:memory.md +18 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:metrics.md +25 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:migrate.md +43 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:milestone.md +15 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:new-runtime.md +22 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:next.md +108 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:note.md +27 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:plan-phase.md +139 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:planner.md +18 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:plant-seed.md +24 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:plugins.md +43 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:pr-review.md +44 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:profile-team.md +26 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:publish-skill.md +22 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:qa.md +19 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:quick.md +138 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:release.md +13 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:remember.md +29 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:research.md +15 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:researcher.md +18 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:retrospective.md +29 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:review-backlog.md +26 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:review.md +160 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:reviewer.md +18 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:security-scan.md +236 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:session-report.md +31 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:ship.md +108 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:skills.md +144 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:soul.md +54 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:status.md +107 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:steer.md +16 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:sync-confluence.md +14 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:sync-jira.md +15 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:tdd.md +46 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:tokens.md +11 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:tool.md +18 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:ui-phase.md +27 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:ui-review.md +28 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:update.md +45 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:validate-phase.md +25 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:verify-phase.md +65 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:workspace.md +32 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/mindforge:workstreams.md +27 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.agent/workflows/publish-release.md +36 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.czrc +3 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.github/pull_request_template.md +29 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.github/workflows/ai-intelligence.yml +55 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.github/workflows/auto-pr.yml +80 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.github/workflows/control-plane.yml +79 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.github/workflows/execution-plane.yml +52 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.github/workflows/mindforge-ai-review.yml +68 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.github/workflows/mindforge-autonomous.yml +70 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.github/workflows/mindforge-ci.yml +224 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.github/workflows/mindforge-observability.yml +71 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.github/workflows/mindforge-release.yml +55 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.github/workflows/observability-plane.yml +40 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.github/workflows/release-plane.yml +43 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.gitlab-ci-mindforge.yml +18 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.husky/pre-commit +1 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/MINDFORGE-SCHEMA.json +165 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/MINDFORGE-V2-SCHEMA.json +47 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/audit/AUDIT-SCHEMA.md +470 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/browser/daemon-protocol.md +24 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/browser/qa-engine.md +16 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/browser/session-manager.md +18 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/browser/visual-verify-spec.md +31 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/bypasses.json +8 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/ci/ci-config-schema.md +21 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/ci/ci-mode.md +179 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/ci/github-actions-adapter.md +224 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/ci/gitlab-ci-adapter.md +31 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/ci/jenkins-adapter.md +44 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/config.json +66 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/dashboard/api-reference.md +122 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/dashboard/dashboard-spec.md +96 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/distribution/marketplace.md +53 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/distribution/registry-client.md +166 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/distribution/registry-schema.md +96 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/distribution/skill-publisher.md +44 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/distribution/skill-validator.md +74 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/ads-protocol.md +54 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/autonomous/auto-executor.md +266 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/autonomous/headless-adapter.md +66 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/autonomous/node-repair.md +190 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/autonomous/progress-reporter.md +58 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/autonomous/steering-manager.md +64 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/autonomous/stuck-detector.md +89 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/compaction-protocol.md +167 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/context-injector.md +154 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/dependency-parser.md +113 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/integrity.json +12 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/knowledge-graph-protocol.md +125 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/nexus-tracer.js +11 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/persona-factory.md +45 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/shard-controller.md +53 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/skills/conflict-resolver.md +69 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/skills/loader.md +184 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/skills/registry.md +98 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/skills/versioning.md +75 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/swarm-controller.md +59 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/temporal-protocol.md +40 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/verification-pipeline.md +111 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/engine/wave-executor.md +285 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/governance/GOVERNANCE-CONFIG.md +17 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/governance/approval-workflow.md +37 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/governance/change-classifier.md +63 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/governance/compliance-gates.md +31 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/governance/policies/sovereign-default.json +16 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/integrations/confluence.md +27 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/integrations/connection-manager.md +163 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/integrations/github.md +25 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/integrations/gitlab.md +13 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/integrations/jira.md +102 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/integrations/slack.md +41 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/intelligence/antipattern-detector.md +75 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/intelligence/difficulty-scorer.md +55 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/intelligence/health-engine.md +208 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/intelligence/skill-gap-analyser.md +40 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/intelligence/smart-compaction.md +71 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/memory/MEMORY-SCHEMA.md +155 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/memory/engine/capture-protocol.md +36 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/memory/engine/global-sync-spec.md +42 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/memory/engine/retrieval-spec.md +44 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/metrics/METRICS-SCHEMA.md +42 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/metrics/quality-tracker.md +32 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/models/model-registry.md +48 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/models/model-router.md +30 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/monorepo/cross-package-planner.md +114 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/monorepo/dependency-graph-builder.md +32 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/monorepo/workspace-detector.md +129 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/org/CONVENTIONS.md +62 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/org/ORG.md +51 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/org/SECURITY.md +50 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/org/TOOLS.md +53 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/org/integrations/INTEGRATIONS-CONFIG.md +58 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/org/skills/MANIFEST.md +15 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/advisor-researcher.md +89 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/analyst.md +112 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/architect.md +108 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/assumptions-analyzer-extend.md +87 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/assumptions-analyzer.md +109 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/codebase-mapper-extend.md +93 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/codebase-mapper.md +770 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/coverage-specialist.md +104 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/debug-specialist.md +118 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/debugger.md +97 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/decision-architect.md +102 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/developer.md +97 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/executor.md +88 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/integration-checker.md +92 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/mf-executor.md +40 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/mf-memory.md +33 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/mf-planner.md +45 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/mf-researcher.md +39 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/mf-reviewer.md +35 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/mf-tool.md +33 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/nyquist-auditor.md +84 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/overrides/README.md +85 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/phase-researcher.md +107 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/plan-checker.md +92 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/planner.md +105 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/project-researcher.md +99 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/qa-engineer.md +113 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/release-manager.md +114 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/research-agent.md +109 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/research-synthesizer.md +101 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/roadmapper-extend.md +100 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/roadmapper.md +103 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/security-reviewer.md +114 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/swarm-templates.json +118 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/tech-writer.md +118 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/ui-auditor.md +94 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/ui-checker.md +89 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/ui-researcher.md +99 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/user-profiler.md +93 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/personas/verifier.md +101 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/plugins/PLUGINS-MANIFEST.md +23 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/plugins/plugin-loader.md +93 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/plugins/plugin-registry.md +44 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/plugins/plugin-schema.md +68 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/pr-review/ai-reviewer.md +266 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/pr-review/finding-formatter.md +46 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/pr-review/review-prompt-templates.md +44 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/production/compatibility-layer.md +39 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/production/migration-engine.md +52 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/production/production-checklist.md +76 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/production/token-optimiser.md +68 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/remediation-queue.json +47 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/skills/accessibility/SKILL.md +106 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/skills/api-design/SKILL.md +98 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/skills/code-quality/SKILL.md +88 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/skills/data-privacy/SKILL.md +126 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/skills/database-patterns/SKILL.md +192 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/skills/documentation/SKILL.md +91 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/skills/incident-response/SKILL.md +180 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/skills/performance/SKILL.md +120 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/skills/security-review/SKILL.md +83 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/skills/testing-standards/SKILL.md +97 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/skills-builder/auto-capture-protocol.md +88 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/skills-builder/learn-protocol.md +161 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/skills-builder/quality-scoring.md +120 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/team/TEAM-PROFILE.md +42 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/team/multi-handoff.md +23 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/team/profiles/README.md +13 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.mindforge/team/session-merger.md +18 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/ARCHITECTURE.md +0 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/AUDIT.jsonl +45 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/HANDOFF.json +8 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/PROJECT.md +33 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/RELEASE-CHECKLIST.md +68 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/REQUIREMENTS.md +23 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/ROADMAP.md +12 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/ROI.jsonl +2 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/STATE.md +31 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/approvals/.gitkeep +1 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/.gitkeep +1 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/org/CONVENTIONS.md +0 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/org/ORG.md +0 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/org/SECURITY.md +0 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/org/TOOLS.md +0 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/personas/analyst.md +0 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/personas/architect.md +0 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/personas/debug-specialist.md +0 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/personas/developer.md +26 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/personas/qa-engineer.md +0 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/personas/release-manager.md +0 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/personas/security-reviewer.md +33 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/personas/tech-writer.md +0 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/skills/api-design/SKILL.md +0 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/skills/code-quality/SKILL.md +0 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/skills/documentation/SKILL.md +0 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/skills/security-review/SKILL.md +23 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/.forge/skills/testing-standards/SKILL.md +27 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/ARCHITECTURE-AUDIT-REPORT.md +90 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/LOGS-BENCHMARKING.md +172 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/ROADMAP_V8.md +49 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/github-actions-logs.md +88 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-1-imp/DAY1-HARDEN.md +823 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-1-imp/DAY1-IMPLEMENT.md +2459 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-1-imp/DAY1-REVIEW.md +288 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-2-imp/DAY2-HARDEN.md +954 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-2-imp/DAY2-IMPLEMENT.md +2347 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-2-imp/DAY2-REVIEW.md +422 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-3-imp/DAY3-HARDEN.md +870 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-3-imp/DAY3-IMPLEMENT.md +2798 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-3-imp/DAY3-REVIEW.md +484 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-4-imp/DAY4-HARDEN.md +1087 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-4-imp/DAY4-IMPLEMENT.md +2874 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-4-imp/DAY4-REVIEW.md +386 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-5-imp/DAY5-HARDEN.md +1078 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-5-imp/DAY5-IMPLEMENT.md +3151 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-5-imp/DAY5-REVIEW.md +345 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-6-imp/DAY6-COMPLETE.md +3919 -0
- 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
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/ci-actions/github-workflows-v2.md +421 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/ci-actions/v2-ci-actions.md +292 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/day-10-imp/DAY10-MULTI-MODEL.md +3402 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/day-11-imp/DAY11-PERSISTENT-MEMORY.md +3237 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/day-12-imp/DAY12-REALTIME-DASHBOARD.md +3301 -0
- 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
- 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
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/day-8-imp/DAY8-AUTONOMOUS-ENGINE.md +3400 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/day-9-imp/DAY9-BROWSER-RUNTIME.md +3293 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/audit-archive/.gitkeep +1 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/decisions/.gitkeep +0 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/jira-sync.json +5 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/milestones/.gitkeep +1 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/phases/.gitkeep +0 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/research/.gitkeep +0 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/screenshots/.gitkeep +0 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/.planning/slack-threads.json +3 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/AGENTS_LEARNING.md +112 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/CHANGELOG.md +1116 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/LICENSE +21 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/MINDFORGE.md +91 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/README.md +424 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/RELEASENOTES.md +199 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/REPLICATION.json +12 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/SECURITY.md +4 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/SOUL.md +52 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/agents/executor/IDENTITY.md +31 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/agents/memory/IDENTITY.md +27 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/agents/planner/IDENTITY.md +35 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/agents/researcher/IDENTITY.md +29 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/agents/reviewer/IDENTITY.md +31 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/agents/tool/IDENTITY.md +27 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/auto-pr.yml +74 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/autonomous/auto-runner.js +378 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/autonomous/context-refactorer.js +64 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/autonomous/headless.js +36 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/autonomous/intent-harvester.js +80 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/autonomous/mesh-self-healer.js +67 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/autonomous/progress-stream.js +49 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/autonomous/repair-operator.js +213 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/autonomous/steer.js +89 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/autonomous/stuck-monitor.js +120 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/browser/browser-daemon.js +139 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/browser/daemon-manager.js +91 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/browser/qa-engine.js +47 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/browser/qa-report-writer.js +32 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/browser/regression-writer.js +27 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/browser/screenshot-store.js +49 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/browser/session-manager.js +93 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/browser/visual-verify-executor.js +89 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/change-classifier.js +86 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/dashboard/api-router.js +198 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/dashboard/approval-handler.js +134 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/dashboard/frontend/index.html +751 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/dashboard/metrics-aggregator.js +296 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/dashboard/revops-api.js +47 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/dashboard/server.js +138 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/dashboard/sse-bridge.js +178 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/dashboard/team-tracker.js +0 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/dashboard/temporal-api.js +82 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/context-entropy-guard.js +94 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/feedback-loop.js +106 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/handover-manager.js +71 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/intelligence-interlock.js +39 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/learning-manager.js +181 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/logic-drift-detector.js +100 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/logic-validator.js +74 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/mesh-syncer.js +129 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/nexus-tracer.js +356 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/orbital-guardian.js +84 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/reason-source-aligner.js +111 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/remediation-engine.js +81 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/self-corrective-synthesizer.js +65 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/skill-evolver.js +105 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/sre-manager.js +117 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/temporal-cli.js +52 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/temporal-hindsight.js +115 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/temporal-hub.js +138 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/test-ceg.js +59 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/test-interlock.js +40 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/test-remediation.js +61 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/test-rsa.js +64 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/test-scs.js +57 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/engine/test-v7-blueprint.js +44 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/gov-audit.js +38 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/approve.js +60 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/config-manager.js +85 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/impact-analyzer.js +141 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/policies/critical-data.json +1 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/policies/default-policies.jsonl +33 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/policy-engine.js +210 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/policy-gate-hardened.js +59 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/quantum-crypto.js +111 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/rbac-manager.js +109 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/test-config.js +40 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/test-crypto-pluggable.js +50 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/test-hardened-gate.js +71 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/trust-verifier.js +81 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/ztai-archiver.js +104 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/governance/ztai-manager.js +239 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/hindsight-injector.js +59 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/install.js +129 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/installer-core.js +805 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/auto-shadow.js +274 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/cli.js +99 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/eis-client.js +95 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/embedding-engine.js +326 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/federated-sync.js +293 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/ghost-pattern-detector.js +69 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/global-sync.js +107 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/identity-synthesizer.js +146 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/knowledge-capture.js +442 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/knowledge-graph.js +609 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/knowledge-indexer.js +172 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/knowledge-store.js +337 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/pillar-health-tracker.js +63 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/semantic-hub.js +211 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/session-memory-loader.js +137 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/memory/vector-hub.js +170 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/migrations/0.1.0-to-0.5.0.js +36 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/migrations/0.5.0-to-0.6.0.js +17 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/migrations/0.6.0-to-1.0.0.js +100 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/migrations/1.0.0-to-2.0.0.js +115 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/migrations/migrate.js +155 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/migrations/schema-versions.js +76 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/migrations/v8-sqlite-migration.js +85 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/mindforge-cc.sh +5 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/mindforge-cli.js +180 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/models/anthropic-provider.js +77 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/models/cloud-broker.js +161 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/models/cost-tracker.js +118 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/models/finops-hub.js +79 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/models/gemini-provider.js +79 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/models/model-broker.js +129 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/models/model-client.js +98 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/models/model-router.js +112 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/models/openai-provider.js +78 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/models/performance-stats.json +22 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/research/research-engine.js +115 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/review/ads-engine.js +126 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/review/ads-synthesizer.js +117 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/review/cross-review-engine.js +92 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/review/finding-synthesizer.js +116 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/review/review-report-writer.js +49 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/revops/debt-monitor.js +60 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/revops/market-evaluator.js +73 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/revops/remediation-queue.js +107 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/revops/roi-engine.js +65 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/revops/router-steering-v2.js +73 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/revops/velocity-forecaster.js +59 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/shard-helper.js +134 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/skill-registry.js +232 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/skill-validator.js +211 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/skills-builder/learn-cli.js +57 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/skills-builder/marketplace-cli.js +54 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/skills-builder/marketplace-client.js +198 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/skills-builder/pattern-detector.js +144 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/skills-builder/skill-generator.js +258 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/skills-builder/skill-registrar.js +107 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/skills-builder/skill-scorer.js +263 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/skills-builder/source-loader.js +268 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/spawn-agent.js +61 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/updater/changelog-fetcher.js +62 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/updater/self-update.js +169 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/updater/version-comparator.js +68 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/validate-config.js +92 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/wizard/config-generator.js +112 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/wizard/environment-detector.js +83 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/wizard/setup-wizard.js +240 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/bin/wizard/theme.js +184 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/CAPABILITIES-MANIFEST.md +64 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Context/Master-Context.md +694 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/INTELLIGENCE-MESH.md +37 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/MIND-FORGE-REFERENCE-V6.md +96 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/PERSONAS.md +920 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/audit-events.md +59 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/checkpoints.md +778 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/commands.md +107 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/config-reference.md +81 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/continuation-format.md +249 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/decimal-phase-calculation.md +64 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/git-integration.md +295 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/git-planning-commit.md +38 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/model-profile-resolution.md +36 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/model-profiles.md +139 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/phase-argument-parsing.md +61 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/planning-config.md +202 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/questioning.md +162 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/sdk-api.md +53 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/skills-api.md +57 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/tdd.md +263 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/ui-brand.md +160 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/user-profiling.md +681 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/verification-patterns.md +612 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/References/workstream-flag.md +58 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Agents/CLAUDE-MD.md +122 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Agents/COPILOT-INSTRUCTIONS.md +7 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Agents/DEBUGGER-PROMPT.md +91 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Agents/PLANNER-PROMPT.md +117 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Codebase/architecture.md +255 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Codebase/concerns.md +310 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Codebase/conventions.md +307 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Codebase/integrations.md +280 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Codebase/stack.md +186 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Codebase/structure.md +285 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Codebase/testing.md +480 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Execution/CONTINUE-HERE.md +78 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Execution/DISCUSSION-LOG.md +63 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Execution/PHASE-PROMPT.md +610 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Execution/STATE.md +176 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Execution/SUMMARY-COMPLEX.md +59 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Execution/SUMMARY-MINIMAL.md +41 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Execution/SUMMARY-STANDARD.md +48 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Execution/SUMMARY.md +248 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Profile/DEV-PREFERENCES.md +21 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Profile/USER-PROFILE.md +146 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Profile/USER-SETUP.md +311 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Project/AGENTS_LEARNING.md +88 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Project/DISCOVERY.md +146 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Project/MILESTONE-ARCHIVE.md +123 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Project/MILESTONE.md +115 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Project/PROJECT.md +206 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Project/REQUIREMENTS.md +231 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Project/RETROSPECTIVE.md +54 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Project/ROADMAP.md +202 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Quality/DEBUG.md +164 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Quality/UAT.md +280 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Quality/UI-SPEC.md +100 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Quality/VALIDATION.md +76 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Quality/VERIFICATION-REPORT.md +322 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Research/ARCHITECTURE.md +204 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Research/FEATURES.md +147 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Research/PITFALLS.md +200 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Research/STACK.md +120 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/Research/SUMMARY.md +170 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/System/CONFIG.json +43 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/Templates/System/CONTEXT.md +352 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/adr/ADR-024-browser-localhost-only.md +17 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/adr/ADR-025-visual-verify-failure-treatment.md +19 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/adr/ADR-026-session-persistence-security.md +20 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/adr/ADR-042-ads-protocol.md +30 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/architecture/NEXUS-DASHBOARD.md +35 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/architecture/PAR-ZTS-SURVEY.md +43 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/architecture/README.md +78 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/architecture/V3-CORE.md +52 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/architecture/V4-SWARM-MESH.md +77 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/architecture/V5-ENTERPRISE.md +131 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/architecture/V6-SOVEREIGN.md +43 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/architecture/adr-039-multi-runtime-support.md +20 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/architecture/adr-040-additive-schema-migration.md +21 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/architecture/adr-041-stable-runtime-interface-contract.md +20 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/architecture/decision-records-index.md +29 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/ci-cd-integration.md +30 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/ci-cd.md +92 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/ci-quickstart.md +78 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/commands-reference.md +144 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/commands-skills/DISCOVERED_SKILLS.md +21 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/contributing/CONTRIBUTING.md +38 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/contributing/plugin-authoring.md +50 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/contributing/skill-authoring.md +41 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/enterprise-setup.md +25 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/faq.md +38 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/feature-dashboard.md +63 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/getting-started.md +44 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/governance-guide.md +99 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/monorepo-guide.md +26 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/persona-customisation.md +56 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/publishing-guide.md +43 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/quick-verify.md +33 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/registry/AGENTS.md +37 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/registry/COMMANDS.md +87 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/registry/HOOKS.md +38 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/registry/PERSONAS.md +64 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/registry/README.md +27 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/registry/SKILLS.md +142 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/registry/WORKFLOWS.md +72 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/release-checklist-guide.md +37 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/requirements.md +29 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/sdk-reference.md +27 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/security/SECURITY.md +55 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/security/ZTAI-OVERVIEW.md +37 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/security/penetration-test-results.md +31 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/security/threat-model.md +142 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/skills-authoring-guide.md +176 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/skills-publishing-guide.md +22 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/team-setup-guide.md +21 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/testing-current-version.md +130 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/troubleshooting.md +139 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/tutorial.md +162 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/upgrade.md +58 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/user-guide.md +244 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/usp-features.md +102 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/docs/workflow-atlas.md +57 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/eslint.config.mjs +31 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/examples/starter-project/.planning/AUDIT.jsonl +1 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/examples/starter-project/.planning/HANDOFF.json +23 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/examples/starter-project/.planning/PROJECT.md +27 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/examples/starter-project/.planning/STATE.md +10 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/examples/starter-project/MINDFORGE.md +40 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/examples/starter-project/README.md +14 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/package-lock.json +3882 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/package.json +66 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/sdk/README.md +69 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/sdk/eslint.config.mjs +34 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/sdk/package-lock.json +1507 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/sdk/package.json +30 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/sdk/src/client.ts +133 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/sdk/src/commands.ts +63 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/sdk/src/events.ts +166 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/sdk/src/index.ts +23 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/sdk/src/memory.ts +257 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/sdk/src/types.ts +87 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/sdk/tsconfig.json +13 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/skills-lock.json +30 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/test/sovereign-status.test.js +18 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/ads.test.js +121 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/audit.test.js +206 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/autonomous.test.js +53 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/browser.test.js +61 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/ci-mode.test.js +162 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/compaction.test.js +161 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/dashboard.test.js +327 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/distribution.test.js +205 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/e2e.test.js +618 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/entropy-test.js +47 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/feedback-loop.test.js +62 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/governance/test-cadia-optimizer.js +112 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/governance/test-policies/deny-security.json +9 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/governance/test-policies/permit-t2.json +10 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/governance.test.js +130 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/install.test.js +209 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/integrations.test.js +128 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/intelligence.test.js +117 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/knowledge-graph.test.js +593 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/learning-engine.test.js +69 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/mca-routing-test.js +37 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/memory.test.js +166 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/metrics.test.js +96 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/migration.test.js +308 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/model-broker.test.js +55 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/model-routing.test.js +111 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/nexus-tracing.test.js +49 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/production.test.js +416 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/release.test.js +99 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/revops-roi.test.js +52 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/run-nexus-tests.js +84 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/sdk.test.js +200 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/security-audit.test.js +67 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/self-building-skills.test.js +285 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/semantic-hub.test.js +91 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/sharding.test.js +87 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/skills-platform.test.js +389 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/sre-zk-proof-test.js +76 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/swarms.test.md +21 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/temporal-vision.test.js +68 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/v7-pillar-integration.test.js +73 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/v7-proactive-homing.test.js +53 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/v7-sovereign-security.test.js +64 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/v8-mesh-sync.test.js +76 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/v8-orbital-governance.test.js +74 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/v8-persistence.test.js +86 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/v8-skill-evolution.test.js +74 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/wave-engine.test.js +336 -0
- package/.mindforge/mirrors/mirror-sre-776a1cf9/tests/ztai-enterprise.test.js +103 -0
- package/.planning/archive/v8-cleanup/.agents/skills/ai-image-generation/SKILL.md +147 -0
- package/.planning/archive/v8-cleanup/.agents/skills/ai-video-generation/SKILL.md +185 -0
- package/.planning/archive/v8-cleanup/.agents/skills/critique/SKILL.md +201 -0
- package/.planning/archive/v8-cleanup/.agents/skills/critique/reference/cognitive-load.md +106 -0
- package/.planning/archive/v8-cleanup/.agents/skills/critique/reference/heuristics-scoring.md +234 -0
- package/.planning/archive/v8-cleanup/.agents/skills/critique/reference/personas.md +178 -0
- package/.planning/archive/v8-cleanup/.agents/skills/elevenlabs-music/SKILL.md +191 -0
- package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/SKILL.md +659 -0
- package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/_sync_all.py +414 -0
- package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/app-interface.csv +31 -0
- package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/charts.csv +26 -0
- package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/colors.csv +162 -0
- package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/design.csv +1776 -0
- package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/draft.csv +1779 -0
- package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/google-fonts.csv +1924 -0
- package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/icons.csv +106 -0
- package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/landing.csv +35 -0
- package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/products.csv +162 -0
- package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/styles.csv +85 -0
- package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/typography.csv +74 -0
- package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/ui-reasoning.csv +162 -0
- package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/scripts/core.py +247 -0
- package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/scripts/design_system.py +1067 -0
- package/.planning/archive/v8-cleanup/.agents/skills/ui-ux-pro-max/scripts/search.py +114 -0
- package/.planning/archive/v8-cleanup/.forge/org/CONVENTIONS.md +0 -0
- package/.planning/archive/v8-cleanup/.forge/org/ORG.md +0 -0
- package/.planning/archive/v8-cleanup/.forge/org/SECURITY.md +0 -0
- package/.planning/archive/v8-cleanup/.forge/org/TOOLS.md +0 -0
- package/.planning/archive/v8-cleanup/.forge/personas/analyst.md +0 -0
- package/.planning/archive/v8-cleanup/.forge/personas/architect.md +0 -0
- package/.planning/archive/v8-cleanup/.forge/personas/debug-specialist.md +0 -0
- package/.planning/archive/v8-cleanup/.forge/personas/developer.md +26 -0
- package/.planning/archive/v8-cleanup/.forge/personas/qa-engineer.md +0 -0
- package/.planning/archive/v8-cleanup/.forge/personas/release-manager.md +0 -0
- package/.planning/archive/v8-cleanup/.forge/personas/security-reviewer.md +33 -0
- package/.planning/archive/v8-cleanup/.forge/personas/tech-writer.md +0 -0
- package/.planning/archive/v8-cleanup/.forge/skills/api-design/SKILL.md +0 -0
- package/.planning/archive/v8-cleanup/.forge/skills/code-quality/SKILL.md +0 -0
- package/.planning/archive/v8-cleanup/.forge/skills/documentation/SKILL.md +0 -0
- package/.planning/archive/v8-cleanup/.forge/skills/security-review/SKILL.md +23 -0
- package/.planning/archive/v8-cleanup/.forge/skills/testing-standards/SKILL.md +27 -0
- package/.planning/archive/v8-cleanup/ARCHITECTURE-AUDIT-REPORT.md +90 -0
- package/.planning/archive/v8-cleanup/LOGS-BENCHMARKING.md +172 -0
- package/.planning/archive/v8-cleanup/MIND-FORGE-V6-ENTERPRISE-PROPOSAL.md +79 -0
- package/.planning/archive/v8-cleanup/ROADMAP_V7.md +67 -0
- package/.planning/archive/v8-cleanup/ROADMAP_V8.md +49 -0
- package/.planning/archive/v8-cleanup/github-actions-logs.md +88 -0
- package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-1-imp/DAY1-HARDEN.md +823 -0
- package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-1-imp/DAY1-IMPLEMENT.md +2459 -0
- package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-1-imp/DAY1-REVIEW.md +288 -0
- package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-2-imp/DAY2-HARDEN.md +954 -0
- package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-2-imp/DAY2-IMPLEMENT.md +2347 -0
- package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-2-imp/DAY2-REVIEW.md +422 -0
- package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-3-imp/DAY3-HARDEN.md +870 -0
- package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-3-imp/DAY3-IMPLEMENT.md +2798 -0
- package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-3-imp/DAY3-REVIEW.md +484 -0
- package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-4-imp/DAY4-HARDEN.md +1087 -0
- package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-4-imp/DAY4-IMPLEMENT.md +2874 -0
- package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-4-imp/DAY4-REVIEW.md +386 -0
- package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-5-imp/DAY5-HARDEN.md +1078 -0
- package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-5-imp/DAY5-IMPLEMENT.md +3151 -0
- package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-5-imp/DAY5-REVIEW.md +345 -0
- package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-6-imp/DAY6-COMPLETE.md +3919 -0
- package/.planning/archive/v8-cleanup/implementation-roadmap/v1.0.0/day-7-imp-prod/DAY7-PRODUCTION-FINAL.md +4513 -0
- package/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/ci-actions/github-workflows-v2.md +421 -0
- package/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/ci-actions/v2-ci-actions.md +292 -0
- package/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/day-10-imp/DAY10-MULTI-MODEL.md +3402 -0
- package/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/day-11-imp/DAY11-PERSISTENT-MEMORY.md +3237 -0
- package/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/day-12-imp/DAY12-REALTIME-DASHBOARD.md +3301 -0
- package/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/day-13-imp/DAY13-SELF-BUILDING-SKILLS.md +3798 -0
- package/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/day-14-prod-v2/DAY14-V2-PRODUCTION-RELEASE.md +2255 -0
- package/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/day-8-imp/DAY8-AUTONOMOUS-ENGINE.md +3400 -0
- package/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/day-9-imp/DAY9-BROWSER-RUNTIME.md +3293 -0
- package/.planning/decisions/SRE-4e54a061.md +19 -0
- package/CHANGELOG.md +14 -0
- package/MINDFORGE.md +5 -4
- package/README.md +3 -2
- package/RELEASENOTES.md +17 -0
- package/bin/autonomous/auto-runner.js +64 -0
- package/bin/engine/learning-manager.js +4 -2
- package/bin/governance/impact-analyzer.js +4 -2
- package/bin/installer-core.js +18 -2
- package/bin/models/model-router.js +3 -1
- package/bin/sre/adversarial-sre.js +109 -0
- package/bin/sre/sentinel.js +128 -0
- package/bin/sre/shadow-mirror.js +122 -0
- package/bin/sre/sli-verifier.js +81 -0
- package/docs/Context/Master-Context.md +22 -2
- package/docs/PERSONAS.md +40 -0
- package/docs/architecture/V8-SRE.md +88 -0
- package/docs/governance-guide.md +43 -17
- package/package.json +2 -2
package/.planning/archive/v8-cleanup/implementation-roadmap/v2.0.0/day-10-imp/DAY10-MULTI-MODEL.md
ADDED
|
@@ -0,0 +1,3402 @@
|
|
|
1
|
+
# MindForge v2 — Day 10: Multi-Model Intelligence Layer
|
|
2
|
+
# Branch: `feat/mindforge-v2-cross-model-review`
|
|
3
|
+
# Prerequisite: `feat/mindforge-v2-browser-runtime` merged to `main`
|
|
4
|
+
# Version target: v2.0.0-alpha.3
|
|
5
|
+
# Theme: "No Single Model Is Perfect. Use Them All."
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## BRANCH SETUP
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
git checkout main
|
|
13
|
+
git pull origin main
|
|
14
|
+
|
|
15
|
+
# Verify Day 9 baseline
|
|
16
|
+
node -e "console.log(require('./package.json').version)" # Must be 2.0.0-alpha.2
|
|
17
|
+
|
|
18
|
+
# All 17 test suites must pass before starting Day 10
|
|
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)
|
|
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 17 must show "passed" — zero failures before Day 10 begins.
|
|
29
|
+
|
|
30
|
+
git checkout -b feat/mindforge-v2-cross-model-review
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## DAY 10 SCOPE
|
|
36
|
+
|
|
37
|
+
Day 10 builds the **Multi-Model Intelligence Layer** — the ability to route
|
|
38
|
+
every MindForge task to the model best suited for it, and to get the same
|
|
39
|
+
code reviewed by multiple AI models simultaneously.
|
|
40
|
+
|
|
41
|
+
**The insight:** Claude is exceptional at reasoning and generation. GPT-4o
|
|
42
|
+
finds different categories of bugs (training on different data = different
|
|
43
|
+
blind spots). Gemini 2.5 Pro's 1M context window ingests entire codebases
|
|
44
|
+
or documentation sets that would exhaust any other model. Using all three
|
|
45
|
+
produces better output than any single model alone.
|
|
46
|
+
|
|
47
|
+
**What this day delivers:**
|
|
48
|
+
|
|
49
|
+
| Component | Description |
|
|
50
|
+
|---|---|
|
|
51
|
+
| Model registry | 7-model registry with provider, strengths, cost, context window |
|
|
52
|
+
| Model router | Persona-to-model mapping with fallback chains |
|
|
53
|
+
| Multi-provider API client | Unified client for Anthropic, OpenAI, Google Gemini |
|
|
54
|
+
| `/mindforge:cross-review` | Adversarial multi-model code review with consensus synthesis |
|
|
55
|
+
| `/mindforge:research` | Deep research via Gemini 2.5 Pro's 1M context |
|
|
56
|
+
| `/mindforge:costs` | Real cost tracking per model per session/phase |
|
|
57
|
+
| Model-aware execute-phase | Persona → model routing in task dispatch |
|
|
58
|
+
| Cost tracking in JSONL | `models_used` field with per-model tokens + USD |
|
|
59
|
+
| `tests/model-routing.test.js` | 18th test suite |
|
|
60
|
+
|
|
61
|
+
**New commands today: 43 total (40 + cross-review + research + costs)**
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
# ═══════════════════════════════════════════════════════════════════════
|
|
66
|
+
# PART 1 — IMPLEMENTATION PROMPT
|
|
67
|
+
# ═══════════════════════════════════════════════════════════════════════
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## TASK 1 — Scaffold Day 10 directory structure
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# Model layer specs
|
|
75
|
+
mkdir -p .mindforge/models
|
|
76
|
+
touch .mindforge/models/model-registry.md
|
|
77
|
+
touch .mindforge/models/model-router.md
|
|
78
|
+
touch .mindforge/models/cost-calculator.md
|
|
79
|
+
touch .mindforge/models/fallback-chains.md
|
|
80
|
+
|
|
81
|
+
# Multi-provider API client
|
|
82
|
+
mkdir -p bin/models
|
|
83
|
+
touch bin/models/model-client.js
|
|
84
|
+
touch bin/models/anthropic-provider.js
|
|
85
|
+
touch bin/models/openai-provider.js
|
|
86
|
+
touch bin/models/gemini-provider.js
|
|
87
|
+
touch bin/models/model-router.js
|
|
88
|
+
touch bin/models/cost-tracker.js
|
|
89
|
+
|
|
90
|
+
# Cross-review engine
|
|
91
|
+
mkdir -p bin/review
|
|
92
|
+
touch bin/review/cross-review-engine.js
|
|
93
|
+
touch bin/review/finding-synthesizer.js
|
|
94
|
+
touch bin/review/review-report-writer.js
|
|
95
|
+
|
|
96
|
+
# Research engine
|
|
97
|
+
mkdir -p bin/research
|
|
98
|
+
touch bin/research/research-engine.js
|
|
99
|
+
touch bin/research/context-packager.js
|
|
100
|
+
|
|
101
|
+
# New commands
|
|
102
|
+
touch .claude/commands/mindforge/cross-review.md
|
|
103
|
+
touch .claude/commands/mindforge/research.md
|
|
104
|
+
touch .claude/commands/mindforge/costs.md
|
|
105
|
+
|
|
106
|
+
for cmd in cross-review research costs; do
|
|
107
|
+
cp .claude/commands/mindforge/${cmd}.md .agent/mindforge/${cmd}.md
|
|
108
|
+
done
|
|
109
|
+
|
|
110
|
+
# New persona
|
|
111
|
+
touch .mindforge/personas/research-agent.md
|
|
112
|
+
|
|
113
|
+
# Test suite
|
|
114
|
+
touch tests/model-routing.test.js
|
|
115
|
+
|
|
116
|
+
# Docs
|
|
117
|
+
touch docs/multi-model-guide.md
|
|
118
|
+
touch docs/cost-management-guide.md
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**Commit:**
|
|
122
|
+
```bash
|
|
123
|
+
git add .
|
|
124
|
+
git commit -m "chore(v2-day10): scaffold multi-model intelligence layer"
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## TASK 2 — Write the Model Registry and Router Specifications
|
|
130
|
+
|
|
131
|
+
### `.mindforge/models/model-registry.md`
|
|
132
|
+
|
|
133
|
+
```markdown
|
|
134
|
+
# MindForge v2 — Model Registry
|
|
135
|
+
|
|
136
|
+
## Overview
|
|
137
|
+
|
|
138
|
+
The MindForge model registry defines every AI model available for routing,
|
|
139
|
+
its capabilities, cost profile, context window, and which MindForge tasks
|
|
140
|
+
it is best suited for.
|
|
141
|
+
|
|
142
|
+
## Registered models (v2.0.0-alpha.3)
|
|
143
|
+
|
|
144
|
+
| Model ID | Provider | Tier | Context | Best for | Cost est. (1M tokens) |
|
|
145
|
+
|---|---|---|---|---|---|
|
|
146
|
+
| `claude-opus-4-5` | Anthropic | Premium | 200K | Architecture, deep security, complex reasoning | ~$15 in / $75 out |
|
|
147
|
+
| `claude-sonnet-4-6` | Anthropic | Standard | 200K | Default execution, balanced quality/speed | ~$3 in / $15 out |
|
|
148
|
+
| `claude-haiku-4-5` | Anthropic | Fast | 200K | Quick tasks, status checks, simple generation | ~$0.25 in / $1.25 out |
|
|
149
|
+
| `gpt-4o` | OpenAI | Premium | 128K | Adversarial code review, finding categories Claude misses | ~$5 in / $15 out |
|
|
150
|
+
| `gpt-4o-mini` | OpenAI | Fast | 128K | Fast review cross-check, cheap second opinion | ~$0.15 in / $0.60 out |
|
|
151
|
+
| `gemini-2.5-pro` | Google | Premium | 1M | Deep research, large codebase analysis, document ingestion | ~$3.50 in / $10.50 out |
|
|
152
|
+
| `gemini-2.0-flash` | Google | Fast | 1M | Fast research, cheap long-context tasks, CI summaries | ~$0.10 in / $0.40 out |
|
|
153
|
+
|
|
154
|
+
## Default routing table (all overridable in MINDFORGE.md)
|
|
155
|
+
|
|
156
|
+
| Task type | Default model | Rationale |
|
|
157
|
+
|---|---|---|
|
|
158
|
+
| `PLANNER_MODEL` | `claude-opus-4-5` | Planning requires deep architecture reasoning |
|
|
159
|
+
| `EXECUTOR_MODEL` | `claude-sonnet-4-6` | Balanced quality/cost for the majority of execution |
|
|
160
|
+
| `REVIEWER_MODEL` | `gpt-4o` | Different training → different bugs caught |
|
|
161
|
+
| `SECURITY_MODEL` | `claude-opus-4-5` | Security review needs the deepest reasoning |
|
|
162
|
+
| `RESEARCH_MODEL` | `gemini-2.5-pro` | 1M context ingests entire docs/codebases at once |
|
|
163
|
+
| `QA_MODEL` | `claude-sonnet-4-6` | QA execution is moderate complexity |
|
|
164
|
+
| `DEBUG_MODEL` | `claude-opus-4-5` | Root cause analysis needs maximum reasoning depth |
|
|
165
|
+
| `QUICK_MODEL` | `claude-haiku-4-5` | Fast, cheap for simple queries and status tasks |
|
|
166
|
+
| `CROSS_REVIEW_SECONDARY` | `gpt-4o` | Second model for cross-review adversarial pass |
|
|
167
|
+
| `CROSS_REVIEW_TERTIARY` | `gemini-2.5-pro` | Optional third model for high-stakes reviews |
|
|
168
|
+
|
|
169
|
+
## Persona-to-model routing
|
|
170
|
+
|
|
171
|
+
| Persona | Assigned model | Override setting |
|
|
172
|
+
|---|---|---|
|
|
173
|
+
| `analyst.md` | `PLANNER_MODEL` | Analyst does research and decomposition |
|
|
174
|
+
| `architect.md` | `PLANNER_MODEL` | Architecture requires deep reasoning |
|
|
175
|
+
| `developer.md` | `EXECUTOR_MODEL` | Standard execution model |
|
|
176
|
+
| `qa-engineer.md` | `QA_MODEL` | QA-specific model |
|
|
177
|
+
| `security-reviewer.md` | `SECURITY_MODEL` | Best model for security |
|
|
178
|
+
| `tech-writer.md` | `EXECUTOR_MODEL` | Standard execution is sufficient |
|
|
179
|
+
| `debug-specialist.md` | `DEBUG_MODEL` | Deep reasoning for root cause |
|
|
180
|
+
| `release-manager.md` | `EXECUTOR_MODEL` | Release tasks are process-driven |
|
|
181
|
+
| `research-agent.md` | `RESEARCH_MODEL` | Gemini 1M context advantage |
|
|
182
|
+
|
|
183
|
+
## Tier-3 change override
|
|
184
|
+
|
|
185
|
+
When the change classifier identifies a Tier 3 change (auth/payment/PII):
|
|
186
|
+
Override the executing model to `SECURITY_MODEL` regardless of persona.
|
|
187
|
+
Tier 3 changes always get the best available model.
|
|
188
|
+
|
|
189
|
+
## `inherit` keyword
|
|
190
|
+
|
|
191
|
+
Setting any model to `inherit` in MINDFORGE.md instructs MindForge to use
|
|
192
|
+
whatever model the current runtime (Claude Code, Cursor, Windsurf) has
|
|
193
|
+
selected by the user. This is the correct choice when the user has already
|
|
194
|
+
chosen their preferred model in the IDE.
|
|
195
|
+
|
|
196
|
+
## Cost thresholds (configurable in MINDFORGE.md)
|
|
197
|
+
|
|
198
|
+
```
|
|
199
|
+
MODEL_COST_WARN_USD=1.00 # Warn when a single session exceeds $1
|
|
200
|
+
MODEL_COST_HARD_LIMIT_USD=10.00 # Stop and notify when daily spend exceeds $10
|
|
201
|
+
MODEL_PREFER_CHEAP_BELOW_DIFFICULTY=2.0 # Use QUICK_MODEL for easy tasks
|
|
202
|
+
```
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
### `.mindforge/models/model-router.md`
|
|
208
|
+
|
|
209
|
+
```markdown
|
|
210
|
+
# MindForge v2 — Model Router
|
|
211
|
+
|
|
212
|
+
## Purpose
|
|
213
|
+
The model router translates MindForge task context into the correct model
|
|
214
|
+
selection at dispatch time. It reads the task persona, the change tier,
|
|
215
|
+
the MINDFORGE.md overrides, and the fallback chain.
|
|
216
|
+
|
|
217
|
+
## Routing decision algorithm
|
|
218
|
+
|
|
219
|
+
```
|
|
220
|
+
INPUT: task.persona, task.tier, MINDFORGE.md settings, model availability
|
|
221
|
+
|
|
222
|
+
STEP 1: Check if Tier 3 override applies
|
|
223
|
+
IF tier == 3 AND task requires code generation:
|
|
224
|
+
RETURN SECURITY_MODEL (override everything else)
|
|
225
|
+
|
|
226
|
+
STEP 2: Map persona to model setting key
|
|
227
|
+
architect / analyst → PLANNER_MODEL
|
|
228
|
+
developer → EXECUTOR_MODEL
|
|
229
|
+
qa-engineer → QA_MODEL
|
|
230
|
+
security-reviewer → SECURITY_MODEL
|
|
231
|
+
debug-specialist → DEBUG_MODEL
|
|
232
|
+
tech-writer → EXECUTOR_MODEL
|
|
233
|
+
release-manager → EXECUTOR_MODEL
|
|
234
|
+
research-agent → RESEARCH_MODEL
|
|
235
|
+
(unknown persona) → EXECUTOR_MODEL
|
|
236
|
+
|
|
237
|
+
STEP 3: Read model ID from MINDFORGE.md (or default)
|
|
238
|
+
IF model_id == "inherit": RETURN "runtime-selected"
|
|
239
|
+
RETURN model_id
|
|
240
|
+
|
|
241
|
+
STEP 4: Check model availability
|
|
242
|
+
IF model is available (API key exists): RETURN model_id
|
|
243
|
+
ELSE: apply fallback chain
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## Fallback chains
|
|
247
|
+
|
|
248
|
+
```
|
|
249
|
+
claude-opus-4-5 → claude-sonnet-4-6 → claude-haiku-4-5
|
|
250
|
+
claude-sonnet-4-6 → claude-haiku-4-5 → (error: no Claude available)
|
|
251
|
+
gpt-4o → gpt-4o-mini → claude-sonnet-4-6 (cross-review fallback)
|
|
252
|
+
gemini-2.5-pro → gemini-2.0-flash → claude-opus-4-5 (research fallback)
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Fallback is used when:
|
|
256
|
+
- The provider API key is not set in environment
|
|
257
|
+
- The provider returns a rate limit error (429)
|
|
258
|
+
- The provider returns a service unavailable error (503)
|
|
259
|
+
- The model has been deprecated
|
|
260
|
+
|
|
261
|
+
## API key detection
|
|
262
|
+
|
|
263
|
+
```javascript
|
|
264
|
+
const API_KEYS = {
|
|
265
|
+
anthropic: process.env.ANTHROPIC_API_KEY,
|
|
266
|
+
openai: process.env.OPENAI_API_KEY,
|
|
267
|
+
google: process.env.GOOGLE_API_KEY || process.env.GEMINI_API_KEY,
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
function isModelAvailable(modelId) {
|
|
271
|
+
const provider = getProvider(modelId);
|
|
272
|
+
return !!API_KEYS[provider];
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## Routing log
|
|
277
|
+
|
|
278
|
+
Every routing decision writes to AUDIT.jsonl:
|
|
279
|
+
|
|
280
|
+
```json
|
|
281
|
+
{
|
|
282
|
+
"event": "model_routed",
|
|
283
|
+
"task": "Plan 3-04",
|
|
284
|
+
"persona": "security-reviewer",
|
|
285
|
+
"tier": 3,
|
|
286
|
+
"requested_model": "claude-opus-4-5",
|
|
287
|
+
"actual_model": "claude-opus-4-5",
|
|
288
|
+
"fallback_applied": false,
|
|
289
|
+
"reason": "Tier 3 + security-reviewer persona → SECURITY_MODEL"
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
### `.mindforge/models/cost-calculator.md`
|
|
297
|
+
|
|
298
|
+
```markdown
|
|
299
|
+
# MindForge v2 — Cost Calculator
|
|
300
|
+
|
|
301
|
+
## Purpose
|
|
302
|
+
Track real USD cost of every model call made by MindForge across all sessions.
|
|
303
|
+
|
|
304
|
+
## Pricing table (approximate, update regularly)
|
|
305
|
+
These are input/output token prices per 1M tokens.
|
|
306
|
+
Actual pricing varies — see each provider's pricing page for current rates.
|
|
307
|
+
|
|
308
|
+
| Model | Input ($/1M) | Output ($/1M) | Cached input ($/1M) |
|
|
309
|
+
|---|---|---|---|
|
|
310
|
+
| claude-opus-4-5 | $15.00 | $75.00 | $1.50 |
|
|
311
|
+
| claude-sonnet-4-6 | $3.00 | $15.00 | $0.30 |
|
|
312
|
+
| claude-haiku-4-5 | $0.25 | $1.25 | $0.03 |
|
|
313
|
+
| gpt-4o | $5.00 | $15.00 | $2.50 |
|
|
314
|
+
| gpt-4o-mini | $0.15 | $0.60 | $0.075 |
|
|
315
|
+
| gemini-2.5-pro | $3.50 | $10.50 | $0.875 |
|
|
316
|
+
| gemini-2.0-flash | $0.10 | $0.40 | $0.025 |
|
|
317
|
+
|
|
318
|
+
## Cost formula
|
|
319
|
+
|
|
320
|
+
```
|
|
321
|
+
cost_usd = (input_tokens / 1_000_000 * input_price)
|
|
322
|
+
+ (output_tokens / 1_000_000 * output_price)
|
|
323
|
+
+ (cached_tokens / 1_000_000 * cached_price)
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
## Cost tracking schema (token-usage.jsonl extension)
|
|
327
|
+
|
|
328
|
+
```json
|
|
329
|
+
{
|
|
330
|
+
"timestamp": "ISO-8601",
|
|
331
|
+
"session_id": "sess_abc",
|
|
332
|
+
"phase": 3,
|
|
333
|
+
"plan": "04",
|
|
334
|
+
"task_name": "Implement JWT middleware",
|
|
335
|
+
"models_used": [
|
|
336
|
+
{
|
|
337
|
+
"model": "claude-sonnet-4-6",
|
|
338
|
+
"provider": "anthropic",
|
|
339
|
+
"input_tokens": 18200,
|
|
340
|
+
"output_tokens": 4800,
|
|
341
|
+
"cached_tokens": 5400,
|
|
342
|
+
"cost_usd": 0.0862,
|
|
343
|
+
"latency_ms": 3240
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
"model": "gpt-4o",
|
|
347
|
+
"provider": "openai",
|
|
348
|
+
"input_tokens": 9400,
|
|
349
|
+
"output_tokens": 2100,
|
|
350
|
+
"cached_tokens": 0,
|
|
351
|
+
"cost_usd": 0.0785,
|
|
352
|
+
"latency_ms": 4120
|
|
353
|
+
}
|
|
354
|
+
],
|
|
355
|
+
"total_cost_usd": 0.1647,
|
|
356
|
+
"cross_review": true,
|
|
357
|
+
"cross_review_consensus_findings": 2
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
## Budget enforcement
|
|
362
|
+
|
|
363
|
+
When `MODEL_COST_HARD_LIMIT_USD` is set in MINDFORGE.md:
|
|
364
|
+
1. Cost tracker reads all entries from today's token-usage.jsonl
|
|
365
|
+
2. If sum > limit: write AUDIT entry, send Slack alert, stop new model calls
|
|
366
|
+
3. Allow in-progress calls to complete (don't mid-request terminate)
|
|
367
|
+
4. Report: "Daily cost limit ${limit} USD reached. Model calls paused until tomorrow."
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
**Commit:**
|
|
371
|
+
```bash
|
|
372
|
+
git add .mindforge/models/
|
|
373
|
+
git commit -m "feat(v2-models): write model registry, router spec, and cost calculator"
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
---
|
|
377
|
+
|
|
378
|
+
## TASK 3 — Implement the Multi-Provider API Client
|
|
379
|
+
|
|
380
|
+
### `bin/models/model-client.js`
|
|
381
|
+
|
|
382
|
+
```javascript
|
|
383
|
+
/**
|
|
384
|
+
* MindForge v2 — Unified Multi-Provider Model Client
|
|
385
|
+
*
|
|
386
|
+
* Provides a consistent interface to Anthropic, OpenAI, and Google Gemini.
|
|
387
|
+
* All providers return the same shape: { content, model, input_tokens, output_tokens, cost_usd }
|
|
388
|
+
*
|
|
389
|
+
* Handles: provider routing, fallback chains, cost tracking, error normalisation.
|
|
390
|
+
*/
|
|
391
|
+
'use strict';
|
|
392
|
+
|
|
393
|
+
const { AnthropicProvider } = require('./anthropic-provider');
|
|
394
|
+
const { OpenAIProvider } = require('./openai-provider');
|
|
395
|
+
const { GeminiProvider } = require('./gemini-provider');
|
|
396
|
+
const CostTracker = require('./cost-tracker');
|
|
397
|
+
|
|
398
|
+
// ── Provider registry ─────────────────────────────────────────────────────────
|
|
399
|
+
const PROVIDERS = {
|
|
400
|
+
'claude-opus-4-5': () => new AnthropicProvider(),
|
|
401
|
+
'claude-sonnet-4-6': () => new AnthropicProvider(),
|
|
402
|
+
'claude-haiku-4-5': () => new AnthropicProvider(),
|
|
403
|
+
'gpt-4o': () => new OpenAIProvider(),
|
|
404
|
+
'gpt-4o-mini': () => new OpenAIProvider(),
|
|
405
|
+
'gemini-2.5-pro': () => new GeminiProvider(),
|
|
406
|
+
'gemini-2.0-flash': () => new GeminiProvider(),
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
const FALLBACK_CHAINS = {
|
|
410
|
+
'claude-opus-4-5': ['claude-sonnet-4-6', 'claude-haiku-4-5'],
|
|
411
|
+
'claude-sonnet-4-6': ['claude-haiku-4-5'],
|
|
412
|
+
'claude-haiku-4-5': [],
|
|
413
|
+
'gpt-4o': ['gpt-4o-mini', 'claude-sonnet-4-6'],
|
|
414
|
+
'gpt-4o-mini': ['claude-sonnet-4-6'],
|
|
415
|
+
'gemini-2.5-pro': ['gemini-2.0-flash', 'claude-opus-4-5'],
|
|
416
|
+
'gemini-2.0-flash': ['claude-sonnet-4-6'],
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
const PROVIDER_API_KEY = {
|
|
420
|
+
'claude-opus-4-5': 'ANTHROPIC_API_KEY',
|
|
421
|
+
'claude-sonnet-4-6': 'ANTHROPIC_API_KEY',
|
|
422
|
+
'claude-haiku-4-5': 'ANTHROPIC_API_KEY',
|
|
423
|
+
'gpt-4o': 'OPENAI_API_KEY',
|
|
424
|
+
'gpt-4o-mini': 'OPENAI_API_KEY',
|
|
425
|
+
'gemini-2.5-pro': 'GOOGLE_API_KEY',
|
|
426
|
+
'gemini-2.0-flash': 'GOOGLE_API_KEY',
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
// ── Availability check ────────────────────────────────────────────────────────
|
|
430
|
+
function isAvailable(modelId) {
|
|
431
|
+
const keyVar = PROVIDER_API_KEY[modelId];
|
|
432
|
+
if (!keyVar) return false;
|
|
433
|
+
return !!(process.env[keyVar] || process.env.GEMINI_API_KEY);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
function resolveModel(requestedModel) {
|
|
437
|
+
if (requestedModel === 'inherit') return null; // Use runtime model
|
|
438
|
+
|
|
439
|
+
if (isAvailable(requestedModel)) return requestedModel;
|
|
440
|
+
|
|
441
|
+
// Apply fallback chain
|
|
442
|
+
const chain = FALLBACK_CHAINS[requestedModel] || [];
|
|
443
|
+
for (const fallback of chain) {
|
|
444
|
+
if (isAvailable(fallback)) {
|
|
445
|
+
process.stderr.write(
|
|
446
|
+
`[model-client] ⚠️ ${requestedModel} unavailable — falling back to ${fallback}\n`
|
|
447
|
+
);
|
|
448
|
+
return fallback;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// No available model in chain
|
|
453
|
+
const keyVar = PROVIDER_API_KEY[requestedModel];
|
|
454
|
+
throw new Error(
|
|
455
|
+
`Model "${requestedModel}" unavailable and no fallback available.\n` +
|
|
456
|
+
`Set ${keyVar} environment variable to enable it.\n` +
|
|
457
|
+
`Fallback chain: ${[requestedModel, ...chain].join(' → ')}`
|
|
458
|
+
);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// ── Main completion function ──────────────────────────────────────────────────
|
|
462
|
+
/**
|
|
463
|
+
* Call an AI model with a system prompt and user message.
|
|
464
|
+
*
|
|
465
|
+
* @param {object} params
|
|
466
|
+
* @param {string} params.model - Model ID from registry
|
|
467
|
+
* @param {string} params.systemPrompt - System instructions
|
|
468
|
+
* @param {string} params.userMessage - User turn content
|
|
469
|
+
* @param {number} [params.maxTokens] - Max output tokens (default: 4096)
|
|
470
|
+
* @param {number} [params.temperature] - Temperature (default: 0.1 for code review)
|
|
471
|
+
* @param {string} [params.taskName] - For cost tracking
|
|
472
|
+
* @param {string} [params.sessionId] - For cost tracking
|
|
473
|
+
* @returns {{ content, model, input_tokens, output_tokens, cost_usd, latency_ms }}
|
|
474
|
+
*/
|
|
475
|
+
async function complete(params) {
|
|
476
|
+
const {
|
|
477
|
+
model: requestedModel,
|
|
478
|
+
systemPrompt,
|
|
479
|
+
userMessage,
|
|
480
|
+
maxTokens = 4096,
|
|
481
|
+
temperature = 0.1,
|
|
482
|
+
taskName = 'unknown',
|
|
483
|
+
sessionId = 'unknown',
|
|
484
|
+
phaseNum,
|
|
485
|
+
planId,
|
|
486
|
+
} = params;
|
|
487
|
+
|
|
488
|
+
const resolvedModelId = resolveModel(requestedModel);
|
|
489
|
+
if (!resolvedModelId) {
|
|
490
|
+
throw new Error('Model is "inherit" — cannot call directly. Use the runtime\'s model.');
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
const providerFactory = PROVIDERS[resolvedModelId];
|
|
494
|
+
if (!providerFactory) throw new Error(`Unknown model: ${resolvedModelId}`);
|
|
495
|
+
|
|
496
|
+
const provider = providerFactory();
|
|
497
|
+
const t0 = Date.now();
|
|
498
|
+
|
|
499
|
+
let result;
|
|
500
|
+
try {
|
|
501
|
+
result = await provider.complete({
|
|
502
|
+
model: resolvedModelId,
|
|
503
|
+
systemPrompt,
|
|
504
|
+
userMessage,
|
|
505
|
+
maxTokens,
|
|
506
|
+
temperature,
|
|
507
|
+
});
|
|
508
|
+
} catch (err) {
|
|
509
|
+
// Rate limit or 5xx — try fallback immediately
|
|
510
|
+
if (err.status === 429 || err.status >= 500) {
|
|
511
|
+
const fallbacks = FALLBACK_CHAINS[resolvedModelId] || [];
|
|
512
|
+
for (const fallback of fallbacks) {
|
|
513
|
+
if (!isAvailable(fallback)) continue;
|
|
514
|
+
process.stderr.write(
|
|
515
|
+
`[model-client] ⚠️ ${resolvedModelId} error (${err.status}) — trying ${fallback}\n`
|
|
516
|
+
);
|
|
517
|
+
const fallbackProvider = PROVIDERS[fallback]();
|
|
518
|
+
result = await fallbackProvider.complete({
|
|
519
|
+
model: fallback, systemPrompt, userMessage, maxTokens, temperature,
|
|
520
|
+
});
|
|
521
|
+
result.model_used = fallback;
|
|
522
|
+
result.fallback_reason = `${resolvedModelId} returned ${err.status}`;
|
|
523
|
+
break;
|
|
524
|
+
}
|
|
525
|
+
if (!result) throw err;
|
|
526
|
+
} else {
|
|
527
|
+
throw err;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
const latencyMs = Date.now() - t0;
|
|
532
|
+
|
|
533
|
+
// Track cost
|
|
534
|
+
const costEntry = {
|
|
535
|
+
timestamp: new Date().toISOString(),
|
|
536
|
+
session_id: sessionId,
|
|
537
|
+
phase: phaseNum,
|
|
538
|
+
plan: planId,
|
|
539
|
+
task_name: taskName,
|
|
540
|
+
model: result.model_used || resolvedModelId,
|
|
541
|
+
provider: PROVIDER_API_KEY[resolvedModelId]?.replace('_API_KEY', '').toLowerCase(),
|
|
542
|
+
input_tokens: result.input_tokens || 0,
|
|
543
|
+
output_tokens: result.output_tokens || 0,
|
|
544
|
+
cached_tokens: result.cached_tokens || 0,
|
|
545
|
+
cost_usd: result.cost_usd || 0,
|
|
546
|
+
latency_ms: latencyMs,
|
|
547
|
+
fallback_applied: !!result.fallback_reason,
|
|
548
|
+
};
|
|
549
|
+
|
|
550
|
+
await CostTracker.record(costEntry);
|
|
551
|
+
|
|
552
|
+
return {
|
|
553
|
+
content: result.content,
|
|
554
|
+
model: costEntry.model,
|
|
555
|
+
input_tokens: costEntry.input_tokens,
|
|
556
|
+
output_tokens: costEntry.output_tokens,
|
|
557
|
+
cost_usd: costEntry.cost_usd,
|
|
558
|
+
latency_ms: latencyMs,
|
|
559
|
+
fallback_reason: result.fallback_reason,
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
module.exports = { complete, isAvailable, resolveModel };
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
---
|
|
567
|
+
|
|
568
|
+
### `bin/models/anthropic-provider.js`
|
|
569
|
+
|
|
570
|
+
```javascript
|
|
571
|
+
/**
|
|
572
|
+
* MindForge v2 — Anthropic Provider
|
|
573
|
+
* Wraps the Anthropic Messages API with cost calculation.
|
|
574
|
+
*/
|
|
575
|
+
'use strict';
|
|
576
|
+
|
|
577
|
+
const https = require('https');
|
|
578
|
+
|
|
579
|
+
const PRICING = {
|
|
580
|
+
'claude-opus-4-5': { input: 15.00, output: 75.00, cached: 1.50 },
|
|
581
|
+
'claude-sonnet-4-6': { input: 3.00, output: 15.00, cached: 0.30 },
|
|
582
|
+
'claude-haiku-4-5': { input: 0.25, output: 1.25, cached: 0.03 },
|
|
583
|
+
};
|
|
584
|
+
|
|
585
|
+
class AnthropicProvider {
|
|
586
|
+
async complete({ model, systemPrompt, userMessage, maxTokens = 4096, temperature = 0.1 }) {
|
|
587
|
+
const apiKey = process.env.ANTHROPIC_API_KEY;
|
|
588
|
+
if (!apiKey) throw Object.assign(new Error('ANTHROPIC_API_KEY not set'), { status: 401 });
|
|
589
|
+
|
|
590
|
+
const body = JSON.stringify({
|
|
591
|
+
model,
|
|
592
|
+
max_tokens: maxTokens,
|
|
593
|
+
temperature,
|
|
594
|
+
system: systemPrompt,
|
|
595
|
+
messages: [{ role: 'user', content: userMessage }],
|
|
596
|
+
});
|
|
597
|
+
|
|
598
|
+
const data = await this._request(apiKey, body);
|
|
599
|
+
|
|
600
|
+
if (data.error) {
|
|
601
|
+
const err = new Error(data.error.message || 'Anthropic API error');
|
|
602
|
+
err.status = data.error.type === 'rate_limit_error' ? 429 : 500;
|
|
603
|
+
throw err;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
const input_tokens = data.usage?.input_tokens || 0;
|
|
607
|
+
const output_tokens = data.usage?.output_tokens || 0;
|
|
608
|
+
const cached_tokens = data.usage?.cache_read_input_tokens || 0;
|
|
609
|
+
const pricing = PRICING[model] || PRICING['claude-sonnet-4-6'];
|
|
610
|
+
|
|
611
|
+
const cost_usd =
|
|
612
|
+
(input_tokens / 1_000_000 * pricing.input) +
|
|
613
|
+
(output_tokens / 1_000_000 * pricing.output) +
|
|
614
|
+
(cached_tokens / 1_000_000 * pricing.cached);
|
|
615
|
+
|
|
616
|
+
const content = data.content?.[0]?.text || '';
|
|
617
|
+
|
|
618
|
+
return { content, model_used: model, input_tokens, output_tokens, cached_tokens, cost_usd };
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
_request(apiKey, body) {
|
|
622
|
+
return new Promise((resolve, reject) => {
|
|
623
|
+
const req = https.request({
|
|
624
|
+
hostname: 'api.anthropic.com',
|
|
625
|
+
path: '/v1/messages',
|
|
626
|
+
method: 'POST',
|
|
627
|
+
headers: {
|
|
628
|
+
'Content-Type': 'application/json',
|
|
629
|
+
'x-api-key': apiKey,
|
|
630
|
+
'anthropic-version': '2023-06-01',
|
|
631
|
+
'Content-Length': Buffer.byteLength(body),
|
|
632
|
+
},
|
|
633
|
+
timeout: 120_000,
|
|
634
|
+
}, res => {
|
|
635
|
+
let raw = '';
|
|
636
|
+
res.on('data', c => (raw += c));
|
|
637
|
+
res.on('end', () => {
|
|
638
|
+
try { resolve(JSON.parse(raw)); }
|
|
639
|
+
catch { resolve({ error: { message: `Invalid JSON: ${raw.slice(0, 200)}` } }); }
|
|
640
|
+
});
|
|
641
|
+
});
|
|
642
|
+
req.on('error', reject);
|
|
643
|
+
req.on('timeout', () => { req.destroy(); reject(Object.assign(new Error('Anthropic request timeout'), { status: 408 })); });
|
|
644
|
+
req.write(body);
|
|
645
|
+
req.end();
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
module.exports = { AnthropicProvider };
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
---
|
|
654
|
+
|
|
655
|
+
### `bin/models/openai-provider.js`
|
|
656
|
+
|
|
657
|
+
```javascript
|
|
658
|
+
/**
|
|
659
|
+
* MindForge v2 — OpenAI Provider
|
|
660
|
+
* Wraps OpenAI Chat Completions API with cost calculation.
|
|
661
|
+
*/
|
|
662
|
+
'use strict';
|
|
663
|
+
|
|
664
|
+
const https = require('https');
|
|
665
|
+
|
|
666
|
+
const PRICING = {
|
|
667
|
+
'gpt-4o': { input: 5.00, output: 15.00, cached: 2.50 },
|
|
668
|
+
'gpt-4o-mini': { input: 0.15, output: 0.60, cached: 0.075 },
|
|
669
|
+
};
|
|
670
|
+
|
|
671
|
+
class OpenAIProvider {
|
|
672
|
+
async complete({ model, systemPrompt, userMessage, maxTokens = 4096, temperature = 0.1 }) {
|
|
673
|
+
const apiKey = process.env.OPENAI_API_KEY;
|
|
674
|
+
if (!apiKey) throw Object.assign(new Error('OPENAI_API_KEY not set'), { status: 401 });
|
|
675
|
+
|
|
676
|
+
const body = JSON.stringify({
|
|
677
|
+
model,
|
|
678
|
+
max_tokens: maxTokens,
|
|
679
|
+
temperature,
|
|
680
|
+
messages: [
|
|
681
|
+
{ role: 'system', content: systemPrompt },
|
|
682
|
+
{ role: 'user', content: userMessage },
|
|
683
|
+
],
|
|
684
|
+
});
|
|
685
|
+
|
|
686
|
+
const data = await this._request(apiKey, body);
|
|
687
|
+
|
|
688
|
+
if (data.error) {
|
|
689
|
+
const err = new Error(data.error.message || 'OpenAI API error');
|
|
690
|
+
err.status = data.error.code === 'rate_limit_exceeded' ? 429 : 500;
|
|
691
|
+
throw err;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
const input_tokens = data.usage?.prompt_tokens || 0;
|
|
695
|
+
const output_tokens = data.usage?.completion_tokens || 0;
|
|
696
|
+
const cached_tokens = data.usage?.prompt_tokens_details?.cached_tokens || 0;
|
|
697
|
+
const pricing = PRICING[model] || PRICING['gpt-4o'];
|
|
698
|
+
|
|
699
|
+
const cost_usd =
|
|
700
|
+
(input_tokens / 1_000_000 * pricing.input) +
|
|
701
|
+
(output_tokens / 1_000_000 * pricing.output) +
|
|
702
|
+
(cached_tokens / 1_000_000 * pricing.cached);
|
|
703
|
+
|
|
704
|
+
const content = data.choices?.[0]?.message?.content || '';
|
|
705
|
+
|
|
706
|
+
return { content, model_used: model, input_tokens, output_tokens, cached_tokens, cost_usd };
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
_request(apiKey, body) {
|
|
710
|
+
return new Promise((resolve, reject) => {
|
|
711
|
+
const req = https.request({
|
|
712
|
+
hostname: 'api.openai.com',
|
|
713
|
+
path: '/v1/chat/completions',
|
|
714
|
+
method: 'POST',
|
|
715
|
+
headers: {
|
|
716
|
+
'Content-Type': 'application/json',
|
|
717
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
718
|
+
'Content-Length': Buffer.byteLength(body),
|
|
719
|
+
},
|
|
720
|
+
timeout: 120_000,
|
|
721
|
+
}, res => {
|
|
722
|
+
let raw = '';
|
|
723
|
+
res.on('data', c => (raw += c));
|
|
724
|
+
res.on('end', () => { try { resolve(JSON.parse(raw)); } catch { resolve({ error: { message: raw.slice(0, 200) } }); } });
|
|
725
|
+
});
|
|
726
|
+
req.on('error', reject);
|
|
727
|
+
req.on('timeout', () => { req.destroy(); reject(Object.assign(new Error('OpenAI timeout'), { status: 408 })); });
|
|
728
|
+
req.write(body);
|
|
729
|
+
req.end();
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
module.exports = { OpenAIProvider };
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
---
|
|
738
|
+
|
|
739
|
+
### `bin/models/gemini-provider.js`
|
|
740
|
+
|
|
741
|
+
```javascript
|
|
742
|
+
/**
|
|
743
|
+
* MindForge v2 — Google Gemini Provider
|
|
744
|
+
* Wraps Google Gemini generateContent API with cost calculation.
|
|
745
|
+
*/
|
|
746
|
+
'use strict';
|
|
747
|
+
|
|
748
|
+
const https = require('https');
|
|
749
|
+
|
|
750
|
+
const PRICING = {
|
|
751
|
+
'gemini-2.5-pro': { input: 3.50, output: 10.50, cached: 0.875 },
|
|
752
|
+
'gemini-2.0-flash': { input: 0.10, output: 0.40, cached: 0.025 },
|
|
753
|
+
};
|
|
754
|
+
|
|
755
|
+
// Maps MindForge model IDs to Google API model names
|
|
756
|
+
const MODEL_NAMES = {
|
|
757
|
+
'gemini-2.5-pro': 'gemini-2.5-pro',
|
|
758
|
+
'gemini-2.0-flash': 'gemini-2.0-flash',
|
|
759
|
+
};
|
|
760
|
+
|
|
761
|
+
class GeminiProvider {
|
|
762
|
+
async complete({ model, systemPrompt, userMessage, maxTokens = 4096, temperature = 0.1 }) {
|
|
763
|
+
const apiKey = process.env.GOOGLE_API_KEY || process.env.GEMINI_API_KEY;
|
|
764
|
+
if (!apiKey) throw Object.assign(new Error('GOOGLE_API_KEY or GEMINI_API_KEY not set'), { status: 401 });
|
|
765
|
+
|
|
766
|
+
const googleModelName = MODEL_NAMES[model] || model;
|
|
767
|
+
|
|
768
|
+
const body = JSON.stringify({
|
|
769
|
+
system_instruction: { parts: [{ text: systemPrompt }] },
|
|
770
|
+
contents: [{ role: 'user', parts: [{ text: userMessage }] }],
|
|
771
|
+
generationConfig: {
|
|
772
|
+
maxOutputTokens: maxTokens,
|
|
773
|
+
temperature,
|
|
774
|
+
},
|
|
775
|
+
});
|
|
776
|
+
|
|
777
|
+
const data = await this._request(apiKey, googleModelName, body);
|
|
778
|
+
|
|
779
|
+
if (data.error) {
|
|
780
|
+
const err = new Error(data.error.message || 'Gemini API error');
|
|
781
|
+
err.status = data.error.code === 429 ? 429 : 500;
|
|
782
|
+
throw err;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
const input_tokens = data.usageMetadata?.promptTokenCount || 0;
|
|
786
|
+
const output_tokens = data.usageMetadata?.candidatesTokenCount || 0;
|
|
787
|
+
const cached_tokens = data.usageMetadata?.cachedContentTokenCount || 0;
|
|
788
|
+
const pricing = PRICING[model] || PRICING['gemini-2.0-flash'];
|
|
789
|
+
|
|
790
|
+
const cost_usd =
|
|
791
|
+
(input_tokens / 1_000_000 * pricing.input) +
|
|
792
|
+
(output_tokens / 1_000_000 * pricing.output) +
|
|
793
|
+
(cached_tokens / 1_000_000 * pricing.cached);
|
|
794
|
+
|
|
795
|
+
const content = data.candidates?.[0]?.content?.parts?.[0]?.text || '';
|
|
796
|
+
|
|
797
|
+
return { content, model_used: model, input_tokens, output_tokens, cached_tokens, cost_usd };
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
_request(apiKey, modelName, body) {
|
|
801
|
+
return new Promise((resolve, reject) => {
|
|
802
|
+
const req = https.request({
|
|
803
|
+
hostname: 'generativelanguage.googleapis.com',
|
|
804
|
+
path: `/v1beta/models/${encodeURIComponent(modelName)}:generateContent?key=${apiKey}`,
|
|
805
|
+
method: 'POST',
|
|
806
|
+
headers: {
|
|
807
|
+
'Content-Type': 'application/json',
|
|
808
|
+
'Content-Length': Buffer.byteLength(body),
|
|
809
|
+
},
|
|
810
|
+
timeout: 180_000, // Gemini with large context can be slow
|
|
811
|
+
}, res => {
|
|
812
|
+
let raw = '';
|
|
813
|
+
res.on('data', c => (raw += c));
|
|
814
|
+
res.on('end', () => { try { resolve(JSON.parse(raw)); } catch { resolve({ error: { message: raw.slice(0, 200) } }); } });
|
|
815
|
+
});
|
|
816
|
+
req.on('error', reject);
|
|
817
|
+
req.on('timeout', () => { req.destroy(); reject(Object.assign(new Error('Gemini timeout'), { status: 408 })); });
|
|
818
|
+
req.write(body);
|
|
819
|
+
req.end();
|
|
820
|
+
});
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
module.exports = { GeminiProvider };
|
|
825
|
+
```
|
|
826
|
+
|
|
827
|
+
---
|
|
828
|
+
|
|
829
|
+
### `bin/models/model-router.js`
|
|
830
|
+
|
|
831
|
+
```javascript
|
|
832
|
+
/**
|
|
833
|
+
* MindForge v2 — Model Router
|
|
834
|
+
* Translates task context (persona, tier) into model selection.
|
|
835
|
+
*/
|
|
836
|
+
'use strict';
|
|
837
|
+
|
|
838
|
+
const fs = require('fs');
|
|
839
|
+
const path = require('path');
|
|
840
|
+
|
|
841
|
+
// Default routing table — overridable in MINDFORGE.md
|
|
842
|
+
const DEFAULTS = {
|
|
843
|
+
PLANNER_MODEL: 'claude-opus-4-5',
|
|
844
|
+
EXECUTOR_MODEL: 'claude-sonnet-4-6',
|
|
845
|
+
REVIEWER_MODEL: 'gpt-4o',
|
|
846
|
+
SECURITY_MODEL: 'claude-opus-4-5',
|
|
847
|
+
RESEARCH_MODEL: 'gemini-2.5-pro',
|
|
848
|
+
QA_MODEL: 'claude-sonnet-4-6',
|
|
849
|
+
DEBUG_MODEL: 'claude-opus-4-5',
|
|
850
|
+
QUICK_MODEL: 'claude-haiku-4-5',
|
|
851
|
+
CROSS_REVIEW_SECONDARY: 'gpt-4o',
|
|
852
|
+
CROSS_REVIEW_TERTIARY: 'gemini-2.5-pro',
|
|
853
|
+
};
|
|
854
|
+
|
|
855
|
+
const PERSONA_TO_SETTING = {
|
|
856
|
+
'analyst': 'PLANNER_MODEL',
|
|
857
|
+
'architect': 'PLANNER_MODEL',
|
|
858
|
+
'developer': 'EXECUTOR_MODEL',
|
|
859
|
+
'qa-engineer': 'QA_MODEL',
|
|
860
|
+
'security-reviewer': 'SECURITY_MODEL',
|
|
861
|
+
'tech-writer': 'EXECUTOR_MODEL',
|
|
862
|
+
'debug-specialist': 'DEBUG_MODEL',
|
|
863
|
+
'release-manager': 'EXECUTOR_MODEL',
|
|
864
|
+
'research-agent': 'RESEARCH_MODEL',
|
|
865
|
+
};
|
|
866
|
+
|
|
867
|
+
let _cachedSettings = null;
|
|
868
|
+
|
|
869
|
+
function loadSettings() {
|
|
870
|
+
if (_cachedSettings) return _cachedSettings;
|
|
871
|
+
|
|
872
|
+
const mindforgemdPath = path.join(process.cwd(), 'MINDFORGE.md');
|
|
873
|
+
const settings = { ...DEFAULTS };
|
|
874
|
+
|
|
875
|
+
if (fs.existsSync(mindforgemdPath)) {
|
|
876
|
+
const content = fs.readFileSync(mindforgemdPath, 'utf8');
|
|
877
|
+
for (const [key] of Object.entries(DEFAULTS)) {
|
|
878
|
+
const match = content.match(new RegExp(`^${key}=(.+)$`, 'm'));
|
|
879
|
+
if (match) settings[key] = match[1].trim();
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
_cachedSettings = settings;
|
|
884
|
+
return settings;
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
function clearCache() { _cachedSettings = null; }
|
|
888
|
+
|
|
889
|
+
/**
|
|
890
|
+
* Resolve the model ID for a given persona and tier.
|
|
891
|
+
*/
|
|
892
|
+
function route(persona, tier = 1) {
|
|
893
|
+
const settings = loadSettings();
|
|
894
|
+
|
|
895
|
+
// Tier 3 override — always use SECURITY_MODEL
|
|
896
|
+
if (tier === 3) {
|
|
897
|
+
const model = settings.SECURITY_MODEL;
|
|
898
|
+
return { model, setting: 'SECURITY_MODEL', reason: 'Tier 3 override' };
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
const settingKey = PERSONA_TO_SETTING[persona] || 'EXECUTOR_MODEL';
|
|
902
|
+
const model = settings[settingKey] || DEFAULTS[settingKey];
|
|
903
|
+
|
|
904
|
+
return { model, setting: settingKey, reason: `Persona "${persona}" → ${settingKey}` };
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
/**
|
|
908
|
+
* Get all routing settings (for display in /mindforge:costs).
|
|
909
|
+
*/
|
|
910
|
+
function getAllSettings() {
|
|
911
|
+
return loadSettings();
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
/**
|
|
915
|
+
* Get the model ID for a specific routing setting.
|
|
916
|
+
*/
|
|
917
|
+
function getModel(settingKey) {
|
|
918
|
+
return loadSettings()[settingKey] || DEFAULTS[settingKey];
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
module.exports = { route, getModel, getAllSettings, clearCache, DEFAULTS, PERSONA_TO_SETTING };
|
|
922
|
+
```
|
|
923
|
+
|
|
924
|
+
---
|
|
925
|
+
|
|
926
|
+
### `bin/models/cost-tracker.js`
|
|
927
|
+
|
|
928
|
+
```javascript
|
|
929
|
+
/**
|
|
930
|
+
* MindForge v2 — Cost Tracker
|
|
931
|
+
* Appends model usage entries to .mindforge/metrics/token-usage.jsonl
|
|
932
|
+
* and enforces daily cost limits.
|
|
933
|
+
*/
|
|
934
|
+
'use strict';
|
|
935
|
+
|
|
936
|
+
const fs = require('fs');
|
|
937
|
+
const path = require('path');
|
|
938
|
+
|
|
939
|
+
const USAGE_LOG = path.join(process.cwd(), '.mindforge', 'metrics', 'token-usage.jsonl');
|
|
940
|
+
const MINDFORGEMD = path.join(process.cwd(), 'MINDFORGE.md');
|
|
941
|
+
|
|
942
|
+
function ensureDir() {
|
|
943
|
+
fs.mkdirSync(path.dirname(USAGE_LOG), { recursive: true });
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
function readSetting(key, defaultVal) {
|
|
947
|
+
try {
|
|
948
|
+
const content = fs.readFileSync(MINDFORGEMD, 'utf8');
|
|
949
|
+
const match = content.match(new RegExp(`^${key}=(.+)$`, 'm'));
|
|
950
|
+
return match ? match[1].trim() : defaultVal;
|
|
951
|
+
} catch { return defaultVal; }
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
/**
|
|
955
|
+
* Record a model usage entry.
|
|
956
|
+
*/
|
|
957
|
+
async function record(entry) {
|
|
958
|
+
ensureDir();
|
|
959
|
+
|
|
960
|
+
// Enrich with today's date for easy daily queries
|
|
961
|
+
const enriched = {
|
|
962
|
+
...entry,
|
|
963
|
+
date: new Date().toISOString().slice(0, 10),
|
|
964
|
+
};
|
|
965
|
+
|
|
966
|
+
fs.appendFileSync(USAGE_LOG, JSON.stringify(enriched) + '\n');
|
|
967
|
+
|
|
968
|
+
// Check daily budget limit
|
|
969
|
+
await checkDailyLimit(entry.cost_usd || 0);
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
/**
|
|
973
|
+
* Get today's total spend.
|
|
974
|
+
*/
|
|
975
|
+
function getTodaySpend() {
|
|
976
|
+
if (!fs.existsSync(USAGE_LOG)) return 0;
|
|
977
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
978
|
+
let total = 0;
|
|
979
|
+
for (const line of fs.readFileSync(USAGE_LOG, 'utf8').split('\n').filter(Boolean)) {
|
|
980
|
+
try {
|
|
981
|
+
const e = JSON.parse(line);
|
|
982
|
+
if (e.date === today) total += e.cost_usd || 0;
|
|
983
|
+
} catch { /* skip malformed lines */ }
|
|
984
|
+
}
|
|
985
|
+
return total;
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
/**
|
|
989
|
+
* Get spend summary for a time window.
|
|
990
|
+
*/
|
|
991
|
+
function getSummary(opts = {}) {
|
|
992
|
+
const { phase, sessionId, days = 7 } = opts;
|
|
993
|
+
if (!fs.existsSync(USAGE_LOG)) return { entries: [], total_usd: 0, by_model: {} };
|
|
994
|
+
|
|
995
|
+
const cutoff = new Date(Date.now() - days * 86_400_000).toISOString().slice(0, 10);
|
|
996
|
+
|
|
997
|
+
const entries = fs.readFileSync(USAGE_LOG, 'utf8')
|
|
998
|
+
.split('\n')
|
|
999
|
+
.filter(Boolean)
|
|
1000
|
+
.map(l => { try { return JSON.parse(l); } catch { return null; } })
|
|
1001
|
+
.filter(e => e && e.date >= cutoff)
|
|
1002
|
+
.filter(e => (!phase || e.phase === phase) && (!sessionId || e.session_id === sessionId));
|
|
1003
|
+
|
|
1004
|
+
const total_usd = entries.reduce((s, e) => s + (e.cost_usd || 0), 0);
|
|
1005
|
+
const by_model = {};
|
|
1006
|
+
for (const e of entries) {
|
|
1007
|
+
const m = e.model || 'unknown';
|
|
1008
|
+
by_model[m] = by_model[m] || { calls: 0, tokens: 0, cost_usd: 0 };
|
|
1009
|
+
by_model[m].calls++;
|
|
1010
|
+
by_model[m].tokens += (e.input_tokens || 0) + (e.output_tokens || 0);
|
|
1011
|
+
by_model[m].cost_usd += e.cost_usd || 0;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
return { entries: entries.length, total_usd, by_model, days };
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
async function checkDailyLimit(latestCost) {
|
|
1018
|
+
const hardLimit = parseFloat(readSetting('MODEL_COST_HARD_LIMIT_USD', '0'));
|
|
1019
|
+
if (hardLimit <= 0) return; // No limit configured
|
|
1020
|
+
|
|
1021
|
+
const todaySpend = getTodaySpend();
|
|
1022
|
+
if (todaySpend >= hardLimit) {
|
|
1023
|
+
// Write AUDIT entry
|
|
1024
|
+
const auditPath = path.join(process.cwd(), '.planning', 'AUDIT.jsonl');
|
|
1025
|
+
if (fs.existsSync(auditPath)) {
|
|
1026
|
+
fs.appendFileSync(auditPath, JSON.stringify({
|
|
1027
|
+
id: `cost-limit-${Date.now()}`,
|
|
1028
|
+
timestamp: new Date().toISOString(),
|
|
1029
|
+
event: 'cost_limit_reached',
|
|
1030
|
+
daily_limit_usd: hardLimit,
|
|
1031
|
+
today_spend_usd: todaySpend,
|
|
1032
|
+
agent: 'mindforge-cost-tracker',
|
|
1033
|
+
session_id: 'system',
|
|
1034
|
+
}) + '\n');
|
|
1035
|
+
}
|
|
1036
|
+
throw Object.assign(
|
|
1037
|
+
new Error(`Daily cost limit $${hardLimit} reached (today: $${todaySpend.toFixed(4)}). Model calls paused.`),
|
|
1038
|
+
{ code: 'COST_LIMIT_REACHED', spend: todaySpend, limit: hardLimit }
|
|
1039
|
+
);
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
module.exports = { record, getTodaySpend, getSummary, checkDailyLimit };
|
|
1044
|
+
```
|
|
1045
|
+
|
|
1046
|
+
**Commit:**
|
|
1047
|
+
```bash
|
|
1048
|
+
git add bin/models/
|
|
1049
|
+
git commit -m "feat(v2-models): implement multi-provider client, router, cost tracker (Anthropic/OpenAI/Gemini)"
|
|
1050
|
+
```
|
|
1051
|
+
|
|
1052
|
+
---
|
|
1053
|
+
|
|
1054
|
+
## TASK 4 — Implement the Cross-Review Engine
|
|
1055
|
+
|
|
1056
|
+
### `bin/review/cross-review-engine.js`
|
|
1057
|
+
|
|
1058
|
+
```javascript
|
|
1059
|
+
/**
|
|
1060
|
+
* MindForge v2 — Cross-Review Engine
|
|
1061
|
+
* Runs the same diff through multiple AI models and synthesizes findings.
|
|
1062
|
+
*
|
|
1063
|
+
* Pipeline:
|
|
1064
|
+
* Round 1 → Primary reviewer (claude-sonnet-4-6 or configured EXECUTOR_MODEL)
|
|
1065
|
+
* Round 2 → Secondary reviewer (gpt-4o — adversarial mode)
|
|
1066
|
+
* Round 3 → Optional tertiary reviewer (gemini-2.5-pro — with full codebase context)
|
|
1067
|
+
* Synthesis → consensus detection, contradiction highlighting, verdict
|
|
1068
|
+
*/
|
|
1069
|
+
'use strict';
|
|
1070
|
+
|
|
1071
|
+
const fs = require('fs');
|
|
1072
|
+
const path = require('path');
|
|
1073
|
+
const ModelClient = require('../models/model-client');
|
|
1074
|
+
const Router = require('../models/model-router');
|
|
1075
|
+
|
|
1076
|
+
// ── Context loading ───────────────────────────────────────────────────────────
|
|
1077
|
+
function loadReviewContext() {
|
|
1078
|
+
const planningDir = path.join(process.cwd(), '.planning');
|
|
1079
|
+
const ctx = {};
|
|
1080
|
+
|
|
1081
|
+
const read = (p) => fs.existsSync(p) ? fs.readFileSync(p, 'utf8').slice(0, 4000) : '';
|
|
1082
|
+
|
|
1083
|
+
ctx.projectMd = read(path.join(planningDir, 'PROJECT.md'));
|
|
1084
|
+
ctx.architectureMd = read(path.join(planningDir, 'ARCHITECTURE.md'));
|
|
1085
|
+
ctx.conventionsMd = read(path.join(process.cwd(), '.mindforge', 'org', 'CONVENTIONS.md'));
|
|
1086
|
+
ctx.securityMd = read(path.join(process.cwd(), '.mindforge', 'org', 'SECURITY.md'));
|
|
1087
|
+
|
|
1088
|
+
// Extract project name
|
|
1089
|
+
const nameMatch = ctx.projectMd.match(/^# (.+)/m);
|
|
1090
|
+
ctx.projectName = nameMatch?.[1] || 'Unknown Project';
|
|
1091
|
+
|
|
1092
|
+
return ctx;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
function loadDiff(options = {}) {
|
|
1096
|
+
const { diffFile, sha, phase } = options;
|
|
1097
|
+
const { execSync } = require('child_process');
|
|
1098
|
+
|
|
1099
|
+
try {
|
|
1100
|
+
if (diffFile && fs.existsSync(diffFile)) {
|
|
1101
|
+
return fs.readFileSync(diffFile, 'utf8');
|
|
1102
|
+
}
|
|
1103
|
+
if (sha) {
|
|
1104
|
+
return execSync(`git diff ${sha}`, { encoding: 'utf8' });
|
|
1105
|
+
}
|
|
1106
|
+
// Default: diff from last commit or staged
|
|
1107
|
+
try {
|
|
1108
|
+
const staged = execSync('git diff --cached', { encoding: 'utf8' });
|
|
1109
|
+
if (staged.trim()) return staged;
|
|
1110
|
+
} catch {}
|
|
1111
|
+
return execSync('git diff HEAD~1', { encoding: 'utf8' });
|
|
1112
|
+
} catch (err) {
|
|
1113
|
+
throw new Error(`Cannot load diff: ${err.message}`);
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
// ── System prompt builders ────────────────────────────────────────────────────
|
|
1118
|
+
function buildPrimarySystemPrompt(ctx) {
|
|
1119
|
+
return `You are a senior code reviewer for the project: ${ctx.projectName}.
|
|
1120
|
+
|
|
1121
|
+
## Project context
|
|
1122
|
+
${ctx.architectureMd.slice(0, 2000)}
|
|
1123
|
+
|
|
1124
|
+
## Coding conventions
|
|
1125
|
+
${ctx.conventionsMd.slice(0, 1500)}
|
|
1126
|
+
|
|
1127
|
+
## Security requirements
|
|
1128
|
+
${ctx.securityMd.slice(0, 1500)}
|
|
1129
|
+
|
|
1130
|
+
## Your review task
|
|
1131
|
+
Review the provided diff carefully. For each issue found, use this exact format:
|
|
1132
|
+
**[CRITICAL|HIGH|MEDIUM|LOW]** \`file:line\` — Description
|
|
1133
|
+
> Specific remediation
|
|
1134
|
+
|
|
1135
|
+
After findings, provide:
|
|
1136
|
+
### Positive observations
|
|
1137
|
+
### Questions for the author
|
|
1138
|
+
### Verdict: [APPROVE|REQUEST_CHANGES|COMMENT]
|
|
1139
|
+
|
|
1140
|
+
Be specific. Cite line numbers. Focus on correctness, security, and architecture.`;
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
function buildAdversarialSystemPrompt(ctx) {
|
|
1144
|
+
return `You are a paranoid senior security engineer reviewing code written by a team you are auditing.
|
|
1145
|
+
Your job is to find BUGS, SECURITY FLAWS, and DESIGN PROBLEMS they missed.
|
|
1146
|
+
|
|
1147
|
+
Project: ${ctx.projectName}
|
|
1148
|
+
Architecture: ${ctx.architectureMd.slice(0, 1500)}
|
|
1149
|
+
|
|
1150
|
+
## Your adversarial approach
|
|
1151
|
+
1. Assume the developers made mistakes — look for them specifically
|
|
1152
|
+
2. Check OWASP Top 10 systematically: injection, auth failures, broken access, crypto, XSS
|
|
1153
|
+
3. Look for race conditions, TOCTOU issues, integer overflow, off-by-one errors
|
|
1154
|
+
4. Check error handling — what happens on failure? Is sensitive data leaked in errors?
|
|
1155
|
+
5. Check all external inputs — are they validated, sanitized, and bounded?
|
|
1156
|
+
|
|
1157
|
+
## Output format
|
|
1158
|
+
For each finding, use exactly:
|
|
1159
|
+
**[CRITICAL|HIGH|MEDIUM|LOW]** \`file:line\` — Description
|
|
1160
|
+
> Remediation
|
|
1161
|
+
|
|
1162
|
+
Be thorough. A missed critical finding in this review is a production incident waiting to happen.`;
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
function buildResearchSystemPrompt(ctx, fullCodebase) {
|
|
1166
|
+
return `You are a technical architecture reviewer with access to the full codebase context.
|
|
1167
|
+
|
|
1168
|
+
Project: ${ctx.projectName}
|
|
1169
|
+
|
|
1170
|
+
## Full codebase context
|
|
1171
|
+
${fullCodebase || 'Not provided for this review'}
|
|
1172
|
+
|
|
1173
|
+
## Your role
|
|
1174
|
+
You have broader context than the other reviewers. Find issues that only emerge
|
|
1175
|
+
when you can see the full picture: architectural inconsistencies, cross-module
|
|
1176
|
+
coupling, patterns that work here but will cause problems in other parts of the system.
|
|
1177
|
+
|
|
1178
|
+
## Output format
|
|
1179
|
+
**[CRITICAL|HIGH|MEDIUM|LOW]** \`file:line\` — Description
|
|
1180
|
+
> Remediation`;
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
// ── Finding parser ────────────────────────────────────────────────────────────
|
|
1184
|
+
const SEVERITY_RE = /\*\*\[(CRITICAL|HIGH|MEDIUM|LOW)\]\*\*\s+`([^`]+)`\s+—\s+(.+)/g;
|
|
1185
|
+
|
|
1186
|
+
function parseFindings(reviewText) {
|
|
1187
|
+
const findings = [];
|
|
1188
|
+
let m;
|
|
1189
|
+
while ((m = SEVERITY_RE.exec(reviewText)) !== null) {
|
|
1190
|
+
findings.push({
|
|
1191
|
+
severity: m[1],
|
|
1192
|
+
location: m[2],
|
|
1193
|
+
description: m[3].trim(),
|
|
1194
|
+
});
|
|
1195
|
+
}
|
|
1196
|
+
return findings;
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
function extractVerdict(reviewText) {
|
|
1200
|
+
const m = reviewText.match(/Verdict:\s*(APPROVE|REQUEST_CHANGES|COMMENT)/i);
|
|
1201
|
+
return m?.[1]?.toUpperCase() || 'COMMENT';
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
// ── Main cross-review function ────────────────────────────────────────────────
|
|
1205
|
+
async function runCrossReview(options = {}) {
|
|
1206
|
+
const {
|
|
1207
|
+
phaseNum,
|
|
1208
|
+
diffFile,
|
|
1209
|
+
sha,
|
|
1210
|
+
models,
|
|
1211
|
+
sessionId = 'unknown',
|
|
1212
|
+
focusArea,
|
|
1213
|
+
includeFullCodebase = false,
|
|
1214
|
+
} = options;
|
|
1215
|
+
|
|
1216
|
+
const ctx = loadReviewContext();
|
|
1217
|
+
const diff = loadDiff({ diffFile, sha });
|
|
1218
|
+
const settings = Router.getAllSettings();
|
|
1219
|
+
|
|
1220
|
+
const primaryModel = settings.EXECUTOR_MODEL || 'claude-sonnet-4-6';
|
|
1221
|
+
const secondaryModel = settings.CROSS_REVIEW_SECONDARY || 'gpt-4o';
|
|
1222
|
+
const tertiaryModel = models?.includes('gemini') ? (settings.CROSS_REVIEW_TERTIARY || 'gemini-2.5-pro') : null;
|
|
1223
|
+
|
|
1224
|
+
if (diff.trim().length === 0) {
|
|
1225
|
+
return { error: 'No diff found. Make sure there are staged or committed changes to review.' };
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
const truncatedDiff = diff.length > 15_000
|
|
1229
|
+
? diff.slice(0, 15_000) + `\n\n[Diff truncated — ${diff.length} chars total]`
|
|
1230
|
+
: diff;
|
|
1231
|
+
|
|
1232
|
+
const userMessage = `Please review this code diff:\n\`\`\`diff\n${truncatedDiff}\n\`\`\``;
|
|
1233
|
+
|
|
1234
|
+
console.log(`\n 🔍 Cross-review: ${primaryModel} → ${secondaryModel}${tertiaryModel ? ` → ${tertiaryModel}` : ''}`);
|
|
1235
|
+
|
|
1236
|
+
// ── Round 1: Primary reviewer ─────────────────────────────────────────────
|
|
1237
|
+
process.stdout.write(` Round 1 (${primaryModel})... `);
|
|
1238
|
+
const round1 = await ModelClient.complete({
|
|
1239
|
+
model: primaryModel,
|
|
1240
|
+
systemPrompt: buildPrimarySystemPrompt(ctx),
|
|
1241
|
+
userMessage,
|
|
1242
|
+
maxTokens: 4096,
|
|
1243
|
+
taskName: `cross-review-round1-phase${phaseNum}`,
|
|
1244
|
+
sessionId,
|
|
1245
|
+
phaseNum,
|
|
1246
|
+
});
|
|
1247
|
+
console.log(`done ($${round1.cost_usd.toFixed(4)})`);
|
|
1248
|
+
|
|
1249
|
+
// ── Round 2: Adversarial reviewer ────────────────────────────────────────
|
|
1250
|
+
process.stdout.write(` Round 2 (${secondaryModel}, adversarial)... `);
|
|
1251
|
+
let round2 = null;
|
|
1252
|
+
try {
|
|
1253
|
+
round2 = await ModelClient.complete({
|
|
1254
|
+
model: secondaryModel,
|
|
1255
|
+
systemPrompt: buildAdversarialSystemPrompt(ctx),
|
|
1256
|
+
userMessage,
|
|
1257
|
+
maxTokens: 4096,
|
|
1258
|
+
taskName: `cross-review-round2-phase${phaseNum}`,
|
|
1259
|
+
sessionId,
|
|
1260
|
+
phaseNum,
|
|
1261
|
+
});
|
|
1262
|
+
console.log(`done ($${round2.cost_usd.toFixed(4)})`);
|
|
1263
|
+
} catch (err) {
|
|
1264
|
+
console.log(`skipped (${err.message.slice(0, 60)})`);
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
// ── Round 3: Tertiary reviewer (optional) ────────────────────────────────
|
|
1268
|
+
let round3 = null;
|
|
1269
|
+
if (tertiaryModel) {
|
|
1270
|
+
process.stdout.write(` Round 3 (${tertiaryModel})... `);
|
|
1271
|
+
try {
|
|
1272
|
+
const fullCodebase = includeFullCodebase ? loadFullCodebaseContext() : null;
|
|
1273
|
+
round3 = await ModelClient.complete({
|
|
1274
|
+
model: tertiaryModel,
|
|
1275
|
+
systemPrompt: buildResearchSystemPrompt(ctx, fullCodebase),
|
|
1276
|
+
userMessage,
|
|
1277
|
+
maxTokens: 4096,
|
|
1278
|
+
taskName: `cross-review-round3-phase${phaseNum}`,
|
|
1279
|
+
sessionId,
|
|
1280
|
+
phaseNum,
|
|
1281
|
+
});
|
|
1282
|
+
console.log(`done ($${round3.cost_usd.toFixed(4)})`);
|
|
1283
|
+
} catch (err) {
|
|
1284
|
+
console.log(`skipped (${err.message.slice(0, 60)})`);
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
// ── Synthesis ─────────────────────────────────────────────────────────────
|
|
1289
|
+
const reviews = [
|
|
1290
|
+
{ model: primaryModel, content: round1.content, role: 'primary' },
|
|
1291
|
+
...(round2 ? [{ model: secondaryModel, content: round2.content, role: 'adversarial' }] : []),
|
|
1292
|
+
...(round3 ? [{ model: tertiaryModel, content: round3.content, role: 'research' }] : []),
|
|
1293
|
+
];
|
|
1294
|
+
|
|
1295
|
+
const synthesis = synthesizeFindings(reviews);
|
|
1296
|
+
const totalCost = (round1.cost_usd || 0) + (round2?.cost_usd || 0) + (round3?.cost_usd || 0);
|
|
1297
|
+
|
|
1298
|
+
return {
|
|
1299
|
+
reviews,
|
|
1300
|
+
synthesis,
|
|
1301
|
+
total_cost_usd: totalCost,
|
|
1302
|
+
diff_length: diff.length,
|
|
1303
|
+
};
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
function loadFullCodebaseContext() {
|
|
1307
|
+
// Read key architecture files for Gemini's large context
|
|
1308
|
+
const files = [
|
|
1309
|
+
'.planning/ARCHITECTURE.md',
|
|
1310
|
+
'.planning/PROJECT.md',
|
|
1311
|
+
'src',
|
|
1312
|
+
];
|
|
1313
|
+
let context = '';
|
|
1314
|
+
for (const f of files) {
|
|
1315
|
+
const p = path.join(process.cwd(), f);
|
|
1316
|
+
if (fs.existsSync(p) && !fs.statSync(p).isDirectory()) {
|
|
1317
|
+
context += `\n\n### ${f}\n${fs.readFileSync(p, 'utf8').slice(0, 20_000)}`;
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
return context.slice(0, 900_000); // Stay within Gemini's 1M context
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
module.exports = { runCrossReview, parseFindings, extractVerdict };
|
|
1324
|
+
```
|
|
1325
|
+
|
|
1326
|
+
---
|
|
1327
|
+
|
|
1328
|
+
### `bin/review/finding-synthesizer.js`
|
|
1329
|
+
|
|
1330
|
+
```javascript
|
|
1331
|
+
/**
|
|
1332
|
+
* MindForge v2 — Finding Synthesizer
|
|
1333
|
+
* Compares findings across multiple model reviews to identify:
|
|
1334
|
+
* - Consensus findings (same issue found by 2+ models = high confidence)
|
|
1335
|
+
* - Model-specific findings (only one model found it)
|
|
1336
|
+
* - Contradictions (models disagree on the right approach)
|
|
1337
|
+
*/
|
|
1338
|
+
'use strict';
|
|
1339
|
+
|
|
1340
|
+
const { parseFindings, extractVerdict } = require('./cross-review-engine');
|
|
1341
|
+
|
|
1342
|
+
/**
|
|
1343
|
+
* Synthesize findings from multiple model reviews.
|
|
1344
|
+
* @param {{ model, content, role }[]} reviews
|
|
1345
|
+
* @returns {{ consensus, by_model, contradictions, overall_verdict, summary }}
|
|
1346
|
+
*/
|
|
1347
|
+
function synthesizeFindings(reviews) {
|
|
1348
|
+
const allFindings = reviews.map(r => ({
|
|
1349
|
+
model: r.model,
|
|
1350
|
+
role: r.role,
|
|
1351
|
+
findings: parseFindings(r.content),
|
|
1352
|
+
verdict: extractVerdict(r.content),
|
|
1353
|
+
}));
|
|
1354
|
+
|
|
1355
|
+
// Find consensus: same file + similar description across 2+ models
|
|
1356
|
+
const consensus = [];
|
|
1357
|
+
const model_specific = {};
|
|
1358
|
+
const contradictions = [];
|
|
1359
|
+
|
|
1360
|
+
// Index findings by location for cross-model comparison
|
|
1361
|
+
const byLocation = {};
|
|
1362
|
+
for (const { model, findings } of allFindings) {
|
|
1363
|
+
for (const f of findings) {
|
|
1364
|
+
const key = normalizeLocation(f.location);
|
|
1365
|
+
if (!byLocation[key]) byLocation[key] = [];
|
|
1366
|
+
byLocation[key].push({ model, ...f });
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
// Classify findings
|
|
1371
|
+
for (const [loc, locFindings] of Object.entries(byLocation)) {
|
|
1372
|
+
const modelNames = [...new Set(locFindings.map(f => f.model))];
|
|
1373
|
+
if (modelNames.length >= 2) {
|
|
1374
|
+
// Consensus finding
|
|
1375
|
+
const highest = highestSeverity(locFindings.map(f => f.severity));
|
|
1376
|
+
consensus.push({
|
|
1377
|
+
location: locFindings[0].location,
|
|
1378
|
+
severity: highest,
|
|
1379
|
+
description: locFindings[0].description,
|
|
1380
|
+
models: modelNames,
|
|
1381
|
+
all_descriptions: locFindings.map(f => ({ model: f.model, text: f.description })),
|
|
1382
|
+
});
|
|
1383
|
+
} else {
|
|
1384
|
+
// Model-specific
|
|
1385
|
+
const model = modelNames[0];
|
|
1386
|
+
if (!model_specific[model]) model_specific[model] = [];
|
|
1387
|
+
model_specific[model].push(...locFindings);
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
// Detect contradictions (same location, different severity by 2+ tiers)
|
|
1392
|
+
for (const [, locFindings] of Object.entries(byLocation)) {
|
|
1393
|
+
if (locFindings.length < 2) continue;
|
|
1394
|
+
const severities = locFindings.map(f => f.severity);
|
|
1395
|
+
if (severityGap(severities) >= 2) {
|
|
1396
|
+
contradictions.push({
|
|
1397
|
+
location: locFindings[0].location,
|
|
1398
|
+
entries: locFindings.map(f => ({ model: f.model, severity: f.severity, description: f.description })),
|
|
1399
|
+
});
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
// Aggregate verdict
|
|
1404
|
+
const verdicts = allFindings.map(r => r.verdict);
|
|
1405
|
+
const hasRequest = verdicts.some(v => v === 'REQUEST_CHANGES');
|
|
1406
|
+
const allApprove = verdicts.every(v => v === 'APPROVE');
|
|
1407
|
+
const overall_verdict = allApprove ? 'APPROVE' : hasRequest ? 'REQUEST_CHANGES' : 'COMMENT';
|
|
1408
|
+
|
|
1409
|
+
const total_findings = consensus.length + Object.values(model_specific).flat().length;
|
|
1410
|
+
|
|
1411
|
+
return {
|
|
1412
|
+
consensus,
|
|
1413
|
+
model_specific,
|
|
1414
|
+
contradictions,
|
|
1415
|
+
overall_verdict,
|
|
1416
|
+
models_used: allFindings.map(r => r.model),
|
|
1417
|
+
total_findings,
|
|
1418
|
+
critical_count: [...consensus, ...Object.values(model_specific).flat()]
|
|
1419
|
+
.filter(f => f.severity === 'CRITICAL').length,
|
|
1420
|
+
};
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
function normalizeLocation(loc) {
|
|
1424
|
+
// Strip exact line numbers for fuzzy matching (same file, near same line = same finding)
|
|
1425
|
+
return loc?.replace(/:\d+$/, '').toLowerCase() || '';
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
const SEVERITY_ORDER = ['LOW', 'MEDIUM', 'HIGH', 'CRITICAL'];
|
|
1429
|
+
|
|
1430
|
+
function highestSeverity(severities) {
|
|
1431
|
+
return severities.reduce((max, s) =>
|
|
1432
|
+
SEVERITY_ORDER.indexOf(s) > SEVERITY_ORDER.indexOf(max) ? s : max, 'LOW');
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
function severityGap(severities) {
|
|
1436
|
+
const indices = severities.map(s => SEVERITY_ORDER.indexOf(s));
|
|
1437
|
+
return Math.max(...indices) - Math.min(...indices);
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
module.exports = { synthesizeFindings };
|
|
1441
|
+
```
|
|
1442
|
+
|
|
1443
|
+
---
|
|
1444
|
+
|
|
1445
|
+
### `bin/review/review-report-writer.js`
|
|
1446
|
+
|
|
1447
|
+
```javascript
|
|
1448
|
+
/**
|
|
1449
|
+
* MindForge v2 — Cross-Review Report Writer
|
|
1450
|
+
* Writes CROSS-REVIEW-[N].md to .planning/phases/[N]/
|
|
1451
|
+
*/
|
|
1452
|
+
'use strict';
|
|
1453
|
+
|
|
1454
|
+
const fs = require('fs');
|
|
1455
|
+
const path = require('path');
|
|
1456
|
+
|
|
1457
|
+
function write(phaseNum, crossReviewResult) {
|
|
1458
|
+
const { reviews, synthesis, total_cost_usd, diff_length } = crossReviewResult;
|
|
1459
|
+
const { consensus, model_specific, contradictions, overall_verdict, total_findings } = synthesis;
|
|
1460
|
+
|
|
1461
|
+
const dir = path.join(process.cwd(), '.planning', 'phases', String(phaseNum));
|
|
1462
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
1463
|
+
|
|
1464
|
+
const verdictIcon = overall_verdict === 'APPROVE' ? '✅' :
|
|
1465
|
+
overall_verdict === 'REQUEST_CHANGES' ? '❌' : '⚠️';
|
|
1466
|
+
|
|
1467
|
+
const lines = [
|
|
1468
|
+
`# Cross-Model Code Review — Phase ${phaseNum}`,
|
|
1469
|
+
`**Generated:** ${new Date().toISOString()}`,
|
|
1470
|
+
`**Models:** ${reviews.map(r => r.model).join(' → ')}`,
|
|
1471
|
+
`**Diff size:** ${diff_length.toLocaleString()} chars`,
|
|
1472
|
+
`**Total cost:** $${total_cost_usd.toFixed(4)}`,
|
|
1473
|
+
`**Verdict:** ${verdictIcon} ${overall_verdict}`,
|
|
1474
|
+
`**Total findings:** ${total_findings} (${consensus.length} consensus, ${Object.values(model_specific).flat().length} model-specific)`,
|
|
1475
|
+
'',
|
|
1476
|
+
'## Consensus Findings (found by 2+ models — high confidence)',
|
|
1477
|
+
'',
|
|
1478
|
+
];
|
|
1479
|
+
|
|
1480
|
+
if (consensus.length === 0) {
|
|
1481
|
+
lines.push('*No consensus findings — models did not agree on any specific issues.*');
|
|
1482
|
+
} else {
|
|
1483
|
+
lines.push('| # | Severity | Location | Description | Models |');
|
|
1484
|
+
lines.push('|---|---|---|---|---|');
|
|
1485
|
+
consensus.forEach((f, i) => {
|
|
1486
|
+
lines.push(`| ${i+1} | **${f.severity}** | \`${f.location}\` | ${f.description.slice(0, 120)} | ${f.models.join(' + ')} |`);
|
|
1487
|
+
});
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
lines.push('', '## Model-Specific Findings', '');
|
|
1491
|
+
for (const [model, findings] of Object.entries(model_specific)) {
|
|
1492
|
+
if (!findings.length) continue;
|
|
1493
|
+
lines.push(`### ${model} only`);
|
|
1494
|
+
lines.push('');
|
|
1495
|
+
findings.slice(0, 10).forEach(f => {
|
|
1496
|
+
lines.push(`**[${f.severity}]** \`${f.location}\` — ${f.description}`);
|
|
1497
|
+
});
|
|
1498
|
+
if (findings.length > 10) lines.push(`*...and ${findings.length - 10} more findings*`);
|
|
1499
|
+
lines.push('');
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
if (contradictions.length > 0) {
|
|
1503
|
+
lines.push('## ⚠️ Contradictions (models disagree — human resolution required)', '');
|
|
1504
|
+
contradictions.forEach((c, i) => {
|
|
1505
|
+
lines.push(`### Contradiction ${i+1}: \`${c.location}\``);
|
|
1506
|
+
c.entries.forEach(e => lines.push(`- **${e.model}** [${e.severity}]: ${e.description}`));
|
|
1507
|
+
lines.push('');
|
|
1508
|
+
});
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
lines.push('## Individual Review Outputs', '');
|
|
1512
|
+
reviews.forEach(r => {
|
|
1513
|
+
lines.push(`<details><summary>${r.model} (${r.role})</summary>`, '');
|
|
1514
|
+
lines.push('```');
|
|
1515
|
+
lines.push(r.content.slice(0, 3000));
|
|
1516
|
+
if (r.content.length > 3000) lines.push(`[truncated — ${r.content.length} chars total]`);
|
|
1517
|
+
lines.push('```', '', '</details>', '');
|
|
1518
|
+
});
|
|
1519
|
+
|
|
1520
|
+
const file = path.join(dir, `CROSS-REVIEW-${phaseNum}.md`);
|
|
1521
|
+
fs.writeFileSync(file, lines.join('\n'));
|
|
1522
|
+
return file;
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
module.exports = { write };
|
|
1526
|
+
```
|
|
1527
|
+
|
|
1528
|
+
**Commit:**
|
|
1529
|
+
```bash
|
|
1530
|
+
git add bin/review/
|
|
1531
|
+
git commit -m "feat(v2-models): implement cross-review engine, finding synthesizer, and report writer"
|
|
1532
|
+
```
|
|
1533
|
+
|
|
1534
|
+
---
|
|
1535
|
+
|
|
1536
|
+
## TASK 5 — Implement the Research Engine
|
|
1537
|
+
|
|
1538
|
+
### `bin/research/research-engine.js`
|
|
1539
|
+
|
|
1540
|
+
```javascript
|
|
1541
|
+
/**
|
|
1542
|
+
* MindForge v2 — Research Engine
|
|
1543
|
+
* Leverages Gemini 2.5 Pro's 1M context for deep research tasks.
|
|
1544
|
+
*
|
|
1545
|
+
* Use cases:
|
|
1546
|
+
* - Library comparison with full documentation
|
|
1547
|
+
* - Legacy codebase analysis
|
|
1548
|
+
* - Regulatory compliance research (GDPR, HIPAA, etc.)
|
|
1549
|
+
* - Pre-planning technical deep-dives
|
|
1550
|
+
*/
|
|
1551
|
+
'use strict';
|
|
1552
|
+
|
|
1553
|
+
const fs = require('fs');
|
|
1554
|
+
const path = require('path');
|
|
1555
|
+
const https = require('https');
|
|
1556
|
+
const ModelClient = require('../models/model-client');
|
|
1557
|
+
const Router = require('../models/model-router');
|
|
1558
|
+
|
|
1559
|
+
const RESEARCH_MODEL = 'gemini-2.5-pro'; // Overridden by RESEARCH_MODEL in MINDFORGE.md
|
|
1560
|
+
|
|
1561
|
+
// ── Context packager ──────────────────────────────────────────────────────────
|
|
1562
|
+
function packageLocalContext(contextPaths = []) {
|
|
1563
|
+
let content = '';
|
|
1564
|
+
const maxPerFile = 50_000; // 50K chars per file to avoid one file dominating
|
|
1565
|
+
|
|
1566
|
+
for (const p of contextPaths) {
|
|
1567
|
+
const fullPath = path.isAbsolute(p) ? p : path.join(process.cwd(), p);
|
|
1568
|
+
if (!fs.existsSync(fullPath)) continue;
|
|
1569
|
+
|
|
1570
|
+
const stat = fs.statSync(fullPath);
|
|
1571
|
+
if (stat.isDirectory()) {
|
|
1572
|
+
// Include all relevant files in directory (recursively, capped at 500K total)
|
|
1573
|
+
const files = walkDir(fullPath, ['.ts', '.tsx', '.js', '.jsx', '.md', '.json']);
|
|
1574
|
+
for (const f of files) {
|
|
1575
|
+
if (content.length > 500_000) break;
|
|
1576
|
+
const text = fs.readFileSync(f, 'utf8').slice(0, maxPerFile);
|
|
1577
|
+
content += `\n\n### ${path.relative(process.cwd(), f)}\n\`\`\`\n${text}\n\`\`\``;
|
|
1578
|
+
}
|
|
1579
|
+
} else {
|
|
1580
|
+
const text = fs.readFileSync(fullPath, 'utf8').slice(0, maxPerFile);
|
|
1581
|
+
content += `\n\n### ${p}\n\`\`\`\n${text}\n\`\`\``;
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
return content;
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
function walkDir(dir, extensions) {
|
|
1589
|
+
const results = [];
|
|
1590
|
+
const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build', '.next', 'coverage']);
|
|
1591
|
+
try {
|
|
1592
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
1593
|
+
if (SKIP_DIRS.has(entry.name)) continue;
|
|
1594
|
+
const fullPath = path.join(dir, entry.name);
|
|
1595
|
+
if (entry.isDirectory()) results.push(...walkDir(fullPath, extensions));
|
|
1596
|
+
else if (extensions.some(ext => entry.name.endsWith(ext))) results.push(fullPath);
|
|
1597
|
+
}
|
|
1598
|
+
} catch {}
|
|
1599
|
+
return results;
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
async function fetchUrl(url) {
|
|
1603
|
+
return new Promise((resolve, reject) => {
|
|
1604
|
+
const protocol = url.startsWith('https') ? require('https') : require('http');
|
|
1605
|
+
protocol.get(url, { timeout: 30_000 }, res => {
|
|
1606
|
+
let body = '';
|
|
1607
|
+
res.on('data', c => (body += c));
|
|
1608
|
+
res.on('end', () => resolve(body.slice(0, 200_000))); // Cap at 200K
|
|
1609
|
+
}).on('error', reject);
|
|
1610
|
+
});
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
// ── Research system prompts ───────────────────────────────────────────────────
|
|
1614
|
+
const RESEARCH_SYSTEM_PROMPTS = {
|
|
1615
|
+
general: `You are a thorough technical researcher. Analyse the provided context deeply and answer the question comprehensively. Cite specific evidence from the context. Structure your response with clear headings. Be concrete — give specific recommendations, not vague guidance.`,
|
|
1616
|
+
|
|
1617
|
+
library_comparison: `You are a senior engineer evaluating libraries for production use.
|
|
1618
|
+
For each library, analyse: API design quality, maintenance status, performance characteristics, security record, bundle size, TypeScript support, community size, known issues.
|
|
1619
|
+
Provide a clear recommendation with rationale. Do not be vague.`,
|
|
1620
|
+
|
|
1621
|
+
codebase_analysis: `You are a senior architect performing a codebase audit.
|
|
1622
|
+
Identify: architectural patterns used, coupling issues, missing abstractions, technical debt, security concerns, performance bottlenecks.
|
|
1623
|
+
Be specific — cite file names and line numbers where relevant.`,
|
|
1624
|
+
|
|
1625
|
+
compliance: `You are a compliance engineer reviewing technical implementation against regulatory requirements.
|
|
1626
|
+
For each requirement: assess whether the codebase meets it, identify specific gaps, provide concrete remediation steps.
|
|
1627
|
+
Be precise about what constitutes compliance vs. non-compliance.`,
|
|
1628
|
+
|
|
1629
|
+
pre_planning: `You are a senior architect helping with pre-implementation planning.
|
|
1630
|
+
Analyse the context provided and answer the planning question with:
|
|
1631
|
+
1. Technical approach recommendation
|
|
1632
|
+
2. Key risks and mitigations
|
|
1633
|
+
3. Estimated complexity
|
|
1634
|
+
4. Specific implementation steps
|
|
1635
|
+
5. Open questions that need resolution before starting`,
|
|
1636
|
+
};
|
|
1637
|
+
|
|
1638
|
+
// ── Main research function ────────────────────────────────────────────────────
|
|
1639
|
+
async function research(params) {
|
|
1640
|
+
const {
|
|
1641
|
+
topic,
|
|
1642
|
+
question,
|
|
1643
|
+
researchType = 'general',
|
|
1644
|
+
contextPaths = [], // Local files/dirs to include
|
|
1645
|
+
urls = [], // URLs to fetch and include
|
|
1646
|
+
sessionId = 'unknown',
|
|
1647
|
+
phaseNum,
|
|
1648
|
+
} = params;
|
|
1649
|
+
|
|
1650
|
+
const model = Router.getModel('RESEARCH_MODEL') || RESEARCH_MODEL;
|
|
1651
|
+
|
|
1652
|
+
// Package context
|
|
1653
|
+
let contextContent = packageLocalContext(contextPaths);
|
|
1654
|
+
|
|
1655
|
+
// Fetch URLs
|
|
1656
|
+
for (const url of urls) {
|
|
1657
|
+
try {
|
|
1658
|
+
const html = await fetchUrl(url);
|
|
1659
|
+
// Strip HTML tags for cleaner context
|
|
1660
|
+
const text = html.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim();
|
|
1661
|
+
contextContent += `\n\n### URL: ${url}\n${text.slice(0, 100_000)}`;
|
|
1662
|
+
} catch (err) {
|
|
1663
|
+
contextContent += `\n\n### URL: ${url}\n[Failed to fetch: ${err.message}]`;
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
|
|
1667
|
+
const systemPrompt = RESEARCH_SYSTEM_PROMPTS[researchType] || RESEARCH_SYSTEM_PROMPTS.general;
|
|
1668
|
+
|
|
1669
|
+
const userMessage = [
|
|
1670
|
+
`## Research Topic\n${topic}`,
|
|
1671
|
+
contextContent ? `\n## Context\n${contextContent}` : '',
|
|
1672
|
+
`\n## Question\n${question}`,
|
|
1673
|
+
].join('\n');
|
|
1674
|
+
|
|
1675
|
+
process.stdout.write(` 🔬 Researching with ${model} (${contextContent.length.toLocaleString()} chars context)... `);
|
|
1676
|
+
|
|
1677
|
+
const result = await ModelClient.complete({
|
|
1678
|
+
model,
|
|
1679
|
+
systemPrompt,
|
|
1680
|
+
userMessage,
|
|
1681
|
+
maxTokens: 8192,
|
|
1682
|
+
temperature: 0.2,
|
|
1683
|
+
taskName: `research-${topic.slice(0, 30)}`,
|
|
1684
|
+
sessionId,
|
|
1685
|
+
phaseNum,
|
|
1686
|
+
});
|
|
1687
|
+
|
|
1688
|
+
console.log(`done ($${result.cost_usd.toFixed(4)})`);
|
|
1689
|
+
|
|
1690
|
+
return {
|
|
1691
|
+
topic,
|
|
1692
|
+
question,
|
|
1693
|
+
research_type: researchType,
|
|
1694
|
+
model_used: result.model,
|
|
1695
|
+
content: result.content,
|
|
1696
|
+
cost_usd: result.cost_usd,
|
|
1697
|
+
context_length: contextContent.length,
|
|
1698
|
+
input_tokens: result.input_tokens,
|
|
1699
|
+
output_tokens: result.output_tokens,
|
|
1700
|
+
};
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
function writeResearchReport(topic, result, outputPath) {
|
|
1704
|
+
const dir = path.dirname(outputPath);
|
|
1705
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
1706
|
+
|
|
1707
|
+
const content = [
|
|
1708
|
+
`# Research Report: ${topic}`,
|
|
1709
|
+
`**Model:** ${result.model_used}`,
|
|
1710
|
+
`**Research type:** ${result.research_type}`,
|
|
1711
|
+
`**Context:** ${result.context_length.toLocaleString()} chars`,
|
|
1712
|
+
`**Cost:** $${result.cost_usd.toFixed(4)}`,
|
|
1713
|
+
`**Generated:** ${new Date().toISOString()}`,
|
|
1714
|
+
'',
|
|
1715
|
+
result.content,
|
|
1716
|
+
].join('\n');
|
|
1717
|
+
|
|
1718
|
+
fs.writeFileSync(outputPath, content);
|
|
1719
|
+
return outputPath;
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
module.exports = { research, writeResearchReport, packageLocalContext, walkDir };
|
|
1723
|
+
```
|
|
1724
|
+
|
|
1725
|
+
**Commit:**
|
|
1726
|
+
```bash
|
|
1727
|
+
git add bin/research/
|
|
1728
|
+
git commit -m "feat(v2-models): implement research engine with Gemini 1M context advantage"
|
|
1729
|
+
```
|
|
1730
|
+
|
|
1731
|
+
---
|
|
1732
|
+
|
|
1733
|
+
## TASK 6 — Write the Research Agent Persona
|
|
1734
|
+
|
|
1735
|
+
### `.mindforge/personas/research-agent.md`
|
|
1736
|
+
|
|
1737
|
+
```markdown
|
|
1738
|
+
# Research Agent Persona
|
|
1739
|
+
|
|
1740
|
+
## Identity
|
|
1741
|
+
You are a thorough technical research specialist with access to Gemini 2.5 Pro's
|
|
1742
|
+
1-million-token context window. You are the agent called when a question requires
|
|
1743
|
+
ingesting entire documentation sets, large codebases, or multiple long documents
|
|
1744
|
+
simultaneously — a task impossible for agents with smaller context windows.
|
|
1745
|
+
|
|
1746
|
+
## When you are activated
|
|
1747
|
+
- `/mindforge:research [topic]` command
|
|
1748
|
+
- `/mindforge:plan-phase --deep-research` flag
|
|
1749
|
+
- When the difficulty scorer identifies domain unfamiliarity (ambiguity > 4.0)
|
|
1750
|
+
- When DISCUSS_PHASE identifies an open research question
|
|
1751
|
+
|
|
1752
|
+
## Your unique capabilities
|
|
1753
|
+
|
|
1754
|
+
### Full documentation ingestion
|
|
1755
|
+
You can read entire library documentation (not just excerpts) before making
|
|
1756
|
+
recommendations. When comparing libraries: ingest ALL docs simultaneously.
|
|
1757
|
+
Do not summarize or excerpt unless told to — read the full context.
|
|
1758
|
+
|
|
1759
|
+
### Codebase archaeology
|
|
1760
|
+
On brownfield projects, you can ingest the entire codebase before planning.
|
|
1761
|
+
You identify: undocumented architectural decisions, hidden dependencies,
|
|
1762
|
+
legacy patterns, technical debt locations.
|
|
1763
|
+
|
|
1764
|
+
### Regulatory completeness
|
|
1765
|
+
For compliance research: ingest the full regulation text, not just summaries.
|
|
1766
|
+
GDPR: 88 articles. HIPAA Security Rule: full text. PCI DSS: full standard.
|
|
1767
|
+
You cite specific article numbers and sub-clauses.
|
|
1768
|
+
|
|
1769
|
+
## Output standard
|
|
1770
|
+
Every research output must have:
|
|
1771
|
+
1. **Executive summary** (3-5 bullet points, actionable)
|
|
1772
|
+
2. **Detailed findings** (with evidence citations from the context)
|
|
1773
|
+
3. **Specific recommendations** (not "consider X" — say "use X because Y")
|
|
1774
|
+
4. **Open questions** (what needs human input before implementation)
|
|
1775
|
+
5. **Sources consulted** (list every file/URL included in context)
|
|
1776
|
+
|
|
1777
|
+
## Model assignment
|
|
1778
|
+
Default: RESEARCH_MODEL (gemini-2.5-pro)
|
|
1779
|
+
This agent should NEVER be assigned a model with context < 500K tokens.
|
|
1780
|
+
The point is large-context reasoning — a smaller model defeats the purpose.
|
|
1781
|
+
```
|
|
1782
|
+
|
|
1783
|
+
**Commit:**
|
|
1784
|
+
```bash
|
|
1785
|
+
git add .mindforge/personas/research-agent.md
|
|
1786
|
+
git commit -m "feat(v2-models): add research-agent persona for Gemini 1M context tasks"
|
|
1787
|
+
```
|
|
1788
|
+
|
|
1789
|
+
---
|
|
1790
|
+
|
|
1791
|
+
## TASK 7 — Write the three new commands
|
|
1792
|
+
|
|
1793
|
+
### `.claude/commands/mindforge/cross-review.md`
|
|
1794
|
+
|
|
1795
|
+
```markdown
|
|
1796
|
+
# MindForge v2 — Cross-Review Command
|
|
1797
|
+
# Usage: /mindforge:cross-review [--phase N] [--models list] [--focus area] [--sha range] [--full-codebase]
|
|
1798
|
+
# Version: v2.0.0-alpha.3
|
|
1799
|
+
|
|
1800
|
+
## Purpose
|
|
1801
|
+
Get the same code diff reviewed by multiple AI models simultaneously.
|
|
1802
|
+
Claude finds what Claude finds. GPT-4o finds what GPT-4o finds.
|
|
1803
|
+
Consensus findings (both models agree) = high confidence issues.
|
|
1804
|
+
Model-specific findings = worth investigating but may be false positives.
|
|
1805
|
+
Contradictions = need human judgment.
|
|
1806
|
+
|
|
1807
|
+
## The adversarial insight
|
|
1808
|
+
Models trained on different data have different blind spots.
|
|
1809
|
+
GPT-4o's adversarial prompt ("review code written by a competitor")
|
|
1810
|
+
consistently finds categories of issues that Claude in primary review mode
|
|
1811
|
+
underweights. Using both captures more of the issue space.
|
|
1812
|
+
|
|
1813
|
+
## Execution flow
|
|
1814
|
+
|
|
1815
|
+
```
|
|
1816
|
+
/mindforge:cross-review --phase 3
|
|
1817
|
+
│
|
|
1818
|
+
▼ Load diff (git diff HEAD~N or staged or --sha range)
|
|
1819
|
+
│ Load review context: PROJECT.md, ARCHITECTURE.md, CONVENTIONS.md, SECURITY.md
|
|
1820
|
+
│
|
|
1821
|
+
▼ Round 1: Primary reviewer (EXECUTOR_MODEL / claude-sonnet-4-6)
|
|
1822
|
+
│ System: senior code reviewer with project context
|
|
1823
|
+
│ Finds: logic errors, convention violations, architecture issues
|
|
1824
|
+
│
|
|
1825
|
+
▼ Round 2: Adversarial reviewer (CROSS_REVIEW_SECONDARY / gpt-4o)
|
|
1826
|
+
│ System: "paranoid auditor reviewing competitor's code"
|
|
1827
|
+
│ Finds: security holes, edge cases, failure modes
|
|
1828
|
+
│
|
|
1829
|
+
▼ Optional Round 3: Research reviewer (CROSS_REVIEW_TERTIARY / gemini-2.5-pro)
|
|
1830
|
+
│ System: architect with full codebase context (1M tokens)
|
|
1831
|
+
│ Finds: cross-module issues, architectural inconsistencies
|
|
1832
|
+
│
|
|
1833
|
+
▼ Synthesis
|
|
1834
|
+
│ Compare findings across models
|
|
1835
|
+
│ Identify consensus (2+ models = high confidence)
|
|
1836
|
+
│ Flag contradictions (human resolution needed)
|
|
1837
|
+
│
|
|
1838
|
+
▼ Write CROSS-REVIEW-[N].md
|
|
1839
|
+
```
|
|
1840
|
+
|
|
1841
|
+
## Flags
|
|
1842
|
+
|
|
1843
|
+
### --phase N (default: current phase)
|
|
1844
|
+
Use the diff from phase N's commits.
|
|
1845
|
+
|
|
1846
|
+
### --models claude,gpt4o,gemini (default: claude,gpt4o)
|
|
1847
|
+
Specify which models to include. `gemini` adds a third research pass.
|
|
1848
|
+
|
|
1849
|
+
### --focus security|architecture|performance
|
|
1850
|
+
Bias the review toward a specific concern.
|
|
1851
|
+
security → both models use security-focused system prompts
|
|
1852
|
+
architecture → both models use architecture-focused prompts
|
|
1853
|
+
|
|
1854
|
+
### --sha base..head
|
|
1855
|
+
Review a specific git SHA range.
|
|
1856
|
+
|
|
1857
|
+
### --full-codebase
|
|
1858
|
+
Include the full codebase as context for Gemini (requires gemini in --models).
|
|
1859
|
+
Warning: costs more but catches cross-module issues.
|
|
1860
|
+
|
|
1861
|
+
## Output
|
|
1862
|
+
|
|
1863
|
+
```
|
|
1864
|
+
⚡ Cross-Model Code Review — Phase 3
|
|
1865
|
+
────────────────────────────────────────────
|
|
1866
|
+
Round 1 (claude-sonnet-4-6)... done ($0.042)
|
|
1867
|
+
Round 2 (gpt-4o, adversarial)... done ($0.079)
|
|
1868
|
+
Synthesis... done
|
|
1869
|
+
|
|
1870
|
+
Consensus findings (2 models agree):
|
|
1871
|
+
HIGH src/auth/login.ts:47 — Missing rate limiting on login attempts
|
|
1872
|
+
MEDIUM src/auth/login.ts:89 — Error message reveals whether email exists
|
|
1873
|
+
|
|
1874
|
+
GPT-4o-only findings: 3 (review CROSS-REVIEW-3.md for details)
|
|
1875
|
+
Claude-only findings: 2 (review CROSS-REVIEW-3.md for details)
|
|
1876
|
+
|
|
1877
|
+
Total cost: $0.121
|
|
1878
|
+
Verdict: ❌ REQUEST_CHANGES (2 consensus findings)
|
|
1879
|
+
|
|
1880
|
+
Report: .planning/phases/3/CROSS-REVIEW-3.md
|
|
1881
|
+
```
|
|
1882
|
+
|
|
1883
|
+
## Integration with /mindforge:ship
|
|
1884
|
+
When `REQUIRE_CROSS_REVIEW=true` in MINDFORGE.md:
|
|
1885
|
+
- `/mindforge:ship` will not create a PR if CROSS-REVIEW-[N].md is missing
|
|
1886
|
+
- If CROSS-REVIEW exists but has CRITICAL consensus findings: PR is blocked
|
|
1887
|
+
- If CROSS-REVIEW exists and all consensus findings are addressed: PR proceeds
|
|
1888
|
+
|
|
1889
|
+
## Cost estimate
|
|
1890
|
+
Two-model review (claude + gpt4o) for a typical phase diff (~10K chars):
|
|
1891
|
+
- Claude Sonnet: ~$0.04-0.08
|
|
1892
|
+
- GPT-4o: ~$0.07-0.12
|
|
1893
|
+
- Total: ~$0.11-0.20 per review
|
|
1894
|
+
|
|
1895
|
+
## AUDIT entry
|
|
1896
|
+
```json
|
|
1897
|
+
{
|
|
1898
|
+
"event": "cross_review_completed",
|
|
1899
|
+
"phase": 3,
|
|
1900
|
+
"models": ["claude-sonnet-4-6", "gpt-4o"],
|
|
1901
|
+
"consensus_findings": 2,
|
|
1902
|
+
"total_findings": 7,
|
|
1903
|
+
"verdict": "REQUEST_CHANGES",
|
|
1904
|
+
"cost_usd": 0.121
|
|
1905
|
+
}
|
|
1906
|
+
```
|
|
1907
|
+
```
|
|
1908
|
+
|
|
1909
|
+
---
|
|
1910
|
+
|
|
1911
|
+
### `.claude/commands/mindforge/research.md`
|
|
1912
|
+
|
|
1913
|
+
```markdown
|
|
1914
|
+
# MindForge v2 — Research Command
|
|
1915
|
+
# Usage: /mindforge:research [topic] [--type general|library|codebase|compliance|planning]
|
|
1916
|
+
# [--context path] [--url URL] [--output path]
|
|
1917
|
+
# Version: v2.0.0-alpha.3
|
|
1918
|
+
|
|
1919
|
+
## Purpose
|
|
1920
|
+
Deep research using Gemini 2.5 Pro's 1-million-token context window.
|
|
1921
|
+
Use when the question requires reading entire documentation sets, the full
|
|
1922
|
+
codebase, or multiple long documents simultaneously.
|
|
1923
|
+
|
|
1924
|
+
## When to use this instead of web search
|
|
1925
|
+
|
|
1926
|
+
| Use web search when | Use /mindforge:research when |
|
|
1927
|
+
|---|---|
|
|
1928
|
+
| Looking up a quick fact | Comparing 3 libraries with full docs |
|
|
1929
|
+
| Finding the latest news | Understanding an entire codebase before planning |
|
|
1930
|
+
| Getting an API reference | Compliance research against full regulatory text |
|
|
1931
|
+
| Quick syntax lookup | Pre-planning deep-dive for complex domain |
|
|
1932
|
+
|
|
1933
|
+
## Research types
|
|
1934
|
+
|
|
1935
|
+
### library (default for library comparisons)
|
|
1936
|
+
```
|
|
1937
|
+
/mindforge:research "Prisma vs Drizzle vs Kysely for our use case" --type library \
|
|
1938
|
+
--url https://www.prisma.io/docs \
|
|
1939
|
+
--url https://orm.drizzle.team/docs \
|
|
1940
|
+
--context .planning/ARCHITECTURE.md
|
|
1941
|
+
```
|
|
1942
|
+
|
|
1943
|
+
### codebase (brownfield analysis)
|
|
1944
|
+
```
|
|
1945
|
+
/mindforge:research "Why does authentication sometimes fail?" --type codebase \
|
|
1946
|
+
--context src/auth \
|
|
1947
|
+
--context src/middleware
|
|
1948
|
+
```
|
|
1949
|
+
Ingests entire source directories into Gemini's context for comprehensive analysis.
|
|
1950
|
+
|
|
1951
|
+
### compliance
|
|
1952
|
+
```
|
|
1953
|
+
/mindforge:research "Are we HIPAA compliant for our PHI handling?" --type compliance \
|
|
1954
|
+
--url https://www.hhs.gov/hipaa/for-professionals/security/laws-regulations/index.html \
|
|
1955
|
+
--context src/models/patient.ts \
|
|
1956
|
+
--context src/api/health-records
|
|
1957
|
+
```
|
|
1958
|
+
|
|
1959
|
+
### planning (pre-implementation research)
|
|
1960
|
+
```
|
|
1961
|
+
/mindforge:research "Should we use microservices or modular monolith?" --type planning \
|
|
1962
|
+
--context .planning/REQUIREMENTS.md \
|
|
1963
|
+
--context .planning/ARCHITECTURE.md
|
|
1964
|
+
```
|
|
1965
|
+
|
|
1966
|
+
## Output
|
|
1967
|
+
|
|
1968
|
+
```
|
|
1969
|
+
🔬 MindForge Research
|
|
1970
|
+
─────────────────────────────────────────────
|
|
1971
|
+
Topic: Prisma vs Drizzle vs Kysely
|
|
1972
|
+
Model: gemini-2.5-pro (1M context)
|
|
1973
|
+
Context: 3 docs ingested (148,000 chars)
|
|
1974
|
+
Cost: $0.31
|
|
1975
|
+
|
|
1976
|
+
## Executive Summary
|
|
1977
|
+
- Prisma: best DX, largest ecosystem, acceptable performance
|
|
1978
|
+
- Drizzle: best TypeScript types, fastest, smallest bundle
|
|
1979
|
+
- Kysely: most flexible, SQL-close, steeper learning curve
|
|
1980
|
+
|
|
1981
|
+
Recommendation: Drizzle for new projects (best TypeScript + performance).
|
|
1982
|
+
Prisma for teams needing excellent docs and migration tooling.
|
|
1983
|
+
Kysely for teams that want SQL control with type safety.
|
|
1984
|
+
|
|
1985
|
+
[Full detailed analysis...]
|
|
1986
|
+
|
|
1987
|
+
Report saved: .planning/research/prisma-vs-drizzle-vs-kysely.md
|
|
1988
|
+
```
|
|
1989
|
+
|
|
1990
|
+
## Cost guidance
|
|
1991
|
+
- Typical research with 50K context: ~$0.20-0.50 (Gemini 2.5 Pro)
|
|
1992
|
+
- Full codebase analysis (500K context): ~$1.50-3.00
|
|
1993
|
+
- Regulatory compliance (100K context): ~$0.40-0.80
|
|
1994
|
+
|
|
1995
|
+
## AUDIT entry
|
|
1996
|
+
```json
|
|
1997
|
+
{
|
|
1998
|
+
"event": "research_completed",
|
|
1999
|
+
"topic": "Prisma vs Drizzle for our use case",
|
|
2000
|
+
"model": "gemini-2.5-pro",
|
|
2001
|
+
"context_length": 148000,
|
|
2002
|
+
"cost_usd": 0.31,
|
|
2003
|
+
"output_path": ".planning/research/prisma-vs-drizzle.md"
|
|
2004
|
+
}
|
|
2005
|
+
```
|
|
2006
|
+
```
|
|
2007
|
+
|
|
2008
|
+
---
|
|
2009
|
+
|
|
2010
|
+
### `.claude/commands/mindforge/costs.md`
|
|
2011
|
+
|
|
2012
|
+
```markdown
|
|
2013
|
+
# MindForge v2 — Costs Command
|
|
2014
|
+
# Usage: /mindforge:costs [--phase N] [--session ID] [--window 7d|30d|today] [--breakdown]
|
|
2015
|
+
# Version: v2.0.0-alpha.3
|
|
2016
|
+
|
|
2017
|
+
## Purpose
|
|
2018
|
+
Real-time cost tracking for all model calls made by MindForge.
|
|
2019
|
+
See exactly what you're spending, per model, per phase, per session.
|
|
2020
|
+
|
|
2021
|
+
## Default output (last 7 days)
|
|
2022
|
+
|
|
2023
|
+
```
|
|
2024
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
2025
|
+
⚡ MindForge Cost Dashboard — [Project]
|
|
2026
|
+
Last 7 days
|
|
2027
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
2028
|
+
|
|
2029
|
+
Total spend: $3.84 | Today: $1.21 | Daily limit: $10.00 (38% used)
|
|
2030
|
+
|
|
2031
|
+
By model:
|
|
2032
|
+
┌─────────────────────────┬────────┬──────────┬─────────┐
|
|
2033
|
+
│ Model │ Calls │ Tokens │ Cost │
|
|
2034
|
+
├─────────────────────────┼────────┼──────────┼─────────┤
|
|
2035
|
+
│ claude-sonnet-4-6 │ 142 │ 1.82M │ $1.92 │
|
|
2036
|
+
│ gpt-4o │ 18 │ 312K │ $0.98 │
|
|
2037
|
+
│ gemini-2.5-pro │ 4 │ 2.14M │ $0.74 │
|
|
2038
|
+
│ claude-opus-4-5 │ 6 │ 198K │ $0.12 │
|
|
2039
|
+
│ claude-haiku-4-5 │ 34 │ 840K │ $0.08 │
|
|
2040
|
+
└─────────────────────────┴────────┴──────────┴─────────┘
|
|
2041
|
+
|
|
2042
|
+
By phase (this week):
|
|
2043
|
+
Phase 3 (Authentication): $1.84 (48%)
|
|
2044
|
+
Phase 4 (Dashboard): $1.21 (32%)
|
|
2045
|
+
Other (quick/debug): $0.79 (20%)
|
|
2046
|
+
|
|
2047
|
+
Most expensive tasks:
|
|
2048
|
+
1. research: Prisma vs Drizzle $0.31 gemini-2.5-pro
|
|
2049
|
+
2. cross-review-round2-phase3 $0.21 gpt-4o
|
|
2050
|
+
3. Plan 3-04 (JWT middleware) $0.18 claude-sonnet-4-6
|
|
2051
|
+
|
|
2052
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
2053
|
+
MINDFORGE.md limits: MODEL_COST_WARN_USD=1.00 MODEL_COST_HARD_LIMIT_USD=10.00
|
|
2054
|
+
```
|
|
2055
|
+
|
|
2056
|
+
## Flags
|
|
2057
|
+
|
|
2058
|
+
### --window today|7d|30d (default: 7d)
|
|
2059
|
+
Change the reporting window.
|
|
2060
|
+
|
|
2061
|
+
### --phase N
|
|
2062
|
+
Show costs for a specific phase only.
|
|
2063
|
+
|
|
2064
|
+
### --breakdown
|
|
2065
|
+
Show per-task cost breakdown (verbose).
|
|
2066
|
+
|
|
2067
|
+
### --routing
|
|
2068
|
+
Show current model routing table (which models are assigned to which tasks).
|
|
2069
|
+
|
|
2070
|
+
## Model routing display (--routing flag)
|
|
2071
|
+
|
|
2072
|
+
```
|
|
2073
|
+
Current model routing (from MINDFORGE.md + defaults):
|
|
2074
|
+
PLANNER_MODEL: claude-opus-4-5
|
|
2075
|
+
EXECUTOR_MODEL: claude-sonnet-4-6 ← most calls
|
|
2076
|
+
REVIEWER_MODEL: gpt-4o
|
|
2077
|
+
SECURITY_MODEL: claude-opus-4-5
|
|
2078
|
+
RESEARCH_MODEL: gemini-2.5-pro
|
|
2079
|
+
QA_MODEL: claude-sonnet-4-6
|
|
2080
|
+
DEBUG_MODEL: claude-opus-4-5
|
|
2081
|
+
QUICK_MODEL: claude-haiku-4-5
|
|
2082
|
+
CROSS_REVIEW_SECONDARY: gpt-4o
|
|
2083
|
+
|
|
2084
|
+
Available providers:
|
|
2085
|
+
Anthropic: ✅ ANTHROPIC_API_KEY set
|
|
2086
|
+
OpenAI: ✅ OPENAI_API_KEY set
|
|
2087
|
+
Google: ❌ GOOGLE_API_KEY not set → gemini models unavailable
|
|
2088
|
+
```
|
|
2089
|
+
|
|
2090
|
+
## Budget management
|
|
2091
|
+
|
|
2092
|
+
Set in MINDFORGE.md:
|
|
2093
|
+
```
|
|
2094
|
+
MODEL_COST_WARN_USD=1.00 # Slack warning when session > $1
|
|
2095
|
+
MODEL_COST_HARD_LIMIT_USD=10.00 # Stop model calls when daily > $10
|
|
2096
|
+
MODEL_PREFER_CHEAP_BELOW_DIFFICULTY=2.0 # Use QUICK_MODEL for easy tasks
|
|
2097
|
+
```
|
|
2098
|
+
|
|
2099
|
+
## AUDIT entry
|
|
2100
|
+
```json
|
|
2101
|
+
{ "event": "costs_viewed", "window": "7d", "total_usd": 3.84 }
|
|
2102
|
+
```
|
|
2103
|
+
```
|
|
2104
|
+
|
|
2105
|
+
**Commit:**
|
|
2106
|
+
```bash
|
|
2107
|
+
for cmd in cross-review research costs; do
|
|
2108
|
+
cp .claude/commands/mindforge/${cmd}.md .agent/mindforge/${cmd}.md
|
|
2109
|
+
done
|
|
2110
|
+
git add .claude/commands/mindforge/ .agent/mindforge/
|
|
2111
|
+
git commit -m "feat(v2-models): add /mindforge:cross-review, /mindforge:research, /mindforge:costs"
|
|
2112
|
+
```
|
|
2113
|
+
|
|
2114
|
+
---
|
|
2115
|
+
|
|
2116
|
+
## TASK 8 — Update CLAUDE.md, execute-phase, MINDFORGE.md
|
|
2117
|
+
|
|
2118
|
+
### Add to `.claude/CLAUDE.md` and `.agent/CLAUDE.md`
|
|
2119
|
+
|
|
2120
|
+
```markdown
|
|
2121
|
+
---
|
|
2122
|
+
|
|
2123
|
+
## MULTI-MODEL INTELLIGENCE LAYER (v2.0.0 — Day 10)
|
|
2124
|
+
|
|
2125
|
+
### Model routing at task dispatch time
|
|
2126
|
+
Before dispatching a task, resolve the model using the router:
|
|
2127
|
+
1. Read the task `<persona>` field
|
|
2128
|
+
2. Check for Tier 3 override (always use SECURITY_MODEL for auth/payment/PII)
|
|
2129
|
+
3. Map persona → model setting key → model ID from MINDFORGE.md or defaults
|
|
2130
|
+
4. Check model availability (API key present?)
|
|
2131
|
+
5. If unavailable: apply fallback chain
|
|
2132
|
+
6. Write `model_routed` AUDIT entry
|
|
2133
|
+
|
|
2134
|
+
### Cross-review integration
|
|
2135
|
+
After `/mindforge:review` or before `/mindforge:ship` (when REQUIRE_CROSS_REVIEW=true):
|
|
2136
|
+
Run cross-review engine via `bin/review/cross-review-engine.js`.
|
|
2137
|
+
Consensus findings (2+ models) are HIGH confidence — address before shipping.
|
|
2138
|
+
|
|
2139
|
+
### Research integration
|
|
2140
|
+
When called via `/mindforge:research`:
|
|
2141
|
+
Package local context files, fetch URLs, pass to Gemini 2.5 Pro.
|
|
2142
|
+
Write research report to `.planning/research/[slug].md`.
|
|
2143
|
+
Reference the report in subsequent plan-phase calls via CONTEXT.md.
|
|
2144
|
+
|
|
2145
|
+
### Cost awareness
|
|
2146
|
+
All model calls go through `bin/models/model-client.js` which tracks costs.
|
|
2147
|
+
Never make raw API calls — always use ModelClient.complete() so costs are tracked.
|
|
2148
|
+
If MODEL_COST_HARD_LIMIT_USD is reached: stop and notify via Slack.
|
|
2149
|
+
|
|
2150
|
+
### New commands (Day 10)
|
|
2151
|
+
- /mindforge:cross-review — adversarial multi-model code review
|
|
2152
|
+
- /mindforge:research — deep research via Gemini 1M context
|
|
2153
|
+
- /mindforge:costs — real-time cost tracking dashboard
|
|
2154
|
+
|
|
2155
|
+
---
|
|
2156
|
+
```
|
|
2157
|
+
|
|
2158
|
+
### Update MINDFORGE.md and MINDFORGE-V2-SCHEMA.json
|
|
2159
|
+
|
|
2160
|
+
```markdown
|
|
2161
|
+
## Multi-model configuration (v2.0.0)
|
|
2162
|
+
|
|
2163
|
+
PLANNER_MODEL=claude-opus-4-5
|
|
2164
|
+
EXECUTOR_MODEL=claude-sonnet-4-6
|
|
2165
|
+
REVIEWER_MODEL=gpt-4o
|
|
2166
|
+
SECURITY_MODEL=claude-opus-4-5
|
|
2167
|
+
RESEARCH_MODEL=gemini-2.5-pro
|
|
2168
|
+
QA_MODEL=claude-sonnet-4-6
|
|
2169
|
+
DEBUG_MODEL=claude-opus-4-5
|
|
2170
|
+
QUICK_MODEL=claude-haiku-4-5
|
|
2171
|
+
CROSS_REVIEW_SECONDARY=gpt-4o
|
|
2172
|
+
CROSS_REVIEW_TERTIARY=gemini-2.5-pro
|
|
2173
|
+
|
|
2174
|
+
MODEL_COST_WARN_USD=1.00
|
|
2175
|
+
MODEL_COST_HARD_LIMIT_USD=10.00
|
|
2176
|
+
MODEL_PREFER_CHEAP_BELOW_DIFFICULTY=2.0
|
|
2177
|
+
REQUIRE_CROSS_REVIEW=false
|
|
2178
|
+
```
|
|
2179
|
+
|
|
2180
|
+
Schema additions to `.mindforge/MINDFORGE-V2-SCHEMA.json`:
|
|
2181
|
+
```json
|
|
2182
|
+
{
|
|
2183
|
+
"PLANNER_MODEL": { "type": "string" },
|
|
2184
|
+
"EXECUTOR_MODEL": { "type": "string" },
|
|
2185
|
+
"REVIEWER_MODEL": { "type": "string" },
|
|
2186
|
+
"SECURITY_MODEL": { "type": "string" },
|
|
2187
|
+
"RESEARCH_MODEL": { "type": "string" },
|
|
2188
|
+
"QA_MODEL": { "type": "string" },
|
|
2189
|
+
"DEBUG_MODEL": { "type": "string" },
|
|
2190
|
+
"QUICK_MODEL": { "type": "string" },
|
|
2191
|
+
"CROSS_REVIEW_SECONDARY": { "type": "string" },
|
|
2192
|
+
"CROSS_REVIEW_TERTIARY": { "type": "string" },
|
|
2193
|
+
"MODEL_COST_WARN_USD": { "type": "number", "minimum": 0 },
|
|
2194
|
+
"MODEL_COST_HARD_LIMIT_USD": { "type": "number", "minimum": 0 },
|
|
2195
|
+
"MODEL_PREFER_CHEAP_BELOW_DIFFICULTY": { "type": "number", "minimum": 0, "maximum": 5 },
|
|
2196
|
+
"REQUIRE_CROSS_REVIEW": { "type": "boolean" }
|
|
2197
|
+
}
|
|
2198
|
+
```
|
|
2199
|
+
|
|
2200
|
+
**Commit:**
|
|
2201
|
+
```bash
|
|
2202
|
+
git add .claude/CLAUDE.md .agent/CLAUDE.md MINDFORGE.md .mindforge/MINDFORGE-V2-SCHEMA.json
|
|
2203
|
+
git commit -m "feat(v2-models): update CLAUDE.md, MINDFORGE.md, and schema for multi-model layer"
|
|
2204
|
+
```
|
|
2205
|
+
|
|
2206
|
+
---
|
|
2207
|
+
|
|
2208
|
+
## TASK 9 — Write the model routing test suite
|
|
2209
|
+
|
|
2210
|
+
### `tests/model-routing.test.js`
|
|
2211
|
+
|
|
2212
|
+
```javascript
|
|
2213
|
+
/**
|
|
2214
|
+
* MindForge v2 — Model Routing Test Suite
|
|
2215
|
+
* Tests: model registry, router, cost tracker, finding synthesizer,
|
|
2216
|
+
* provider availability detection, fallback chains.
|
|
2217
|
+
*
|
|
2218
|
+
* No real API calls made — providers are tested via unit logic only.
|
|
2219
|
+
*
|
|
2220
|
+
* Run: node tests/model-routing.test.js
|
|
2221
|
+
*/
|
|
2222
|
+
'use strict';
|
|
2223
|
+
|
|
2224
|
+
const fs = require('fs');
|
|
2225
|
+
const path = require('path');
|
|
2226
|
+
const os = require('os');
|
|
2227
|
+
const assert = require('assert');
|
|
2228
|
+
|
|
2229
|
+
let passed = 0, failed = 0;
|
|
2230
|
+
function test(name, fn) {
|
|
2231
|
+
try { fn(); console.log(` ✅ ${name}`); passed++; }
|
|
2232
|
+
catch(e) { console.error(` ❌ ${name}\n ${e.message}`); failed++; }
|
|
2233
|
+
}
|
|
2234
|
+
|
|
2235
|
+
const Router = require('../bin/models/model-router');
|
|
2236
|
+
const CostTracker = require('../bin/models/cost-tracker');
|
|
2237
|
+
const { synthesizeFindings } = require('../bin/review/finding-synthesizer');
|
|
2238
|
+
const { parseFindings, extractVerdict } = require('../bin/review/cross-review-engine');
|
|
2239
|
+
const ResearchEngine = require('../bin/research/research-engine');
|
|
2240
|
+
|
|
2241
|
+
// ── Temp project factory ──────────────────────────────────────────────────────
|
|
2242
|
+
function mkProject() {
|
|
2243
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'mf-models-'));
|
|
2244
|
+
const write = (rel, c) => { const f = path.join(dir, rel); fs.mkdirSync(path.dirname(f), { recursive: true }); fs.writeFileSync(f, c); return f; };
|
|
2245
|
+
const read = rel => { const f = path.join(dir, rel); return fs.existsSync(f) ? fs.readFileSync(f, 'utf8') : null; };
|
|
2246
|
+
const exists = rel => fs.existsSync(path.join(dir, rel));
|
|
2247
|
+
const cleanup = () => { try { fs.rmSync(dir, { recursive: true, force: true }); } catch {} };
|
|
2248
|
+
return { dir, write, read, exists, cleanup };
|
|
2249
|
+
}
|
|
2250
|
+
|
|
2251
|
+
// ── Review text fixtures ──────────────────────────────────────────────────────
|
|
2252
|
+
const REVIEW_WITH_FINDINGS = `
|
|
2253
|
+
## Code Review
|
|
2254
|
+
|
|
2255
|
+
**[CRITICAL]** \`src/auth/login.ts:47\` — SQL injection via unsanitised userId parameter
|
|
2256
|
+
> Use parameterised queries: db.query('SELECT * FROM users WHERE id = $1', [userId])
|
|
2257
|
+
|
|
2258
|
+
**[HIGH]** \`src/auth/login.ts:89\` — Error message reveals whether email exists in database
|
|
2259
|
+
> Return generic "Invalid credentials" for both wrong email and wrong password
|
|
2260
|
+
|
|
2261
|
+
**[MEDIUM]** \`src/utils/format.ts:12\` — parseInt without radix parameter may give unexpected results in some browsers
|
|
2262
|
+
> Always specify radix: parseInt(str, 10)
|
|
2263
|
+
|
|
2264
|
+
### Verdict: REQUEST_CHANGES
|
|
2265
|
+
`;
|
|
2266
|
+
|
|
2267
|
+
const ADVERSARIAL_REVIEW = `
|
|
2268
|
+
**[HIGH]** \`src/auth/login.ts:47\` — Input not sanitised before database query
|
|
2269
|
+
> Parameterise all queries
|
|
2270
|
+
|
|
2271
|
+
**[HIGH]** \`src/auth/session.ts:22\` — JWT secret hardcoded in source code
|
|
2272
|
+
> Load from environment variable: process.env.JWT_SECRET
|
|
2273
|
+
|
|
2274
|
+
**[LOW]** \`src/utils/helper.ts:5\` — Dead code that will never execute
|
|
2275
|
+
> Remove unreachable code block
|
|
2276
|
+
|
|
2277
|
+
### Verdict: REQUEST_CHANGES
|
|
2278
|
+
`;
|
|
2279
|
+
|
|
2280
|
+
const CLEAN_REVIEW = `
|
|
2281
|
+
The code looks well-structured and follows the project conventions.
|
|
2282
|
+
|
|
2283
|
+
### Positive observations
|
|
2284
|
+
- Good error handling
|
|
2285
|
+
- Clean separation of concerns
|
|
2286
|
+
|
|
2287
|
+
### Verdict: APPROVE
|
|
2288
|
+
`;
|
|
2289
|
+
|
|
2290
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
2291
|
+
console.log('\nMindForge v2 — Model Routing Tests\n');
|
|
2292
|
+
|
|
2293
|
+
// ── File existence ────────────────────────────────────────────────────────────
|
|
2294
|
+
console.log('Required files:');
|
|
2295
|
+
[
|
|
2296
|
+
'bin/models/model-client.js',
|
|
2297
|
+
'bin/models/anthropic-provider.js',
|
|
2298
|
+
'bin/models/openai-provider.js',
|
|
2299
|
+
'bin/models/gemini-provider.js',
|
|
2300
|
+
'bin/models/model-router.js',
|
|
2301
|
+
'bin/models/cost-tracker.js',
|
|
2302
|
+
'bin/review/cross-review-engine.js',
|
|
2303
|
+
'bin/review/finding-synthesizer.js',
|
|
2304
|
+
'bin/review/review-report-writer.js',
|
|
2305
|
+
'bin/research/research-engine.js',
|
|
2306
|
+
'.mindforge/models/model-registry.md',
|
|
2307
|
+
'.mindforge/models/model-router.md',
|
|
2308
|
+
'.mindforge/models/cost-calculator.md',
|
|
2309
|
+
'.mindforge/personas/research-agent.md',
|
|
2310
|
+
'.claude/commands/mindforge/cross-review.md',
|
|
2311
|
+
'.claude/commands/mindforge/research.md',
|
|
2312
|
+
'.claude/commands/mindforge/costs.md',
|
|
2313
|
+
].forEach(f => test(`${f} exists`, () => assert.ok(fs.existsSync(f), `Missing: ${f}`)));
|
|
2314
|
+
|
|
2315
|
+
// ── Model router ──────────────────────────────────────────────────────────────
|
|
2316
|
+
console.log('\nModel router:');
|
|
2317
|
+
|
|
2318
|
+
test('route: developer persona returns EXECUTOR_MODEL', () => {
|
|
2319
|
+
Router.clearCache();
|
|
2320
|
+
const { model, setting } = Router.route('developer', 1);
|
|
2321
|
+
assert.strictEqual(setting, 'EXECUTOR_MODEL');
|
|
2322
|
+
assert.ok(model, 'Should return a model ID');
|
|
2323
|
+
});
|
|
2324
|
+
|
|
2325
|
+
test('route: architect persona returns PLANNER_MODEL', () => {
|
|
2326
|
+
Router.clearCache();
|
|
2327
|
+
const { model, setting } = Router.route('architect', 1);
|
|
2328
|
+
assert.strictEqual(setting, 'PLANNER_MODEL');
|
|
2329
|
+
});
|
|
2330
|
+
|
|
2331
|
+
test('route: security-reviewer persona returns SECURITY_MODEL', () => {
|
|
2332
|
+
Router.clearCache();
|
|
2333
|
+
const { setting } = Router.route('security-reviewer', 1);
|
|
2334
|
+
assert.strictEqual(setting, 'SECURITY_MODEL');
|
|
2335
|
+
});
|
|
2336
|
+
|
|
2337
|
+
test('route: debug-specialist persona returns DEBUG_MODEL', () => {
|
|
2338
|
+
Router.clearCache();
|
|
2339
|
+
const { setting } = Router.route('debug-specialist', 1);
|
|
2340
|
+
assert.strictEqual(setting, 'DEBUG_MODEL');
|
|
2341
|
+
});
|
|
2342
|
+
|
|
2343
|
+
test('route: research-agent persona returns RESEARCH_MODEL', () => {
|
|
2344
|
+
Router.clearCache();
|
|
2345
|
+
const { setting } = Router.route('research-agent', 1);
|
|
2346
|
+
assert.strictEqual(setting, 'RESEARCH_MODEL');
|
|
2347
|
+
});
|
|
2348
|
+
|
|
2349
|
+
test('route: Tier 3 override returns SECURITY_MODEL regardless of persona', () => {
|
|
2350
|
+
Router.clearCache();
|
|
2351
|
+
const developerTier3 = Router.route('developer', 3);
|
|
2352
|
+
const architectTier3 = Router.route('architect', 3);
|
|
2353
|
+
assert.strictEqual(developerTier3.setting, 'SECURITY_MODEL', 'Developer on Tier 3 → SECURITY_MODEL');
|
|
2354
|
+
assert.strictEqual(architectTier3.setting, 'SECURITY_MODEL', 'Architect on Tier 3 → SECURITY_MODEL');
|
|
2355
|
+
assert.ok(developerTier3.reason.includes('Tier 3'), 'Should state Tier 3 override reason');
|
|
2356
|
+
});
|
|
2357
|
+
|
|
2358
|
+
test('route: unknown persona falls back to EXECUTOR_MODEL', () => {
|
|
2359
|
+
Router.clearCache();
|
|
2360
|
+
const { setting } = Router.route('wizard', 1);
|
|
2361
|
+
assert.strictEqual(setting, 'EXECUTOR_MODEL');
|
|
2362
|
+
});
|
|
2363
|
+
|
|
2364
|
+
test('getModel: returns default for known setting key', () => {
|
|
2365
|
+
Router.clearCache();
|
|
2366
|
+
const model = Router.getModel('EXECUTOR_MODEL');
|
|
2367
|
+
assert.ok(model, 'Should return a model ID');
|
|
2368
|
+
assert.ok(typeof model === 'string', 'Should be a string');
|
|
2369
|
+
});
|
|
2370
|
+
|
|
2371
|
+
test('getAllSettings: returns all 10 default settings', () => {
|
|
2372
|
+
Router.clearCache();
|
|
2373
|
+
const settings = Router.getAllSettings();
|
|
2374
|
+
const required = ['PLANNER_MODEL', 'EXECUTOR_MODEL', 'REVIEWER_MODEL', 'SECURITY_MODEL',
|
|
2375
|
+
'RESEARCH_MODEL', 'QA_MODEL', 'DEBUG_MODEL', 'QUICK_MODEL',
|
|
2376
|
+
'CROSS_REVIEW_SECONDARY', 'CROSS_REVIEW_TERTIARY'];
|
|
2377
|
+
required.forEach(k => assert.ok(settings[k], `Missing default: ${k}`));
|
|
2378
|
+
});
|
|
2379
|
+
|
|
2380
|
+
test('router reads overrides from MINDFORGE.md', () => {
|
|
2381
|
+
const p = mkProject();
|
|
2382
|
+
p.write('MINDFORGE.md', 'EXECUTOR_MODEL=claude-haiku-4-5\n');
|
|
2383
|
+
const origCwd = process.cwd();
|
|
2384
|
+
process.chdir(p.dir);
|
|
2385
|
+
Router.clearCache();
|
|
2386
|
+
try {
|
|
2387
|
+
const { model } = Router.route('developer', 1);
|
|
2388
|
+
assert.strictEqual(model, 'claude-haiku-4-5', 'Should use override from MINDFORGE.md');
|
|
2389
|
+
} finally { process.chdir(origCwd); Router.clearCache(); p.cleanup(); }
|
|
2390
|
+
});
|
|
2391
|
+
|
|
2392
|
+
// ── Finding parser ────────────────────────────────────────────────────────────
|
|
2393
|
+
console.log('\nFinding parser:');
|
|
2394
|
+
|
|
2395
|
+
test('parseFindings: extracts 3 findings from review text', () => {
|
|
2396
|
+
const findings = parseFindings(REVIEW_WITH_FINDINGS);
|
|
2397
|
+
assert.strictEqual(findings.length, 3, `Expected 3, got ${findings.length}`);
|
|
2398
|
+
});
|
|
2399
|
+
|
|
2400
|
+
test('parseFindings: correctly extracts CRITICAL severity', () => {
|
|
2401
|
+
const findings = parseFindings(REVIEW_WITH_FINDINGS);
|
|
2402
|
+
const critical = findings.find(f => f.severity === 'CRITICAL');
|
|
2403
|
+
assert.ok(critical, 'Should find CRITICAL finding');
|
|
2404
|
+
assert.ok(critical.location.includes('login.ts'), 'Should extract file location');
|
|
2405
|
+
assert.ok(critical.description.includes('SQL injection'), 'Should extract description');
|
|
2406
|
+
});
|
|
2407
|
+
|
|
2408
|
+
test('parseFindings: returns empty array for clean review', () => {
|
|
2409
|
+
const findings = parseFindings(CLEAN_REVIEW);
|
|
2410
|
+
assert.strictEqual(findings.length, 0, 'Clean review should have no findings');
|
|
2411
|
+
});
|
|
2412
|
+
|
|
2413
|
+
test('extractVerdict: extracts REQUEST_CHANGES', () => {
|
|
2414
|
+
assert.strictEqual(extractVerdict(REVIEW_WITH_FINDINGS), 'REQUEST_CHANGES');
|
|
2415
|
+
});
|
|
2416
|
+
|
|
2417
|
+
test('extractVerdict: extracts APPROVE', () => {
|
|
2418
|
+
assert.strictEqual(extractVerdict(CLEAN_REVIEW), 'APPROVE');
|
|
2419
|
+
});
|
|
2420
|
+
|
|
2421
|
+
test('extractVerdict: defaults to COMMENT when no verdict', () => {
|
|
2422
|
+
assert.strictEqual(extractVerdict('Some review without verdict'), 'COMMENT');
|
|
2423
|
+
});
|
|
2424
|
+
|
|
2425
|
+
// ── Finding synthesizer ───────────────────────────────────────────────────────
|
|
2426
|
+
console.log('\nFinding synthesizer:');
|
|
2427
|
+
|
|
2428
|
+
test('synthesizeFindings: detects consensus on same file:line', () => {
|
|
2429
|
+
const reviews = [
|
|
2430
|
+
{ model: 'claude-sonnet-4-6', content: REVIEW_WITH_FINDINGS, role: 'primary' },
|
|
2431
|
+
{ model: 'gpt-4o', content: ADVERSARIAL_REVIEW, role: 'adversarial' },
|
|
2432
|
+
];
|
|
2433
|
+
const synthesis = synthesizeFindings(reviews);
|
|
2434
|
+
assert.ok(synthesis.consensus.length > 0, 'Should have at least 1 consensus finding');
|
|
2435
|
+
// login.ts:47 appears in both reviews (SQL injection / unsanitised input)
|
|
2436
|
+
const loginFinding = synthesis.consensus.find(f => f.location?.includes('login.ts'));
|
|
2437
|
+
assert.ok(loginFinding, 'login.ts finding should be consensus');
|
|
2438
|
+
assert.ok(loginFinding.models.length >= 2, 'Consensus finding should list 2+ models');
|
|
2439
|
+
});
|
|
2440
|
+
|
|
2441
|
+
test('synthesizeFindings: overall_verdict is REQUEST_CHANGES when any model requests changes', () => {
|
|
2442
|
+
const reviews = [
|
|
2443
|
+
{ model: 'claude-sonnet-4-6', content: REVIEW_WITH_FINDINGS, role: 'primary' },
|
|
2444
|
+
{ model: 'gpt-4o', content: CLEAN_REVIEW, role: 'adversarial' },
|
|
2445
|
+
];
|
|
2446
|
+
const synthesis = synthesizeFindings(reviews);
|
|
2447
|
+
assert.strictEqual(synthesis.overall_verdict, 'REQUEST_CHANGES', 'Mixed verdicts → REQUEST_CHANGES');
|
|
2448
|
+
});
|
|
2449
|
+
|
|
2450
|
+
test('synthesizeFindings: overall_verdict is APPROVE when all models approve', () => {
|
|
2451
|
+
const reviews = [
|
|
2452
|
+
{ model: 'claude-sonnet-4-6', content: CLEAN_REVIEW, role: 'primary' },
|
|
2453
|
+
{ model: 'gpt-4o', content: CLEAN_REVIEW, role: 'adversarial' },
|
|
2454
|
+
];
|
|
2455
|
+
const synthesis = synthesizeFindings(reviews);
|
|
2456
|
+
assert.strictEqual(synthesis.overall_verdict, 'APPROVE', 'All approve → APPROVE');
|
|
2457
|
+
});
|
|
2458
|
+
|
|
2459
|
+
test('synthesizeFindings: counts critical findings', () => {
|
|
2460
|
+
const reviews = [
|
|
2461
|
+
{ model: 'claude-sonnet-4-6', content: REVIEW_WITH_FINDINGS, role: 'primary' },
|
|
2462
|
+
{ model: 'gpt-4o', content: ADVERSARIAL_REVIEW, role: 'adversarial' },
|
|
2463
|
+
];
|
|
2464
|
+
const synthesis = synthesizeFindings(reviews);
|
|
2465
|
+
assert.ok(typeof synthesis.critical_count === 'number', 'Should count critical findings');
|
|
2466
|
+
assert.ok(typeof synthesis.total_findings === 'number', 'Should count total findings');
|
|
2467
|
+
});
|
|
2468
|
+
|
|
2469
|
+
test('synthesizeFindings: identifies model-specific findings', () => {
|
|
2470
|
+
const reviews = [
|
|
2471
|
+
{ model: 'claude-sonnet-4-6', content: REVIEW_WITH_FINDINGS, role: 'primary' },
|
|
2472
|
+
{ model: 'gpt-4o', content: ADVERSARIAL_REVIEW, role: 'adversarial' },
|
|
2473
|
+
];
|
|
2474
|
+
const synthesis = synthesizeFindings(reviews);
|
|
2475
|
+
// model_specific should have entries for each model
|
|
2476
|
+
const hasModelSpecific = Object.values(synthesis.model_specific).some(arr => arr.length > 0);
|
|
2477
|
+
assert.ok(hasModelSpecific, 'Should have some model-specific findings');
|
|
2478
|
+
});
|
|
2479
|
+
|
|
2480
|
+
// ── Cost tracker ──────────────────────────────────────────────────────────────
|
|
2481
|
+
console.log('\nCost tracker:');
|
|
2482
|
+
|
|
2483
|
+
test('cost tracker records entries to token-usage.jsonl', async () => {
|
|
2484
|
+
const p = mkProject();
|
|
2485
|
+
const origCwd = process.cwd();
|
|
2486
|
+
process.chdir(p.dir);
|
|
2487
|
+
try {
|
|
2488
|
+
await CostTracker.record({
|
|
2489
|
+
timestamp: new Date().toISOString(),
|
|
2490
|
+
session_id: 'test-session',
|
|
2491
|
+
phase: 3,
|
|
2492
|
+
plan: '04',
|
|
2493
|
+
task_name: 'test task',
|
|
2494
|
+
model: 'claude-sonnet-4-6',
|
|
2495
|
+
provider: 'anthropic',
|
|
2496
|
+
input_tokens: 1000,
|
|
2497
|
+
output_tokens: 500,
|
|
2498
|
+
cached_tokens: 0,
|
|
2499
|
+
cost_usd: 0.0105,
|
|
2500
|
+
latency_ms: 2500,
|
|
2501
|
+
});
|
|
2502
|
+
const logPath = path.join(p.dir, '.mindforge', 'metrics', 'token-usage.jsonl');
|
|
2503
|
+
assert.ok(fs.existsSync(logPath), 'token-usage.jsonl should be created');
|
|
2504
|
+
const entry = JSON.parse(fs.readFileSync(logPath, 'utf8').trim());
|
|
2505
|
+
assert.strictEqual(entry.model, 'claude-sonnet-4-6');
|
|
2506
|
+
assert.strictEqual(entry.cost_usd, 0.0105);
|
|
2507
|
+
assert.ok(entry.date, 'Should include date field');
|
|
2508
|
+
} finally { process.chdir(origCwd); p.cleanup(); }
|
|
2509
|
+
});
|
|
2510
|
+
|
|
2511
|
+
test('getSummary: returns totals correctly', async () => {
|
|
2512
|
+
const p = mkProject();
|
|
2513
|
+
const origCwd = process.cwd();
|
|
2514
|
+
process.chdir(p.dir);
|
|
2515
|
+
try {
|
|
2516
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
2517
|
+
const logDir = path.join(p.dir, '.mindforge', 'metrics');
|
|
2518
|
+
fs.mkdirSync(logDir, { recursive: true });
|
|
2519
|
+
// Write two entries
|
|
2520
|
+
const entries = [
|
|
2521
|
+
{ date: today, model: 'claude-sonnet-4-6', cost_usd: 0.05, input_tokens: 1000, output_tokens: 500 },
|
|
2522
|
+
{ date: today, model: 'gpt-4o', cost_usd: 0.12, input_tokens: 2000, output_tokens: 800 },
|
|
2523
|
+
];
|
|
2524
|
+
fs.writeFileSync(
|
|
2525
|
+
path.join(logDir, 'token-usage.jsonl'),
|
|
2526
|
+
entries.map(e => JSON.stringify(e)).join('\n') + '\n'
|
|
2527
|
+
);
|
|
2528
|
+
const summary = CostTracker.getSummary({ days: 1 });
|
|
2529
|
+
assert.ok(Math.abs(summary.total_usd - 0.17) < 0.001, `Total should be ~0.17, got ${summary.total_usd}`);
|
|
2530
|
+
assert.ok(summary.by_model['claude-sonnet-4-6'], 'Should have claude entry');
|
|
2531
|
+
assert.ok(summary.by_model['gpt-4o'], 'Should have gpt-4o entry');
|
|
2532
|
+
} finally { process.chdir(origCwd); p.cleanup(); }
|
|
2533
|
+
});
|
|
2534
|
+
|
|
2535
|
+
test('getTodaySpend: returns 0 when no entries', () => {
|
|
2536
|
+
const p = mkProject();
|
|
2537
|
+
const origCwd = process.cwd();
|
|
2538
|
+
process.chdir(p.dir);
|
|
2539
|
+
try {
|
|
2540
|
+
const spend = CostTracker.getTodaySpend();
|
|
2541
|
+
assert.strictEqual(spend, 0, 'Empty log should return 0 spend');
|
|
2542
|
+
} finally { process.chdir(origCwd); p.cleanup(); }
|
|
2543
|
+
});
|
|
2544
|
+
|
|
2545
|
+
// ── Research engine: context packager ─────────────────────────────────────────
|
|
2546
|
+
console.log('\nResearch engine:');
|
|
2547
|
+
|
|
2548
|
+
test('packageLocalContext: reads a file into context', () => {
|
|
2549
|
+
const p = mkProject();
|
|
2550
|
+
const origCwd = process.cwd();
|
|
2551
|
+
process.chdir(p.dir);
|
|
2552
|
+
try {
|
|
2553
|
+
p.write('docs/architecture.md', '# Architecture\n\nThis is a microservices system.');
|
|
2554
|
+
const ctx = ResearchEngine.packageLocalContext(['docs/architecture.md']);
|
|
2555
|
+
assert.ok(ctx.includes('microservices'), 'Should include file content');
|
|
2556
|
+
assert.ok(ctx.includes('docs/architecture.md'), 'Should include filename');
|
|
2557
|
+
} finally { process.chdir(origCwd); p.cleanup(); }
|
|
2558
|
+
});
|
|
2559
|
+
|
|
2560
|
+
test('packageLocalContext: returns empty string for non-existent paths', () => {
|
|
2561
|
+
const p = mkProject();
|
|
2562
|
+
const origCwd = process.cwd();
|
|
2563
|
+
process.chdir(p.dir);
|
|
2564
|
+
try {
|
|
2565
|
+
const ctx = ResearchEngine.packageLocalContext(['nonexistent/path.md']);
|
|
2566
|
+
assert.strictEqual(ctx, '', 'Should return empty string for missing files');
|
|
2567
|
+
} finally { process.chdir(origCwd); p.cleanup(); }
|
|
2568
|
+
});
|
|
2569
|
+
|
|
2570
|
+
test('walkDir: skips node_modules and .git', () => {
|
|
2571
|
+
const p = mkProject();
|
|
2572
|
+
const origCwd = process.cwd();
|
|
2573
|
+
process.chdir(p.dir);
|
|
2574
|
+
try {
|
|
2575
|
+
p.write('src/index.ts', 'export default {}');
|
|
2576
|
+
p.write('node_modules/lodash/index.js', '// lodash');
|
|
2577
|
+
p.write('.git/config', '[core]');
|
|
2578
|
+
const files = ResearchEngine.walkDir(p.dir, ['.ts', '.js']);
|
|
2579
|
+
const hasNodeModules = files.some(f => f.includes('node_modules'));
|
|
2580
|
+
const hasGit = files.some(f => f.includes('.git'));
|
|
2581
|
+
assert.ok(!hasNodeModules, 'Should skip node_modules');
|
|
2582
|
+
assert.ok(!hasGit, 'Should skip .git');
|
|
2583
|
+
assert.ok(files.some(f => f.includes('index.ts')), 'Should include src/index.ts');
|
|
2584
|
+
} finally { process.chdir(origCwd); p.cleanup(); }
|
|
2585
|
+
});
|
|
2586
|
+
|
|
2587
|
+
// ── Review report writer ──────────────────────────────────────────────────────
|
|
2588
|
+
console.log('\nReview report writer:');
|
|
2589
|
+
|
|
2590
|
+
test('review report writer creates CROSS-REVIEW-[N].md', () => {
|
|
2591
|
+
const { write } = require('../bin/review/review-report-writer');
|
|
2592
|
+
const p = mkProject();
|
|
2593
|
+
const origCwd = process.cwd();
|
|
2594
|
+
process.chdir(p.dir);
|
|
2595
|
+
try {
|
|
2596
|
+
const mockResult = {
|
|
2597
|
+
reviews: [
|
|
2598
|
+
{ model: 'claude-sonnet-4-6', content: REVIEW_WITH_FINDINGS, role: 'primary' },
|
|
2599
|
+
{ model: 'gpt-4o', content: ADVERSARIAL_REVIEW, role: 'adversarial' },
|
|
2600
|
+
],
|
|
2601
|
+
synthesis: synthesizeFindings([
|
|
2602
|
+
{ model: 'claude-sonnet-4-6', content: REVIEW_WITH_FINDINGS, role: 'primary' },
|
|
2603
|
+
{ model: 'gpt-4o', content: ADVERSARIAL_REVIEW, role: 'adversarial' },
|
|
2604
|
+
]),
|
|
2605
|
+
total_cost_usd: 0.121,
|
|
2606
|
+
diff_length: 5000,
|
|
2607
|
+
};
|
|
2608
|
+
const file = write(3, mockResult);
|
|
2609
|
+
assert.ok(fs.existsSync(file), 'Report file should be created');
|
|
2610
|
+
const content = fs.readFileSync(file, 'utf8');
|
|
2611
|
+
assert.ok(content.includes('Cross-Model Code Review — Phase 3'), 'Should have correct title');
|
|
2612
|
+
assert.ok(content.includes('$0.1210'), 'Should include cost');
|
|
2613
|
+
assert.ok(content.includes('claude-sonnet-4-6'), 'Should list primary model');
|
|
2614
|
+
assert.ok(content.includes('gpt-4o'), 'Should list secondary model');
|
|
2615
|
+
} finally { process.chdir(origCwd); p.cleanup(); }
|
|
2616
|
+
});
|
|
2617
|
+
|
|
2618
|
+
// ── All 43 commands ───────────────────────────────────────────────────────────
|
|
2619
|
+
console.log('\nAll 43 commands (40 + 3 Day 10):');
|
|
2620
|
+
|
|
2621
|
+
const ALL_COMMANDS = [
|
|
2622
|
+
'help','init-project','plan-phase','execute-phase','verify-phase','ship',
|
|
2623
|
+
'next','quick','status','debug',
|
|
2624
|
+
'skills','review','security-scan','map-codebase','discuss-phase',
|
|
2625
|
+
'audit','milestone','complete-milestone','approve','sync-jira','sync-confluence',
|
|
2626
|
+
'health','retrospective','profile-team','metrics',
|
|
2627
|
+
'init-org','install-skill','publish-skill','pr-review','workspace','benchmark',
|
|
2628
|
+
'update','migrate','plugins','tokens','release',
|
|
2629
|
+
'auto','steer', // Day 8
|
|
2630
|
+
'browse','qa', // Day 9
|
|
2631
|
+
'cross-review','research','costs', // Day 10
|
|
2632
|
+
];
|
|
2633
|
+
|
|
2634
|
+
assert.strictEqual(ALL_COMMANDS.length, 43);
|
|
2635
|
+
|
|
2636
|
+
test('all 43 commands in .claude/commands/mindforge/', () => {
|
|
2637
|
+
const missing = ALL_COMMANDS.filter(c => !fs.existsSync(`.claude/commands/mindforge/${c}.md`));
|
|
2638
|
+
assert.strictEqual(missing.length, 0, `Missing: ${missing.join(', ')}`);
|
|
2639
|
+
});
|
|
2640
|
+
|
|
2641
|
+
test('all 43 commands mirrored in .agent/mindforge/', () => {
|
|
2642
|
+
const missing = ALL_COMMANDS.filter(c => !fs.existsSync(`.agent/mindforge/${c}.md`));
|
|
2643
|
+
assert.strictEqual(missing.length, 0, `Missing: ${missing.join(', ')}`);
|
|
2644
|
+
});
|
|
2645
|
+
|
|
2646
|
+
// ── MINDFORGE.md v2 schema ────────────────────────────────────────────────────
|
|
2647
|
+
console.log('\nMINDFORGE.md v2 model schema:');
|
|
2648
|
+
|
|
2649
|
+
test('schema includes all model routing settings', () => {
|
|
2650
|
+
const schema = JSON.parse(fs.readFileSync('.mindforge/MINDFORGE-V2-SCHEMA.json', 'utf8'));
|
|
2651
|
+
['PLANNER_MODEL', 'EXECUTOR_MODEL', 'REVIEWER_MODEL', 'SECURITY_MODEL',
|
|
2652
|
+
'RESEARCH_MODEL', 'QA_MODEL', 'DEBUG_MODEL', 'QUICK_MODEL'].forEach(k => {
|
|
2653
|
+
assert.ok(schema.properties?.[k], `Schema should define ${k}`);
|
|
2654
|
+
});
|
|
2655
|
+
});
|
|
2656
|
+
|
|
2657
|
+
test('schema includes cost settings with minimum: 0', () => {
|
|
2658
|
+
const schema = JSON.parse(fs.readFileSync('.mindforge/MINDFORGE-V2-SCHEMA.json', 'utf8'));
|
|
2659
|
+
const costLimit = schema.properties?.MODEL_COST_HARD_LIMIT_USD;
|
|
2660
|
+
assert.ok(costLimit, 'Should define MODEL_COST_HARD_LIMIT_USD');
|
|
2661
|
+
assert.strictEqual(costLimit.minimum, 0);
|
|
2662
|
+
});
|
|
2663
|
+
|
|
2664
|
+
// ── Version ───────────────────────────────────────────────────────────────────
|
|
2665
|
+
console.log('\nVersion:');
|
|
2666
|
+
|
|
2667
|
+
test('package.json is v2.0.0-alpha.3', () => {
|
|
2668
|
+
const v = JSON.parse(fs.readFileSync('package.json', 'utf8')).version;
|
|
2669
|
+
assert.ok(v === '2.0.0-alpha.3' || v.startsWith('2.'), `Expected v2.x.x, got ${v}`);
|
|
2670
|
+
});
|
|
2671
|
+
|
|
2672
|
+
// ── Results ───────────────────────────────────────────────────────────────────
|
|
2673
|
+
console.log(`\n${'─'.repeat(55)}`);
|
|
2674
|
+
console.log(`Results: ${passed} passed, ${failed} failed`);
|
|
2675
|
+
if (failed > 0) { console.error(`\n❌ ${failed} test(s) failed.\n`); process.exit(1); }
|
|
2676
|
+
else { console.log(`\n✅ All model routing tests passed.\n`); }
|
|
2677
|
+
```
|
|
2678
|
+
|
|
2679
|
+
**Commit:**
|
|
2680
|
+
```bash
|
|
2681
|
+
git add tests/model-routing.test.js
|
|
2682
|
+
git commit -m "test(v2-models): add comprehensive model routing test suite (18th suite)"
|
|
2683
|
+
```
|
|
2684
|
+
|
|
2685
|
+
---
|
|
2686
|
+
|
|
2687
|
+
## TASK 10 — Bump version and update CHANGELOG
|
|
2688
|
+
|
|
2689
|
+
```bash
|
|
2690
|
+
node -e "
|
|
2691
|
+
const fs = require('fs');
|
|
2692
|
+
const p = JSON.parse(fs.readFileSync('package.json','utf8'));
|
|
2693
|
+
p.version = '2.0.0-alpha.3';
|
|
2694
|
+
fs.writeFileSync('package.json', JSON.stringify(p, null, 2) + '\n');
|
|
2695
|
+
console.log('Bumped to v2.0.0-alpha.3');
|
|
2696
|
+
"
|
|
2697
|
+
```
|
|
2698
|
+
|
|
2699
|
+
Update `CHANGELOG.md`:
|
|
2700
|
+
|
|
2701
|
+
```markdown
|
|
2702
|
+
## [2.0.0-alpha.3] — Day 10: Multi-Model Intelligence Layer
|
|
2703
|
+
|
|
2704
|
+
### Added
|
|
2705
|
+
|
|
2706
|
+
**Model Registry & Router:**
|
|
2707
|
+
- .mindforge/models/model-registry.md — 7-model registry (Claude, GPT-4o, Gemini)
|
|
2708
|
+
- .mindforge/models/model-router.md — persona-to-model routing algorithm
|
|
2709
|
+
- bin/models/model-router.js — reads MINDFORGE.md overrides, applies Tier 3 override
|
|
2710
|
+
- Persona-to-model routing: developer→executor, security-reviewer→security, architect→planner
|
|
2711
|
+
- Tier 3 override: auth/payment/PII tasks always use SECURITY_MODEL
|
|
2712
|
+
- Fallback chains: unavailable model → next in tier → error with helpful message
|
|
2713
|
+
|
|
2714
|
+
**Multi-Provider API Client:**
|
|
2715
|
+
- bin/models/model-client.js — unified interface across all three providers
|
|
2716
|
+
- bin/models/anthropic-provider.js — Anthropic Messages API with cost calculation
|
|
2717
|
+
- bin/models/openai-provider.js — OpenAI Chat Completions API with cost calculation
|
|
2718
|
+
- bin/models/gemini-provider.js — Google Gemini generateContent API with cost calculation
|
|
2719
|
+
- Automatic retry fallback on 429/5xx (e.g., gpt-4o → gpt-4o-mini → claude-sonnet-4-6)
|
|
2720
|
+
- bin/models/cost-tracker.js — records every call to token-usage.jsonl with USD cost
|
|
2721
|
+
|
|
2722
|
+
**Cross-Review Engine:**
|
|
2723
|
+
- bin/review/cross-review-engine.js — 2-3 model review pipeline with context loading
|
|
2724
|
+
- bin/review/finding-synthesizer.js — consensus detection, model-specific findings, contradiction detection
|
|
2725
|
+
- bin/review/review-report-writer.js — CROSS-REVIEW-[N].md with full synthesis
|
|
2726
|
+
- Adversarial second-reviewer prompt: "paranoid auditor reviewing competitor's code"
|
|
2727
|
+
|
|
2728
|
+
**Research Engine:**
|
|
2729
|
+
- bin/research/research-engine.js — Gemini 2.5 Pro with 1M context for deep research
|
|
2730
|
+
- Context packager: local files/dirs + URL fetching, up to 900K chars for Gemini
|
|
2731
|
+
- Research types: general, library_comparison, codebase_analysis, compliance, pre_planning
|
|
2732
|
+
- .mindforge/personas/research-agent.md — research agent persona
|
|
2733
|
+
|
|
2734
|
+
**New Commands (total: 43):**
|
|
2735
|
+
- /mindforge:cross-review — adversarial multi-model code review
|
|
2736
|
+
- /mindforge:research — deep research via Gemini 1M context
|
|
2737
|
+
- /mindforge:costs — real-time cost tracking dashboard
|
|
2738
|
+
|
|
2739
|
+
**Configuration:**
|
|
2740
|
+
- MINDFORGE.md model settings: PLANNER_MODEL, EXECUTOR_MODEL, REVIEWER_MODEL, SECURITY_MODEL, etc.
|
|
2741
|
+
- MODEL_COST_HARD_LIMIT_USD — daily budget enforcement with AUDIT entry
|
|
2742
|
+
- REQUIRE_CROSS_REVIEW — gate /mindforge:ship on cross-review completion
|
|
2743
|
+
|
|
2744
|
+
**Tests:**
|
|
2745
|
+
- tests/model-routing.test.js — 18th test suite (router, synthesizer, cost tracker, research engine)
|
|
2746
|
+
```
|
|
2747
|
+
|
|
2748
|
+
```bash
|
|
2749
|
+
git add CHANGELOG.md package.json
|
|
2750
|
+
git commit -m "chore(v2-alpha3): Day 10 complete — multi-model intelligence layer, v2.0.0-alpha.3"
|
|
2751
|
+
git push origin feat/mindforge-v2-cross-model-review
|
|
2752
|
+
```
|
|
2753
|
+
|
|
2754
|
+
---
|
|
2755
|
+
|
|
2756
|
+
## TASK 11 — Run full test battery
|
|
2757
|
+
|
|
2758
|
+
```bash
|
|
2759
|
+
#!/usr/bin/env bash
|
|
2760
|
+
echo "MindForge v2 Day 10 — Test Battery"
|
|
2761
|
+
SUITES=(install wave-engine audit compaction skills-platform \
|
|
2762
|
+
integrations governance intelligence metrics \
|
|
2763
|
+
distribution ci-mode sdk production migration e2e \
|
|
2764
|
+
autonomous browser model-routing)
|
|
2765
|
+
FAIL=0
|
|
2766
|
+
for s in "${SUITES[@]}"; do
|
|
2767
|
+
printf " %-30s" "${s}..."
|
|
2768
|
+
node tests/${s}.test.js 2>&1 | tail -1 | grep -q "passed" && echo "✅" || { echo "❌"; ((FAIL++)); }
|
|
2769
|
+
done
|
|
2770
|
+
echo ""
|
|
2771
|
+
echo "Commands: $(ls .claude/commands/mindforge/ | wc -l | tr -d ' ') (expected: 43)"
|
|
2772
|
+
[ "$FAIL" -eq 0 ] && echo "✅ ALL 18 SUITES PASSED" || { echo "❌ ${FAIL} FAILURES"; exit 1; }
|
|
2773
|
+
```
|
|
2774
|
+
|
|
2775
|
+
---
|
|
2776
|
+
|
|
2777
|
+
# ═══════════════════════════════════════════════════════════════════════
|
|
2778
|
+
# PART 2 — REVIEW PROMPT
|
|
2779
|
+
# ═══════════════════════════════════════════════════════════════════════
|
|
2780
|
+
|
|
2781
|
+
---
|
|
2782
|
+
|
|
2783
|
+
## DAY 10 REVIEW
|
|
2784
|
+
|
|
2785
|
+
Activate **`architect.md` + `security-reviewer.md` + `qa-engineer.md`** simultaneously.
|
|
2786
|
+
|
|
2787
|
+
Day 10 risk profile:
|
|
2788
|
+
1. **API key leakage** — three providers, three sets of credentials, all in-process
|
|
2789
|
+
2. **Cost runaway** — no provider charges before you know it's spent
|
|
2790
|
+
3. **Finding synthesis false positives** — consensus detection could merge unrelated findings
|
|
2791
|
+
4. **Research engine URL fetching** — fetching arbitrary URLs is a SSRF vector
|
|
2792
|
+
5. **Model fallback chain opacity** — silent fallbacks may change cost profiles dramatically
|
|
2793
|
+
|
|
2794
|
+
---
|
|
2795
|
+
|
|
2796
|
+
## REVIEW PASS 1 — API Security: Key Handling
|
|
2797
|
+
|
|
2798
|
+
Read `anthropic-provider.js`, `openai-provider.js`, `gemini-provider.js`.
|
|
2799
|
+
|
|
2800
|
+
- [ ] **API keys logged in error messages.** The providers catch HTTP errors and include the response body. If the API returns a 401 with the key in the error body (unlikely but possible), it could appear in logs. Fix: "Strip any 40+ char alphanumeric strings from error messages before logging or throwing: `err.message = err.message.replace(/[a-zA-Z0-9-_]{40,}/g, '[REDACTED]')`"
|
|
2801
|
+
|
|
2802
|
+
- [ ] **Gemini API key in URL path.** The Gemini provider passes the API key as a query parameter: `?key=${apiKey}`. This means the API key appears in Node.js HTTP logs, proxy logs, and any access log. OpenAI and Anthropic use header-based auth (safer). Fix: "Use the `x-goog-api-key` header for Gemini instead of query parameter auth. Change the path to remove the key and add a header: `'x-goog-api-key': apiKey`."
|
|
2803
|
+
|
|
2804
|
+
- [ ] **No timeout on research engine URL fetching.** The `fetchUrl()` function uses `https.get()` with `timeout: 30_000`. But the `timeout` option in `https.get()` is the socket timeout, not the total request timeout. A slow server can keep the socket alive and never trigger this. Fix: "Use `setTimeout` to abort the request after 30 seconds: `const timer = setTimeout(() => { req.destroy(); }, 30_000);` and clear it in the response handler."
|
|
2805
|
+
|
|
2806
|
+
---
|
|
2807
|
+
|
|
2808
|
+
## REVIEW PASS 2 — Cost Tracker: Budget Enforcement
|
|
2809
|
+
|
|
2810
|
+
Read `cost-tracker.js`.
|
|
2811
|
+
|
|
2812
|
+
- [ ] **`checkDailyLimit` throws AFTER recording the entry.** The flow is: `record(entry)` → appends to JSONL → `checkDailyLimit()`. If the limit has been reached, the entry is already recorded AND the cost has been spent — the exception just prevents future calls. This is correct (you can't unspend the API call). But the error message says "Model calls paused" — this is misleading because the current call already happened. Fix: "Call `checkDailyLimit()` BEFORE appending the entry: check if the CURRENT total + new cost would exceed the limit. If yes: throw before the API call is made (caller must check the error before calling the model)."
|
|
2813
|
+
|
|
2814
|
+
- [ ] **Cost tracker doesn't handle corrupt JSONL lines gracefully in `getSummary`.** The `try-catch` in `getSummary` silently skips corrupt lines with `/* skip malformed lines */`. But it logs nothing — a developer with a corrupt token-usage.jsonl would silently get wrong cost totals. Fix: "Log a warning for each skipped line: `process.stderr.write('[cost-tracker] Skipped malformed entry at line N\n')`"
|
|
2815
|
+
|
|
2816
|
+
- [ ] **`getTodaySpend()` is called in `checkDailyLimit()` which is called in `record()`.** For a session with 100 model calls, this reads and parses the entire JSONL file 100 times. Fix: "Cache the daily total in memory with a 1-minute TTL. Recompute from file only when cache expires."
|
|
2817
|
+
|
|
2818
|
+
---
|
|
2819
|
+
|
|
2820
|
+
## REVIEW PASS 3 — Finding Synthesizer: Accuracy
|
|
2821
|
+
|
|
2822
|
+
Read `finding-synthesizer.js`.
|
|
2823
|
+
|
|
2824
|
+
- [ ] **`normalizeLocation` strips ALL trailing digits.** `src/auth/login.ts:47` → `src/auth/login.ts`. This means findings from different lines in the SAME file are treated as the same finding. Example: "SQL injection at line 47" and "XSS at line 312" in login.ts would both normalize to `src/auth/login.ts` and be incorrectly identified as consensus. Fix: "Use a line-range band for fuzzy matching — round line numbers to the nearest 20: `loc.replace(/:(\d+)$/, (_, n) => ':' + (Math.round(parseInt(n) / 20) * 20))`."
|
|
2825
|
+
|
|
2826
|
+
- [ ] **Contradiction detection checks severity gap ≥ 2 but the gap is based on SEVERITY_ORDER indices.** `HIGH` is index 2, `LOW` is index 0 — gap of 2. This means HIGH vs LOW is a contradiction, but HIGH vs MEDIUM (gap of 1) is not. Is this the right threshold? Lowering to ≥ 1 would flag HIGH vs MEDIUM as a contradiction (e.g., one model says HIGH, another says MEDIUM for the same finding). The current implementation seems reasonable but should be documented.
|
|
2827
|
+
|
|
2828
|
+
---
|
|
2829
|
+
|
|
2830
|
+
## REVIEW PASS 4 — Research Engine: SSRF Risk
|
|
2831
|
+
|
|
2832
|
+
Read `research-engine.js`.
|
|
2833
|
+
|
|
2834
|
+
- [ ] **`fetchUrl` is a Server-Side Request Forgery (SSRF) vector.** The function fetches any URL passed to it. If a user passes an internal URL like `http://169.254.169.254/latest/meta-data/` (AWS metadata service), the research engine would fetch it and potentially expose cloud credentials to the Gemini model. Fix: "Block private IP ranges in `fetchUrl`: refuse any URL whose host resolves to RFC 1918 addresses (10.x, 172.16-31.x, 192.168.x), localhost (127.x, ::1), and link-local (169.254.x)."
|
|
2835
|
+
|
|
2836
|
+
- [ ] **`walkDir` reads binary files.** The function walks all files with matching extensions (`.ts`, `.js`, `.md`). But `.js` files could include compiled bundles (dist/, build/) which are binary-like in content and waste context tokens. The `SKIP_DIRS` already excludes `dist` and `build` — verify they cover common framework output directories: `.next`, `out`, `public`, `static`.
|
|
2837
|
+
|
|
2838
|
+
---
|
|
2839
|
+
|
|
2840
|
+
## REVIEW PASS 5 — Model Client: Fallback Transparency
|
|
2841
|
+
|
|
2842
|
+
Read `model-client.js`.
|
|
2843
|
+
|
|
2844
|
+
- [ ] **Silent fallback changes cost profile without notification.** When `gpt-4o` is unavailable and falls back to `claude-sonnet-4-6`, the cross-review loses its adversarial perspective (GPT-4o's different training) silently. The caller receives a result that looks like a cross-review but is actually two Claude calls. Fix: "When a fallback is applied, include a visible warning in the response content: prepend `[FALLBACK: ${originalModel} → ${fallbackModel}. Cross-model diversity reduced.]` so the cross-review report reflects this."
|
|
2845
|
+
|
|
2846
|
+
- [ ] **Cost tracking in `complete()` uses `result.cost_usd` which may be 0.** If a provider's cost calculation produces 0 (e.g., because `input_tokens` is 0 in a bad response), the cost tracker records 0. This leads to inaccurate cost summaries. Fix: "If `result.cost_usd === 0` but `result.input_tokens > 0` or `result.output_tokens > 0`: recalculate cost from token counts and PRICING table."
|
|
2847
|
+
|
|
2848
|
+
---
|
|
2849
|
+
|
|
2850
|
+
## REVIEW PASS 6 — Test Suite
|
|
2851
|
+
|
|
2852
|
+
Read `tests/model-routing.test.js`.
|
|
2853
|
+
|
|
2854
|
+
- [ ] **`checkDailyLimit` is not directly tested.** The review found a correctness issue in the limit check (after-the-fact vs before-the-fact). Add a test that verifies `checkDailyLimit` throws BEFORE a new entry would exceed the limit.
|
|
2855
|
+
|
|
2856
|
+
- [ ] **Missing test: Gemini API key in header (not URL).** After hardening, verify the Gemini provider uses header auth. Add a test that inspects the request path and verifies it does NOT contain the API key.
|
|
2857
|
+
|
|
2858
|
+
- [ ] **Missing test: fallback chain — model unavailable.** The router has a fallback chain but no test verifies it. Add a test that simulates an unavailable model (no API key) and verifies the router returns a fallback.
|
|
2859
|
+
|
|
2860
|
+
---
|
|
2861
|
+
|
|
2862
|
+
## REVIEW SUMMARY TABLE
|
|
2863
|
+
|
|
2864
|
+
```
|
|
2865
|
+
## Day 10 Review Summary
|
|
2866
|
+
|
|
2867
|
+
| Category | BLOCKING | MAJOR | MINOR | SUGGESTION |
|
|
2868
|
+
|--------------------|----------|-------|-------|------------|
|
|
2869
|
+
| API Security | | | | |
|
|
2870
|
+
| Cost Tracker | | | | |
|
|
2871
|
+
| Finding Synthesizer| | | | |
|
|
2872
|
+
| Research Engine | | | | |
|
|
2873
|
+
| Model Client | | | | |
|
|
2874
|
+
| Test Suite | | | | |
|
|
2875
|
+
| **TOTAL** | | | | |
|
|
2876
|
+
|
|
2877
|
+
## Verdict
|
|
2878
|
+
[ ] ✅ APPROVED — Proceed to HARDEN section
|
|
2879
|
+
[ ] ⚠️ APPROVED WITH CONDITIONS
|
|
2880
|
+
[ ] ❌ NOT APPROVED
|
|
2881
|
+
```
|
|
2882
|
+
|
|
2883
|
+
---
|
|
2884
|
+
|
|
2885
|
+
# ═══════════════════════════════════════════════════════════════════════
|
|
2886
|
+
# PART 3 — HARDENING PROMPT
|
|
2887
|
+
# ═══════════════════════════════════════════════════════════════════════
|
|
2888
|
+
|
|
2889
|
+
---
|
|
2890
|
+
|
|
2891
|
+
## DAY 10 HARDENING
|
|
2892
|
+
|
|
2893
|
+
Activate **`security-reviewer.md` + `architect.md`** simultaneously.
|
|
2894
|
+
|
|
2895
|
+
```bash
|
|
2896
|
+
for suite in install wave-engine audit compaction skills-platform \
|
|
2897
|
+
integrations governance intelligence metrics \
|
|
2898
|
+
distribution ci-mode sdk production migration e2e \
|
|
2899
|
+
autonomous browser model-routing; do
|
|
2900
|
+
printf " %-30s" "${suite}..."
|
|
2901
|
+
node tests/${suite}.test.js 2>&1 | tail -1
|
|
2902
|
+
done
|
|
2903
|
+
```
|
|
2904
|
+
|
|
2905
|
+
---
|
|
2906
|
+
|
|
2907
|
+
## HARDEN 1 — Fix Gemini API key: header auth instead of URL query param
|
|
2908
|
+
|
|
2909
|
+
Update `bin/models/gemini-provider.js`:
|
|
2910
|
+
|
|
2911
|
+
```javascript
|
|
2912
|
+
_request(apiKey, modelName, body) {
|
|
2913
|
+
return new Promise((resolve, reject) => {
|
|
2914
|
+
const req = https.request({
|
|
2915
|
+
hostname: 'generativelanguage.googleapis.com',
|
|
2916
|
+
// KEY FIX: Remove API key from URL — use x-goog-api-key header instead
|
|
2917
|
+
path: `/v1beta/models/${encodeURIComponent(modelName)}:generateContent`,
|
|
2918
|
+
method: 'POST',
|
|
2919
|
+
headers: {
|
|
2920
|
+
'Content-Type': 'application/json',
|
|
2921
|
+
'x-goog-api-key': apiKey, // ← header auth (key never in URL/logs)
|
|
2922
|
+
'Content-Length': Buffer.byteLength(body),
|
|
2923
|
+
},
|
|
2924
|
+
timeout: 180_000,
|
|
2925
|
+
}, res => {
|
|
2926
|
+
let raw = '';
|
|
2927
|
+
res.on('data', c => (raw += c));
|
|
2928
|
+
res.on('end', () => { try { resolve(JSON.parse(raw)); } catch { resolve({ error: { message: raw.slice(0, 200) } }); } });
|
|
2929
|
+
});
|
|
2930
|
+
req.on('error', reject);
|
|
2931
|
+
req.on('timeout', () => { req.destroy(); reject(Object.assign(new Error('Gemini timeout'), { status: 408 })); });
|
|
2932
|
+
req.write(body);
|
|
2933
|
+
req.end();
|
|
2934
|
+
});
|
|
2935
|
+
}
|
|
2936
|
+
```
|
|
2937
|
+
|
|
2938
|
+
**Commit:**
|
|
2939
|
+
```bash
|
|
2940
|
+
git add bin/models/gemini-provider.js
|
|
2941
|
+
git commit -m "harden(v2-models): fix Gemini API key — use x-goog-api-key header, not URL query param"
|
|
2942
|
+
```
|
|
2943
|
+
|
|
2944
|
+
---
|
|
2945
|
+
|
|
2946
|
+
## HARDEN 2 — Fix SSRF in research engine URL fetching
|
|
2947
|
+
|
|
2948
|
+
Update `bin/research/research-engine.js`:
|
|
2949
|
+
|
|
2950
|
+
```javascript
|
|
2951
|
+
// Add SSRF protection before fetchUrl
|
|
2952
|
+
const { URL } = require('url');
|
|
2953
|
+
const dns = require('dns').promises;
|
|
2954
|
+
|
|
2955
|
+
// Private IP ranges that must never be fetched (SSRF protection)
|
|
2956
|
+
const PRIVATE_RANGES = [
|
|
2957
|
+
/^127\./, // Loopback
|
|
2958
|
+
/^10\./, // RFC 1918
|
|
2959
|
+
/^172\.(1[6-9]|2\d|3[01])\./, // RFC 1918
|
|
2960
|
+
/^192\.168\./, // RFC 1918
|
|
2961
|
+
/^169\.254\./, // Link-local (AWS metadata)
|
|
2962
|
+
/^::1$/, // IPv6 loopback
|
|
2963
|
+
/^fc00:/, // IPv6 private
|
|
2964
|
+
/^fe80:/, // IPv6 link-local
|
|
2965
|
+
];
|
|
2966
|
+
|
|
2967
|
+
async function isSafeUrl(url) {
|
|
2968
|
+
let parsed;
|
|
2969
|
+
try { parsed = new URL(url); } catch { return false; }
|
|
2970
|
+
|
|
2971
|
+
// Block non-http(s) protocols
|
|
2972
|
+
if (!['http:', 'https:'].includes(parsed.protocol)) return false;
|
|
2973
|
+
|
|
2974
|
+
const host = parsed.hostname;
|
|
2975
|
+
|
|
2976
|
+
// Resolve hostname to IP and check against private ranges
|
|
2977
|
+
try {
|
|
2978
|
+
const { address } = await dns.lookup(host);
|
|
2979
|
+
if (PRIVATE_RANGES.some(r => r.test(address))) {
|
|
2980
|
+
process.stderr.write(`[research-engine] SSRF blocked: ${url} resolves to private IP ${address}\n`);
|
|
2981
|
+
return false;
|
|
2982
|
+
}
|
|
2983
|
+
} catch {
|
|
2984
|
+
// DNS resolution failed — block the URL (fail-safe)
|
|
2985
|
+
process.stderr.write(`[research-engine] URL blocked: cannot resolve hostname "${host}"\n`);
|
|
2986
|
+
return false;
|
|
2987
|
+
}
|
|
2988
|
+
|
|
2989
|
+
return true;
|
|
2990
|
+
}
|
|
2991
|
+
|
|
2992
|
+
// Updated fetchUrl with SSRF protection and proper timeout
|
|
2993
|
+
async function fetchUrl(url) {
|
|
2994
|
+
// SSRF check
|
|
2995
|
+
if (!await isSafeUrl(url)) {
|
|
2996
|
+
throw new Error(`URL blocked by SSRF protection: ${url}`);
|
|
2997
|
+
}
|
|
2998
|
+
|
|
2999
|
+
return new Promise((resolve, reject) => {
|
|
3000
|
+
const protocol = url.startsWith('https') ? require('https') : require('http');
|
|
3001
|
+
|
|
3002
|
+
let settled = false;
|
|
3003
|
+
const settle = (fn, val) => { if (!settled) { settled = true; fn(val); } };
|
|
3004
|
+
|
|
3005
|
+
// Hard timeout — kills the request regardless of socket state
|
|
3006
|
+
const hardTimer = setTimeout(() => {
|
|
3007
|
+
settle(reject, Object.assign(new Error(`URL fetch timeout after 30s: ${url}`), { code: 'FETCH_TIMEOUT' }));
|
|
3008
|
+
}, 30_000);
|
|
3009
|
+
|
|
3010
|
+
const req = protocol.get(url, res => {
|
|
3011
|
+
let body = '';
|
|
3012
|
+
res.on('data', c => (body += c));
|
|
3013
|
+
res.on('end', () => { clearTimeout(hardTimer); settle(resolve, body.slice(0, 200_000)); });
|
|
3014
|
+
});
|
|
3015
|
+
|
|
3016
|
+
req.on('error', err => { clearTimeout(hardTimer); settle(reject, err); });
|
|
3017
|
+
req.end();
|
|
3018
|
+
});
|
|
3019
|
+
}
|
|
3020
|
+
```
|
|
3021
|
+
|
|
3022
|
+
**Commit:**
|
|
3023
|
+
```bash
|
|
3024
|
+
git add bin/research/research-engine.js
|
|
3025
|
+
git commit -m "harden(v2-models): fix SSRF in research URL fetcher — block private IPs, DNS resolution check"
|
|
3026
|
+
```
|
|
3027
|
+
|
|
3028
|
+
---
|
|
3029
|
+
|
|
3030
|
+
## HARDEN 3 — Fix cost tracker: check limit before API call
|
|
3031
|
+
|
|
3032
|
+
Update `bin/models/cost-tracker.js`:
|
|
3033
|
+
|
|
3034
|
+
```javascript
|
|
3035
|
+
// New: pre-flight check function (call BEFORE making the API call)
|
|
3036
|
+
async function preflight(estimatedCost = 0) {
|
|
3037
|
+
const hardLimit = parseFloat(readSetting('MODEL_COST_HARD_LIMIT_USD', '0'));
|
|
3038
|
+
if (hardLimit <= 0) return; // No limit configured
|
|
3039
|
+
|
|
3040
|
+
const todaySpend = getTodaySpendCached();
|
|
3041
|
+
const projected = todaySpend + estimatedCost;
|
|
3042
|
+
|
|
3043
|
+
if (projected >= hardLimit) {
|
|
3044
|
+
throw Object.assign(
|
|
3045
|
+
new Error(
|
|
3046
|
+
`Daily cost limit $${hardLimit} would be reached ` +
|
|
3047
|
+
`(today: $${todaySpend.toFixed(4)}, projected: $${projected.toFixed(4)}). ` +
|
|
3048
|
+
`Model call prevented.`
|
|
3049
|
+
),
|
|
3050
|
+
{ code: 'COST_LIMIT_WOULD_BE_REACHED', spend: todaySpend, limit: hardLimit }
|
|
3051
|
+
);
|
|
3052
|
+
}
|
|
3053
|
+
}
|
|
3054
|
+
|
|
3055
|
+
// Cached daily spend (1 minute TTL)
|
|
3056
|
+
let _dailyCache = { value: 0, computed_at: 0 };
|
|
3057
|
+
function getTodaySpendCached() {
|
|
3058
|
+
const AGE_MS = Date.now() - _dailyCache.computed_at;
|
|
3059
|
+
if (AGE_MS > 60_000) { // Cache expired — recompute
|
|
3060
|
+
_dailyCache.value = getTodaySpend();
|
|
3061
|
+
_dailyCache.computed_at = Date.now();
|
|
3062
|
+
}
|
|
3063
|
+
return _dailyCache.value;
|
|
3064
|
+
}
|
|
3065
|
+
|
|
3066
|
+
// Updated record to warn on malformed lines
|
|
3067
|
+
async function record(entry) {
|
|
3068
|
+
ensureDir();
|
|
3069
|
+
const enriched = { ...entry, date: new Date().toISOString().slice(0, 10) };
|
|
3070
|
+
fs.appendFileSync(USAGE_LOG, JSON.stringify(enriched) + '\n');
|
|
3071
|
+
// Invalidate cache after new entry
|
|
3072
|
+
_dailyCache.computed_at = 0;
|
|
3073
|
+
// Soft check after record (for reporting, not prevention)
|
|
3074
|
+
// Hard check via preflight() before API calls
|
|
3075
|
+
}
|
|
3076
|
+
|
|
3077
|
+
module.exports = { record, preflight, getTodaySpend, getTodaySpendCached, getSummary };
|
|
3078
|
+
```
|
|
3079
|
+
|
|
3080
|
+
Also update `bin/models/model-client.js` to call `preflight` before each API call:
|
|
3081
|
+
|
|
3082
|
+
```javascript
|
|
3083
|
+
// At start of complete() function — add before the provider factory:
|
|
3084
|
+
// Pre-flight cost check (prevents exceeding daily limit)
|
|
3085
|
+
try {
|
|
3086
|
+
await CostTracker.preflight(0.5); // Conservative estimate — actual cost tracked after
|
|
3087
|
+
} catch (costErr) {
|
|
3088
|
+
if (costErr.code === 'COST_LIMIT_WOULD_BE_REACHED') throw costErr;
|
|
3089
|
+
// Other errors from preflight: ignore (don't block on cost check failures)
|
|
3090
|
+
}
|
|
3091
|
+
```
|
|
3092
|
+
|
|
3093
|
+
**Commit:**
|
|
3094
|
+
```bash
|
|
3095
|
+
git add bin/models/cost-tracker.js bin/models/model-client.js
|
|
3096
|
+
git commit -m "harden(v2-models): fix cost limit to prevent API calls BEFORE limit breach, add cache"
|
|
3097
|
+
```
|
|
3098
|
+
|
|
3099
|
+
---
|
|
3100
|
+
|
|
3101
|
+
## HARDEN 4 — Fix finding synthesizer location normalization
|
|
3102
|
+
|
|
3103
|
+
Update `bin/review/finding-synthesizer.js`:
|
|
3104
|
+
|
|
3105
|
+
```javascript
|
|
3106
|
+
// Replace normalizeLocation with line-band approach:
|
|
3107
|
+
function normalizeLocation(loc) {
|
|
3108
|
+
if (!loc) return '';
|
|
3109
|
+
// Use ±20 line band for fuzzy matching:
|
|
3110
|
+
// "src/auth/login.ts:47" → "src/auth/login.ts:40" (nearest 20-line band)
|
|
3111
|
+
// This prevents "login.ts:47" and "login.ts:312" being treated as the same finding
|
|
3112
|
+
return loc.toLowerCase().replace(/:(\d+)$/, (_, n) => {
|
|
3113
|
+
const band = Math.round(parseInt(n, 10) / 20) * 20;
|
|
3114
|
+
return `:${band}`;
|
|
3115
|
+
});
|
|
3116
|
+
}
|
|
3117
|
+
```
|
|
3118
|
+
|
|
3119
|
+
Add documentation comment explaining the threshold:
|
|
3120
|
+
|
|
3121
|
+
```javascript
|
|
3122
|
+
// SEVERITY_ORDER gap threshold for contradiction detection:
|
|
3123
|
+
// Gap ≥ 2 means: [LOW, MEDIUM, HIGH, CRITICAL] indices differ by 2+
|
|
3124
|
+
// HIGH (idx 2) vs LOW (idx 0) = gap 2 → contradiction
|
|
3125
|
+
// HIGH (idx 2) vs MEDIUM (idx 1) = gap 1 → NOT a contradiction (difference of opinion)
|
|
3126
|
+
// This is intentional: adjacent severity disagreements are normal; large gaps indicate
|
|
3127
|
+
// fundamentally different assessments of risk.
|
|
3128
|
+
function severityGap(severities) {
|
|
3129
|
+
const indices = severities.map(s => SEVERITY_ORDER.indexOf(s));
|
|
3130
|
+
return Math.max(...indices) - Math.min(...indices);
|
|
3131
|
+
}
|
|
3132
|
+
```
|
|
3133
|
+
|
|
3134
|
+
**Commit:**
|
|
3135
|
+
```bash
|
|
3136
|
+
git add bin/review/finding-synthesizer.js
|
|
3137
|
+
git commit -m "harden(v2-models): fix finding location normalization — use line-band not file-only"
|
|
3138
|
+
```
|
|
3139
|
+
|
|
3140
|
+
---
|
|
3141
|
+
|
|
3142
|
+
## HARDEN 5 — Add fallback transparency to cross-review
|
|
3143
|
+
|
|
3144
|
+
Update `bin/models/model-client.js`:
|
|
3145
|
+
|
|
3146
|
+
```javascript
|
|
3147
|
+
// In the fallback section — add transparency warning:
|
|
3148
|
+
if (err.status === 429 || err.status >= 500) {
|
|
3149
|
+
const fallbacks = FALLBACK_CHAINS[resolvedModelId] || [];
|
|
3150
|
+
for (const fallback of fallbacks) {
|
|
3151
|
+
if (!isAvailable(fallback)) continue;
|
|
3152
|
+
process.stderr.write(`[model-client] ⚠️ ${resolvedModelId} error (${err.status}) → ${fallback}\n`);
|
|
3153
|
+
const fallbackProvider = PROVIDERS[fallback]();
|
|
3154
|
+
result = await fallbackProvider.complete({ model: fallback, systemPrompt, userMessage, maxTokens, temperature });
|
|
3155
|
+
result.model_used = fallback;
|
|
3156
|
+
result.fallback_reason = `${resolvedModelId} → ${fallback} (${err.status})`;
|
|
3157
|
+
// Add visible warning to content so reports reflect the fallback
|
|
3158
|
+
result.content = `[FALLBACK NOTICE: ${resolvedModelId} unavailable — used ${fallback} instead. ` +
|
|
3159
|
+
`Cross-model diversity may be reduced.]\n\n${result.content}`;
|
|
3160
|
+
break;
|
|
3161
|
+
}
|
|
3162
|
+
if (!result) throw err;
|
|
3163
|
+
}
|
|
3164
|
+
```
|
|
3165
|
+
|
|
3166
|
+
**Commit:**
|
|
3167
|
+
```bash
|
|
3168
|
+
git add bin/models/model-client.js
|
|
3169
|
+
git commit -m "harden(v2-models): add fallback transparency notice in model response content"
|
|
3170
|
+
```
|
|
3171
|
+
|
|
3172
|
+
---
|
|
3173
|
+
|
|
3174
|
+
## HARDEN 6 — Write 3 ADRs for Day 10 decisions
|
|
3175
|
+
|
|
3176
|
+
### `.planning/decisions/ADR-027-multi-model-routing.md`
|
|
3177
|
+
|
|
3178
|
+
```markdown
|
|
3179
|
+
# ADR-027: Persona determines model; Tier 3 always overrides to SECURITY_MODEL
|
|
3180
|
+
|
|
3181
|
+
**Status:** Accepted | **Date:** v2.0.0 | **Day:** 10
|
|
3182
|
+
|
|
3183
|
+
## Context
|
|
3184
|
+
Which model should execute which task in a multi-model environment?
|
|
3185
|
+
|
|
3186
|
+
## Decision
|
|
3187
|
+
Persona → model routing. Tier 3 changes override to SECURITY_MODEL unconditionally.
|
|
3188
|
+
|
|
3189
|
+
## Rationale
|
|
3190
|
+
The persona already encodes the type of reasoning needed. Architect needs deep planning
|
|
3191
|
+
reasoning (Opus). Developer needs balanced quality/speed (Sonnet). Research agent needs
|
|
3192
|
+
1M context (Gemini). Mapping persona → model is more stable than mapping task content.
|
|
3193
|
+
|
|
3194
|
+
Tier 3 override is non-negotiable: auth/payment/PII code is high-stakes enough to always
|
|
3195
|
+
warrant the best available reasoning, regardless of what persona is executing.
|
|
3196
|
+
|
|
3197
|
+
## Consequences
|
|
3198
|
+
Teams can tune routing by changing personas in PLAN files.
|
|
3199
|
+
Budget-conscious teams can set EXECUTOR_MODEL=claude-haiku-4-5 for simpler tasks.
|
|
3200
|
+
```
|
|
3201
|
+
|
|
3202
|
+
### `.planning/decisions/ADR-028-adversarial-cross-review.md`
|
|
3203
|
+
|
|
3204
|
+
```markdown
|
|
3205
|
+
# ADR-028: Cross-review uses adversarial system prompt for secondary model
|
|
3206
|
+
|
|
3207
|
+
**Status:** Accepted | **Date:** v2.0.0 | **Day:** 10
|
|
3208
|
+
|
|
3209
|
+
## Context
|
|
3210
|
+
Why use an adversarial prompt for the secondary model in cross-review?
|
|
3211
|
+
|
|
3212
|
+
## Decision
|
|
3213
|
+
Secondary model (CROSS_REVIEW_SECONDARY) uses a "paranoid auditor reviewing competitor's code"
|
|
3214
|
+
system prompt. Primary model uses the standard senior-reviewer prompt.
|
|
3215
|
+
|
|
3216
|
+
## Rationale
|
|
3217
|
+
The primary and secondary models must use different cognitive frames to be useful.
|
|
3218
|
+
If both use the same "senior reviewer" prompt, they tend to find the same categories of issues
|
|
3219
|
+
(both are trying to be helpful and thorough). The adversarial frame specifically activates
|
|
3220
|
+
critical, suspicious reasoning — finding issues the primary model rationalised away.
|
|
3221
|
+
Empirically, adversarial prompting finds 30-50% more security issues than collaborative prompting.
|
|
3222
|
+
|
|
3223
|
+
## Consequences
|
|
3224
|
+
Secondary model reviews may include false positives (being adversarial means casting a wide net).
|
|
3225
|
+
The synthesis step filters for consensus — false positives in one model don't become consensus findings.
|
|
3226
|
+
```
|
|
3227
|
+
|
|
3228
|
+
### `.planning/decisions/ADR-029-gemini-header-auth.md`
|
|
3229
|
+
|
|
3230
|
+
```markdown
|
|
3231
|
+
# ADR-029: Gemini uses x-goog-api-key header, not URL query parameter
|
|
3232
|
+
|
|
3233
|
+
**Status:** Accepted | **Date:** v2.0.0 | **Day:** 10
|
|
3234
|
+
|
|
3235
|
+
## Context
|
|
3236
|
+
Google's Gemini API supports both query-param auth (?key=...) and header auth (x-goog-api-key).
|
|
3237
|
+
|
|
3238
|
+
## Decision
|
|
3239
|
+
MindForge uses x-goog-api-key header exclusively.
|
|
3240
|
+
|
|
3241
|
+
## Rationale
|
|
3242
|
+
Query-parameter API keys appear in:
|
|
3243
|
+
- Node.js HTTP access logs (request URLs are logged)
|
|
3244
|
+
- Proxy/gateway access logs
|
|
3245
|
+
- Browser network inspector if used client-side
|
|
3246
|
+
- Any URL-based telemetry or tracing
|
|
3247
|
+
|
|
3248
|
+
Header-based auth keeps the key out of all URL-based logs.
|
|
3249
|
+
This is consistent with Anthropic (x-api-key) and OpenAI (Authorization: Bearer) patterns.
|
|
3250
|
+
|
|
3251
|
+
## Consequences
|
|
3252
|
+
All three providers now use header-based auth consistently.
|
|
3253
|
+
```
|
|
3254
|
+
|
|
3255
|
+
**Commit:**
|
|
3256
|
+
```bash
|
|
3257
|
+
git add .planning/decisions/ADR-027*.md \
|
|
3258
|
+
.planning/decisions/ADR-028*.md \
|
|
3259
|
+
.planning/decisions/ADR-029*.md
|
|
3260
|
+
git commit -m "docs(adr): add ADR-027 model routing, ADR-028 adversarial review, ADR-029 Gemini header auth"
|
|
3261
|
+
```
|
|
3262
|
+
|
|
3263
|
+
---
|
|
3264
|
+
|
|
3265
|
+
## HARDEN 7 — Add hardening tests
|
|
3266
|
+
|
|
3267
|
+
```javascript
|
|
3268
|
+
// Add to tests/model-routing.test.js:
|
|
3269
|
+
|
|
3270
|
+
console.log('\nHardening tests:');
|
|
3271
|
+
|
|
3272
|
+
test('Gemini provider uses x-goog-api-key header (NOT URL query param)', () => {
|
|
3273
|
+
const c = fs.readFileSync('bin/models/gemini-provider.js', 'utf8');
|
|
3274
|
+
assert.ok(c.includes('x-goog-api-key'), 'Should use x-goog-api-key header');
|
|
3275
|
+
// Must NOT have apiKey in the URL path
|
|
3276
|
+
assert.ok(!c.includes('?key='), 'Must NOT put API key in URL query param');
|
|
3277
|
+
assert.ok(!c.includes('key=${'), 'Must NOT interpolate API key in URL');
|
|
3278
|
+
});
|
|
3279
|
+
|
|
3280
|
+
test('research engine has SSRF protection for private IPs', () => {
|
|
3281
|
+
const c = fs.readFileSync('bin/research/research-engine.js', 'utf8');
|
|
3282
|
+
assert.ok(c.includes('169.254'), 'Should block AWS metadata IP');
|
|
3283
|
+
assert.ok(c.includes('127\\.'), 'Should block loopback');
|
|
3284
|
+
assert.ok(c.includes('isSafeUrl') || c.includes('PRIVATE_RANGES'), 'Should have SSRF check');
|
|
3285
|
+
});
|
|
3286
|
+
|
|
3287
|
+
test('cost tracker has preflight check before API call', () => {
|
|
3288
|
+
const c = fs.readFileSync('bin/models/cost-tracker.js', 'utf8');
|
|
3289
|
+
assert.ok(c.includes('preflight'), 'Should export preflight function');
|
|
3290
|
+
const modClient = fs.readFileSync('bin/models/model-client.js', 'utf8');
|
|
3291
|
+
assert.ok(modClient.includes('preflight'), 'model-client should call preflight before API call');
|
|
3292
|
+
});
|
|
3293
|
+
|
|
3294
|
+
test('finding synthesizer uses line-band normalization (not file-only)', () => {
|
|
3295
|
+
const c = fs.readFileSync('bin/review/finding-synthesizer.js', 'utf8');
|
|
3296
|
+
assert.ok(c.includes('band') || c.includes('Math.round'), 'Should use line-band normalization');
|
|
3297
|
+
assert.ok(!c.includes("loc?.replace(/:\\d+$/,"), 'Should NOT strip all line numbers');
|
|
3298
|
+
});
|
|
3299
|
+
|
|
3300
|
+
test('model client adds fallback notice to response content', () => {
|
|
3301
|
+
const c = fs.readFileSync('bin/models/model-client.js', 'utf8');
|
|
3302
|
+
assert.ok(
|
|
3303
|
+
c.includes('FALLBACK NOTICE') || c.includes('fallback_reason'),
|
|
3304
|
+
'Should add transparency notice when fallback is applied'
|
|
3305
|
+
);
|
|
3306
|
+
});
|
|
3307
|
+
|
|
3308
|
+
test('cost limit check prevents call before spending (preflight before record)', () => {
|
|
3309
|
+
const c = fs.readFileSync('bin/models/cost-tracker.js', 'utf8');
|
|
3310
|
+
// The preflight function must be defined
|
|
3311
|
+
assert.ok(c.includes('async function preflight'), 'Should have preflight function');
|
|
3312
|
+
// The record function should NOT contain the limit check (moved to preflight)
|
|
3313
|
+
const recordFnMatch = c.match(/async function record\([\s\S]*?\}\n}/);
|
|
3314
|
+
if (recordFnMatch) {
|
|
3315
|
+
assert.ok(!recordFnMatch[0].includes('COST_LIMIT'), 'record() should not enforce limit (preflight does)');
|
|
3316
|
+
}
|
|
3317
|
+
});
|
|
3318
|
+
```
|
|
3319
|
+
|
|
3320
|
+
**Commit:**
|
|
3321
|
+
```bash
|
|
3322
|
+
git add tests/model-routing.test.js
|
|
3323
|
+
git commit -m "test(v2-models): add hardening tests — Gemini header auth, SSRF, cost preflight, line-band synthesis"
|
|
3324
|
+
```
|
|
3325
|
+
|
|
3326
|
+
---
|
|
3327
|
+
|
|
3328
|
+
## HARDEN 8 — Final pre-merge verification
|
|
3329
|
+
|
|
3330
|
+
```bash
|
|
3331
|
+
#!/usr/bin/env bash
|
|
3332
|
+
echo "MindForge v2 Day 10 — Pre-Merge Verification"
|
|
3333
|
+
echo "══════════════════════════════════════════════"
|
|
3334
|
+
PASS=true
|
|
3335
|
+
|
|
3336
|
+
V=$(node -e "console.log(require('./package.json').version)")
|
|
3337
|
+
[[ "${V}" == "2.0.0-alpha.3" ]] && echo " Version: ${V} ✅" || { echo " ❌ ${V}"; PASS=false; }
|
|
3338
|
+
|
|
3339
|
+
echo ""
|
|
3340
|
+
FAIL=0
|
|
3341
|
+
for s in install wave-engine audit compaction skills-platform \
|
|
3342
|
+
integrations governance intelligence metrics \
|
|
3343
|
+
distribution ci-mode sdk production migration e2e \
|
|
3344
|
+
autonomous browser model-routing; do
|
|
3345
|
+
printf " %-30s" "${s}..."
|
|
3346
|
+
node tests/${s}.test.js 2>&1 | tail -1 | grep -q "passed" && echo "✅" || { echo "❌"; ((FAIL++)); PASS=false; }
|
|
3347
|
+
done
|
|
3348
|
+
|
|
3349
|
+
CMDS=$(ls .claude/commands/mindforge/ | wc -l | tr -d ' ')
|
|
3350
|
+
[ "$CMDS" -ge 43 ] && echo " Commands: ${CMDS} ✅" || { echo " ❌ Commands: ${CMDS}"; PASS=false; }
|
|
3351
|
+
|
|
3352
|
+
ADRS=$(ls .planning/decisions/ADR-*.md 2>/dev/null | wc -l | tr -d ' ')
|
|
3353
|
+
[ "$ADRS" -ge 29 ] && echo " ADRs: ${ADRS} ✅" || { echo " ❌ ADRs: ${ADRS}"; PASS=false; }
|
|
3354
|
+
|
|
3355
|
+
# No API keys in source
|
|
3356
|
+
KEYS=$(grep -rE "(sk-[a-zA-Z0-9]{20,}|AKIA[A-Z0-9]{16}|AIza[a-zA-Z0-9_-]{35})" \
|
|
3357
|
+
--include="*.js" --include="*.ts" --exclude-dir=node_modules . 2>/dev/null | \
|
|
3358
|
+
grep -v "example\|TEST_ONLY\|REDACTED" || true)
|
|
3359
|
+
[ -z "$KEYS" ] && echo " API keys: clean ✅" || { echo " ❌ API keys in source"; PASS=false; }
|
|
3360
|
+
|
|
3361
|
+
# Gemini key NOT in URL
|
|
3362
|
+
grep -r "?key=\${" bin/models/ 2>/dev/null && { echo " ❌ Gemini key in URL"; PASS=false; } || echo " Gemini header auth ✅"
|
|
3363
|
+
|
|
3364
|
+
echo ""
|
|
3365
|
+
$PASS && echo "✅ ALL CHECKS PASSED — Day 10 complete" || { echo "❌ FAILURES"; exit 1; }
|
|
3366
|
+
```
|
|
3367
|
+
|
|
3368
|
+
**Final commit:**
|
|
3369
|
+
```bash
|
|
3370
|
+
git add .
|
|
3371
|
+
git commit -m "harden(v2-day10): complete all hardening — SSRF, Gemini auth, cost preflight, synthesis fix"
|
|
3372
|
+
git push origin feat/mindforge-v2-cross-model-review
|
|
3373
|
+
```
|
|
3374
|
+
|
|
3375
|
+
---
|
|
3376
|
+
|
|
3377
|
+
## DAY 10 COMPLETE
|
|
3378
|
+
|
|
3379
|
+
| Component | Status |
|
|
3380
|
+
|---|---|
|
|
3381
|
+
| Model registry (7 models, 3 providers) | ✅ |
|
|
3382
|
+
| Model router (persona→model, Tier 3 override, MINDFORGE.md overrides) | ✅ |
|
|
3383
|
+
| Anthropic provider (Messages API + cost calculation) | ✅ |
|
|
3384
|
+
| OpenAI provider (Chat Completions + cost calculation) | ✅ |
|
|
3385
|
+
| Gemini provider (generateContent + header auth) | ✅ |
|
|
3386
|
+
| Model client (unified, fallback chains, transparency notices) | ✅ |
|
|
3387
|
+
| Cost tracker (preflight check, cached daily spend, JSONL) | ✅ |
|
|
3388
|
+
| Cross-review engine (2-3 model pipeline, adversarial prompt) | ✅ |
|
|
3389
|
+
| Finding synthesizer (consensus, model-specific, contradictions, line-band) | ✅ |
|
|
3390
|
+
| Review report writer (CROSS-REVIEW-[N].md) | ✅ |
|
|
3391
|
+
| Research engine (Gemini 1M, SSRF protection, URL+local context) | ✅ |
|
|
3392
|
+
| Research agent persona | ✅ |
|
|
3393
|
+
| `/mindforge:cross-review` command (43rd) | ✅ |
|
|
3394
|
+
| `/mindforge:research` command (43rd) | ✅ |
|
|
3395
|
+
| `/mindforge:costs` command (43rd) | ✅ |
|
|
3396
|
+
| `tests/model-routing.test.js` (18th suite) | ✅ |
|
|
3397
|
+
| ADR-027, ADR-028, ADR-029 | ✅ |
|
|
3398
|
+
| CHANGELOG v2.0.0-alpha.3 | ✅ |
|
|
3399
|
+
|
|
3400
|
+
**MindForge v2.0.0-alpha.3: 43 commands · 18 test suites · 29 ADRs**
|
|
3401
|
+
**Branch:** `feat/mindforge-v2-cross-model-review`
|
|
3402
|
+
**Day 10 complete. Open PR → merge → start Day 11 (Persistent Memory)**
|