fix(tui): show connection host in footer

This commit is contained in:
WB
2026-06-04 00:45:29 +09:00
committed by Shakker
parent 1893a0727a
commit 479e2aaae3
5 changed files with 29 additions and 3 deletions

View File

@@ -54,7 +54,7 @@ Notes:
- Header: connection URL, current agent, current session.
- Chat log: user messages, assistant replies, system notices, tool cards.
- Status line: connection/run state (connecting, running, streaming, idle, error).
- Footer: connection state + agent + session + model + goal state + think/fast/verbose/trace/reasoning + token counts + deliver.
- Footer: connection host when available + agent + session + model + goal state + think/fast/verbose/trace/reasoning + token counts + deliver.
- Input: text editor with autocomplete.
## Mental model: agents + sessions
@@ -67,7 +67,7 @@ Notes:
- Session scope:
- `per-sender` (default): each agent has many sessions.
- `global`: the TUI always uses the `global` session (the picker may be empty).
- The current agent + session are always visible in the footer.
- For URL-backed connections, the footer includes the connection host alongside the current agent and session.
- If the session has a [goal](/tools/goal), the footer shows its compact state
such as `Pursuing goal`, `Goal paused (/goal resume)`, or
`Goal achieved`.

View File

@@ -5,6 +5,7 @@ import {
extractContentFromMessage,
extractTextFromMessage,
extractThinkingFromMessage,
formatConnectionHostFooter,
formatGoalFooter,
isCommandMessage,
sanitizeRenderableText,
@@ -45,6 +46,19 @@ describe("formatGoalFooter", () => {
});
});
describe("formatConnectionHostFooter", () => {
it("renders only the connection hostname", () => {
expect(formatConnectionHostFooter("ws://gateway-host:18789")).toBe("host gateway-host");
expect(
formatConnectionHostFooter("wss://user:secret@example.com:443/path?token=redacted"),
).toBe("host example.com");
});
it("skips non-url local connection labels", () => {
expect(formatConnectionHostFooter("local embedded")).toBeNull();
});
});
describe("extractTextFromMessage", () => {
it("prefers final_answer text over commentary text for assistant messages", () => {
const text = extractTextFromMessage({

View File

@@ -443,6 +443,15 @@ export function formatTokens(total?: number | null, context?: number | null) {
return `tokens ${totalLabel}/${formatTokenCount(context)}${pct !== null ? ` (${pct}%)` : ""}`;
}
export function formatConnectionHostFooter(connectionUrl: string): string | null {
try {
const hostname = new URL(connectionUrl.trim()).hostname.trim();
return hostname ? `host ${hostname}` : null;
} catch {
return null;
}
}
function formatGoalUsage(goal: SessionGoal): string | null {
if (goal.tokenBudget === undefined) {
return goal.tokensUsed > 0 ? formatTokenCount(goal.tokensUsed) : null;

View File

@@ -364,6 +364,7 @@ describe.sequential("TUI PTY harness", () => {
it("renders local ready on startup", () => {
expect(fixture.run.output()).toContain("local ready");
expect(fixture.run.output()).toContain("host local");
});
it(

View File

@@ -35,7 +35,7 @@ import { editorTheme, theme } from "./theme/theme.js";
import type { TuiBackend } from "./tui-backend.js";
import { createCommandHandlers } from "./tui-command-handlers.js";
import { createEventHandlers } from "./tui-event-handlers.js";
import { formatGoalFooter, formatTokens } from "./tui-formatters.js";
import { formatConnectionHostFooter, formatGoalFooter, formatTokens } from "./tui-formatters.js";
import {
buildTuiLastSessionScopeKey,
readTuiLastSessionKey,
@@ -1199,7 +1199,9 @@ export async function runTui(opts: RunTuiOptions): Promise<TuiResult> {
const reasoning = sessionInfo.reasoningLevel ?? "off";
const reasoningLabel =
reasoning === "on" ? "reasoning" : reasoning === "stream" ? "reasoning:stream" : null;
const hostLabel = formatConnectionHostFooter(client.connection.url);
const footerParts = [
hostLabel,
`agent ${agentLabel}`,
`session ${sessionLabel}`,
modelLabel,