| 211 | } |
| 212 | |
| 213 | function compactConsoleSummary(consoleState) { |
| 214 | const artifacts = consoleState.dashboard.artifacts; |
| 215 | const staleArtifacts = [ |
| 216 | artifacts.nextActionReport, |
| 217 | artifacts.approvalCapsule, |
| 218 | ].filter((artifact) => artifact && artifact.stale); |
| 219 | const historicalStaleArtifacts = staleArtifacts.filter((artifact) => ( |
| 220 | artifact.path === '.planning/approval-capsules/latest.md' && |
| 221 | (artifact.staleReasons || []).includes('no current repair or approval boundary is queued') |
| 222 | )); |
| 223 | |
| 224 | return { |
| 225 | status: consoleState.status, |
| 226 | mode: consoleState.mode, |
| 227 | command: consoleState.nextAction.command, |
| 228 | label: consoleState.nextAction.label, |
| 229 | canRunNow: consoleState.nextAction.canRunNow, |
| 230 | boundary: consoleState.boundary.kind, |
| 231 | risk: consoleState.boundary.risk, |
| 232 | pending: consoleState.dashboard.pending, |
| 233 | gitDirty: consoleState.dashboard.git.dirty, |
| 234 | changedFiles: consoleState.dashboard.git.changedFiles, |
| 235 | artifactsStale: staleArtifacts.length, |
| 236 | artifactsNeedAttention: staleArtifacts.length - historicalStaleArtifacts.length, |
| 237 | historicalArtifactsStale: historicalStaleArtifacts.length, |
| 238 | stackStatus: consoleState.stack?.status || 'unknown', |
| 239 | stackPrs: consoleState.stack?.prCount || 0, |
| 240 | stackBlocked: consoleState.stack?.blockedCount || 0, |
| 241 | stackReportPath: consoleState.stack?.reportPath || null, |
| 242 | stackApprovalCapsulePath: consoleState.stack?.approvalCapsulePath || null, |
| 243 | latestStackApprovalCapsulePath: consoleState.stack?.latestApprovalCapsulePath || null, |
| 244 | verificationProfile: consoleState.verificationProfile.id, |
| 245 | primaryVerification: consoleState.verificationProfile.primaryCommand, |
| 246 | reportPath: consoleState.reportPath || null, |
| 247 | nextReportPath: consoleState.decision.reportPath || null, |
| 248 | approvalCapsulePath: consoleState.decision.approvalCapsule?.path || null, |
| 249 | latestApprovalCapsulePath: consoleState.decision.approvalCapsule ? '.planning/approval-capsules/latest.md' : null, |
| 250 | }; |
| 251 | } |
| 252 | |
| 253 | function writeConsoleReport(projectRoot, consoleState) { |
| 254 | const outDir = path.join(projectRoot, '.planning', 'operator-console'); |