* Called after every run_tests completes. Attempts automatic phase * transitions and returns a summary string to inject into the conversation, * or null if no transition occurred. * * @param {object} testResult - Structured result from run_tests * @returns {string|null}
(testResult)
| 44 | * @returns {string|null} |
| 45 | */ |
| 46 | processTestResult(testResult) { |
| 47 | const phase = this._state.phase; |
| 48 | |
| 49 | // ── RED phase ────────────────────────────────────────────────────────── |
| 50 | if (phase === 'red') { |
| 51 | if (!this._state.redConfirmed) { |
| 52 | const r = this._state.confirmRed(testResult); |
| 53 | return r.message; |
| 54 | } |
| 55 | // Red confirmed — check if target is now passing (impl written) |
| 56 | if (testResult && testResult.exitCode === 0 && testResult.failed === 0 && testResult.passed > 0) { |
| 57 | const r = this._state.advanceToGreen(testResult); |
| 58 | return r.message; |
| 59 | } |
| 60 | return null; |
| 61 | } |
| 62 | |
| 63 | // ── REFACTOR phase ───────────────────────────────────────────────────── |
| 64 | if (phase === 'refactor') { |
| 65 | if (testResult && testResult.failed === 0 && testResult.errors === 0 && testResult.passed > 0) { |
| 66 | const r = this._state.completeCycle(testResult); |
| 67 | return r.message; |
| 68 | } |
| 69 | return null; |
| 70 | } |
| 71 | |
| 72 | // ── IDLE phase with active loop ──────────────────────────────────────── |
| 73 | // When all requirements are done and a clean suite runs, the loop completes. |
| 74 | if (phase === 'idle' && this._state.loopActive) { |
| 75 | if (this._state.allRequirementsDone()) { |
| 76 | const isClean = testResult && testResult.failed === 0 && testResult.errors === 0 && testResult.passed > 0; |
| 77 | if (isClean) { |
| 78 | this._state.markRegressionClean(); |
| 79 | const done = this._state.requirements.length; |
| 80 | const checklist = this._state.requirements |
| 81 | .map(r => ` ✓ ${r.id}: ${r.text}`) |
| 82 | .join('\n'); |
| 83 | return `[TDD LOOP COMPLETE] All ${done} requirement(s) fulfilled and full suite is clean.\n${checklist}`; |
| 84 | } |
| 85 | return '[TDD LOOP] All requirements are green. Run run_tests (full suite, no filter) to confirm no regressions and complete the loop.'; |
| 86 | } |
| 87 | // There is an active or pending requirement waiting to be worked on |
| 88 | const next = this._state.activeRequirement() || this._state.pendingRequirements()[0]; |
| 89 | if (next) { |
| 90 | const done = this._state.doneRequirements().length; |
| 91 | const total = this._state.requirements.length; |
| 92 | return `[TDD LOOP] ${done}/${total} done. Next requirement: "${next.text}" (${next.id}). Write a failing test for it, then call tdd_begin_cycle.`; |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | return null; |
| 97 | } |
| 98 | |
| 99 | /** |
| 100 | * Returns the current phase prompt to inject into the system context. |