From 46172b46b27f5201c3334b15976ece663b89f9ef Mon Sep 17 00:00:00 2001 From: Genie Date: Fri, 1 May 2026 14:37:11 -0300 Subject: [PATCH] feat(doctor): add `Pgserve (canonical backbone)` section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirrors `omni doctor`'s `pgserve-canonical` check on the genie side so operators see the same shared-backbone visibility from both halves of the canonical-stack. Surfaces three signals: ✓ pgserve binary canonical port 8432 ✓ pgserve under pm2 online — shared backbone for genie-serve + omni-api …or, when something is off: ! pgserve binary not on PATH (or `pgserve port` failed) Install canonical pgserve: bun add -g pgserve@^2.1.0 ! pgserve under pm2 binary present but not registered under pm2 Register canonical pgserve: pgserve install Probes ------ - Binary detection via `pgserve port` (NOT `--version` — that flag doesn't exist in pgserve@^2.1.0 and false-negatived in historical doctor implementations; same lesson surfaced in `omni doctor --fix` on 2026-04-30). - Pm2 registration + online status via `pgserve status --json`. Severity -------- Both checks are WARN, never FAIL. Genie can auto-spawn its own daemon as a fallback for fingerprint-routed CLI commands, so a missing canonical pgserve doesn't break local development — it just means genie isn't sharing the backbone with omni and other automagik services on this host. Tests ----- Live-validated on canonical-pgserve-running host: both checks PASS, section renders cleanly, exit-code unchanged. --- src/genie-commands/doctor.ts | 92 ++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/src/genie-commands/doctor.ts b/src/genie-commands/doctor.ts index af567fa54..d94d58d71 100644 --- a/src/genie-commands/doctor.ts +++ b/src/genie-commands/doctor.ts @@ -712,6 +712,97 @@ export function checkLegacyAgentFrontmatter(workspaceRoot?: string): CheckResult return results; } +/** + * Check canonical pgserve state — whether the pgserve binary is on PATH, + * registered under pm2, and listening on the canonical port. Mirrors omni + * doctor's `pgserve-canonical` check so both halves of the canonical-stack + * surface the same shared-backbone visibility. + * + * Three outcomes: + * - pgserve missing → WARN with install hint (not FAIL because genie can + * auto-spawn its own daemon as a fallback for fingerprint-routed CLI). + * - pgserve installed but not under pm2 → WARN pointing at `pgserve install`. + * - pgserve registered + reachable → PASS, surface the canonical URL so + * operators can verify what genie-serve / omni-api are connecting to. + */ +async function checkPgserveCanonical(): Promise { + const results: CheckResult[] = []; + + // Step 1: pgserve binary on PATH? Probe via `pgserve port` (NOT --version + // — that flag doesn't exist in pgserve@^2.1.0 and false-negatived in + // historical doctor implementations). + let canonicalPort: number | null = null; + try { + const out = execFileSync('pgserve', ['port'], { + encoding: 'utf8', + timeout: 3000, + stdio: ['ignore', 'pipe', 'ignore'], + }); + const parsed = Number.parseInt(out.trim(), 10); + if (Number.isFinite(parsed) && parsed > 0 && parsed <= 65535) { + canonicalPort = parsed; + } + } catch { + /* pgserve binary missing or non-zero exit — handled below */ + } + + if (canonicalPort === null) { + results.push({ + name: 'pgserve binary', + status: 'warn', + message: 'not on PATH (or `pgserve port` failed)', + suggestion: + 'Install canonical pgserve: bun add -g pgserve@^2.1.0 (then run `pgserve install` to register under pm2)', + }); + return results; + } + results.push({ + name: 'pgserve binary', + status: 'pass', + message: `canonical port ${canonicalPort}`, + }); + + // Step 2: pm2-supervised? Check via `pgserve status --json`. + try { + const status = execFileSync('pgserve', ['status', '--json'], { + encoding: 'utf8', + timeout: 3000, + stdio: ['ignore', 'pipe', 'ignore'], + }); + const parsed = JSON.parse(status) as { installed?: boolean; status?: string }; + if (parsed.installed === true && parsed.status === 'online') { + results.push({ + name: 'pgserve under pm2', + status: 'pass', + message: `online — shared backbone for genie-serve + omni-api on :${canonicalPort}`, + }); + } else if (parsed.installed === true) { + results.push({ + name: 'pgserve under pm2', + status: 'warn', + message: `registered but status=${parsed.status ?? 'unknown'}`, + suggestion: 'Recover with: pm2 restart pgserve (logs: ~/.pgserve/logs/)', + }); + } else { + results.push({ + name: 'pgserve under pm2', + status: 'warn', + message: 'binary present but not registered under pm2', + suggestion: 'Register canonical pgserve: pgserve install', + }); + } + } catch { + results.push({ + name: 'pgserve under pm2', + status: 'warn', + message: '`pgserve status` failed (pm2 unreachable?)', + suggestion: 'Verify pm2: pm2 list | Re-register: pgserve install', + }); + } + + return results; +} + /** * Main doctor command */ @@ -765,6 +856,7 @@ export async function doctorCommand(options?: { runCheckSection('Tmux', await checkTmux(), counts); runCheckSection('Tmux Configs', checkTmuxConfigs(), counts); runCheckSection('Worker Profiles', await checkWorkerProfiles(), counts); + runCheckSection('Pgserve (canonical backbone)', await checkPgserveCanonical(), counts); runCheckSection('Omni Bridge', await checkBridge(), counts); runCheckSection('Agent Config', checkLegacyAgentFrontmatter(), counts); runCheckSection('Genie Specialist', checkGenieAgentTemplate(), counts);