mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-05 15:09:42 +02:00
feat: add CPU limiting and Ralph Loop wizard plan generation
CPU Limiting: - Add CpuLimitConfig type and settings in App Settings - Use nice command for process priority (-20 to 19) - Optional cpulimit integration for hard CPU limits (if installed) - Applied to new sessions via screen-manager and session modules Ralph Loop Wizard: - 3-step wizard: Describe → Plan → Launch - New /api/generate-plan endpoint generates implementation steps via Claude - Plan editor with checkboxes, priorities (P0/P1/P2), reordering - Skip plan option for manual workflows - Compact wizard modal layout UI Updates: - Form section headers for grouped settings - CPU limit status indicator (cpulimit availability) - Wizard modal wider layout and inline fields Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
+48
-3
@@ -21,7 +21,7 @@ import { existsSync } from 'node:fs';
|
||||
import { dirname } from 'node:path';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import * as pty from 'node-pty';
|
||||
import { SessionState, SessionStatus, SessionConfig, ScreenSession, RalphTrackerState, RalphTodoItem, ActiveBashTool } from './types.js';
|
||||
import { SessionState, SessionStatus, SessionConfig, ScreenSession, RalphTrackerState, RalphTodoItem, ActiveBashTool, CpuLimitConfig, DEFAULT_CPU_LIMIT_CONFIG } from './types.js';
|
||||
import { TaskTracker, type BackgroundTask } from './task-tracker.js';
|
||||
import { RalphTracker } from './ralph-tracker.js';
|
||||
import { BashToolParser } from './bash-tool-parser.js';
|
||||
@@ -435,6 +435,9 @@ export class Session extends EventEmitter {
|
||||
private _parentAgentId: string | null = null;
|
||||
private _childAgentIds: string[] = [];
|
||||
|
||||
// CPU limiting configuration
|
||||
private _cpuLimitConfig: CpuLimitConfig = { ...DEFAULT_CPU_LIMIT_CONFIG };
|
||||
|
||||
// Store handler references for cleanup (prevents memory leaks)
|
||||
private _taskTrackerHandlers: {
|
||||
taskCreated: (task: BackgroundTask) => void;
|
||||
@@ -472,6 +475,7 @@ export class Session extends EventEmitter {
|
||||
screenManager?: ScreenManager;
|
||||
useScreen?: boolean;
|
||||
screenSession?: ScreenSession; // For restored sessions - pass the existing screen
|
||||
cpuLimitConfig?: CpuLimitConfig; // CPU limiting configuration
|
||||
}) {
|
||||
super();
|
||||
this.id = config.id || uuidv4();
|
||||
@@ -484,6 +488,11 @@ export class Session extends EventEmitter {
|
||||
this._useScreen = config.useScreen ?? (this._screenManager !== null && ScreenManager.isScreenAvailable());
|
||||
this._screenSession = config.screenSession || null; // Use existing screen if provided
|
||||
|
||||
// Apply CPU limit configuration if provided
|
||||
if (config.cpuLimitConfig) {
|
||||
this._cpuLimitConfig = { ...config.cpuLimitConfig };
|
||||
}
|
||||
|
||||
// Initialize task tracker and forward events (store handlers for cleanup)
|
||||
this._taskTracker = new TaskTracker();
|
||||
this._taskTrackerHandlers = {
|
||||
@@ -644,6 +653,32 @@ export class Session extends EventEmitter {
|
||||
if (idx >= 0) this._childAgentIds.splice(idx, 1);
|
||||
}
|
||||
|
||||
// CPU limit config getters and setters
|
||||
get cpuLimitConfig(): CpuLimitConfig {
|
||||
return { ...this._cpuLimitConfig };
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CPU limit configuration.
|
||||
* Note: This only affects new sessions; existing running processes won't be limited.
|
||||
*/
|
||||
setCpuLimit(config: Partial<CpuLimitConfig>): void {
|
||||
if (config.enabled !== undefined) {
|
||||
this._cpuLimitConfig.enabled = config.enabled;
|
||||
}
|
||||
if (config.niceValue !== undefined) {
|
||||
// Clamp to valid range
|
||||
this._cpuLimitConfig.niceValue = Math.max(-20, Math.min(19, config.niceValue));
|
||||
}
|
||||
if (config.cpuLimitPercent !== undefined) {
|
||||
// Clamp to valid range
|
||||
this._cpuLimitConfig.cpuLimitPercent = Math.max(1, Math.min(100, config.cpuLimitPercent));
|
||||
}
|
||||
if (config.useCpulimitIfAvailable !== undefined) {
|
||||
this._cpuLimitConfig.useCpulimitIfAvailable = config.useCpulimitIfAvailable;
|
||||
}
|
||||
}
|
||||
|
||||
// Token tracking getters and setters
|
||||
get totalTokens(): number {
|
||||
return this._totalInputTokens + this._totalOutputTokens;
|
||||
@@ -759,6 +794,9 @@ export class Session extends EventEmitter {
|
||||
ralphCompletionPhrase: this._ralphTracker.loopState.completionPhrase || undefined,
|
||||
parentAgentId: this._parentAgentId || undefined,
|
||||
childAgentIds: this._childAgentIds.length > 0 ? this._childAgentIds : undefined,
|
||||
cpuLimitEnabled: this._cpuLimitConfig.enabled,
|
||||
cpuLimitNiceValue: this._cpuLimitConfig.niceValue,
|
||||
cpuLimitPercent: this._cpuLimitConfig.cpuLimitPercent,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -796,6 +834,13 @@ export class Session extends EventEmitter {
|
||||
enabled: this._autoClearEnabled,
|
||||
threshold: this._autoClearThreshold,
|
||||
},
|
||||
// CPU limit configuration
|
||||
cpuLimit: {
|
||||
enabled: this._cpuLimitConfig.enabled,
|
||||
niceValue: this._cpuLimitConfig.niceValue,
|
||||
cpuLimitPercent: this._cpuLimitConfig.cpuLimitPercent,
|
||||
useCpulimitIfAvailable: this._cpuLimitConfig.useCpulimitIfAvailable,
|
||||
},
|
||||
// Ralph tracking state
|
||||
ralphLoop: this._ralphTracker.loopState,
|
||||
ralphTodos: this._ralphTracker.todos,
|
||||
@@ -845,7 +890,7 @@ export class Session extends EventEmitter {
|
||||
console.log('[Session] Attaching to existing screen session:', this._screenSession!.screenName);
|
||||
} else {
|
||||
// Create a new screen session
|
||||
this._screenSession = await this._screenManager.createScreen(this.id, this.workingDir, 'claude', this._name);
|
||||
this._screenSession = await this._screenManager.createScreen(this.id, this.workingDir, 'claude', this._name, this._cpuLimitConfig);
|
||||
console.log('[Session] Created screen session:', this._screenSession.screenName);
|
||||
|
||||
// Wait a moment for screen to fully start
|
||||
@@ -1051,7 +1096,7 @@ export class Session extends EventEmitter {
|
||||
console.log('[Session] Attaching to existing screen session:', this._screenSession!.screenName);
|
||||
} else {
|
||||
// Create a new screen session
|
||||
this._screenSession = await this._screenManager.createScreen(this.id, this.workingDir, 'shell', this._name);
|
||||
this._screenSession = await this._screenManager.createScreen(this.id, this.workingDir, 'shell', this._name, this._cpuLimitConfig);
|
||||
console.log('[Session] Created screen session:', this._screenSession.screenName);
|
||||
|
||||
// Wait a moment for screen to fully start
|
||||
|
||||
Reference in New Issue
Block a user