feat(vibe): reconcile mutable session previews in playback

This commit is contained in:
kami
2026-08-01 23:47:02 +04:00
parent 51ef7c84db
commit 57df1cfe9f
20 changed files with 1311 additions and 312 deletions
@@ -36,6 +36,19 @@ export interface AppendVibeEventInput {
payload?: Record<string, unknown>;
}
/**
* An explicit advancement protocol for a plan item that was durably served
* but cannot be played locally. `eventId` is the idempotency key for this
* state transition; it is intentionally separate from a retry of /next.
*/
export interface AdvanceUnplayableVibeItemInput {
expectedPlanVersion: number;
planVersionId: string;
ordinal: number;
trackId: string;
eventId: string;
}
export class VibeSessionNotFoundError extends Error {}
export class VibeSessionLifecycleError extends Error {}
export class VibePlanNotFoundError extends Error {}
@@ -142,6 +155,21 @@ export class VibeSessionCoordinator {
}
}
async advancePastUnplayable(
userId: string,
sessionId: string,
input: AdvanceUnplayableVibeItemInput,
): Promise<VibeSessionResponse> {
try {
const served = await this.db.advancePastUnplayableVibePlanItem(sessionId, userId, input);
const response = await this.getPlan(userId, sessionId);
if (served.stale) return response;
return { ...response, now: served.item, preview: response.preview };
} catch (error) {
throw this.mapLifecycleError(error);
}
}
async appendEvent(
userId: string,
sessionId: string,