From 71768dda5c19900700264146794fa05700013b6d Mon Sep 17 00:00:00 2001 From: J Date: Fri, 12 Jun 2026 14:14:20 +0800 Subject: [PATCH] fix(desktop): improve renderer recovery prompt Co-authored-by: multica-agent --- .../src/main/renderer-recovery.test.ts | 28 ++++++++++++++++++- apps/desktop/src/main/renderer-recovery.ts | 22 +++++++++++---- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/apps/desktop/src/main/renderer-recovery.test.ts b/apps/desktop/src/main/renderer-recovery.test.ts index afacaaeb4..9704b163a 100644 --- a/apps/desktop/src/main/renderer-recovery.test.ts +++ b/apps/desktop/src/main/renderer-recovery.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it, vi, beforeEach, afterEach } from "vitest"; -import { installRendererRecoveryHandlers } from "./renderer-recovery"; +import { createElectronReloadPrompt, installRendererRecoveryHandlers } from "./renderer-recovery"; type Handler = (...args: unknown[]) => void; @@ -109,4 +109,30 @@ describe("installRendererRecoveryHandlers", () => { expect(showReloadPrompt).not.toHaveBeenCalled(); expect(fixture.reload).not.toHaveBeenCalled(); }); + + it("shows actionable recovery guidance before diagnostic details", async () => { + let detail = ""; + const showMessageBox = vi.fn( + async (options: { title: string; message: string; detail: string }) => { + detail = options.detail; + return { response: 1 }; + }, + ); + const showReloadPrompt = createElectronReloadPrompt(showMessageBox); + + await showReloadPrompt({ kind: "unresponsive", context: {} }); + + expect(showMessageBox).toHaveBeenCalledWith( + expect.objectContaining({ + title: "Multica needs to reload", + message: "The desktop window has been stuck for a few seconds.", + detail: expect.stringContaining( + "Click Reload to refresh this window and keep using Multica.", + ), + }), + ); + expect(detail).toContain("what you were doing right before this message appeared"); + expect(detail).toContain("Activity Monitor sample"); + expect(detail).toContain("Diagnostic details:\nkind: unresponsive\ncontext: {}"); + }); }); diff --git a/apps/desktop/src/main/renderer-recovery.ts b/apps/desktop/src/main/renderer-recovery.ts index e6df0cfb0..4e26d052e 100644 --- a/apps/desktop/src/main/renderer-recovery.ts +++ b/apps/desktop/src/main/renderer-recovery.ts @@ -109,18 +109,30 @@ function isRecoverableRendererExit(details: unknown) { function rendererRecoveryMessage(kind: ReloadPromptPayload["kind"]) { switch (kind) { case "render-process-gone": - return "The desktop renderer process stopped responding or crashed."; + return "The desktop window stopped unexpectedly."; case "preload-error": - return "The desktop preload script failed before the app could start."; + return "The desktop window could not finish starting."; case "unresponsive": - return "The desktop window is not responding."; + return "The desktop window has been stuck for a few seconds."; } } function rendererRecoveryDetail(payload: ReloadPromptPayload) { + const guidance = [ + "Click Reload to refresh this window and keep using Multica.", + "If this keeps happening, please tell us what you were doing right before this message appeared and whether Reload recovered the window.", + ]; + + if (payload.kind === "unresponsive") { + guidance.push( + "For macOS reports, an Activity Monitor sample of the Multica Helper (Renderer) process helps us find what blocked the app.", + ); + } + return [ - "Reloading is the safest recovery path for this window.", + ...guidance, "", + "Diagnostic details:", `kind: ${payload.kind}`, `context: ${JSON.stringify(payload.context)}`, ].join("\n"); @@ -132,4 +144,4 @@ function defaultDevLog(tag: string, ...args: unknown[]) { function formatError(error: unknown) { return error instanceof Error ? (error.stack ?? error.message) : String(error); -} \ No newline at end of file +}