Fix branch selector for single message and --no-session mode

- Allow branch selector to open with single user message (changed <= 1 to === 0 check)
- Support in-memory branching for --no-session mode (no files created)
- Add isEnabled() getter to SessionManager
- Update sessionFile getter to return null when sessions disabled
- Update SessionSwitchEvent types to allow null session files
- Add branching tests for single message and --no-session scenarios

fixes #163
This commit is contained in:
Mario Zechner 2025-12-10 22:41:32 +01:00
parent 09a48fd1c3
commit 3d35e7c469
10 changed files with 292 additions and 27 deletions

View file

@ -231,6 +231,11 @@ export class SessionManager {
this.enabled = false;
}
/** Check if session persistence is enabled */
isEnabled(): boolean {
return this.enabled;
}
private getSessionDirectory(): string {
const cwd = process.cwd();
// Replace all path separators and colons (for Windows drive letters) with dashes
@ -637,32 +642,43 @@ export class SessionManager {
/**
* Create a branched session from session entries up to (but not including) a specific entry index.
* This preserves compaction events and all entry types.
* Returns the new session file path.
* Returns the new session file path, or null if in --no-session mode (in-memory only).
*/
createBranchedSessionFromEntries(entries: SessionEntry[], branchBeforeIndex: number): string {
createBranchedSessionFromEntries(entries: SessionEntry[], branchBeforeIndex: number): string | null {
const newSessionId = uuidv4();
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
const newSessionFile = join(this.sessionDir, `${timestamp}_${newSessionId}.jsonl`);
// Copy all entries up to (but not including) the branch point
// Build new entries list (up to but not including branch point)
const newEntries: SessionEntry[] = [];
for (let i = 0; i < branchBeforeIndex; i++) {
const entry = entries[i];
if (entry.type === "session") {
// Rewrite session header with new ID and branchedFrom
const newHeader: SessionHeader = {
newEntries.push({
...entry,
id: newSessionId,
timestamp: new Date().toISOString(),
branchedFrom: this.sessionFile,
};
appendFileSync(newSessionFile, JSON.stringify(newHeader) + "\n");
branchedFrom: this.enabled ? this.sessionFile : undefined,
});
} else {
// Copy other entries as-is
appendFileSync(newSessionFile, JSON.stringify(entry) + "\n");
newEntries.push(entry);
}
}
return newSessionFile;
if (this.enabled) {
// Write to file
for (const entry of newEntries) {
appendFileSync(newSessionFile, JSON.stringify(entry) + "\n");
}
return newSessionFile;
} else {
// In-memory mode: replace inMemoryEntries, no file created
this.inMemoryEntries = newEntries;
this.sessionId = newSessionId;
return null;
}
}
}