diff --git a/src/AppState.ts b/src/AppState.ts index e8cca3b..cf2944e 100644 --- a/src/AppState.ts +++ b/src/AppState.ts @@ -1,6 +1,6 @@ import { EventEmitter } from 'node:events'; -export type AppPhase = 'idle' | 'sending' | 'thinking' | 'prompting'; +export type AppPhase = 'idle' | 'sending' | 'thinking' | 'prompting' | 'asking'; export interface AppStateEvents { changed: [phase: AppPhase]; @@ -47,13 +47,24 @@ export class AppState extends EventEmitter { }, 500); } - /** A permission or question prompt is active */ + /** A permission prompt is active (label updated externally by permission timer) */ public prompting(label: string): void { this.stopTimer(); this._promptLabel = label; this.setPhase('prompting'); } + /** A question prompt is active (has its own elapsed timer) */ + public asking(label: string): void { + this.stopTimer(); + this._sendStartTime = Date.now(); + this._promptLabel = label; + this.setPhase('asking'); + this._timer = setInterval(() => { + this.emit('changed', this._phase); + }, 500); + } + /** Query is done, back to idle */ public idle(): void { this.stopTimer(); diff --git a/src/PromptManager.ts b/src/PromptManager.ts index 47528d3..e1627b4 100644 --- a/src/PromptManager.ts +++ b/src/PromptManager.ts @@ -223,6 +223,7 @@ export class PromptManager { if (!q) { return; } + this.appState.asking(`${q.header}: Select [1-${q.options.length + 1}]`); this.term.log(`\x1b[1m${q.question}\x1b[0m`); for (let i = 0; i < q.options.length; i++) { this.term.log(` \x1b[36m${i + 1})\x1b[0m ${q.options[i].label} — ${q.options[i].description}`); diff --git a/src/terminal.ts b/src/terminal.ts index 0e95592..8a789b8 100644 --- a/src/terminal.ts +++ b/src/terminal.ts @@ -66,10 +66,14 @@ export class Terminal { } case 'prompting': return '🔔 ' + this.formatLogLine(this.appState.promptLabel ?? ''); + case 'asking': { + const elapsed = this.appState.elapsedSeconds ?? 0; + return '🔔 ' + this.formatLogLine(`(${elapsed}s) ${this.appState.promptLabel ?? ''}`); + } } } - private refreshSticky(): void { + private buildSticky(): string { const columns = process.stdout.columns || 80; let output = ''; @@ -101,7 +105,7 @@ export class Terminal { this.stickyLineCount = statusScreenLines + editorScreenLines; - process.stdout.write(output); + return output; } private writeHistory(line: string): void { @@ -109,9 +113,9 @@ export class Terminal { output += this.clearStickyZone(); output += line; output += '\n'; - process.stdout.write(output); this.stickyLineCount = 0; - this.refreshSticky(); + output += this.buildSticky(); + process.stdout.write(output); } /** Call when AppState changes to refresh the sticky zone */ @@ -119,8 +123,8 @@ export class Terminal { let output = ''; output += this.clearStickyZone(); this.stickyLineCount = 0; + output += this.buildSticky(); process.stdout.write(output); - this.refreshSticky(); } public log(message: string, ...args: unknown[]): void { @@ -138,8 +142,8 @@ export class Terminal { this.editorContent = prepareEditor(editor, prompt); this.cursorHidden = hideCursor; this.stickyLineCount = 0; + output += this.buildSticky(); process.stdout.write(output); - this.refreshSticky(); } public write(data: string): void {