diff --git a/src/session.ts b/src/session.ts index b8d86e7b..9397c056 100644 --- a/src/session.ts +++ b/src/session.ts @@ -2542,19 +2542,17 @@ export class Session extends EventEmitter { * For interactive sessions, this is how you send user input to Claude. * Remember to include `\r` (carriage return) to simulate pressing Enter. * - * @param data - The input data to send (text, escape sequences, etc.) - * * @example * ```typescript * session.write('hello world'); // Text only, no Enter * session.write('\r'); // Enter key * session.write('ls -la\r'); // Command with Enter * ``` - */ - /** - * @returns true if the data reached a PTY. A session whose PTY is gone silently - * swallowed every write before this signal existed, which is how input could - * disappear with the caller believing it had been delivered. + * + * @param data - The input data to send (text, escape sequences, etc.) + * @returns true if the data reached a PTY. A session whose PTY is gone still + * discards the data, but it used to do so with no signal at all — which is how + * input could disappear while the caller believed it had been delivered. */ write(data: string): boolean { this._trackSubmit(data); @@ -2605,6 +2603,19 @@ export class Session extends EventEmitter { * half-open socket silently drops frames with no error) would type a prompt * twice whenever an ACK is lost after the write landed. */ + shouldApplyInput(clientId: string, seq: number): boolean { + const last = this._appliedInputSeq.get(clientId); + if (last !== undefined && seq <= last) return false; + // Re-insert to move this client to the MRU end for fair eviction. + if (last !== undefined) this._appliedInputSeq.delete(clientId); + this._appliedInputSeq.set(clientId, seq); + if (this._appliedInputSeq.size > Session.MAX_INPUT_DEDUP_CLIENTS) { + const oldest = this._appliedInputSeq.keys().next().value; + if (oldest !== undefined) this._appliedInputSeq.delete(oldest); + } + return true; + } + /** * Undo the bookkeeping of {@link shouldApplyInput} for a delivery that failed. * @@ -2622,19 +2633,6 @@ export class Session extends EventEmitter { } } - shouldApplyInput(clientId: string, seq: number): boolean { - const last = this._appliedInputSeq.get(clientId); - if (last !== undefined && seq <= last) return false; - // Re-insert to move this client to the MRU end for fair eviction. - if (last !== undefined) this._appliedInputSeq.delete(clientId); - this._appliedInputSeq.set(clientId, seq); - if (this._appliedInputSeq.size > Session.MAX_INPUT_DEDUP_CLIENTS) { - const oldest = this._appliedInputSeq.keys().next().value; - if (oldest !== undefined) this._appliedInputSeq.delete(oldest); - } - return true; - } - /** * Sends input via the terminal multiplexer's direct input mechanism. * diff --git a/test/mocks/mock-session.ts b/test/mocks/mock-session.ts index 9e886bf5..7d7a5be7 100644 --- a/test/mocks/mock-session.ts +++ b/test/mocks/mock-session.ts @@ -30,7 +30,6 @@ export class MockSession extends EventEmitter { this._muxName = `codeman-test-${id.slice(0, 8)}`; } - /** Direct PTY write (used by session.write()) */ /** * Set to simulate a session whose PTY is gone: both write paths report failure, * which is the state in which input used to disappear silently.