feat: add long-running session support and process management

- Add buffer management for 12-24+ hour sessions
- Terminal buffer: 5MB max with auto-trim to 4MB
- Text output: 2MB max with auto-trim to 1.5MB
- Messages: 1000 max, keeps recent 800

- Add DELETE /api/sessions endpoint to kill all sessions
- Enhanced session.stop() with SIGKILL fallback
- Kill process groups to terminate child processes
- Clean up respawn controller on session delete

- Add terminal batching at 60fps for performance
- Add bufferStats to session details for monitoring

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
arkon
2026-01-18 21:36:03 +01:00
co-authored by Claude Opus 4.5
parent c81d014ec1
commit 4712af433c
3 changed files with 479 additions and 94 deletions
+110 -1
View File
@@ -92,6 +92,115 @@ export interface TaskAssignment {
assignedAt: number;
}
// Error codes for consistent error handling
export enum ApiErrorCode {
NOT_FOUND = 'NOT_FOUND',
INVALID_INPUT = 'INVALID_INPUT',
SESSION_BUSY = 'SESSION_BUSY',
OPERATION_FAILED = 'OPERATION_FAILED',
ALREADY_EXISTS = 'ALREADY_EXISTS',
INTERNAL_ERROR = 'INTERNAL_ERROR',
}
// Mapping of error codes to user-friendly messages
export const ErrorMessages: Record<ApiErrorCode, string> = {
[ApiErrorCode.NOT_FOUND]: 'The requested resource was not found',
[ApiErrorCode.INVALID_INPUT]: 'Invalid input provided',
[ApiErrorCode.SESSION_BUSY]: 'Session is currently busy',
[ApiErrorCode.OPERATION_FAILED]: 'The operation failed',
[ApiErrorCode.ALREADY_EXISTS]: 'Resource already exists',
[ApiErrorCode.INTERNAL_ERROR]: 'An internal error occurred',
};
// API Request/Response types for type safety
export interface CreateSessionRequest {
workingDir?: string;
}
export interface RunPromptRequest {
prompt: string;
}
export interface SessionInputRequest {
input: string;
}
export interface ResizeRequest {
cols: number;
rows: number;
}
export interface CreateCaseRequest {
name: string;
description?: string;
}
export interface QuickStartRequest {
caseName?: string;
}
export interface CreateScheduledRunRequest {
prompt: string;
workingDir?: string;
durationMinutes: number;
}
export interface QuickRunRequest {
prompt: string;
workingDir?: string;
}
export interface ApiResponse<T = unknown> {
success: boolean;
error?: string;
errorCode?: ApiErrorCode;
data?: T;
}
// Helper functions for creating consistent error responses
export function createErrorResponse(code: ApiErrorCode, details?: string): ApiResponse {
return {
success: false,
error: details || ErrorMessages[code],
errorCode: code,
};
}
export function createSuccessResponse<T>(data?: T): ApiResponse<T> {
return {
success: true,
data,
};
}
export interface SessionResponse {
success: boolean;
session?: SessionState & {
claudeSessionId: string | null;
totalCost: number;
textOutput: string;
terminalBuffer: string;
messageCount: number;
isWorking: boolean;
lastPromptTime: number;
};
error?: string;
}
export interface QuickStartResponse {
success: boolean;
sessionId?: string;
casePath?: string;
caseName?: string;
error?: string;
}
export interface CaseInfo {
name: string;
path: string;
hasClaudeMd?: boolean;
}
export const DEFAULT_CONFIG: AppConfig = {
pollIntervalMs: 1000,
defaultTimeoutMs: 300000, // 5 minutes
@@ -101,7 +210,7 @@ export const DEFAULT_CONFIG: AppConfig = {
idleTimeoutMs: 5000, // 5 seconds of no activity after prompt
updatePrompt: 'update all the docs and CLAUDE.md',
interStepDelayMs: 1000, // 1 second between steps
enabled: true,
enabled: false, // disabled by default
},
};