perf: speed up session creation by ~500ms — remove redundant sleep, reduce tmux wait, fire-and-forget config

This commit is contained in:
arkon
2026-02-20 04:30:02 +01:00
parent 544ef67aeb
commit 99ad44e907
6 changed files with 54 additions and 34 deletions
+2 -6
View File
@@ -878,9 +878,7 @@ export class Session extends EventEmitter {
// Create a new mux session
this._muxSession = await this._mux.createSession(this.id, this.workingDir, 'claude', this._name, this._niceConfig, this._model);
console.log('[Session] Created mux session:', this._muxSession.muxName);
// Wait a moment for mux to fully start
await new Promise(resolve => setTimeout(resolve, MUX_STARTUP_DELAY_MS));
// No extra sleep — createSession() already waits for tmux readiness
}
// Attach to the mux session via PTY
@@ -1176,9 +1174,7 @@ export class Session extends EventEmitter {
// Create a new mux session
this._muxSession = await this._mux.createSession(this.id, this.workingDir, 'shell', this._name, this._niceConfig);
console.log('[Session] Created mux session:', this._muxSession.muxName);
// Wait a moment for mux to fully start
await new Promise(resolve => setTimeout(resolve, MUX_STARTUP_DELAY_MS));
// No extra sleep — createSession() already waits for tmux readiness
}
// Attach to the mux session via PTY
+5 -3
View File
@@ -45,8 +45,8 @@ import { findClaudeDir } from './utils/claude-cli-resolver.js';
/** Timeout for exec commands (5 seconds) */
const EXEC_TIMEOUT_MS = 5000;
/** Delay after tmux session creation (300ms) */
const TMUX_CREATION_WAIT_MS = 300;
/** Delay after tmux session creation — enough for detached tmux to be queryable */
const TMUX_CREATION_WAIT_MS = 100;
/** Delay after tmux kill command (200ms) */
const TMUX_KILL_WAIT_MS = 200;
@@ -298,7 +298,9 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer {
);
}
await Promise.all(configPromises);
// Fire-and-forget — these are non-critical UX niceties that don't need
// to complete before the session is usable. Errors are already swallowed.
void Promise.all(configPromises);
// Get the PID of the pane process
const pid = this.getPanePid(muxName);
+17
View File
@@ -96,6 +96,23 @@ const BUILTIN_RESPAWN_PRESETS = [
builtIn: true,
createdAt: 0,
},
{
id: 'ralph-todo',
name: 'Ralph/Todo',
description: 'Ralph Loop task list — works through todos with progress tracking',
config: {
idleTimeoutMs: 8000,
updatePrompt: 'update CLAUDE.md with discoveries and progress notes, mark completed tasks in @fix_plan.md, write a brief summary so the next cycle can continue seamlessly.',
interStepDelayMs: 3000,
sendClear: true,
sendInit: true,
kickstartPrompt: 'read @fix_plan.md for task status, continue on the next uncompleted task. When ALL tasks are complete, output <promise>COMPLETE</promise>.',
autoAcceptPrompts: true,
},
durationMinutes: 480,
builtIn: true,
createdAt: 0,
},
{
id: 'overnight-autonomous',
name: 'Overnight',
+27 -22
View File
@@ -4635,37 +4635,42 @@ NOW: Generate the implementation plan for the task above. Think step by step.`;
return undefined;
}
// Helper to get global Nice priority config from settings
private async getGlobalNiceConfig(): Promise<NiceConfig | undefined> {
// Read ~/.claudeman/settings.json once and return the parsed object.
// Cached for 2s to avoid redundant reads during session creation bursts.
private _settingsCache: { data: Record<string, unknown>; ts: number } | null = null;
private async readSettings(): Promise<Record<string, unknown>> {
const now = Date.now();
if (this._settingsCache && now - this._settingsCache.ts < 2000) {
return this._settingsCache.data;
}
const settingsPath = join(homedir(), '.claudeman', 'settings.json');
try {
const content = await fs.readFile(settingsPath, 'utf-8');
const settings = JSON.parse(content);
if (settings.nice && settings.nice.enabled) {
return {
enabled: settings.nice.enabled ?? false,
niceValue: settings.nice.niceValue ?? DEFAULT_NICE_CONFIG.niceValue,
};
}
} catch (err) {
if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {
console.error('Failed to read Nice priority settings:', err);
}
const data = JSON.parse(content) as Record<string, unknown>;
this._settingsCache = { data, ts: now };
return data;
} catch {
return {};
}
}
// Helper to get global Nice priority config from settings
private async getGlobalNiceConfig(): Promise<NiceConfig | undefined> {
const settings = await this.readSettings();
const nice = settings.nice as { enabled?: boolean; niceValue?: number } | undefined;
if (nice && nice.enabled) {
return {
enabled: nice.enabled ?? false,
niceValue: nice.niceValue ?? DEFAULT_NICE_CONFIG.niceValue,
};
}
return undefined;
}
// Helper to get model configuration from settings
private async getModelConfig(): Promise<{ defaultModel?: string; agentTypeOverrides?: Record<string, string> } | null> {
const settingsPath = join(homedir(), '.claudeman', 'settings.json');
try {
const content = await fs.readFile(settingsPath, 'utf-8');
return JSON.parse(content).modelConfig || null;
} catch {
return null;
}
const settings = await this.readSettings();
return (settings.modelConfig as { defaultModel?: string; agentTypeOverrides?: Record<string, string> }) || null;
}
private async startScheduledRun(prompt: string, workingDir: string, durationMinutes: number): Promise<ScheduledRun> {