In the previous chapter, Interactive Configuration Flow, we built a beautiful visual dashboard that lets users turn the entire sandbox ON or OFF.
But what if you want the sandbox ON for everything except one specific command?
Imagine you are running a secure facility. Most visitors must go through security screening (the Sandbox). However, the CEO (a specific command) needs to breeze through without delay.
If you had to shut down security for the entire building just to let the CEO in, that would be unsafe and annoying.
The Problem:
Sometimes, a specific command (like npm login or git push) fails inside the sandbox because it needs access to your local keys or specific hardware.
The Solution: We create a Command Exclusion Logic. This allows the user to add specific commands to a "VIP List." When the system sees these commands, it lets them run locally, even if the sandbox is technically "On."
To build this, we need to handle text input from the terminal and save it safely.
Up until now, our command was just sandbox. Now, we are introducing a "child" command: sandbox exclude. This tells our controller: "I don't want the menu; I want to perform a specific action."
When a user types:
sandbox exclude "npm run test"
We need to separate the Instruction (exclude) from the Data ("npm run test").
Users often put quotes around arguments to keep them safe from the shell. However, we don't want to save the quotes into our settings file. We need to clean the input (e.g., turn "git" into git).
We save these exceptions to a Local settings file (.claude/settings.local.json). Why local? Because your exclusions (like your specific test scripts) might not apply to your teammate's computer.
The user interacts with this logic entirely through the command line, without opening the visual menu.
Example Input:
sandbox exclude "git push"
What Happens:
exclude keyword."git push", cleans it, and adds it to the list.Example Output:
โ Added "git push" to excluded commands in .claude/settings.local.json
Let's look at what happens inside sandbox-toggle.tsx when this command is run. This logic sits inside the call function we started in Chapter 3.
Let's break down the implementation in sandbox-toggle.tsx. This code runs before we try to show the visual menu.
First, we look at the raw arguments (args) provided by the user.
// sandbox-toggle.tsx
// args might be: 'exclude "npm start"'
const parts = trimmedArgs.split(' ');
const subcommand = parts[0]; // "exclude"
if (subcommand === 'exclude') {
// ... enter exclusion logic
}
Explanation: We split the string by spaces. The first word determines our path. If it is exclude, we skip the visual menu.
We need to get the actual command pattern the user wants to whitelist. We can't just take parts[1] because the command might have spaces (like npm run test).
// Remove "exclude " from the start of the string
const commandPattern = trimmedArgs.slice('exclude '.length).trim();
if (!commandPattern) {
onDone('Error: Please provide a command pattern.');
return null;
}
Explanation: We slice the string to remove the first word. If the result is empty (the user just typed sandbox exclude), we show an error.
We use a Regular Expression (Regex) to gently peel off quotes if they exist.
// Remove quotes from start (^) or end ($)
const cleanPattern = commandPattern.replace(/^["']|["']$/g, '');
Explanation:
"git push" becomes git push.'npm test' becomes npm test.Now we hand the data off to our helper function to actually write to the disk.
// Import from the adapter
import { addToExcludedCommands } from '../../utils/sandbox/sandbox-adapter.js';
// Save it!
addToExcludedCommands(cleanPattern);
Explanation: This helper function handles the messy JSON reading and writing, keeping our Controller code simple.
Finally, we calculate where the file is so we can tell the user. Users love knowing exactly what file we just modified.
// Calculate relative path for clarity
const settingsPath = getSettingsFilePathForSource('localSettings');
const relativePath = relative(getCwdState(), settingsPath);
const msg = `Added "${cleanPattern}" to excluded commands in ${relativePath}`;
onDone(color('success')(msg));
Explanation: Instead of showing a long, ugly absolute path like /Users/jdoe/project/.claude/..., we show .claude/settings.local.json. It's a small detail that improves User Experience (UX).
Congratulations! You have completed the Sandbox Toggle tutorial series.
Let's review what we built:
You now have a fully functional, robust CLI tool feature that is safe, user-friendly, and configurable. Happy coding!
Generated by Code IQ