From 083877d2867e8ef791a6a54167fcc922dd9fcc2a Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Fri, 9 Jan 2026 17:50:19 +0100 Subject: [PATCH] fix: audit doctor service entrypoint --- package.json | 1 + src/commands/doctor-gateway-services.ts | 76 +++++++++++++++++-------- src/daemon/service-audit.ts | 1 + 3 files changed, 54 insertions(+), 24 deletions(-) diff --git a/package.json b/package.json index 50cb8758f..76f42406a 100644 --- a/package.json +++ b/package.json @@ -80,6 +80,7 @@ "test:e2e": "vitest run --config vitest.e2e.config.ts", "test:live": "vitest run --config vitest.live.config.ts", "test:docker:qr": "bash scripts/e2e/qr-import-docker.sh", + "test:docker:doctor-switch": "bash scripts/e2e/doctor-install-switch-docker.sh", "protocol:gen": "tsx scripts/protocol-gen.ts", "protocol:gen:swift": "tsx scripts/protocol-gen-swift.ts", "protocol:check": "pnpm protocol:gen && pnpm protocol:gen:swift && git diff --exit-code -- dist/protocol.schema.json apps/macos/Sources/ClawdbotProtocol/GatewayModels.swift", diff --git a/src/commands/doctor-gateway-services.ts b/src/commands/doctor-gateway-services.ts index a12e1151c..e32f4f2e2 100644 --- a/src/commands/doctor-gateway-services.ts +++ b/src/commands/doctor-gateway-services.ts @@ -22,6 +22,7 @@ import { resolveGatewayService } from "../daemon/service.js"; import { auditGatewayServiceConfig, needsNodeRuntimeMigration, + SERVICE_AUDIT_CODES, } from "../daemon/service-audit.js"; import { buildServiceEnvironment } from "../daemon/service-env.js"; import type { RuntimeEnv } from "../runtime.js"; @@ -48,6 +49,17 @@ function detectGatewayRuntime( return DEFAULT_GATEWAY_DAEMON_RUNTIME; } +function findGatewayEntrypoint(programArguments?: string[]): string | null { + if (!programArguments || programArguments.length === 0) return null; + const gatewayIndex = programArguments.indexOf("gateway"); + if (gatewayIndex <= 0) return null; + return programArguments[gatewayIndex - 1] ?? null; +} + +function normalizeExecutablePath(value: string): string { + return path.resolve(value); +} + export async function maybeMigrateLegacyGatewayService( cfg: ClawdbotConfig, mode: "local" | "remote", @@ -171,6 +183,46 @@ export async function maybeRepairGatewayServiceConfig( env: process.env, command, }); + const needsNodeRuntime = needsNodeRuntimeMigration(audit.issues); + const systemNodePath = needsNodeRuntime + ? await resolveSystemNodePath(process.env) + : null; + if (needsNodeRuntime && !systemNodePath) { + note( + "System Node 22+ not found. Install via Homebrew/apt/choco and rerun doctor to migrate off Bun/version managers.", + "Gateway runtime", + ); + } + + const devMode = + process.argv[1]?.includes(`${path.sep}src${path.sep}`) && + process.argv[1]?.endsWith(".ts"); + const port = resolveGatewayPort(cfg, process.env); + const runtimeChoice = detectGatewayRuntime(command.programArguments); + const { programArguments, workingDirectory } = + await resolveGatewayProgramArguments({ + port, + dev: devMode, + runtime: needsNodeRuntime && systemNodePath ? "node" : runtimeChoice, + nodePath: systemNodePath ?? undefined, + }); + const expectedEntrypoint = findGatewayEntrypoint(programArguments); + const currentEntrypoint = findGatewayEntrypoint(command.programArguments); + if ( + expectedEntrypoint && + currentEntrypoint && + normalizeExecutablePath(expectedEntrypoint) !== + normalizeExecutablePath(currentEntrypoint) + ) { + audit.issues.push({ + code: SERVICE_AUDIT_CODES.gatewayEntrypointMismatch, + message: + "Gateway service entrypoint does not match the current install.", + detail: `${currentEntrypoint} -> ${expectedEntrypoint}`, + level: "recommended", + }); + } + if (audit.issues.length === 0) return; note( @@ -207,30 +259,6 @@ export async function maybeRepairGatewayServiceConfig( initialValue: true, }); if (!repair) return; - - const needsNodeRuntime = needsNodeRuntimeMigration(audit.issues); - const systemNodePath = needsNodeRuntime - ? await resolveSystemNodePath(process.env) - : null; - if (needsNodeRuntime && !systemNodePath) { - note( - "System Node 22+ not found. Install via Homebrew/apt/choco and rerun doctor to migrate off Bun/version managers.", - "Gateway runtime", - ); - } - - const devMode = - process.argv[1]?.includes(`${path.sep}src${path.sep}`) && - process.argv[1]?.endsWith(".ts"); - const port = resolveGatewayPort(cfg, process.env); - const runtimeChoice = detectGatewayRuntime(command.programArguments); - const { programArguments, workingDirectory } = - await resolveGatewayProgramArguments({ - port, - dev: devMode, - runtime: needsNodeRuntime && systemNodePath ? "node" : runtimeChoice, - nodePath: systemNodePath ?? undefined, - }); const environment = buildServiceEnvironment({ env: process.env, port, diff --git a/src/daemon/service-audit.ts b/src/daemon/service-audit.ts index cf40e758e..ff9e8405b 100644 --- a/src/daemon/service-audit.ts +++ b/src/daemon/service-audit.ts @@ -30,6 +30,7 @@ export type ServiceConfigAudit = { export const SERVICE_AUDIT_CODES = { gatewayCommandMissing: "gateway-command-missing", + gatewayEntrypointMismatch: "gateway-entrypoint-mismatch", gatewayPathMissing: "gateway-path-missing", gatewayPathMissingDirs: "gateway-path-missing-dirs", gatewayPathNonMinimal: "gateway-path-nonminimal",