refactor: extract server.ts routes into domain modules (phase 3)

Split 6,710-line server.ts into focused route modules using port
interfaces for dependency injection. 107/109 routes extracted into
12 domain files with auth middleware, 5 port interfaces, and shared
helpers. Server.ts retains orchestration (SSE, lifecycle, state).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
arkon
2026-02-28 19:12:45 +01:00
co-authored by Claude Opus 4.6
parent e0a2774d37
commit e05d507254
23 changed files with 4606 additions and 4153 deletions
+22
View File
@@ -0,0 +1,22 @@
/**
* @fileoverview Config port — capabilities for app configuration and settings.
* Route modules that read or modify configuration depend on this port.
*/
import type { ClaudeMode, NiceConfig } from '../../types.js';
import type { StateStore } from '../../state-store.js';
export interface ConfigPort {
readonly store: StateStore;
readonly port: number;
readonly https: boolean;
readonly testMode: boolean;
readonly serverStartTime: number;
getGlobalNiceConfig(): Promise<NiceConfig | undefined>;
getModelConfig(): Promise<{ defaultModel?: string; agentTypeOverrides?: Record<string, string> } | null>;
getClaudeModeConfig(): Promise<{ claudeMode?: ClaudeMode; allowedTools?: string }>;
getDefaultClaudeMdPath(): Promise<string | undefined>;
getLightState(): unknown;
startTranscriptWatcher(sessionId: string, transcriptPath: string): void;
stopTranscriptWatcher(sessionId: string): void;
}
+14
View File
@@ -0,0 +1,14 @@
/**
* @fileoverview Event port — capabilities for broadcasting events to SSE clients.
* Route modules that need to notify the frontend depend on this port.
*/
import type { BackgroundTask } from '../../session.js';
export interface EventPort {
broadcast(event: string, data: unknown): void;
sendPushNotifications(event: string, data: Record<string, unknown>): void;
batchTerminalData(sessionId: string, data: string): void;
broadcastSessionStateDebounced(sessionId: string): void;
batchTaskUpdate(sessionId: string, task: BackgroundTask): void;
}
+13
View File
@@ -0,0 +1,13 @@
/**
* @fileoverview Barrel export for all port interfaces.
*
* Ports define the capabilities that route modules can depend on.
* WebServer implements all ports; route modules declare only what they need
* via TypeScript intersection types (e.g., SessionPort & EventPort).
*/
export type { SessionPort } from './session-port.js';
export type { EventPort } from './event-port.js';
export type { RespawnPort } from './respawn-port.js';
export type { ConfigPort } from './config-port.js';
export type { InfraPort, ScheduledRun } from './infra-port.js';
+38
View File
@@ -0,0 +1,38 @@
/**
* @fileoverview Infra port — capabilities for infrastructure services.
* Route modules that interact with mux, push, teams, tunnel, etc. depend on this port.
*/
import type { TerminalMultiplexer } from '../../mux-interface.js';
import type { RunSummaryTracker } from '../../run-summary.js';
import type { PlanOrchestrator } from '../../plan-orchestrator.js';
import type { TeamWatcher } from '../../team-watcher.js';
import type { TunnelManager } from '../../tunnel-manager.js';
import type { PushSubscriptionStore } from '../../push-store.js';
/** A scheduled autonomous run with session lifecycle management */
export interface ScheduledRun {
id: string;
prompt: string;
workingDir: string;
durationMinutes: number;
startedAt: number;
endAt: number;
status: 'running' | 'completed' | 'failed' | 'stopped';
sessionId: string | null;
completedTasks: number;
totalCost: number;
logs: string[];
}
export interface InfraPort {
readonly mux: TerminalMultiplexer;
readonly runSummaryTrackers: Map<string, RunSummaryTracker>;
readonly activePlanOrchestrators: Map<string, PlanOrchestrator>;
readonly scheduledRuns: Map<string, ScheduledRun>;
readonly teamWatcher: TeamWatcher;
readonly tunnelManager: TunnelManager;
readonly pushStore: PushSubscriptionStore;
startScheduledRun(prompt: string, workingDir: string, durationMinutes: number): Promise<ScheduledRun>;
stopScheduledRun(id: string): Promise<void>;
}
+17
View File
@@ -0,0 +1,17 @@
/**
* @fileoverview Respawn port — capabilities for respawn controller management.
* Route modules that control respawn cycling depend on this port.
*/
import type { Session } from '../../session.js';
import type { RespawnController, RespawnConfig } from '../../respawn-controller.js';
import type { PersistedRespawnConfig } from '../../types.js';
export interface RespawnPort {
readonly respawnControllers: Map<string, RespawnController>;
readonly respawnTimers: Map<string, { timer: NodeJS.Timeout; endAt: number; startedAt: number }>;
setupRespawnListeners(sessionId: string, controller: RespawnController): void;
setupTimedRespawn(sessionId: string, durationMinutes: number): void;
restoreRespawnController(session: Session, config: PersistedRespawnConfig, source: string): void;
saveRespawnConfig(sessionId: string, config: RespawnConfig, durationMinutes?: number): void;
}
+15
View File
@@ -0,0 +1,15 @@
/**
* @fileoverview Session port — capabilities for session lifecycle management.
* Route modules that manage sessions depend on this port.
*/
import type { Session } from '../../session.js';
export interface SessionPort {
readonly sessions: ReadonlyMap<string, Session>;
cleanupSession(sessionId: string, killMux?: boolean, reason?: string): Promise<void>;
setupSessionListeners(session: Session): Promise<void>;
persistSessionState(session: Session): void;
persistSessionStateNow(session: Session): void;
getSessionStateWithRespawn(session: Session): unknown;
}