feat: add backend session branching support

Add the backend contract and session-domain support for
'Branch from here':
- new branchSession IPC method and sessions:branch channel
- branchOrigin metadata on SessionRecord
- session branching helper that truncates the transcript at a
  chosen user message and clears runtime state
- AryxAppService branching flow with scratchpad directory support
- persistence normalization and regression coverage

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
David Kaya
2026-03-29 18:24:05 +02:00
co-authored by Copilot
parent a670817870
commit 7aae1b2cd5
10 changed files with 337 additions and 13 deletions
+18
View File
@@ -62,6 +62,7 @@ import {
} from '@shared/domain/approval';
import { isScratchpadProject, type ProjectRecord } from '@shared/domain/project';
import {
branchSessionRecord,
duplicateSessionRecord,
querySessions as queryWorkspaceSessions,
renameSessionRecord,
@@ -703,6 +704,23 @@ export class AryxAppService extends EventEmitter<AppServiceEvents> {
return this.persistAndBroadcast(workspace);
}
async branchSession(sessionId: string, messageId: string): Promise<WorkspaceState> {
const workspace = await this.loadWorkspace();
const session = this.requireSession(workspace, sessionId);
const pattern = this.requirePattern(workspace, session.patternId);
const branch = branchSessionRecord(session, pattern, createId('session'), messageId, nowIso());
if (isScratchpadProject(branch.projectId)) {
branch.cwd = undefined;
}
await this.ensureScratchpadSessionDirectory(branch);
workspace.sessions.unshift(branch);
workspace.selectedProjectId = branch.projectId;
workspace.selectedPatternId = branch.patternId;
workspace.selectedSessionId = branch.id;
return this.persistAndBroadcast(workspace);
}
async renameSession(sessionId: string, title: string): Promise<WorkspaceState> {
const workspace = await this.loadWorkspace();
const session = this.requireSession(workspace, sessionId);