diff --git a/src/respawn-controller.ts b/src/respawn-controller.ts index 5fa2ffaa..c50cde6e 100644 --- a/src/respawn-controller.ts +++ b/src/respawn-controller.ts @@ -355,7 +355,7 @@ export class RespawnController extends EventEmitter { this.stepTimer = setTimeout(() => { const prompt = this.config.kickstartPrompt!; this.log(`Sending kickstart prompt: "${prompt}"`); - this.session.write(prompt + '\r'); // \r triggers key.return in Ink/Claude CLI + this.session.writeViaScreen(prompt + '\r'); // \r triggers key.return in Ink/Claude CLI this.emit('stepSent', 'kickstart', prompt); this.setState('waiting_kickstart'); this.promptDetected = false; @@ -418,7 +418,7 @@ export class RespawnController extends EventEmitter { this.stepTimer = setTimeout(() => { const input = this.config.updatePrompt + '\r\n'; // CRLF for screen + Claude CLI this.log(`Sending update prompt: "${this.config.updatePrompt}"`); - this.session.write(input); + this.session.writeViaScreen(input); this.emit('stepSent', 'update', this.config.updatePrompt); this.setState('waiting_update'); this.promptDetected = false; @@ -432,7 +432,7 @@ export class RespawnController extends EventEmitter { this.stepTimer = setTimeout(() => { this.log('Sending /clear'); - this.session.write('/clear\r\n'); // CRLF for screen + Claude CLI + this.session.writeViaScreen('/clear\r\n'); // CRLF for screen + Claude CLI this.emit('stepSent', 'clear', '/clear'); this.setState('waiting_clear'); this.promptDetected = false; @@ -445,7 +445,7 @@ export class RespawnController extends EventEmitter { this.stepTimer = setTimeout(() => { this.log('Sending /init'); - this.session.write('/init\r\n'); // CRLF for screen + Claude CLI + this.session.writeViaScreen('/init\r\n'); // CRLF for screen + Claude CLI this.emit('stepSent', 'init', '/init'); this.setState('waiting_init'); this.promptDetected = false; diff --git a/src/session.ts b/src/session.ts index 9108a813..270b17e2 100644 --- a/src/session.ts +++ b/src/session.ts @@ -898,23 +898,26 @@ export class Session extends EventEmitter { } // Send input to the PTY (for interactive sessions) - // When using screen, prefers screen -X stuff for reliable input delivery write(data: string): void { - // Try screen -X stuff first if we have a screen session - // This is more reliable for sending Enter key to Claude CLI - if (this._screenManager && this._screenSession) { - const success = this._screenManager.sendInput(this.id, data); - if (success) { - return; - } - // Fall through to PTY write if screen command failed - } - if (this.ptyProcess) { this.ptyProcess.write(data); } } + // Send input via screen -X stuff (for programmatic input like respawn controller) + // This bypasses PTY and sends directly to screen, more reliable for Enter key + writeViaScreen(data: string): boolean { + if (this._screenManager && this._screenSession) { + return this._screenManager.sendInput(this.id, data); + } + // Fallback to PTY write + if (this.ptyProcess) { + this.ptyProcess.write(data); + return true; + } + return false; + } + // Resize the PTY resize(cols: number, rows: number): void { if (this.ptyProcess) {