From 86ce154fc179477c986bebd4371f4971e0567541 Mon Sep 17 00:00:00 2001 From: tdwd Date: Tue, 8 Sep 2026 12:59:38 +0200 Subject: [PATCH] splash: dial the backend that is actually running The boot screen printed "ATDT 1-800-CLAUDE" on every session, codex included. It survived two sweeps that were looking straight at it, because both grepped for [Cc]laude and the string is all caps. The lesson is in the test: a sweep for a name has to be case-insensitive, or the one SHOUTED mention is exactly the one it cannot see. The line joins the rest of the copy that names the agent, in agentname.go, so there is still one place to change and a third backend gets it for free. --- agentname.go | 10 ++++++++++ agentname_test.go | 18 ++++++++++++++++++ asset_gen_test.go | 2 +- splash.go | 4 ++-- view.go | 2 +- 5 files changed, 32 insertions(+), 4 deletions(-) diff --git a/agentname.go b/agentname.go index bce00b4..5f95437 100644 --- a/agentname.go +++ b/agentname.go @@ -3,6 +3,8 @@ package main +import "strings" + // ---- what the running backend is called on screen ---- // // Every user-visible mention of the agent goes through here. Before this, the @@ -34,6 +36,14 @@ func agentTagline(backend string) string { return "claude on your Max plan" } +// agentDialString is the splash screen's dial-up line. Pure BBS flavour — ATDT +// was the Hayes modem command to dial — but it names the agent, so it belongs +// with the rest of the copy that does. Upper case because a 1980s board would +// have printed it that way, and because the number is a joke about the name. +func agentDialString(backend string) string { + return "ATDT 1-800-" + strings.ToUpper(agentName(backend)) + " . . ." +} + // promptPlaceholder is the empty-input hint. func promptPlaceholder(backend string) string { return "Ask " + agentName(backend) + "… (enter sends · alt+enter / ctrl+j / \\↵ for a new line)" diff --git a/agentname_test.go b/agentname_test.go index a860e17..c8f51c5 100644 --- a/agentname_test.go +++ b/agentname_test.go @@ -27,6 +27,12 @@ func TestAgentLabelsFollowTheBackend(t *testing.T) { if got := agentTagline(c.backend); !strings.Contains(got, c.want) { t.Errorf("tagline for %q = %q, want it to name %q", c.backend, got, c.want) } + // The splash dials the agent by name, in caps. It reached this test late: + // a sweep for [Cc]laude cannot match CLAUDE, so the one all-caps mention + // in the program survived two passes that were looking straight at it. + if got := agentDialString(c.backend); !strings.Contains(got, strings.ToUpper(c.want)) { + t.Errorf("dial string for %q = %q, want it to name %q", c.backend, got, strings.ToUpper(c.want)) + } } // The taglines name different plans, so one is not silently reused. if agentTagline(backendClaude) == agentTagline(backendCodex) { @@ -81,3 +87,15 @@ func TestCodexModelsFrameFillsThePicker(t *testing.T) { t.Errorf("picker rows = %+v, want the reported model", items) } } + +// The splash actually renders the dial line, so the helper cannot drift from +// what is drawn. +func TestSplashDialsTheRunningBackend(t *testing.T) { + out := stripANSI(splashScreen(90, 0, splashFinalFrame, 0, backendCodex)) + if !strings.Contains(out, "1-800-CODEX") { + t.Errorf("codex splash should dial CODEX, got:\n%s", out) + } + if strings.Contains(out, "CLAUDE") { + t.Errorf("codex splash still names claude:\n%s", out) + } +} diff --git a/asset_gen_test.go b/asset_gen_test.go index c4f3313..4e0fc01 100644 --- a/asset_gen_test.go +++ b/asset_gen_test.go @@ -80,7 +80,7 @@ func TestGenerateThemeAssets(t *testing.T) { // genSplashScreen renders the boot screen at its final reveal frame. height 0 // returns the bare content (no vertical centering), so the image is compact. func genSplashScreen() string { - return splashScreen(90, 0, splashFinalFrame, 0) + return splashScreen(90, 0, splashFinalFrame, 0, backendClaude) } // previewModel builds a real model mid-turn — a user request, a plain reply, diff --git a/splash.go b/splash.go index c061de1..40e26f6 100644 --- a/splash.go +++ b/splash.go @@ -84,7 +84,7 @@ func centerBlock(lines []string, width int, style lipgloss.Style) []string { // modem handshake, a scene divider, a SAUCE-style credit, and a logon prompt. // Sections reveal one frame at a time so the boot looks like a real modem // negotiation; the first keypress dismisses it regardless of progress. -func splashScreen(width, height, frame, logoIdx int) string { +func splashScreen(width, height, frame, logoIdx int, backend string) string { if width < 44 { width = 44 } @@ -102,7 +102,7 @@ func splashScreen(width, height, frame, logoIdx int) string { ) } if frame >= 3 { - lines = append(lines, center(cDim.Render("ATDT 1-800-CLAUDE . . ."))) + lines = append(lines, center(cDim.Render(agentDialString(backend)))) } if frame >= 4 { lines = append(lines, center(dAdd.Render("CONNECT 57600/ARQ/V.42bis/LAPM"))) diff --git a/view.go b/view.go index 465d066..e3ddc29 100644 --- a/view.go +++ b/view.go @@ -17,7 +17,7 @@ func (m model) View() string { return "starting…" } if m.splash { - return splashScreen(m.w, m.h, m.splashFrame, m.logoIdx) + return splashScreen(m.w, m.h, m.splashFrame, m.logoIdx, m.backend) } bg := m.renderBackground() // Modal overlays float on top of the live transcript via placeOverlay