true, 'ts' => date('c'), 'window_min' => $WINDOW_MIN, 'recent_commits' => [], 'other_opus_commits' => [], 'playwright_latest' => [], 'conflicts' => [], 'advice' => [] ]; // Recent commits (last N minutes) $since = date('Y-m-d\TH:i:s', time() - $WINDOW_MIN * 60); $cmd = "cd $REPO && git log --since=\"$since\" --pretty=format:'%h|%an|%at|%s' 2>&1 | head -30"; $logs = @shell_exec($cmd); if ($logs) { foreach (explode("\n", trim($logs)) as $line) { if (!$line) continue; $parts = explode('|', $line, 4); if (count($parts) < 4) continue; $c = [ 'hash' => $parts[0], 'author' => $parts[1], 'ts' => date('c', (int)$parts[2]), 'subject' => $parts[3] ]; $out['recent_commits'][] = $c; // Flag commits from other Opus (contains "Opus" or starts with version-like) if (preg_match('/\b(Opus|opus|V\d+|D9\d|B\d+|autre)/', $parts[3]) && !preg_match('/^auto-(sync|commit)/', $parts[3])) { $out['other_opus_commits'][] = $c; } } } // Playwright latest results foreach (['playwright-dsh-predict-latest.json', 'playwright-latest-e2e.json'] as $f) { $p = "$REPO/api/$f"; if (is_file($p)) { $d = @json_decode(@file_get_contents($p), true); if (is_array($d)) { $pages = $d['pages'] ?? []; $out['playwright_latest'][$f] = [ 'ts' => $d['ts'] ?? '?', 'total_pages' => count($pages), 'pass' => count(array_filter($pages, fn($p)=>($p['status']??'')==='PASS')), 'fail' => count(array_filter($pages, fn($p)=>($p['status']??'')==='FAIL')) ]; } } } // Detect potential conflicts: files modified by multiple recent commits $conflictCmd = "cd $REPO && git log --since=\"$since\" --name-only --pretty=format:'' 2>&1 | grep -v '^$' | sort | uniq -c | sort -rn | head -10"; $conflictOut = @shell_exec($conflictCmd); if ($conflictOut) { foreach (explode("\n", trim($conflictOut)) as $line) { $line = trim($line); if (!$line) continue; if (preg_match('/^(\d+)\s+(.+)$/', $line, $m)) { $count = (int)$m[1]; $file = $m[2]; if ($count >= 2) { $out['conflicts'][] = ['file' => $file, 'modification_count' => $count]; } } } } // Advice if (count($out['other_opus_commits']) > 0) { $out['advice'][] = count($out['other_opus_commits']) . " other Opus commit(s) in last {$WINDOW_MIN}min - pull before new work"; } if (count($out['conflicts']) > 0) { $out['advice'][] = "Files modified by multiple commits: review to avoid doublons"; } $pending_stubs = @glob('/var/www/html/api/wired-pending/intent-opus4-*.php'); $out['pending_stubs_count'] = count($pending_stubs ?: []); if (count($pending_stubs ?: []) > 120) { $out['advice'][] = "Pending stubs = " . count($pending_stubs) . " (hig) - consider approving or purging"; } if (empty($out['advice'])) { $out['advice'][] = "No conflicts detected - safe to commit"; } echo json_encode($out, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);