diff --git a/web/src/client/components/session-card.ts b/web/src/client/components/session-card.ts index cc528fbe..073c65a7 100644 --- a/web/src/client/components/session-card.ts +++ b/web/src/client/components/session-card.ts @@ -27,6 +27,7 @@ export class SessionCard extends LitElement { @property({ type: Object }) session!: Session; @state() private killing = false; @state() private killingFrame = 0; + @state() private hasEscPrompt = false; private killingInterval: number | null = null; @@ -47,6 +48,10 @@ export class SessionCard extends LitElement { ); } + private handleEscPromptChange(event: CustomEvent) { + this.hasEscPrompt = event.detail.hasEscPrompt; + } + private async handleKillClick(e: Event) { e.stopPropagation(); e.preventDefault(); @@ -151,10 +156,9 @@ export class SessionCard extends LitElement { render() { return html`
@@ -211,6 +215,7 @@ export class SessionCard extends LitElement { .sessionId=${this.session.id} class="w-full h-full" style="pointer-events: none;" + @esc-prompt-change=${this.handleEscPromptChange} > `}
diff --git a/web/src/client/components/vibe-terminal-buffer.ts b/web/src/client/components/vibe-terminal-buffer.ts index 3345a63a..c96d5285 100644 --- a/web/src/client/components/vibe-terminal-buffer.ts +++ b/web/src/client/components/vibe-terminal-buffer.ts @@ -25,6 +25,7 @@ export class VibeTerminalBuffer extends LitElement { @state() private error: string | null = null; @state() private displayedFontSize = 14; @state() private visibleRows = 0; + @state() private containsEscPrompt = false; private container: HTMLElement | null = null; private resizeObserver: ResizeObserver | null = null; @@ -122,6 +123,9 @@ export class VibeTerminalBuffer extends LitElement { this.buffer = snapshot; this.error = null; + // Check if buffer contains "esc to interrupt" text + this.checkForEscPrompt(); + // Recalculate dimensions now that we have the actual cols this.calculateDimensions(); @@ -130,6 +134,35 @@ export class VibeTerminalBuffer extends LitElement { }); } + private checkForEscPrompt() { + if (!this.buffer) { + this.containsEscPrompt = false; + return; + } + + // Check if any line contains "esc to interrupt" (case insensitive) + const searchText = 'esc to interrupt'; + const found = this.buffer.cells.some((row) => { + const lineText = row + .map((cell) => cell.char) + .join('') + .toLowerCase(); + return lineText.includes(searchText); + }); + + if (found !== this.containsEscPrompt) { + this.containsEscPrompt = found; + // Dispatch event to notify parent + this.dispatchEvent( + new CustomEvent('esc-prompt-change', { + detail: { hasEscPrompt: found }, + bubbles: true, + composed: true, + }) + ); + } + } + private unsubscribeFromBuffer() { if (this.unsubscribe) { this.unsubscribe();