feat(agent): require explicit named branches for session forks

Require fork scope and source branch selection, preserve the branch name in the destination, and cover named-branch behavior across backends.
This commit is contained in:
David Brailovsky 2026-09-01 12:35:14 +02:00
parent 86bac52f94
commit f8da63be59
9 changed files with 98 additions and 61 deletions

View file

@ -129,8 +129,7 @@ export class SqliteStorage implements Storage {
return Promise.resolve(readSessionStats(this.db, this.sessionId));
}
snapshot(options: ForkOptions | undefined, _context: Context): Promise<SqliteStorageSnapshot> {
options ??= {};
snapshot(options: ForkOptions, _context: Context): Promise<SqliteStorageSnapshot> {
if (this.state !== "open") return Promise.reject(new Error("SqliteStorage is closed"));
const result = this.commitQueue.then(() => this.readSnapshot(options));
this.commitQueue = result.then(
@ -151,12 +150,12 @@ export class SqliteStorage implements Storage {
private readSnapshotEntries(options: ForkOptions, scalarValues: readonly StoredValue<unknown>[]): Entry[] {
if (options.scope === "tree") return readAllEntryRows(this.db, this.sessionId).map(decodeEntryRow);
const mainAddress = branchTip("main");
const mainTip = scalarValues.find(
(stored) => stored.address.namespace === mainAddress.namespace && stored.address.key === mainAddress.key,
const sourceAddress = branchTip(options.branch);
const sourceTip = scalarValues.find(
(stored) => stored.address.namespace === sourceAddress.namespace && stored.address.key === sourceAddress.key,
) as StoredValue<string | null> | undefined;
if (mainTip === undefined) throw new Error("Source session is missing main branch");
const requested = options.entryId ?? mainTip.value;
if (sourceTip === undefined) throw new Error(`Unknown source branch: ${options.branch}`);
const requested = options.entryId ?? sourceTip.value;
return requested === null
? []
: scanBranchEntries(this.db, this.sessionId, { start: requested, order: "oldestFirst" });