Welcome back! In Command Architecture, we learned how the application finds and executes code (the "Menu" and the "Kitchen").
However, executing commands in isolation isn't enough. A smart CLI needs a Memory. It needs to know:
In this chapter, we explore Session State and the concept of Modes.
Think of the plan CLI like a modern car. A car has different Driving Modes:
The car is the same, but the Mode changes how the system behaves.
In our application, we have a "Plan Mode". When active, the CLI focuses on high-level architectural planning and might restrict accidental code execution. Switching modes updates the Global State so every part of the app knows how to behave.
In the previous chapter, we saw the call function. It receives a context object. This context is the gateway to our application's memory.
Inside plan.tsx, we access the state functions like this:
export async function call(onDone, context, args) {
// 1. Get the tools to read/write memory
const { getAppState, setAppState } = context;
// 2. Read the current memory (Snapshot)
const appState = getAppState();
// ...
}
getAppState: Gives us a snapshot of everything happening right now.setAppState: Allows us to change the memory.
The most important piece of state for the plan command is the Mode. This lives inside a specific section of the state called toolPermissionContext.
Here is how we check if we are already in Plan Mode:
// Look inside the permission context
const currentMode = appState.toolPermissionContext.mode;
// Check our logic
if (currentMode !== 'plan') {
// We are NOT in plan mode yet.
// We need to switch gears!
}
If currentMode is 'standard', we treat the user differently than if it is 'plan'.
This is the core of this chapter. If the user isn't in Plan Mode, we need to transition them.
Changing state in a modern application isn't just state.mode = 'plan'. We must respect Immutability. We take the previous state and create a new version of it with our changes.
Here is the code inside plan.tsx that performs the switch:
// Update the global state
setAppState(prev => ({
...prev, // Keep everything else the same
// Update the permission context to 'plan'
toolPermissionContext: applyPermissionUpdate(
prepareContextForPlanMode(prev.toolPermissionContext),
{ type: 'setMode', mode: 'plan', destination: 'session' }
)
}));
setAppState(prev => ...): We use a function to ensure we are modifying the latest version of the state....prev: This spreads the old state, ensuring we don't accidentally delete other data (like user preferences).prepareContextForPlanMode: A helper that sets up the rules for the new mode.applyPermissionUpdate: This securely commits the change to the mode setting.
What happens when you type plan?
standard mode.plan mode.
Once the mode is set to 'plan', the application behavior changes.
If we run the command again, the if (currentMode !== 'plan') check returns false. The code skips the transition logic and instead shows the user the current plan.
// We are already in plan mode!
const planContent = getPlan();
if (!planContent) {
onDone('Already in plan mode. No plan written yet.');
return null;
}
Note: In future chapters, other systems will also check appState.mode. for example, the AI might refuse to edit code if it's strictly in 'plan' mode.
In this chapter, we learned:
'plan') to define the "driving style" of the application.getAppState() to see where we are.setAppState() to safely transition between modes.Now that our application knows what mode it is in, we need a way to show complex information to the userβmore than just simple text messages.
π Next Step: React-Ink UI Rendering
Generated by Code IQ