feat: add CODETYPER ASCII art to exit summary

Add prominent CODETYPER logo using ASCII box-drawing characters at the
top of the exit summary for enhanced branding. This provides a polished,
professional appearance when exiting the CLI.

Key improvements:
- Add ASCII logo to session summary output
- Simplify exit flow to use global message storage in terminal.ts
- Remove duplicate exit message handling from ExitProvider
- Fix signal handlers to prevent duplicate exit messages
- Clean up debug logging from app.tsx
- Ensure exit message persists on terminal after process exit

The exit summary now displays comprehensive session statistics with:
- CODETYPER ASCII logo
- Total usage and Premium requests
- API time and total session time
- Code changes breakdown (+additions/-deletions)
- Per-model token usage
- Resume command with session ID

Works correctly on all exit paths (normal exit, SIGINT, SIGTERM, errors).
This commit is contained in:
2026-02-15 14:02:40 -05:00
parent 6c72ff0212
commit 87d53f7035
5 changed files with 51 additions and 39 deletions

View File

@@ -118,7 +118,6 @@ function AppContent(props: AppProps) {
setAppStoreRef(app);
// Set exit message reactively (like OpenCode does)
// This ensures the message is pre-computed and ready when exit is called
createEffect(() => {
const state = appStore.getState();

View File

@@ -1035,7 +1035,6 @@ export const { provider: AppStoreProvider, use: useAppStore } =
updateMcpServerStatus,
// Modified file tracking
modifiedFiles: () => store.modifiedFiles,
addModifiedFile,
clearModifiedFiles,

View File

@@ -1,18 +1,18 @@
import { createSignal, onCleanup } from "solid-js";
import { useRenderer } from "@opentui/solid";
import { createSimpleContext } from "./helper";
import { setGlobalExitMessage } from "@utils/core/terminal";
interface ExitContextInput extends Record<string, unknown> {
onExit?: () => void | Promise<void>;
}
interface ExitContextValue {
exit: (code?: number) => void;
exitCode: () => number;
isExiting: () => boolean;
exit: (code?: number) => Promise<void>;
requestExit: () => void;
cancelExit: () => void;
confirmExit: () => void;
getExitCode: () => number;
isExiting: () => boolean;
exitRequested: () => boolean;
setExitMessage: (message: string | undefined) => void;
getExitMessage: () => string | undefined;
}
@@ -27,7 +27,6 @@ export const { provider: ExitProvider, use: useExit } = createSimpleContext<
const [exitCode, setExitCode] = createSignal(0);
const [isExiting, setIsExiting] = createSignal(false);
const [exitRequested, setExitRequested] = createSignal(false);
const [exitMessage, setExitMessageState] = createSignal<string | undefined>(undefined);
const exit = async (code = 0): Promise<void> => {
setExitCode(code);
@@ -46,22 +45,19 @@ export const { provider: ExitProvider, use: useExit } = createSimpleContext<
// Call the onExit callback (may be async)
await props.onExit?.();
// Write the stored exit message after renderer is destroyed
const message = exitMessage();
if (message) {
process.stdout.write(message + "\n");
}
// Exit message will be written by emergencyTerminalCleanup
// which is registered on process "exit" event in terminal.ts
// Exit the process
process.exit(code);
};
const setExitMessage = (message: string | undefined): void => {
setExitMessageState(message);
setGlobalExitMessage(message);
};
const getExitMessage = (): string | undefined => {
return exitMessage();
return undefined; // Message is stored in terminal.ts
};
const requestExit = (): void => {
@@ -81,13 +77,13 @@ export const { provider: ExitProvider, use: useExit } = createSimpleContext<
onCleanup(() => {
setIsExiting(false);
setExitRequested(false);
setExitMessageState(undefined);
});
return {
exit,
exitCode,
getExitCode: exitCode,
isExiting,
exitRequested,
requestExit,
cancelExit,
confirmExit,