fix: fixing the exit message service to use constants

- Avoiding mouse events for exit messages on terminal on stop process
This commit is contained in:
2026-02-06 11:49:23 -05:00
parent d1b00a2115
commit f767987a42
4 changed files with 98 additions and 1 deletions

View File

@@ -0,0 +1,34 @@
/**
* Exit message constants for the post-exit banner
*
* Displayed after the TUI exits to show session info
* and the resume command.
*/
/** Small block art logo (3 rows) used as visual marker */
export const EXIT_LOGO = [
"█▀▀█",
"█ █",
"▀▀▀▀",
] as const;
/** ANSI style codes for exit message */
export const EXIT_STYLES = {
RESET: "\x1b[0m",
DIM: "\x1b[90m",
HIGHLIGHT: "\x1b[96m",
BOLD: "\x1b[1m",
LOGO_COLOR: "\x1b[36m",
} as const;
/** Maximum width for the session description before truncation */
export const EXIT_DESCRIPTION_MAX_WIDTH = 50;
/** Padding before each exit message line */
export const EXIT_LINE_PADDING = " ";
/** Gap between logo and text */
export const EXIT_LOGO_GAP = " ";
/** Truncation indicator */
export const EXIT_TRUNCATION_MARKER = "\u2026";

View File

@@ -15,6 +15,7 @@ export interface TuiInput {
export interface TuiOutput {
exitCode: number;
sessionId?: string;
sessionTitle?: string;
}
export interface Config {

View File

@@ -0,0 +1,50 @@
/**
* Exit message formatter
*
* Formats the post-exit banner shown after the TUI closes,
* displaying session info and the resume command.
*/
import { EOL } from "os";
import {
EXIT_LOGO,
EXIT_STYLES,
EXIT_DESCRIPTION_MAX_WIDTH,
EXIT_LINE_PADDING,
EXIT_LOGO_GAP,
EXIT_TRUNCATION_MARKER,
} from "@constants/exit-message";
/** Truncate text to a max width, appending ellipsis if needed */
const truncateText = (text: string, maxWidth: number): string => {
if (text.length <= maxWidth) return text;
return text.slice(0, maxWidth - 1) + EXIT_TRUNCATION_MARKER;
};
/** Format the exit banner with session info */
export const formatExitMessage = (
sessionId?: string,
sessionTitle?: string,
): string => {
if (!sessionId) return "";
const { RESET, DIM, HIGHLIGHT, LOGO_COLOR } = EXIT_STYLES;
const pad = EXIT_LINE_PADDING;
const gap = EXIT_LOGO_GAP;
const description = sessionTitle
? truncateText(sessionTitle, EXIT_DESCRIPTION_MAX_WIDTH)
: "";
const resumeCommand = `codetyper --resume ${sessionId}`;
const lines: string[] = [
"",
`${pad}${LOGO_COLOR}${EXIT_LOGO[0]}${RESET}${gap}${HIGHLIGHT}${description}${RESET}`,
`${pad}${LOGO_COLOR}${EXIT_LOGO[1]}${RESET}${gap}${DIM}${resumeCommand}${RESET}`,
`${pad}${LOGO_COLOR}${EXIT_LOGO[2]}${RESET}`,
"",
];
return lines.join(EOL);
};

View File

@@ -17,6 +17,7 @@ import {
getExecutionState,
} from "@services/chat-tui-service";
import { TERMINAL_RESET } from "@constants/terminal";
import { formatExitMessage } from "@services/exit-message";
import { copyToClipboard } from "@services/clipboard/text-clipboard";
import versionData from "@/version.json";
import { ExitProvider, useExit } from "@tui-solid/context/exit";
@@ -25,6 +26,7 @@ import {
AppStoreProvider,
useAppStore,
setAppStoreRef,
appStore,
} from "@tui-solid/context/app";
import { ThemeProvider, useTheme } from "@tui-solid/context/theme";
import { KeybindProvider } from "@tui-solid/context/keybind";
@@ -111,6 +113,7 @@ function AppContent(props: AppProps) {
const toast = useToast();
const theme = useTheme();
const renderer = useRenderer();
renderer.disableStdoutInterception();
const [fileList, setFileList] = createSignal<string[]>([]);
setAppStoreRef(app);
@@ -561,6 +564,16 @@ export function tui(options: TuiRenderOptions): Promise<TuiOutput> {
const handleExit = (output: TuiOutput): void => {
try {
writeSync(1, TERMINAL_RESET);
const state = appStore.getState();
const firstUserLog = state?.logs?.find(
(log: { type: string }) => log.type === "user",
);
const sessionTitle = firstUserLog?.content;
const exitMsg = formatExitMessage(output.sessionId, sessionTitle);
if (exitMsg) {
writeSync(1, exitMsg);
}
} catch {
// Ignore - stdout may already be closed
}
@@ -571,7 +584,6 @@ export function tui(options: TuiRenderOptions): Promise<TuiOutput> {
targetFps: 60,
exitOnCtrlC: false,
useKittyKeyboard: {},
useMouse: true,
});
});
}