feat(dashboard): add draft planning sessions with debounced auto-creation
Introduce a draft lifecycle for planning sessions: typing into the PlanningModeModal textarea now creates a server-side draft after a 300ms debounce, persisted with status='draft' so the user's in-flight plan survives modal close/reopen and shows up immediately in the session list. - planning.ts: new createDraftSession path; persistSession status union widened to include 'draft'; Session gains an explicit title field so subsequent updates don't clobber it. - register-planning-subtask-routes.ts: wires the createPlanningDraft POST endpoint that the modal calls on debounce. - ai-session-store.ts: tracks the draft status across queries so the session list and locks behave the same as any active session. - legacy.ts: client wrapper for createPlanningDraft. - PlanningModeModal styling, tests, and ModalReentry coverage updated for the new flow. - docs/architecture.md notes the expanded ai_sessions.status lifecycle. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2593,12 +2593,28 @@ export function startPlanning(
|
||||
});
|
||||
}
|
||||
|
||||
export function createPlanningDraft(
|
||||
initialPlan: string,
|
||||
projectId?: string,
|
||||
modelOverride?: { planningModelProvider?: string; planningModelId?: string },
|
||||
): Promise<{ sessionId: string; title: string }> {
|
||||
return api<{ sessionId: string; title: string }>(withProjectId("/planning/create-draft", projectId), {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
initialPlan,
|
||||
planningModelProvider: modelOverride?.planningModelProvider,
|
||||
planningModelId: modelOverride?.planningModelId,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
/** Start a new planning session with AI streaming support */
|
||||
export function startPlanningStreaming(
|
||||
initialPlan: string,
|
||||
projectId?: string,
|
||||
modelOverride?: { planningModelProvider?: string; planningModelId?: string },
|
||||
planningOptions?: { planningDepth?: "small" | "medium" | "large"; customQuestionCount?: number },
|
||||
existingSessionId?: string,
|
||||
): Promise<{ sessionId: string }> {
|
||||
return api<{ sessionId: string }>(withProjectId("/planning/start-streaming", projectId), {
|
||||
method: "POST",
|
||||
@@ -2608,6 +2624,7 @@ export function startPlanningStreaming(
|
||||
planningModelId: modelOverride?.planningModelId,
|
||||
planningDepth: planningOptions?.planningDepth,
|
||||
customQuestionCount: planningOptions?.customQuestionCount,
|
||||
...(existingSessionId ? { existingSessionId } : {}),
|
||||
}),
|
||||
});
|
||||
}
|
||||
@@ -7100,7 +7117,7 @@ export function reorderTodoItems(listId: string, itemIds: string[], projectId?:
|
||||
export interface AiSessionSummary {
|
||||
id: string;
|
||||
type: "planning" | "subtask" | "mission_interview" | "milestone_interview" | "slice_interview";
|
||||
status: "generating" | "awaiting_input" | "complete" | "error";
|
||||
status: "draft" | "generating" | "awaiting_input" | "complete" | "error";
|
||||
title: string;
|
||||
projectId: string | null;
|
||||
lockedByTab: string | null;
|
||||
|
||||
Reference in New Issue
Block a user