Fix worktree runtime isolation recovery

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
dotta 2026-03-26 10:36:49 -05:00
parent c74cda1851
commit ab82e3f022
8 changed files with 715 additions and 2 deletions

View file

@ -30,6 +30,7 @@ import { heartbeatService, reconcilePersistedRuntimeServicesOnStartup, routineSe
import { createStorageServiceFromConfig } from "./storage/index.js";
import { printStartupBanner } from "./startup-banner.js";
import { getBoardClaimWarningUrl, initializeBoardClaimChallenge } from "./board-claim.js";
import { maybePersistWorktreeRuntimePorts } from "./worktree-config.js";
type BetterAuthSessionUser = {
id: string;
@ -69,7 +70,7 @@ export interface StartedServer {
}
export async function startServer(): Promise<StartedServer> {
const config = loadConfig();
let config = loadConfig();
if (process.env.PAPERCLIP_SECRETS_PROVIDER === undefined) {
process.env.PAPERCLIP_SECRETS_PROVIDER = config.secretsProvider;
}
@ -167,6 +168,18 @@ export async function startServer(): Promise<StartedServer> {
const normalized = host.trim().toLowerCase();
return normalized === "127.0.0.1" || normalized === "localhost" || normalized === "::1";
}
function rewriteLocalUrlPort(rawUrl: string | undefined, port: number): string | undefined {
if (!rawUrl) return undefined;
try {
const parsed = new URL(rawUrl);
if (!isLoopbackHost(parsed.hostname)) return rawUrl;
parsed.port = String(port);
return parsed.toString();
} catch {
return rawUrl;
}
}
const LOCAL_BOARD_USER_ID = "local-board";
const LOCAL_BOARD_USER_EMAIL = "local@paperclip.local";
@ -233,6 +246,7 @@ export async function startServer(): Promise<StartedServer> {
let embeddedPostgresStartedByThisProcess = false;
let migrationSummary: MigrationSummary = "skipped";
let activeDatabaseConnectionString: string;
let resolvedEmbeddedPostgresPort: number | null = null;
let startupDbInfo:
| { mode: "external-postgres"; connectionString: string }
| { mode: "embedded-postgres"; dataDir: string; port: number };
@ -395,6 +409,7 @@ export async function startServer(): Promise<StartedServer> {
db = createDb(embeddedConnectionString);
logger.info("Embedded PostgreSQL ready");
activeDatabaseConnectionString = embeddedConnectionString;
resolvedEmbeddedPostgresPort = port;
startupDbInfo = { mode: "embedded-postgres", dataDir, port };
}
@ -476,6 +491,19 @@ export async function startServer(): Promise<StartedServer> {
}
const listenPort = await detectPort(config.port);
if (listenPort !== config.port) {
config.port = listenPort;
}
if (resolvedEmbeddedPostgresPort !== null && resolvedEmbeddedPostgresPort !== config.embeddedPostgresPort) {
config.embeddedPostgresPort = resolvedEmbeddedPostgresPort;
}
if (config.authBaseUrlMode === "explicit" && config.authPublicBaseUrl) {
config.authPublicBaseUrl = rewriteLocalUrlPort(config.authPublicBaseUrl, listenPort);
}
maybePersistWorktreeRuntimePorts({
serverPort: listenPort,
databasePort: resolvedEmbeddedPostgresPort,
});
const uiMode = config.uiDevMiddleware ? "vite-dev" : config.serveUi ? "static" : "none";
const storageService = createStorageServiceFromConfig(config);
const app = await createApp(db as any, {