fix: remove duplicate TUI header rendered on session_start (#1663)
This commit is contained in:
parent
ee7c6b5c2b
commit
0997b4945d
5 changed files with 29 additions and 72 deletions
|
|
@ -323,11 +323,13 @@ function pruneRemovedBundledExtensions(
|
|||
for (const prevFile of manifest.installedExtensionRootFiles) {
|
||||
removeIfStale(prevFile)
|
||||
}
|
||||
} else {
|
||||
// Fallback: explicitly remove known stale files from pre-manifest-tracking versions
|
||||
// env-utils.js was moved from extensions/ root → gsd/ in v2.39.x (#1634)
|
||||
removeIfStale('env-utils.js')
|
||||
}
|
||||
|
||||
// Always remove known stale files regardless of manifest state.
|
||||
// These were installed by pre-manifest versions so they may not appear in
|
||||
// installedExtensionRootFiles even when a manifest exists.
|
||||
// env-utils.js was moved from extensions/ root → gsd/ in v2.39.x (#1634)
|
||||
removeIfStale('env-utils.js')
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -14,12 +14,28 @@ import { deriveState } from "../state.js";
|
|||
import { getAutoDashboardData, isAutoActive, isAutoPaused, markToolEnd, markToolStart } from "../auto.js";
|
||||
import { isParallelActive, shutdownParallel } from "../parallel-orchestrator.js";
|
||||
import { saveActivityLog } from "../activity-log.js";
|
||||
import { maybeRenderGsdHeader } from "./register-shortcuts.js";
|
||||
|
||||
// Skip the welcome screen on the very first session_start — cli.ts already
|
||||
// printed it before the TUI launched. Only re-print on /clear (subsequent sessions).
|
||||
let isFirstSession = true;
|
||||
|
||||
export function registerHooks(pi: ExtensionAPI): void {
|
||||
pi.on("session_start", async (_event, ctx) => {
|
||||
resetWriteGateState();
|
||||
maybeRenderGsdHeader(ctx);
|
||||
if (isFirstSession) {
|
||||
isFirstSession = false;
|
||||
} else {
|
||||
try {
|
||||
const gsdBinPath = process.env.GSD_BIN_PATH;
|
||||
if (gsdBinPath) {
|
||||
const { dirname } = await import('node:path');
|
||||
const { printWelcomeScreen } = await import(
|
||||
join(dirname(gsdBinPath), 'welcome-screen.js')
|
||||
) as { printWelcomeScreen: (opts: { version: string; modelName?: string; provider?: string }) => void };
|
||||
printWelcomeScreen({ version: process.env.GSD_VERSION || '0.0.0' });
|
||||
}
|
||||
} catch { /* non-fatal */ }
|
||||
}
|
||||
loadToolApiKeys();
|
||||
try {
|
||||
const [{ getRemoteConfigStatus }, { getLatestPromptSummary }] = await Promise.all([
|
||||
|
|
|
|||
|
|
@ -2,20 +2,11 @@ import { existsSync } from "node:fs";
|
|||
import { join } from "node:path";
|
||||
|
||||
import type { ExtensionAPI } from "@gsd/pi-coding-agent";
|
||||
import { Key, Text } from "@gsd/pi-tui";
|
||||
import { Key } from "@gsd/pi-tui";
|
||||
|
||||
import { GSDDashboardOverlay } from "../dashboard-overlay.js";
|
||||
import { shortcutDesc } from "../../shared/mod.js";
|
||||
|
||||
export const GSD_LOGO_LINES = [
|
||||
" ██████╗ ███████╗██████╗ ",
|
||||
" ██╔════╝ ██╔════╝██╔══██╗",
|
||||
" ██║ ███╗███████╗██║ ██║",
|
||||
" ██║ ██║╚════██║██║ ██║",
|
||||
" ╚██████╔╝███████║██████╔╝",
|
||||
" ╚═════╝ ╚══════╝╚═════╝ ",
|
||||
];
|
||||
|
||||
export function registerShortcuts(pi: ExtensionAPI): void {
|
||||
pi.registerShortcut(Key.ctrlAlt("g"), {
|
||||
description: shortcutDesc("Open GSD dashboard", "/gsd status"),
|
||||
|
|
@ -39,17 +30,3 @@ export function registerShortcuts(pi: ExtensionAPI): void {
|
|||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function maybeRenderGsdHeader(ctx: { ui: any }): void {
|
||||
try {
|
||||
const theme = ctx.ui.theme;
|
||||
const version = process.env.GSD_VERSION || "0.0.0";
|
||||
const logoText = GSD_LOGO_LINES.map((line) => theme.fg("accent", line)).join("\n");
|
||||
const titleLine = ` ${theme.bold("Get Shit Done")} ${theme.fg("dim", `v${version}`)}`;
|
||||
const headerContent = `${logoText}\n${titleLine}`;
|
||||
ctx.ui.setHeader((_ui: unknown, _theme: unknown) => new Text(headerContent, 1, 0));
|
||||
} catch {
|
||||
// no TUI
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -216,23 +216,9 @@ export function registerNativeSearchHooks(pi: NativeSearchPI): { getIsAnthropic:
|
|||
return payload;
|
||||
});
|
||||
|
||||
// Basic startup diagnostics — provider-specific info comes from model_select
|
||||
pi.on("session_start", async (_event: any, ctx: any) => {
|
||||
pi.on("session_start", async (_event: any, _ctx: any) => {
|
||||
// Reset session-level search budget (#1309)
|
||||
sessionSearchCount = 0;
|
||||
|
||||
const hasBrave = !!process.env.BRAVE_API_KEY;
|
||||
const hasJina = !!process.env.JINA_API_KEY;
|
||||
const hasAnswers = !!process.env.BRAVE_ANSWERS_KEY;
|
||||
const hasTavily = !!process.env.TAVILY_API_KEY;
|
||||
|
||||
const parts: string[] = ["Web search v4 loaded"];
|
||||
if (hasBrave) parts.push("Brave ✓");
|
||||
if (hasAnswers) parts.push("Answers ✓");
|
||||
if (hasJina) parts.push("Jina ✓");
|
||||
if (hasTavily) parts.push("Tavily ✓");
|
||||
|
||||
ctx.ui.notify(parts.join(" · "), "info");
|
||||
});
|
||||
|
||||
return { getIsAnthropic: () => isAnthropicProvider };
|
||||
|
|
|
|||
|
|
@ -433,41 +433,17 @@ test("model_select shows warning for non-Anthropic without Brave key", async ()
|
|||
}
|
||||
});
|
||||
|
||||
test("session_start shows v4 loaded message", async () => {
|
||||
test("session_start resets search count and shows no startup notification", async () => {
|
||||
const pi = createMockPI();
|
||||
registerNativeSearchHooks(pi);
|
||||
|
||||
await pi.fire("session_start", { type: "session_start" });
|
||||
|
||||
// Tool status is now shown in the welcome screen bar layout — no notification on session_start
|
||||
const infoNotif = pi.notifications.find(
|
||||
(n) => n.level === "info" && n.message.includes("v4")
|
||||
);
|
||||
assert.ok(infoNotif, "Should have v4 info notification");
|
||||
assert.ok(
|
||||
infoNotif!.message.startsWith("Web search v4 loaded"),
|
||||
`Should start with 'Web search v4 loaded' — got: ${infoNotif!.message}`
|
||||
);
|
||||
});
|
||||
|
||||
test("session_start shows Brave status when key present", async () => {
|
||||
const originalKey = process.env.BRAVE_API_KEY;
|
||||
process.env.BRAVE_API_KEY = "test-key";
|
||||
|
||||
try {
|
||||
const pi = createMockPI();
|
||||
registerNativeSearchHooks(pi);
|
||||
|
||||
await pi.fire("session_start", { type: "session_start" });
|
||||
|
||||
const info = pi.notifications.find((n) => n.level === "info");
|
||||
assert.ok(info!.message.includes("Brave"), "Should mention Brave in status");
|
||||
|
||||
const warning = pi.notifications.find((n) => n.level === "warning");
|
||||
assert.equal(warning, undefined, "Should NOT show warning when Brave key is present");
|
||||
} finally {
|
||||
if (originalKey) process.env.BRAVE_API_KEY = originalKey;
|
||||
else delete process.env.BRAVE_API_KEY;
|
||||
}
|
||||
assert.equal(infoNotif, undefined, "Should NOT emit a v4 startup notification (welcome screen handles this)");
|
||||
});
|
||||
|
||||
test("BRAVE_TOOL_NAMES contains expected tool names", () => {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue