feat(coding-agent): reflect agent run state in terminal title
The terminal title (OSC 0) now carries a run-state prefix: an animated spinner while the agent is working and a steady dot when idle, so a backgrounded tab/pane shows which session is busy vs done. `setTerminalTitleState` also exposes an `attention` ([!]) state for callers; rendering is gated by `tui.titleState` (default on), dedups writes, and is TTY-guarded. Refs can1357/oh-my-pi#3587
This commit is contained in:
@@ -30,6 +30,7 @@ import { nextActionableTask } from "../../tools/todo";
|
||||
import { SpeechEnhancer } from "../../tts/speech-enhancer";
|
||||
import { vocalizer } from "../../tts/vocalizer";
|
||||
import { canonicalizeMessage } from "../../utils/thinking-display";
|
||||
import { setTerminalTitleState } from "../../utils/title-generator";
|
||||
import { interruptHint } from "../shared";
|
||||
import { createAssistantMessageComponent } from "../utils/interactive-context-helpers";
|
||||
import { assistantUsageIsBilled } from "../utils/transcript-render-helpers";
|
||||
@@ -386,6 +387,7 @@ export class EventController {
|
||||
this.ctx.statusLine.markActivityStart();
|
||||
this.#setTerminalProgress(true);
|
||||
this.ctx.ensureLoadingAnimation();
|
||||
setTerminalTitleState("working");
|
||||
this.ctx.ui.requestRender();
|
||||
}
|
||||
|
||||
@@ -875,6 +877,7 @@ export class EventController {
|
||||
async #handleToolExecutionStart(event: Extract<AgentSessionEvent, { type: "tool_execution_start" }>): Promise<void> {
|
||||
this.#ensureWorkingLoaderWhileStreaming();
|
||||
this.#updateWorkingMessageFromIntent(event.intent);
|
||||
if (event.toolName === "ask") setTerminalTitleState("attention");
|
||||
this.#resolveDisplaceablePoll(event.toolName);
|
||||
if (!this.ctx.pendingTools.has(event.toolCallId)) {
|
||||
if (event.toolName === "read" && readArgsHaveTarget(event.args) && !readArgsTargetInternalUrl(event.args)) {
|
||||
@@ -964,6 +967,7 @@ export class EventController {
|
||||
// which only fire `tool_execution_end`, never `_update` — do not leave
|
||||
// the UI looking idle while the session keeps streaming (#3857).
|
||||
this.#ensureWorkingLoaderWhileStreaming();
|
||||
if (event.toolName === "ask") setTerminalTitleState("working");
|
||||
if (event.toolName === "read") {
|
||||
if (this.#inlineReadToolImages(event.toolCallId, event.result)) {
|
||||
const component = this.ctx.pendingTools.get(event.toolCallId);
|
||||
@@ -1071,6 +1075,7 @@ export class EventController {
|
||||
// the loader and finalizes it at its own agent_end (isStreaming === false by
|
||||
// then). Mirrors the collab guest's !isStreaming loader reconciler.
|
||||
if (this.ctx.session.isStreaming) return;
|
||||
setTerminalTitleState("idle");
|
||||
|
||||
await this.#finishAgentEnd();
|
||||
}
|
||||
|
||||
@@ -124,7 +124,12 @@ import type { EventBus } from "../utils/event-bus";
|
||||
import { getEditorCommand, openInEditor } from "../utils/external-editor";
|
||||
import { getSessionAccentAnsi, getSessionAccentHex } from "../utils/session-color";
|
||||
import { messageHasDisplayableThinking } from "../utils/thinking-display";
|
||||
import { popTerminalTitle, pushTerminalTitle, setSessionTerminalTitle } from "../utils/title-generator";
|
||||
import {
|
||||
popTerminalTitle,
|
||||
pushTerminalTitle,
|
||||
setSessionTerminalTitle,
|
||||
setTerminalTitleStateEnabled,
|
||||
} from "../utils/title-generator";
|
||||
import type { AssistantMessageComponent } from "./components/assistant-message";
|
||||
import type { BashExecutionComponent } from "./components/bash-execution";
|
||||
import { ChatBlock, type ChatBlockHost } from "./components/chat-block";
|
||||
@@ -947,6 +952,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
||||
// the initial welcome frame does not append over the previous run's scrollback.
|
||||
this.ui.start({ clearScrollback: options.clearInitialTerminalHistory === true });
|
||||
pushTerminalTitle();
|
||||
setTerminalTitleStateEnabled(this.settings.get("tui.titleState"));
|
||||
setSessionTerminalTitle(this.sessionManager.getSessionName(), this.sessionManager.getCwd());
|
||||
this.updateEditorBorderColor();
|
||||
// Single side-effect point for title changes: every setSessionName caller
|
||||
|
||||
Reference in New Issue
Block a user