mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-09 16:59:43 +02:00
refactor: migrate session.ts and respawn-controller.ts to shared utilities
- Replace local BufferAccumulator in session.ts with shared utility - Replace local BufferAccumulator in respawn-controller.ts with shared utility - Import buffer constants from config/buffer-limits.ts - Reduces code duplication and centralizes buffer management Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -38,20 +38,11 @@ import { EventEmitter } from 'node:events';
|
|||||||
import { Session } from './session.js';
|
import { Session } from './session.js';
|
||||||
import { AiIdleChecker, type AiCheckResult, type AiCheckState } from './ai-idle-checker.js';
|
import { AiIdleChecker, type AiCheckResult, type AiCheckState } from './ai-idle-checker.js';
|
||||||
import { AiPlanChecker, type AiPlanCheckResult } from './ai-plan-checker.js';
|
import { AiPlanChecker, type AiPlanCheckResult } from './ai-plan-checker.js';
|
||||||
|
import { BufferAccumulator } from './utils/buffer-accumulator.js';
|
||||||
// ========== Configuration Constants ==========
|
import {
|
||||||
|
MAX_RESPAWN_BUFFER_SIZE,
|
||||||
/**
|
TRIM_RESPAWN_BUFFER_TO as RESPAWN_BUFFER_TRIM_SIZE,
|
||||||
* Maximum terminal buffer size for respawn controller.
|
} from './config/buffer-limits.js';
|
||||||
* Buffer is trimmed when this limit is exceeded to prevent memory issues.
|
|
||||||
*/
|
|
||||||
const MAX_RESPAWN_BUFFER_SIZE = 1024 * 1024; // 1MB
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Size to trim buffer to when MAX_RESPAWN_BUFFER_SIZE is exceeded.
|
|
||||||
* Keeps the most recent output for pattern detection.
|
|
||||||
*/
|
|
||||||
const RESPAWN_BUFFER_TRIM_SIZE = 512 * 1024; // 512KB
|
|
||||||
|
|
||||||
// ========== Constants ==========
|
// ========== Constants ==========
|
||||||
|
|
||||||
@@ -153,57 +144,6 @@ export interface DetectionStatus {
|
|||||||
nextAction: string;
|
nextAction: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========== Buffer Accumulator ==========
|
|
||||||
|
|
||||||
/**
|
|
||||||
* High-performance buffer accumulator using array-based collection.
|
|
||||||
* Reduces GC pressure by avoiding repeated string concatenation.
|
|
||||||
*/
|
|
||||||
class BufferAccumulator {
|
|
||||||
private chunks: string[] = [];
|
|
||||||
private totalLength: number = 0;
|
|
||||||
private readonly maxSize: number;
|
|
||||||
private readonly trimSize: number;
|
|
||||||
|
|
||||||
constructor(maxSize: number, trimSize: number) {
|
|
||||||
this.maxSize = maxSize;
|
|
||||||
this.trimSize = trimSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
append(data: string): void {
|
|
||||||
if (!data) return;
|
|
||||||
this.chunks.push(data);
|
|
||||||
this.totalLength += data.length;
|
|
||||||
if (this.totalLength > this.maxSize) {
|
|
||||||
this.trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get value(): string {
|
|
||||||
if (this.chunks.length === 0) return '';
|
|
||||||
if (this.chunks.length === 1) return this.chunks[0];
|
|
||||||
const result = this.chunks.join('');
|
|
||||||
this.chunks = [result];
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
get length(): number {
|
|
||||||
return this.totalLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
clear(): void {
|
|
||||||
this.chunks = [];
|
|
||||||
this.totalLength = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private trim(): void {
|
|
||||||
const full = this.chunks.join('');
|
|
||||||
const trimmed = full.slice(-this.trimSize);
|
|
||||||
this.chunks = [trimmed];
|
|
||||||
this.totalLength = trimmed.length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ========== Type Definitions ==========
|
// ========== Type Definitions ==========
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+9
-93
@@ -26,33 +26,20 @@ import { TaskTracker, type BackgroundTask } from './task-tracker.js';
|
|||||||
import { RalphTracker } from './ralph-tracker.js';
|
import { RalphTracker } from './ralph-tracker.js';
|
||||||
import { BashToolParser } from './bash-tool-parser.js';
|
import { BashToolParser } from './bash-tool-parser.js';
|
||||||
import { ScreenManager } from './screen-manager.js';
|
import { ScreenManager } from './screen-manager.js';
|
||||||
|
import { BufferAccumulator } from './utils/buffer-accumulator.js';
|
||||||
|
import {
|
||||||
|
MAX_TERMINAL_BUFFER_SIZE,
|
||||||
|
TRIM_TERMINAL_TO as TERMINAL_BUFFER_TRIM_SIZE,
|
||||||
|
MAX_TEXT_OUTPUT_SIZE,
|
||||||
|
TRIM_TEXT_TO as TEXT_OUTPUT_TRIM_SIZE,
|
||||||
|
MAX_MESSAGES,
|
||||||
|
MAX_LINE_BUFFER_SIZE,
|
||||||
|
} from './config/buffer-limits.js';
|
||||||
|
|
||||||
export type { BackgroundTask } from './task-tracker.js';
|
export type { BackgroundTask } from './task-tracker.js';
|
||||||
export type { RalphTrackerState, RalphTodoItem, ActiveBashTool } from './types.js';
|
export type { RalphTrackerState, RalphTodoItem, ActiveBashTool } from './types.js';
|
||||||
export { withTimeout };
|
export { withTimeout };
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// Buffer Size Constants
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
/** Maximum terminal buffer size in characters (2MB) - reduced from 5MB for better render performance */
|
|
||||||
const MAX_TERMINAL_BUFFER_SIZE = 2 * 1024 * 1024;
|
|
||||||
|
|
||||||
/** When trimming terminal buffer, keep the most recent portion (1.5MB) */
|
|
||||||
const TERMINAL_BUFFER_TRIM_SIZE = 1.5 * 1024 * 1024;
|
|
||||||
|
|
||||||
/** Maximum text output buffer size (1MB) - ANSI-stripped text */
|
|
||||||
const MAX_TEXT_OUTPUT_SIZE = 1 * 1024 * 1024;
|
|
||||||
|
|
||||||
/** When trimming text output, keep the most recent portion (768KB) */
|
|
||||||
const TEXT_OUTPUT_TRIM_SIZE = 768 * 1024;
|
|
||||||
|
|
||||||
/** Maximum number of Claude JSON messages to keep in memory */
|
|
||||||
const MAX_MESSAGES = 1000;
|
|
||||||
|
|
||||||
/** Maximum line buffer size (64KB) - prevents unbounded growth for long lines */
|
|
||||||
const MAX_LINE_BUFFER_SIZE = 64 * 1024;
|
|
||||||
|
|
||||||
/** Line buffer flush interval (100ms) - forces processing of partial lines */
|
/** Line buffer flush interval (100ms) - forces processing of partial lines */
|
||||||
const LINE_BUFFER_FLUSH_INTERVAL = 100;
|
const LINE_BUFFER_FLUSH_INTERVAL = 100;
|
||||||
|
|
||||||
@@ -155,77 +142,6 @@ export function getAugmentedPath(): string {
|
|||||||
return _augmentedPath;
|
return _augmentedPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// Buffer Accumulator (reduces GC pressure from string concatenation)
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
/**
|
|
||||||
* High-performance buffer accumulator using array-based collection.
|
|
||||||
*
|
|
||||||
* Reduces GC pressure by avoiding repeated string concatenation (`+=`).
|
|
||||||
* Instead, chunks are pushed to an array and joined only when needed.
|
|
||||||
* Automatically trims when size limits are exceeded.
|
|
||||||
*/
|
|
||||||
class BufferAccumulator {
|
|
||||||
private chunks: string[] = [];
|
|
||||||
private totalLength: number = 0;
|
|
||||||
private readonly maxSize: number;
|
|
||||||
private readonly trimSize: number;
|
|
||||||
|
|
||||||
constructor(maxSize: number, trimSize: number) {
|
|
||||||
this.maxSize = maxSize;
|
|
||||||
this.trimSize = trimSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Append data to the buffer */
|
|
||||||
append(data: string): void {
|
|
||||||
if (!data) return;
|
|
||||||
this.chunks.push(data);
|
|
||||||
this.totalLength += data.length;
|
|
||||||
|
|
||||||
// Trim if exceeded max size
|
|
||||||
if (this.totalLength > this.maxSize) {
|
|
||||||
this.trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the full buffer content (joins all chunks) */
|
|
||||||
get value(): string {
|
|
||||||
if (this.chunks.length === 0) return '';
|
|
||||||
if (this.chunks.length === 1) return this.chunks[0];
|
|
||||||
|
|
||||||
// Consolidate chunks on access
|
|
||||||
const result = this.chunks.join('');
|
|
||||||
this.chunks = [result];
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get current buffer length without joining */
|
|
||||||
get length(): number {
|
|
||||||
return this.totalLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Clear the buffer */
|
|
||||||
clear(): void {
|
|
||||||
this.chunks = [];
|
|
||||||
this.totalLength = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Set buffer to a specific value */
|
|
||||||
set(value: string): void {
|
|
||||||
this.chunks = value ? [value] : [];
|
|
||||||
this.totalLength = value?.length || 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Trim buffer to keep only the most recent data */
|
|
||||||
private trim(): void {
|
|
||||||
const full = this.chunks.join('');
|
|
||||||
const trimmed = full.slice(-this.trimSize);
|
|
||||||
this.chunks = [trimmed];
|
|
||||||
this.totalLength = trimmed.length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps a promise with a timeout to prevent indefinite hangs.
|
* Wraps a promise with a timeout to prevent indefinite hangs.
|
||||||
* If the promise doesn't resolve within the timeout, rejects with TimeoutError.
|
* If the promise doesn't resolve within the timeout, rejects with TimeoutError.
|
||||||
|
|||||||
Reference in New Issue
Block a user