feat(FN-3447): add planning session rewind capability with modal back actio

This merge delivers four major features: a planning session rewind system (FN-3447, steps 1–4) with a new backend route for rolling back sessions, modal back-action wiring, and updated typing; workspace verification gates (FN-3385) for agent prompt editing; an agents view org chart spacing rework (F

Fusion-Task-Id: FN-3447
This commit is contained in:
Fusion
2026-05-04 19:56:48 -07:00
committed by gsxdsm
parent 79bf77bd5e
commit cb3ab98e70
9 changed files with 261 additions and 10 deletions

View File

@@ -728,6 +728,48 @@ export function registerPlanningSubtaskRoutes(ctx: ApiRoutesContext, deps: Plann
}
});
router.post("/planning/:sessionId/back", async (req, res) => {
try {
const { sessionId } = req.params;
if (!sessionId || typeof sessionId !== "string") {
throw badRequest("sessionId is required");
}
const tabId = typeof req.body?.tabId === "string" && req.body.tabId.trim().length > 0
? req.body.tabId.trim()
: undefined;
const lockCheck = checkSessionLock(sessionId, tabId, aiSessionStore);
if (!lockCheck.allowed) {
res.status(409).json({
error: "Session locked by another tab",
lockedByTab: lockCheck.currentHolder,
});
return;
}
const { store: scopedStore } = await getProjectContext(req);
const settings = await scopedStore.getSettings();
const { rewindSession } = await import("../planning.js");
const rewound = await rewindSession(
sessionId,
scopedStore.getRootDir(),
settings.promptOverrides,
);
res.json(rewound);
} catch (err: unknown) {
if (err instanceof ApiError) {
throw err;
}
if (err instanceof Error && err.name === "SessionNotFoundError") {
throw notFound(err instanceof Error ? err.message : String(err));
} else if (err instanceof Error && err.name === "InvalidSessionStateError") {
throw badRequest(err instanceof Error ? err.message : String(err));
} else {
rethrowAsApiError(err, "Failed to rewind planning session");
}
}
});
/**
* POST /api/planning/:sessionId/retry
* Retry a failed planning session.
@@ -1317,6 +1359,7 @@ export function registerPlanningSubtaskRoutes(ctx: ApiRoutesContext, deps: Plann
"POST /planning/start",
"POST /planning/start-streaming",
"POST /planning/respond",
"POST /planning/:sessionId/back",
"POST /planning/:sessionId/retry",
"POST /planning/:sessionId/stop",
"POST /planning/cancel",