In the previous chapter, React-based Terminal UI, we built a beautiful, interactive interface that asks the user for confirmation. However, right now, our interface is like a shiny car with no engine. If we "save" a tag, nothing actually happens to the underlying data.
In this chapter, we will explore Session State Management.
Command Line tools are usually stateless. This means when you run a command like ls or mkdir, it does its job and instantly forgets everything.
But for our tag tool, we have a unique challenge.
tag bugfix, we need to attach that label to specifically the current session's log file.We need a way to identify which session is currently active.
Think of Session State Management as a Librarian.
getSessionId) to see who you are.getTranscriptPath).saveTag).
Let's look at how we use these tools inside our tag.tsx file. We import helper functions from our bootstrap and utils folders.
First, we need to know the unique ID of the current window/session.
import { getSessionId } from '../../bootstrap/state.js';
// Inside your component or logic
const id = getSessionId();
if (!id) {
console.error("No active session found!");
return; // Stop execution
}
Explanation:
getSessionId(): This function looks at the environment to find a unique code (UUID) that represents the current terminal window.Before we save a new tag, we might want to see if one already exists (to warn the user).
import { getCurrentSessionTag } from '../../utils/sessionStorage.js';
// Pass the ID we just got
const currentTag = getCurrentSessionTag(id);
if (currentTag === 'bugfix') {
console.log("This session is already tagged as bugfix!");
}
Explanation:
getCurrentSessionTag(id): This acts like a database query. It looks up the session by ID and returns the string attached to it, or null if there is no tag.Finally, if the user confirms they want to add the tag, we save it.
import { saveTag, getTranscriptPath } from '../../utils/sessionStorage.js';
// 1. Find where the log file lives on disk
const fullPath = getTranscriptPath();
// 2. Write the tag to our database
await saveTag(id, 'new-tag-name', fullPath);
Explanation:
getTranscriptPath(): Returns the file path (e.g., /Users/me/.tag/logs/session-123.json).saveTag(...): This is an asynchronous operation (note the await). It writes the tag to a persistent JSON file so that even if you restart your computer, the tag remains.How does the application actually know "Current Session ID"?
TAG_SESSION_ID).tag, the CLI reads this variable.metadata.json file that acts as a simple database.
While you mostly use the helpers, it is helpful to see a simplified version of how getSessionId is implemented internally.
// internal/bootstrap/state.ts (Simplified)
let globalSessionId: string | null = null;
export function getSessionId() {
// 1. If we already found it, return it (caching)
if (globalSessionId) return globalSessionId;
// 2. Look for the specific environment variable
const envId = process.env.TAG_SESSION_ID;
// 3. Store and return
globalSessionId = envId || null;
return globalSessionId;
}
And here is a simplified view of saveTag:
// internal/utils/sessionStorage.ts (Simplified)
import fs from 'fs/promises';
export async function saveTag(id, tagName, path) {
// 1. Load the existing database file
const dbData = await fs.readFile(DB_PATH, 'utf-8');
const db = JSON.parse(dbData);
// 2. Update the record for this session
db[id] = {
...db[id], // Keep existing data (like start time)
tag: tagName,
logPath: path
};
// 3. Save it back to disk
await fs.writeFile(DB_PATH, JSON.stringify(db));
}
In this chapter, we learned:
getSessionId to read environment variables and figure out which terminal window is active.saveTag to write metadata to a file, linking the session ID to a user-defined label.
Now our application has a UI (Chapter 2) and a Brain (Chapter 3). But what if the user types something dangerous or messy, like tag "Start <script>hack</script>"? We need to clean the data before we save it.
Next Chapter: Input Sanitization
Generated by Code IQ