In the previous chapter, CLI Command Definition, we created the menu entry for our feature. We hung the sign on the door. Now, when the user actually walks through that door (presses Enter), we need someone to greet them and decide where they should go.
Welcome to the Sandbox Controller.
When a user runs the sandbox command, they might want to do different things:
sandbox exclude "git" to quickly add a rule without opening the menu.We cannot just immediately show the graphics. We need a "Traffic Controller" logic layer to:
In our project, this logic lives in the call function inside sandbox-toggle.tsx.
Before a plane takes off, pilots check the engines and the weather. similarly, before we run any sandbox logic, we must ensure the environment is safe. We use the Sandbox Manager Interface to ask:
Users can type extra words after the command, like:
sandbox exclude "npm install"
The controller needs to take that long string (exclude "npm install") and chop it up to understand the Intent (Exclude) and the Data ("npm install").
null).
Let's visualize how the Controller makes decisions when the call function starts.
The call function is the heart of this chapter. It is an async function that receives args (the text the user typed). Let's break down its responsibilities using simplified code.
First, we act as a bouncer. If the user isn't on the list (unsupported platform) or if the club is closed (policy lock), we stop them at the door.
// sandbox-toggle.tsx
export async function call(onDone, _context, args) {
// 1. Ask the Manager if we are allowed here
if (!SandboxManager.isSupportedPlatform()) {
onDone('Error: Sandboxing is not supported on this OS.');
return null; // Stop execution
}
// 2. Check for Enterprise Policy locks
if (SandboxManager.areSandboxSettingsLockedByPolicy()) {
onDone('Error: Settings are locked by policy.');
return null; // Stop execution
}
Explanation: We return null here because there is nothing else to do. Calling onDone prints the error message to the user.
We also check if the tools (like Docker) are installed. Note that we don't stop execution here; we just gather the info to pass it along later.
// Check health, but don't exit yet
const depCheck = SandboxManager.checkDependencies();
Explanation: We store the result in depCheck. We will pass this to the UI so it can show a yellow warning icon if needed.
Now we look at what the user typed (args).
Path A: Interactive Mode (No Arguments)
If the user just typed sandbox and hit Enter, args will be empty. This is the most common use case.
const trimmedArgs = args?.trim() || '';
// If the user said nothing else...
if (!trimmedArgs) {
// ... Render the Graphical UI
return <SandboxSettings onComplete={onDone} depCheck={depCheck} />;
}
Explanation: Here we return a React Component (<SandboxSettings />). The CLI framework will take this and draw it on the terminal screen. This leads us to the topic of Chapter 4.
Path B: Headless Mode (Specific Command)
If the user typed sandbox exclude "git", we handle it immediately without showing a UI.
// Split "exclude git" into ["exclude", "git"]
const parts = trimmedArgs.split(' ');
const subcommand = parts[0]; // "exclude"
if (subcommand === 'exclude') {
// Logic to add the exclusion rule
const pattern = trimmedArgs.slice('exclude '.length);
addToExcludedCommands(pattern);
onDone(`Success: Added "${pattern}" to exclusions.`);
return null;
}
Explanation: We perform the logic (updating the settings file) and call onDone with a success message. We return null because we don't need to render a persistent UI.
If the user types something crazy like sandbox dance, we need to tell them we don't know how to do that.
// If we don't recognize the subcommand
const errorMsg = `Error: Unknown subcommand "${subcommand}".`;
onDone(errorMsg);
return null;
}
The Sandbox Controller is the brain that sits between the user's keystrokes and the application's features. It ensures that:
In the code above, when we returned <SandboxSettings />, we promised the user a visual interface. It is time to fulfill that promise.
Next Chapter: Interactive Configuration Flow
Generated by Code IQ