From e6676692fc96872c89fc470b6645a8b510814fe4 Mon Sep 17 00:00:00 2001 From: ace-pm Date: Tue, 21 Apr 2026 00:44:28 +0200 Subject: [PATCH] fix(sf-tui): remove welcome overlay that hangs on enter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The per-session branded welcome overlay was added by the SF rebrand (9d739dfa5) as a boxed 'Press any key to continue...' splash shown once per sf session. In practice: Enter doesn't dismiss it and typing renders as garbled characters behind the overlay, blocking every TUI launch. Branding was redundant with the header (installed at session_start) and the footer (git branch + model). Shortcuts are discoverable via help. Deleting the overlay eliminates the hang vector entirely. Legacy-extension migration warnings (migrations.ts 'Press any key...') are unaffected — those are vendored upstream Pi code on a different code path and only fire when deprecated extensions are present. --- src/resources/extensions/sf-tui/index.ts | 9 -- src/resources/extensions/sf-tui/welcome.ts | 124 --------------------- 2 files changed, 133 deletions(-) delete mode 100644 src/resources/extensions/sf-tui/welcome.ts diff --git a/src/resources/extensions/sf-tui/index.ts b/src/resources/extensions/sf-tui/index.ts index cd88f890e..2f0c330bd 100644 --- a/src/resources/extensions/sf-tui/index.ts +++ b/src/resources/extensions/sf-tui/index.ts @@ -4,7 +4,6 @@ * Features: * - Powerline footer: git branch, diff stats, last commit, model, cost, context * - Header: project name + branch + model - * - Welcome overlay on session start * - Prompt history stash: Ctrl+Alt+H overlay */ @@ -15,13 +14,10 @@ import { openStashOverlay, readStash, pushStash, writeStash } from "./stash.js"; import { openMarketplaceOverlay } from "./marketplace.js"; import { renderFooter } from "./footer.js"; import { renderHeader } from "./header.js"; -import { showWelcomeOverlay } from "./welcome.js"; import { invalidateGitStatus } from "./git.js"; import { registerSessionEmoji } from "./emoji.js"; import { registerSessionColor } from "./color-band.js"; -let hasShownWelcome = false; - function installHeader(ctx: ExtensionContext): void { if (!ctx.hasUI) return; ctx.ui.setHeader((_tui, theme) => { @@ -76,11 +72,6 @@ export default function sfTui(pi: ExtensionAPI): void { handler: openMarketplaceOverlay, }); - if (!hasShownWelcome) { - hasShownWelcome = true; - await showWelcomeOverlay(ctx); - } - wasAutoActive = isAutoActive(); }); diff --git a/src/resources/extensions/sf-tui/welcome.ts b/src/resources/extensions/sf-tui/welcome.ts deleted file mode 100644 index 4415a1317..000000000 --- a/src/resources/extensions/sf-tui/welcome.ts +++ /dev/null @@ -1,124 +0,0 @@ -import type { ExtensionContext, Theme } from "@singularity-forge/pi-coding-agent"; -import { visibleWidth, truncateToWidth, matchesKey, Key } from "@singularity-forge/pi-tui"; -import { refreshGitStatus } from "./git.js"; - -const LOGO_LINES = [ - " ╭────╮ ╭────╮ ", - " │ │ │ ", - " ╰────┤ ╰────╮ ", - " │ │ ", - " ╰────╯ ╰────╯ ", -]; - -function padCenter(text: string, width: number): string { - const vis = visibleWidth(text); - const pad = Math.max(0, Math.floor((width - vis) / 2)); - return " ".repeat(pad) + text; -} - -class WelcomeOverlay { - private tui: { requestRender: () => void }; - private theme: Theme; - private onClose: () => void; - - constructor( - tui: { requestRender: () => void }, - theme: Theme, - onClose: () => void, - ) { - this.tui = tui; - this.theme = theme; - this.onClose = onClose; - } - - handleInput(data: string): void { - if ( - matchesKey(data, Key.escape) || - matchesKey(data, Key.return) || - matchesKey(data, Key.enter) || - matchesKey(data, Key.space) || - data === "q" - ) { - this.onClose(); - } - } - - render(width: number): string[] { - const th = this.theme; - const boxW = Math.min(70, width - 4); - const innerW = boxW - 4; - - const pad = (s: string) => s + " ".repeat(Math.max(0, width - visibleWidth(s))); - const box = (s: string) => { - const len = visibleWidth(s); - return th.fg("dim", "│ ") + s + " ".repeat(Math.max(0, boxW - 2 - len)) + th.fg("dim", " │"); - }; - - const lines: string[] = []; - lines.push(pad(th.fg("dim", "╭" + "─".repeat(boxW) + "╮"))); - - for (const logoLine of LOGO_LINES) { - lines.push(pad(box(padCenter(th.fg("accent", logoLine), innerW)))); - } - - const title = th.bold(th.fg("accent", "Singularity Forge")); - lines.push(pad(box(padCenter(title, innerW)))); - lines.push(pad(box(""))); - - const version = `v${process.env.SF_VERSION || "0.0.0"}`; - lines.push(pad(box(padCenter(th.fg("dim", version), innerW)))); - lines.push(pad(box(""))); - - const git = refreshGitStatus(process.cwd()); - if (git.branch) { - const dirty = git.dirty ? th.fg("error", "✗") : th.fg("success", "✓"); - lines.push(pad(box(padCenter(`${th.fg("dim", "Git:")} ${th.fg("accent", git.branch)} ${dirty}`, innerW)))); - if (git.lastCommit) { - const msg = truncateToWidth(git.lastCommit.message, innerW - 14); - lines.push(pad(box(padCenter(`${th.fg("dim", "Last commit:")} ${th.fg("dim", msg)}`, innerW)))); - } - lines.push(pad(box(""))); - } - - const shortcuts = [ - `${th.fg("dim", "Ctrl+Alt+H")} prompt history`, - `${th.fg("dim", "Ctrl+Alt+G")} dashboard`, - `${th.fg("dim", "Ctrl+Alt+N")} notifications`, - ]; - for (const sc of shortcuts) { - lines.push(pad(box(padCenter(sc, innerW)))); - } - lines.push(pad(box(""))); - - lines.push(pad(box(padCenter(th.fg("dim", "Press any key to continue..."), innerW)))); - lines.push(pad(th.fg("dim", "╰" + "─".repeat(boxW) + "╯"))); - lines.push(""); - - return lines; - } -} - -export async function showWelcomeOverlay(ctx: ExtensionContext): Promise { - if (!ctx.hasUI) return; - - await ctx.ui.custom( - (tui, theme, _kb, done) => { - const overlay = new WelcomeOverlay(tui, theme, () => done(true)); - return { - render: (w) => overlay.render(w), - invalidate: () => {}, - handleInput: (d) => overlay.handleInput(d), - }; - }, - { - overlay: true, - overlayOptions: { - width: "90%", - minWidth: 50, - maxHeight: "90%", - anchor: "center", - backdrop: true, - }, - }, - ); -}