chore: bump version to 0.1439

This commit is contained in:
arkon
2026-01-30 17:50:02 +01:00
parent 5b6dd078f1
commit b520ce44e5
23 changed files with 225 additions and 36 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ When user says "COM":
1. Increment version in BOTH `package.json` AND `CLAUDE.md` 1. Increment version in BOTH `package.json` AND `CLAUDE.md`
2. Run: `git add -A && git commit -m "chore: bump version to X.XXXX" && git push && npm run build && systemctl --user restart claudeman-web` 2. Run: `git add -A && git commit -m "chore: bump version to X.XXXX" && git push && npm run build && systemctl --user restart claudeman-web`
**Version**: 0.1438 (must match `package.json`) **Version**: 0.1439 (must match `package.json`)
## Project Overview ## Project Overview
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "claudeman", "name": "claudeman",
"version": "0.1438", "version": "0.1439",
"description": "The missing control plane for Claude Code - run 20 autonomous agents with real-time monitoring and session persistence", "description": "The missing control plane for Claude Code - run 20 autonomous agents with real-time monitoring and session persistence",
"type": "module", "type": "module",
"main": "dist/index.js", "main": "dist/index.js",
+12
View File
@@ -338,6 +338,9 @@ export class Session extends EventEmitter {
// Image watcher setting (per-session toggle) // Image watcher setting (per-session toggle)
private _imageWatcherEnabled: boolean = true; private _imageWatcherEnabled: boolean = true;
// Flicker filter setting (per-session toggle, applied on frontend)
private _flickerFilterEnabled: boolean = false;
// Timer tracking for cleanup (prevents memory leaks) // Timer tracking for cleanup (prevents memory leaks)
private _autoCompactTimer: NodeJS.Timeout | null = null; private _autoCompactTimer: NodeJS.Timeout | null = null;
private _autoClearTimer: NodeJS.Timeout | null = null; private _autoClearTimer: NodeJS.Timeout | null = null;
@@ -694,6 +697,14 @@ export class Session extends EventEmitter {
this._imageWatcherEnabled = enabled; this._imageWatcherEnabled = enabled;
} }
get flickerFilterEnabled(): boolean {
return this._flickerFilterEnabled;
}
set flickerFilterEnabled(enabled: boolean) {
this._flickerFilterEnabled = enabled;
}
isIdle(): boolean { isIdle(): boolean {
return this._status === 'idle'; return this._status === 'idle';
} }
@@ -734,6 +745,7 @@ export class Session extends EventEmitter {
niceEnabled: this._niceConfig.enabled, niceEnabled: this._niceConfig.enabled,
niceValue: this._niceConfig.niceValue, niceValue: this._niceConfig.niceValue,
color: this._color, color: this._color,
flickerFilterEnabled: this._flickerFilterEnabled,
}; };
} }
+2
View File
@@ -180,6 +180,8 @@ export interface SessionState {
niceValue?: number; niceValue?: number;
/** User-assigned color for visual differentiation */ /** User-assigned color for visual differentiation */
color?: SessionColor; color?: SessionColor;
/** Flicker filter enabled (buffers output after screen clears) */
flickerFilterEnabled?: boolean;
} }
// ========== Global Stats Types ========== // ========== Global Stats Types ==========
+132 -2
View File
@@ -631,6 +631,7 @@ class ClaudemanApp {
// Once set, never recalculated. Persisted to localStorage and server. // Once set, never recalculated. Persisted to localStorage and server.
this.subagentParentMap = new Map(); this.subagentParentMap = new Map();
this.ralphStatePanelCollapsed = true; // Default to collapsed this.ralphStatePanelCollapsed = true; // Default to collapsed
this.ralphClosedSessions = new Set(); // Sessions where user explicitly closed Ralph panel
// Plan subagent windows (visible agents during plan generation) // Plan subagent windows (visible agents during plan generation)
this.planSubagents = new Map(); // Map<agentId, { type, model, status, startTime, element, relativePos }> this.planSubagents = new Map(); // Map<agentId, { type, model, status, startTime, element, relativePos }>
@@ -667,6 +668,11 @@ class ClaudemanApp {
this._wasAtBottomBeforeWrite = true; // Default to true for sticky scroll this._wasAtBottomBeforeWrite = true; // Default to true for sticky scroll
this.syncWaitTimeout = null; // Timeout for incomplete sync blocks this.syncWaitTimeout = null; // Timeout for incomplete sync blocks
// Flicker filter state (buffers output after screen clears)
this.flickerFilterBuffer = '';
this.flickerFilterActive = false;
this.flickerFilterTimeout = null;
// Render debouncing // Render debouncing
this.renderSessionTabsTimeout = null; this.renderSessionTabsTimeout = null;
this.renderRalphStatePanelTimeout = null; this.renderRalphStatePanelTimeout = null;
@@ -1053,6 +1059,44 @@ class ClaudemanApp {
this._wasAtBottomBeforeWrite = this.isTerminalAtBottom(); this._wasAtBottomBeforeWrite = this.isTerminalAtBottom();
} }
// Check if flicker filter is enabled for current session
const session = this.activeSessionId ? this.sessions.get(this.activeSessionId) : null;
const flickerFilterEnabled = session?.flickerFilterEnabled ?? false;
// Flicker filter: detect screen clear patterns and buffer output
if (flickerFilterEnabled) {
// Detect Ink's screen clear patterns:
// - ESC[2J (clear entire screen)
// - ESC[H ESC[J (cursor home + clear to end)
// - ESC[?25l ESC[H (hide cursor + home - common Ink pattern)
const hasScreenClear = data.includes('\x1b[2J') ||
data.includes('\x1b[H\x1b[J') ||
(data.includes('\x1b[H') && data.includes('\x1b[?25l'));
if (hasScreenClear) {
// Screen clear detected - activate flicker filter
this.flickerFilterActive = true;
this.flickerFilterBuffer += data;
// Clear any existing timeout and set a new one
if (this.flickerFilterTimeout) {
clearTimeout(this.flickerFilterTimeout);
}
this.flickerFilterTimeout = setTimeout(() => {
this.flickerFilterTimeout = null;
this.flushFlickerBuffer();
}, SYNC_WAIT_TIMEOUT_MS); // 50ms buffer window
return; // Don't process normally, wait for buffer window
}
if (this.flickerFilterActive) {
// Filter is active, accumulate data
this.flickerFilterBuffer += data;
return; // Continue buffering
}
}
// Accumulate raw data (may contain DEC 2026 markers) // Accumulate raw data (may contain DEC 2026 markers)
this.pendingWrites += data; this.pendingWrites += data;
@@ -1090,6 +1134,28 @@ class ClaudemanApp {
} }
} }
/**
* Flush the flicker filter buffer to the terminal.
* Called after the buffer window expires.
*/
flushFlickerBuffer() {
if (!this.flickerFilterBuffer) return;
// Transfer buffered data to normal pending writes
this.pendingWrites += this.flickerFilterBuffer;
this.flickerFilterBuffer = '';
this.flickerFilterActive = false;
// Trigger a normal flush
if (!this.writeFrameScheduled) {
this.writeFrameScheduled = true;
requestAnimationFrame(() => {
this.flushPendingWrites();
this.writeFrameScheduled = false;
});
}
}
/** /**
* Flush pending writes to terminal, processing DEC 2026 sync markers. * Flush pending writes to terminal, processing DEC 2026 sync markers.
* Strips markers and writes content atomically within a single frame. * Strips markers and writes content atomically within a single frame.
@@ -1366,6 +1432,7 @@ class ClaudemanApp {
} }
this.terminalBuffers.delete(data.id); this.terminalBuffers.delete(data.id);
this.ralphStates.delete(data.id); // Clean up ralph state for this session this.ralphStates.delete(data.id); // Clean up ralph state for this session
this.ralphClosedSessions.delete(data.id); // Clean up closed tracking for this session
this.projectInsights.delete(data.id); // Clean up project insights for this session this.projectInsights.delete(data.id); // Clean up project insights for this session
this.closeSessionLogViewerWindows(data.id); // Close log viewer windows for this session this.closeSessionLogViewerWindows(data.id); // Close log viewer windows for this session
this.closeSessionImagePopups(data.id); // Close image popup windows for this session this.closeSessionImagePopups(data.id); // Close image popup windows for this session
@@ -1803,16 +1870,22 @@ class ClaudemanApp {
// Ralph loop/todo events // Ralph loop/todo events
addListener('session:ralphLoopUpdate', (e) => { addListener('session:ralphLoopUpdate', (e) => {
const data = JSON.parse(e.data); const data = JSON.parse(e.data);
// Skip if user explicitly closed this session's Ralph panel
if (this.ralphClosedSessions.has(data.sessionId)) return;
this.updateRalphState(data.sessionId, { loop: data.state }); this.updateRalphState(data.sessionId, { loop: data.state });
}); });
addListener('session:ralphTodoUpdate', (e) => { addListener('session:ralphTodoUpdate', (e) => {
const data = JSON.parse(e.data); const data = JSON.parse(e.data);
// Skip if user explicitly closed this session's Ralph panel
if (this.ralphClosedSessions.has(data.sessionId)) return;
this.updateRalphState(data.sessionId, { todos: data.todos }); this.updateRalphState(data.sessionId, { todos: data.todos });
}); });
addListener('session:ralphCompletionDetected', (e) => { addListener('session:ralphCompletionDetected', (e) => {
const data = JSON.parse(e.data); const data = JSON.parse(e.data);
// Skip if user explicitly closed this session's Ralph panel
if (this.ralphClosedSessions.has(data.sessionId)) return;
// Prevent duplicate notifications for the same completion // Prevent duplicate notifications for the same completion
const completionKey = `${data.sessionId}:${data.phrase}`; const completionKey = `${data.sessionId}:${data.phrase}`;
if (this._shownCompletions?.has(completionKey)) { if (this._shownCompletions?.has(completionKey)) {
@@ -1846,11 +1919,15 @@ class ClaudemanApp {
// RALPH_STATUS block and circuit breaker events // RALPH_STATUS block and circuit breaker events
addListener('session:ralphStatusUpdate', (e) => { addListener('session:ralphStatusUpdate', (e) => {
const data = JSON.parse(e.data); const data = JSON.parse(e.data);
// Skip if user explicitly closed this session's Ralph panel
if (this.ralphClosedSessions.has(data.sessionId)) return;
this.updateRalphState(data.sessionId, { statusBlock: data.block }); this.updateRalphState(data.sessionId, { statusBlock: data.block });
}); });
addListener('session:circuitBreakerUpdate', (e) => { addListener('session:circuitBreakerUpdate', (e) => {
const data = JSON.parse(e.data); const data = JSON.parse(e.data);
// Skip if user explicitly closed this session's Ralph panel
if (this.ralphClosedSessions.has(data.sessionId)) return;
this.updateRalphState(data.sessionId, { circuitBreaker: data.status }); this.updateRalphState(data.sessionId, { circuitBreaker: data.status });
// Notify if circuit breaker opens // Notify if circuit breaker opens
if (data.status.state === 'OPEN') { if (data.status.state === 'OPEN') {
@@ -2222,6 +2299,13 @@ class ClaudemanApp {
clearTimeout(timer); clearTimeout(timer);
} }
this.idleTimers.clear(); this.idleTimers.clear();
// Clear flicker filter state
if (this.flickerFilterTimeout) {
clearTimeout(this.flickerFilterTimeout);
this.flickerFilterTimeout = null;
}
this.flickerFilterBuffer = '';
this.flickerFilterActive = false;
// Clear pending hooks // Clear pending hooks
this.pendingHooks.clear(); this.pendingHooks.clear();
// Clear tab alerts // Clear tab alerts
@@ -2250,8 +2334,8 @@ class ClaudemanApp {
} }
data.sessions.forEach(s => { data.sessions.forEach(s => {
this.sessions.set(s.id, s); this.sessions.set(s.id, s);
// Load ralph state from session data // Load ralph state from session data (only if not explicitly closed by user)
if (s.ralphLoop || s.ralphTodos) { if ((s.ralphLoop || s.ralphTodos) && !this.ralphClosedSessions.has(s.id)) {
this.ralphStates.set(s.id, { this.ralphStates.set(s.id, {
loop: s.ralphLoop || null, loop: s.ralphLoop || null,
todos: s.ralphTodos || [] todos: s.ralphTodos || []
@@ -2842,6 +2926,14 @@ class ClaudemanApp {
async selectSession(sessionId) { async selectSession(sessionId) {
if (this.activeSessionId === sessionId) return; if (this.activeSessionId === sessionId) return;
// Clean up flicker filter state when switching sessions
if (this.flickerFilterTimeout) {
clearTimeout(this.flickerFilterTimeout);
this.flickerFilterTimeout = null;
}
this.flickerFilterBuffer = '';
this.flickerFilterActive = false;
this.activeSessionId = sessionId; this.activeSessionId = sessionId;
this.hideWelcome(); this.hideWelcome();
// Clear idle hooks on view, but keep action hooks until user interacts // Clear idle hooks on view, but keep action hooks until user interacts
@@ -5754,6 +5846,9 @@ class ClaudemanApp {
const sessionId = data.sessionId; const sessionId = data.sessionId;
// Clear from closed set in case user previously closed Ralph for this session
this.ralphClosedSessions.delete(sessionId);
// Step 2: Configure Ralph tracker for this session // Step 2: Configure Ralph tracker for this session
await fetch(`/api/sessions/${sessionId}/ralph-config`, { await fetch(`/api/sessions/${sessionId}/ralph-config`, {
method: 'POST', method: 'POST',
@@ -6932,6 +7027,7 @@ class ClaudemanApp {
document.getElementById('modalAutoClearEnabled').checked = session.autoClearEnabled ?? false; document.getElementById('modalAutoClearEnabled').checked = session.autoClearEnabled ?? false;
document.getElementById('modalAutoClearThreshold').value = session.autoClearThreshold ?? 140000; document.getElementById('modalAutoClearThreshold').value = session.autoClearThreshold ?? 140000;
document.getElementById('modalImageWatcherEnabled').checked = session.imageWatcherEnabled ?? true; document.getElementById('modalImageWatcherEnabled').checked = session.imageWatcherEnabled ?? true;
document.getElementById('modalFlickerFilterEnabled').checked = session.flickerFilterEnabled ?? false;
// Initialize color picker with current session color // Initialize color picker with current session color
const currentColor = session.color || 'default'; const currentColor = session.color || 'default';
@@ -7010,6 +7106,26 @@ class ClaudemanApp {
} }
} }
async toggleFlickerFilter() {
if (!this.editingSessionId) return;
const enabled = document.getElementById('modalFlickerFilterEnabled').checked;
try {
await fetch(`/api/sessions/${this.editingSessionId}/flicker-filter`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ enabled })
});
// Update local session state
const session = this.sessions.get(this.editingSessionId);
if (session) {
session.flickerFilterEnabled = enabled;
}
this.showToast(`Flicker filter ${enabled ? 'enabled' : 'disabled'}`, 'success');
} catch (err) {
this.showToast('Failed to toggle flicker filter', 'error');
}
}
async autoSaveRespawnConfig() { async autoSaveRespawnConfig() {
if (!this.editingSessionId) return; if (!this.editingSessionId) return;
const config = { const config = {
@@ -7715,6 +7831,11 @@ class ClaudemanApp {
const config = this.getRalphConfig(); const config = this.getRalphConfig();
// If user is enabling Ralph, clear from closed set
if (config.enabled) {
this.ralphClosedSessions.delete(this.editingSessionId);
}
try { try {
const res = await fetch(`/api/sessions/${this.editingSessionId}/ralph-config`, { const res = await fetch(`/api/sessions/${this.editingSessionId}/ralph-config`, {
method: 'POST', method: 'POST',
@@ -9045,6 +9166,9 @@ class ClaudemanApp {
async closeRalphTracker() { async closeRalphTracker() {
if (!this.activeSessionId) return; if (!this.activeSessionId) return;
// Mark this session as explicitly closed - will stay hidden until user re-enables
this.ralphClosedSessions.add(this.activeSessionId);
// Disable tracker via API // Disable tracker via API
await fetch(`/api/sessions/${this.activeSessionId}/ralph-config`, { await fetch(`/api/sessions/${this.activeSessionId}/ralph-config`, {
method: 'POST', method: 'POST',
@@ -9343,6 +9467,12 @@ class ClaudemanApp {
if (!panel) return; if (!panel) return;
// If user explicitly closed this session's Ralph panel, keep it hidden
if (this.ralphClosedSessions.has(this.activeSessionId)) {
panel.style.display = 'none';
return;
}
const state = this.ralphStates.get(this.activeSessionId); const state = this.ralphStates.get(this.activeSessionId);
// Check if there's anything to show // Check if there's anything to show
+10
View File
@@ -583,6 +583,16 @@
</label> </label>
<span class="form-hint">Auto-popup new images (screenshots, generated files) in this session's directory</span> <span class="form-hint">Auto-popup new images (screenshots, generated files) in this session's directory</span>
</div> </div>
<div class="form-section-header">Performance</div>
<div class="form-row form-row-switch">
<label>Flicker Filter</label>
<label class="switch">
<input type="checkbox" id="modalFlickerFilterEnabled" onchange="app.toggleFlickerFilter()">
<span class="slider"></span>
</label>
<span class="form-hint">Buffers output after screen clears to reduce Ink UI flickering (adds ~50ms latency)</span>
</div>
</div><!-- End context-tab --> </div><!-- End context-tab -->
<!-- Ralph Wiggum Tab Content --> <!-- Ralph Wiggum Tab Content -->
+39 -4
View File
@@ -280,6 +280,7 @@ export class WebServer extends EventEmitter {
private store = getStore(); private store = getStore();
private port: number; private port: number;
private https: boolean; private https: boolean;
private testMode: boolean;
private screenManager: ScreenManager; private screenManager: ScreenManager;
// Terminal batching for performance // Terminal batching for performance
private terminalBatches: Map<string, string> = new Map(); private terminalBatches: Map<string, string> = new Map();
@@ -325,10 +326,11 @@ export class WebServer extends EventEmitter {
error: (error: Error, sessionId?: string) => void; error: (error: Error, sessionId?: string) => void;
} | null = null; } | null = null;
constructor(port: number = 3000, https: boolean = false) { constructor(port: number = 3000, https: boolean = false, testMode: boolean = false) {
super(); super();
this.port = port; this.port = port;
this.https = https; this.https = https;
this.testMode = testMode;
if (https) { if (https) {
const { key, cert } = getOrCreateSelfSignedCert(); const { key, cert } = getOrCreateSelfSignedCert();
@@ -1879,6 +1881,32 @@ export class WebServer extends EventEmitter {
}; };
}); });
// Toggle flicker filter for a session
this.app.post('/api/sessions/:id/flicker-filter', async (req) => {
const { id } = req.params as { id: string };
const body = req.body as { enabled: boolean };
const session = this.sessions.get(id);
if (!session) {
return createErrorResponse(ApiErrorCode.NOT_FOUND, 'Session not found');
}
if (body.enabled === undefined) {
return createErrorResponse(ApiErrorCode.INVALID_INPUT, 'enabled field is required');
}
session.flickerFilterEnabled = body.enabled;
this.persistSessionState(session);
this.broadcast('session:updated', this.getSessionStateWithRespawn(session));
return {
success: true,
data: {
flickerFilterEnabled: body.enabled,
},
};
});
// Quick run (create session, run prompt, return result, then cleanup) // Quick run (create session, run prompt, return result, then cleanup)
this.app.post('/api/run', async (req) => { this.app.post('/api/run', async (req) => {
// Prevent unbounded session creation // Prevent unbounded session creation
@@ -4414,7 +4442,10 @@ NOW: Generate the implementation plan for the task above. Think step by step.`;
// Restore screen sessions BEFORE accepting connections // Restore screen sessions BEFORE accepting connections
// This prevents race conditions where clients connect before state is ready // This prevents race conditions where clients connect before state is ready
await this.restoreScreenSessions(); // CRITICAL: Skip in test mode to prevent tests from picking up user sessions
if (!this.testMode) {
await this.restoreScreenSessions();
}
// Clean up stale sessions from state file that don't have active screens // Clean up stale sessions from state file that don't have active screens
this.cleanupStaleSessions(); this.cleanupStaleSessions();
@@ -4587,6 +4618,10 @@ NOW: Generate the implementation plan for the task above. Think step by step.`;
niceValue: savedState.niceValue, niceValue: savedState.niceValue,
}); });
} }
// Flicker filter (frontend-applied but persisted)
if (savedState.flickerFilterEnabled !== undefined) {
session.flickerFilterEnabled = savedState.flickerFilterEnabled;
}
// Respawn controller // Respawn controller
if (savedState.respawnEnabled && savedState.respawnConfig) { if (savedState.respawnEnabled && savedState.respawnConfig) {
try { try {
@@ -4751,8 +4786,8 @@ NOW: Generate the implementation plan for the task above. Think step by step.`;
} }
} }
export async function startWebServer(port: number = 3000, https: boolean = false): Promise<WebServer> { export async function startWebServer(port: number = 3000, https: boolean = false, testMode: boolean = false): Promise<WebServer> {
const server = new WebServer(port, https); const server = new WebServer(port, https, testMode);
await server.start(); await server.start();
return server; return server;
} }
+1 -1
View File
@@ -171,7 +171,7 @@ describe('Agent-Browser Enhanced Tests', () => {
closeBrowser(); closeBrowser();
// Start web server // Start web server
server = new WebServer(TEST_PORT); server = new WebServer(TEST_PORT, false, true);
await server.start(); await server.start();
await new Promise(r => setTimeout(r, 1000)); await new Promise(r => setTimeout(r, 1000));
+1 -1
View File
@@ -135,7 +135,7 @@ describe('Browser Framework Comparison Benchmark', () => {
// Start web servers for each framework // Start web servers for each framework
for (const [name, port] of Object.entries(PORTS)) { for (const [name, port] of Object.entries(PORTS)) {
const server = new WebServer(port); const server = new WebServer(port, false, true);
await server.start(); await server.start();
servers.push(server); servers.push(server);
console.log(`✅ Started server for ${name} on port ${port}`); console.log(`✅ Started server for ${name} on port ${port}`);
+4 -4
View File
@@ -92,7 +92,7 @@ describe('Browser E2E Tests', () => {
beforeAll(async () => { beforeAll(async () => {
closeBrowser(); closeBrowser();
server = new WebServer(TEST_PORT_BROWSER); server = new WebServer(TEST_PORT_BROWSER, false, true);
await server.start(); await server.start();
await new Promise(r => setTimeout(r, 1000)); await new Promise(r => setTimeout(r, 1000));
@@ -211,7 +211,7 @@ describe('SSE Events API', () => {
let createdSessions: string[] = []; let createdSessions: string[] = [];
beforeAll(async () => { beforeAll(async () => {
server = new WebServer(TEST_PORT_SSE); server = new WebServer(TEST_PORT_SSE, false, true);
await server.start(); await server.start();
await new Promise(r => setTimeout(r, 1000)); await new Promise(r => setTimeout(r, 1000));
}, 30000); }, 30000);
@@ -280,7 +280,7 @@ describe('Hook Events API', () => {
let createdSessions: string[] = []; let createdSessions: string[] = [];
beforeAll(async () => { beforeAll(async () => {
server = new WebServer(TEST_PORT_HOOK); server = new WebServer(TEST_PORT_HOOK, false, true);
await server.start(); await server.start();
await new Promise(r => setTimeout(r, 1000)); await new Promise(r => setTimeout(r, 1000));
}, 30000); }, 30000);
@@ -345,7 +345,7 @@ describe('Ralph API', () => {
let createdSessions: string[] = []; let createdSessions: string[] = [];
beforeAll(async () => { beforeAll(async () => {
server = new WebServer(TEST_PORT_RALPH); server = new WebServer(TEST_PORT_RALPH, false, true);
await server.start(); await server.start();
await new Promise(r => setTimeout(r, 1000)); await new Promise(r => setTimeout(r, 1000));
}, 30000); }, 30000);
+1 -1
View File
@@ -32,7 +32,7 @@ let setupComplete = false;
describe('Playwright Direct API Tests', () => { describe('Playwright Direct API Tests', () => {
beforeAll(async () => { beforeAll(async () => {
// Start web server // Start web server
server = new WebServer(TEST_PORT); server = new WebServer(TEST_PORT, false, true);
await server.start(); await server.start();
await new Promise(r => setTimeout(r, 1000)); await new Promise(r => setTimeout(r, 1000));
+1 -1
View File
@@ -34,7 +34,7 @@ describe('Puppeteer/Chrome Tests', () => {
beforeAll(async () => { beforeAll(async () => {
// Start web server // Start web server
server = new WebServer(TEST_PORT); server = new WebServer(TEST_PORT, false, true);
await server.start(); await server.start();
await new Promise(r => setTimeout(r, 1000)); await new Promise(r => setTimeout(r, 1000));
+1 -1
View File
@@ -17,7 +17,7 @@ export interface ServerFixture {
* @returns ServerFixture with server instance and connection info * @returns ServerFixture with server instance and connection info
*/ */
export async function createServerFixture(port: number): Promise<ServerFixture> { export async function createServerFixture(port: number): Promise<ServerFixture> {
const server = new WebServer(port); const server = new WebServer(port, false, true);
await server.start(); await server.start();
// Wait for server to be fully ready // Wait for server to be fully ready
+3 -3
View File
@@ -13,7 +13,7 @@ describe('Edge Cases and Error Handling', () => {
const createdCases: string[] = []; const createdCases: string[] = [];
beforeAll(async () => { beforeAll(async () => {
server = new WebServer(TEST_PORT); server = new WebServer(TEST_PORT, false, true);
await server.start(); await server.start();
baseUrl = `http://localhost:${TEST_PORT}`; baseUrl = `http://localhost:${TEST_PORT}`;
}); });
@@ -261,7 +261,7 @@ describe('Concurrent Session Handling', () => {
let baseUrl: string; let baseUrl: string;
beforeAll(async () => { beforeAll(async () => {
server = new WebServer(TEST_PORT + 1); server = new WebServer(TEST_PORT + 1, false, true);
await server.start(); await server.start();
baseUrl = `http://localhost:${TEST_PORT + 1}`; baseUrl = `http://localhost:${TEST_PORT + 1}`;
}); });
@@ -362,7 +362,7 @@ describe('API Request Validation', () => {
let baseUrl: string; let baseUrl: string;
beforeAll(async () => { beforeAll(async () => {
server = new WebServer(TEST_PORT + 2); server = new WebServer(TEST_PORT + 2, false, true);
await server.start(); await server.start();
baseUrl = `http://localhost:${TEST_PORT + 2}`; baseUrl = `http://localhost:${TEST_PORT + 2}`;
}); });
+1 -1
View File
@@ -93,7 +93,7 @@ describe('File Link Click Tests', () => {
testLogFile = join(testDir, 'test.log'); testLogFile = join(testDir, 'test.log');
writeFileSync(testLogFile, '=== Test Log Started ===\n'); writeFileSync(testLogFile, '=== Test Log Started ===\n');
server = new WebServer(TEST_PORT); server = new WebServer(TEST_PORT, false, true);
await server.start(); await server.start();
await new Promise(r => setTimeout(r, 1000)); await new Promise(r => setTimeout(r, 1000));
+2 -2
View File
@@ -200,7 +200,7 @@ describe('Hook Event API', () => {
let testSessionId: string; let testSessionId: string;
beforeAll(async () => { beforeAll(async () => {
server = new WebServer(TEST_PORT); server = new WebServer(TEST_PORT, false, true);
await server.start(); await server.start();
baseUrl = `http://localhost:${TEST_PORT}`; baseUrl = `http://localhost:${TEST_PORT}`;
@@ -382,7 +382,7 @@ describe('Hook Data Sanitization', () => {
let testSessionId: string; let testSessionId: string;
beforeAll(async () => { beforeAll(async () => {
server = new WebServer(TEST_PORT + 1); // Port 3131 server = new WebServer(TEST_PORT + 1, false, true); // Port 3131
await server.start(); await server.start();
baseUrl = `http://localhost:${TEST_PORT + 1}`; baseUrl = `http://localhost:${TEST_PORT + 1}`;
+2 -2
View File
@@ -18,7 +18,7 @@ describe('Integration Flows', () => {
const createdSessions: string[] = []; const createdSessions: string[] = [];
beforeAll(async () => { beforeAll(async () => {
server = new WebServer(TEST_PORT); server = new WebServer(TEST_PORT, false, true);
await server.start(); await server.start();
baseUrl = `http://localhost:${TEST_PORT}`; baseUrl = `http://localhost:${TEST_PORT}`;
}); });
@@ -278,7 +278,7 @@ describe('SSE Event Flow', () => {
const createdSessions: string[] = []; const createdSessions: string[] = [];
beforeAll(async () => { beforeAll(async () => {
server = new WebServer(TEST_PORT + 1); server = new WebServer(TEST_PORT + 1, false, true);
await server.start(); await server.start();
baseUrl = `http://localhost:${TEST_PORT + 1}`; baseUrl = `http://localhost:${TEST_PORT + 1}`;
}); });
+3 -3
View File
@@ -13,7 +13,7 @@ describe('Quick Start API', () => {
const createdCases: string[] = []; const createdCases: string[] = [];
beforeAll(async () => { beforeAll(async () => {
server = new WebServer(TEST_PORT); server = new WebServer(TEST_PORT, false, true);
await server.start(); await server.start();
baseUrl = `http://localhost:${TEST_PORT}`; baseUrl = `http://localhost:${TEST_PORT}`;
}); });
@@ -147,7 +147,7 @@ describe('Session Management', () => {
let baseUrl: string; let baseUrl: string;
beforeAll(async () => { beforeAll(async () => {
server = new WebServer(TEST_PORT + 1); server = new WebServer(TEST_PORT + 1, false, true);
await server.start(); await server.start();
baseUrl = `http://localhost:${TEST_PORT + 1}`; baseUrl = `http://localhost:${TEST_PORT + 1}`;
}); });
@@ -204,7 +204,7 @@ describe('Case Management', () => {
const createdCases: string[] = []; const createdCases: string[] = [];
beforeAll(async () => { beforeAll(async () => {
server = new WebServer(TEST_PORT + 2); server = new WebServer(TEST_PORT + 2, false, true);
await server.start(); await server.start();
baseUrl = `http://localhost:${TEST_PORT + 2}`; baseUrl = `http://localhost:${TEST_PORT + 2}`;
}); });
+1 -1
View File
@@ -27,7 +27,7 @@ describe('Ralph Integration Tests', () => {
const createdSessions: string[] = []; const createdSessions: string[] = [];
beforeAll(async () => { beforeAll(async () => {
server = new WebServer(TEST_PORT); server = new WebServer(TEST_PORT, false, true);
await server.start(); await server.start();
baseUrl = `http://localhost:${TEST_PORT}`; baseUrl = `http://localhost:${TEST_PORT}`;
}); });
+2 -2
View File
@@ -9,7 +9,7 @@ describe('Scheduled Runs API', () => {
const createdRuns: string[] = []; const createdRuns: string[] = [];
beforeAll(async () => { beforeAll(async () => {
server = new WebServer(TEST_PORT); server = new WebServer(TEST_PORT, false, true);
await server.start(); await server.start();
baseUrl = `http://localhost:${TEST_PORT}`; baseUrl = `http://localhost:${TEST_PORT}`;
}); });
@@ -181,7 +181,7 @@ describe('Quick Run API', () => {
let baseUrl: string; let baseUrl: string;
beforeAll(async () => { beforeAll(async () => {
server = new WebServer(TEST_PORT + 1); server = new WebServer(TEST_PORT + 1, false, true);
await server.start(); await server.start();
baseUrl = `http://localhost:${TEST_PORT + 1}`; baseUrl = `http://localhost:${TEST_PORT + 1}`;
}); });
+2 -2
View File
@@ -19,7 +19,7 @@ describe('Session Cleanup', () => {
const createdSessions: string[] = []; const createdSessions: string[] = [];
beforeAll(async () => { beforeAll(async () => {
server = new WebServer(TEST_PORT); server = new WebServer(TEST_PORT, false, true);
await server.start(); await server.start();
baseUrl = `http://localhost:${TEST_PORT}`; baseUrl = `http://localhost:${TEST_PORT}`;
}); });
@@ -186,7 +186,7 @@ describe('Resource Management', () => {
const createdCases: string[] = []; const createdCases: string[] = [];
beforeAll(async () => { beforeAll(async () => {
server = new WebServer(TEST_PORT + 1); server = new WebServer(TEST_PORT + 1, false, true);
await server.start(); await server.start();
baseUrl = `http://localhost:${TEST_PORT + 1}`; baseUrl = `http://localhost:${TEST_PORT + 1}`;
}); });
+1 -1
View File
@@ -8,7 +8,7 @@ describe('Interactive Session Lifecycle', () => {
let baseUrl: string; let baseUrl: string;
beforeAll(async () => { beforeAll(async () => {
server = new WebServer(TEST_PORT); server = new WebServer(TEST_PORT, false, true);
await server.start(); await server.start();
baseUrl = `http://localhost:${TEST_PORT}`; baseUrl = `http://localhost:${TEST_PORT}`;
}); });
+2 -2
View File
@@ -37,7 +37,7 @@ describe('SSE Events', () => {
let baseUrl: string; let baseUrl: string;
beforeAll(async () => { beforeAll(async () => {
server = new WebServer(TEST_PORT); server = new WebServer(TEST_PORT, false, true);
await server.start(); await server.start();
baseUrl = `http://localhost:${TEST_PORT}`; baseUrl = `http://localhost:${TEST_PORT}`;
}); });
@@ -180,7 +180,7 @@ describe('SSE Event Types', () => {
let baseUrl: string; let baseUrl: string;
beforeAll(async () => { beforeAll(async () => {
server = new WebServer(TEST_PORT + 1); server = new WebServer(TEST_PORT + 1, false, true);
await server.start(); await server.start();
baseUrl = `http://localhost:${TEST_PORT + 1}`; baseUrl = `http://localhost:${TEST_PORT + 1}`;
}); });