authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-02-26 20:43:54-08:00
committergravatar for jmarminge@gmail.comJulius Marminge <jmarminge@gmail.com> 2026-02-26 21:05:53-08:00
log0b299246488b90cea223dd86ce516116270b1215
treec79808b9702328f9dad8aacc2542be93e02c4bdf
parent49472da6699256f6aafc88820e482e403d0ab693

Recover bootstrap thread from snapshot when IDs are missing

- Fetch orchestration snapshot when bootstrap project/thread IDs are absent - Resolve project by current workspace and choose latest non-deleted thread - Continue auto-navigation and expansion using resolved fallback IDs

1 files changed, 31 insertions(+), 5 deletions(-)

apps/web/src/routes/__root.tsx+31-5
...@@ -198,26 +198,52 @@ function EventRouter() {...@@ -198,26 +198,52 @@ function EventRouter() {
198 return;198 return;
199 }199 }
200200
201 if (!payload.bootstrapProjectId || !payload.bootstrapThreadId) {201 const fallbackSnapshot =
202 payload.bootstrapProjectId && payload.bootstrapThreadId
203 ? null
204 : await api.orchestration.getSnapshot().catch(() => null);
205 if (disposed) {
206 return;
207 }
208
209 const bootstrapProjectId =
210 payload.bootstrapProjectId ??
211 fallbackSnapshot?.projects.find(
212 (project) => project.workspaceRoot === payload.cwd && project.deletedAt === null,
213 )?.id;
214 if (!bootstrapProjectId) {
202 return;215 return;
203 }216 }
204 dispatch({217 dispatch({
205 type: "SET_PROJECT_EXPANDED",218 type: "SET_PROJECT_EXPANDED",
206 projectId: payload.bootstrapProjectId,219 projectId: bootstrapProjectId,
207 expanded: true,220 expanded: true,
208 });221 });
222
223 const bootstrapThreadId =
224 payload.bootstrapThreadId ??
225 fallbackSnapshot?.threads
226 .filter((thread) => thread.projectId === bootstrapProjectId && thread.deletedAt === null)
227 .toSorted((a, b) => {
228 const byDate = new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime();
229 if (byDate !== 0) return byDate;
230 return b.id.localeCompare(a.id);
231 })[0]?.id;
232 if (!bootstrapThreadId) {
233 return;
234 }
209 if (pathnameRef.current !== "/") {235 if (pathnameRef.current !== "/") {
210 return;236 return;
211 }237 }
212 if (handledBootstrapThreadIdRef.current === payload.bootstrapThreadId) {238 if (handledBootstrapThreadIdRef.current === bootstrapThreadId) {
213 return;239 return;
214 }240 }
215 await navigate({241 await navigate({
216 to: "/$threadId",242 to: "/$threadId",
217 params: { threadId: payload.bootstrapThreadId },243 params: { threadId: bootstrapThreadId },
218 replace: true,244 replace: true,
219 });245 });
220 handledBootstrapThreadIdRef.current = payload.bootstrapThreadId;246 handledBootstrapThreadIdRef.current = bootstrapThreadId;
221 })().catch(() => undefined);247 })().catch(() => undefined);
222 });248 });
223 const unsubServerConfigUpdated = onServerConfigUpdated((payload) => {249 const unsubServerConfigUpdated = onServerConfigUpdated((payload) => {