Welcome back!
In the previous chapter, Configuration Source Hierarchy, we learned how our application combines "House Rules" and "Personal Preferences" to decide if a project is risky.
But what happens if the result is "Too Risky" and the user shouts "STOP!"?
Or what if the user simply changes their mind and hits Ctrl+C on their keyboard?
We cannot just pull the plug on the application. If we do that, we might leave the terminal in a broken state (cursor missing, colors messed up) or leave files half-written. We need a way to leave the room politely.
This chapter introduces Graceful Exit Management.
Imagine you are driving a car. You see a roadblock (the Trust Dialog). You decide not to proceed.
process.exit): This is like teleporting out of the car while it's moving. The car crashes, the engine is still running, and it's a mess.In the TrustDialog project, we need to handle exits gracefully to ensure the user's terminal remains usable and clean.
Our application uses a library called Ink to take control of your terminal (to draw menus and colors). If we crash or exit abruptly, the terminal might think the application is still running. You might lose your typing cursor or get stuck in a weird color mode.
gracefulShutdownSync
We use a centralized function called gracefulShutdownSync. Its job is to:
There are two main parts to this system:
useExitOnCtrlCDWithKeybindingsCtrl+C (Cancel) or Ctrl+D (End of Input).gracefulShutdownSync
Let's look at how we wire this up in TrustDialog.tsx. We want the application to stop if the user selects "Exit" from the menu OR if they use a keyboard shortcut.
When the user manually selects "No, exit" in the dropdown menu:
// Inside TrustDialog.tsx - onChange handler
const onChange = (value) => {
if (value === "exit") {
// 1. User chose to exit
// 2. We call the shutdown function with error code 1
gracefulShutdownSync(1);
return;
}
// ... else proceed with trust
};
Explanation:
gracefulShutdownSync(1): We pass the number 1. In computer programming, an exit code of 0 means "Success", and anything else (like 1) means "Something went wrong" or "The user cancelled."
Users are used to pressing Ctrl+C to kill command-line apps. We use a React Hook to listen for this.
// Inside TrustDialog.tsx
import { useExitOnCtrlCDWithKeybindings } from '../../hooks/useExitOnCtrlCDWithKeybindings';
// This hook listens for Ctrl+C and Ctrl+D
const exitState = useExitOnCtrlCDWithKeybindings(() => {
// Logic to run when keys are pressed:
return gracefulShutdownSync(1);
});
Explanation:
useExitOnCtrlCDWithKeybindings: This function runs in the background.
What actually happens when you press Ctrl+C?
Let's look at the simplified implementation of the "Brake" system.
This utility lives in utils/gracefulShutdown.ts. It acts as the final gatekeeper.
// utils/gracefulShutdown.ts (Simplified)
import { unmount } from '../ink'; // Our UI library
export function gracefulShutdownSync(exitCode: number) {
// 1. Clean up the UI
// This restores the cursor and clears the screen buffer
unmount();
// 2. Force stop the process
// We use the exit code provided (0 or 1)
process.exit(exitCode);
}
Explanation:
unmount(): This is critical. Without this, your terminal might look "glitched" after the app closes.process.exit(): This is the standard Node.js command to stop a program.
This lives in hooks/useExitOnCtrlCDWithKeybindings.ts. It connects the keyboard to the shutdown utility.
// hooks/useExitOnCtrlCDWithKeybindings.ts (Simplified concept)
import { useInput } from 'ink';
export function useExitOnCtrlCDWithKeybindings(onExit: () => void) {
// Ink provides a hook to read raw keystrokes
useInput((input, key) => {
// If Ctrl+C or Ctrl+D is pressed
if ((input === 'c' && key.ctrl) || (input === 'd' && key.ctrl)) {
// Trigger the exit function passed in
onExit();
}
});
return { pending: false };
}
Explanation:
useInput: This allows us to intercept every keystroke before it appears on the screen.Ctrl key and the letter c.onExit(): This executes the gracefulShutdownSync we defined earlier.
You might wonder, "Why not just write process.exit(1) everywhere?"
gracefulShutdownSync).gracefulShutdownSync describes intent better than process.exit.In this chapter, we learned:
gracefulShutdownSync: The utility that cleans up the UI and stops the process.Ctrl+C to trigger the shutdown.Now the application is safe. It asks for permission (Chapter 1), detects risks (Chapter 2 & 3), and stops cleanly if refused (Chapter 4).
But what if the user says "Yes"?
If the user trusts the application, we let them in. But we also want to keep a record of what happened. Did they say yes? Was it a risky project? We need to log this data.
Next up: Trust Analytics & Auditing
Generated by Code IQ