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();