/** * In-window screen shown when the sidecar dies under a running window. * Replaces the dead web UI (which would otherwise sit there failing every * fetch) with an explanation and a recovery path. Rendered as a data: URL * in the existing BrowserWindow, so the preload bridge stays available — * the buttons drive the same `window.executor` IPC the settings page uses. */ export interface CrashScreenOptions { /** Whether a crash report was sent upstream (DSN build, not opted out). */ readonly reported: boolean;} export const sidecarCrashHtml = ({ reported }: CrashScreenOptions): string => `<!doctype html><html> <head> <meta charset="utf-8" /> <title>Executor</title> <style> :root { color-scheme: dark; } body { margin: 0; min-height: 100vh; display: grid; place-items: center; background: #0a0a0a; color: #fafafa; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; } .card { max-width: 26rem; padding: 2rem; text-align: center; } .icon { font-size: 2rem; margin-bottom: 0.75rem; } h1 { font-size: 1.15rem; font-weight: 600; margin: 0 0 0.5rem; } p { font-size: 0.875rem; color: #a1a1aa; line-height: 1.5; margin: 0 0 1.5rem; } .row { display: flex; gap: 0.6rem; justify-content: center; } button { padding: 0.55rem 1.1rem; border-radius: 6px; border: 1px solid transparent; background: #fafafa; color: #0a0a0a; font: inherit; font-size: 0.875rem; cursor: pointer; white-space: nowrap; } button.secondary { background: transparent; color: #fafafa; border-color: #3f3f46; } #status { margin-top: 1.25rem; min-height: 1.2em; font-size: 0.8rem; color: #a1a1aa; } .reset-row { margin-top: 1.75rem; font-size: 0.75rem; color: #71717a; } .reset-row a { color: #f87171; text-decoration: underline; cursor: pointer; } </style> </head> <body> <main class="card"> <div class="icon">⚠️</div> <h1>The local Executor server stopped unexpectedly</h1> <p> Your data is safe.${reported ? " A crash report was sent automatically so this can get fixed." : ""} Restart the server to keep working. </p> <div class="row"> <button id="restart">Restart server</button> <button id="update" class="secondary">Check for updates</button> <button id="export" class="secondary">Export diagnostics</button> </div> <p id="status"></p> <p class="reset-row"> Still won't start after restarting? <a id="reset" href="#">Reset data</a> clears a damaged database to get the app running again. </p> </main> <script> const status = document.getElementById("status"); document.getElementById("restart").addEventListener("click", async () => { status.textContent = "Restarting\\u2026"; try { // Main restarts the sidecar and reloads this window on success. await window.executor.restartServer(); } catch { status.textContent = "Restart failed \\u2014 try quitting and reopening Executor."; } }); document.getElementById("update").addEventListener("click", async () => { status.textContent = "Checking for updates\\u2026"; try { // Outcomes surface as native dialogs (install prompt / no updates). await window.executor.checkForUpdates(); status.textContent = ""; } catch { status.textContent = "Update check failed \\u2014 check your network."; } }); document.getElementById("export").addEventListener("click", async () => { status.textContent = "Exporting\\u2026"; try { await window.executor.exportDiagnostics(); status.textContent = "Diagnostics saved to Downloads."; } catch { status.textContent = "Export failed \\u2014 see the log file."; } }); document.getElementById("reset").addEventListener("click", async (event) => { event.preventDefault(); try { // Native confirm runs in main; on accept, state is backed up and // the server restarts (window reloads on success). false = cancel. const didReset = await window.executor.resetState(); if (!didReset) return; status.textContent = ""; } catch { status.textContent = "Reset failed \\u2014 see the log file."; } }); </script> </body></html>`;
/**
* In-window screen shown when the sidecar dies under a running window.
* Replaces the dead web UI (which would otherwise sit there failing every
* fetch) with an explanation and a recovery path. Rendered as a data: URL
* in the existing BrowserWindow, so the preload bridge stays available —
* the buttons drive the same `window.executor` IPC the settings page uses.
*/
export interface CrashScreenOptions {
/** Whether a crash report was sent upstream (DSN build, not opted out). */
readonly reported: boolean;
}
export const sidecarCrashHtml = ({ reported }: CrashScreenOptions): string => `<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Executor</title>
<style>
:root { color-scheme: dark; }
body {
margin: 0;
min-height: 100vh;
display: grid;
place-items: center;
background: #0a0a0a;
color: #fafafa;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}
.card { max-width: 26rem; padding: 2rem; text-align: center; }
.icon { font-size: 2rem; margin-bottom: 0.75rem; }
h1 { font-size: 1.15rem; font-weight: 600; margin: 0 0 0.5rem; }
p { font-size: 0.875rem; color: #a1a1aa; line-height: 1.5; margin: 0 0 1.5rem; }
.row { display: flex; gap: 0.6rem; justify-content: center; }
button {
padding: 0.55rem 1.1rem;
border-radius: 6px;
border: 1px solid transparent;
background: #fafafa;
color: #0a0a0a;
font: inherit;
font-size: 0.875rem;
cursor: pointer;
white-space: nowrap;
}
button.secondary { background: transparent; color: #fafafa; border-color: #3f3f46; }
#status { margin-top: 1.25rem; min-height: 1.2em; font-size: 0.8rem; color: #a1a1aa; }
.reset-row { margin-top: 1.75rem; font-size: 0.75rem; color: #71717a; }
.reset-row a { color: #f87171; text-decoration: underline; cursor: pointer; }
</style>
</head>
<body>
<main class="card">
<div class="icon">⚠️</div>
<h1>The local Executor server stopped unexpectedly</h1>
<p>
Your data is safe.${reported ? " A crash report was sent automatically so this can get fixed." : ""}
Restart the server to keep working.
</p>
<div class="row">
<button id="restart">Restart server</button>
<button id="update" class="secondary">Check for updates</button>
<button id="export" class="secondary">Export diagnostics</button>
</div>
<p id="status"></p>
<p class="reset-row">
Still won't start after restarting?
<a id="reset" href="#">Reset data</a>
clears a damaged database to get the app running again.
</p>
</main>
<script>
const status = document.getElementById("status");
document.getElementById("restart").addEventListener("click", async () => {
status.textContent = "Restarting\\u2026";
try {
// Main restarts the sidecar and reloads this window on success.
await window.executor.restartServer();
} catch {
status.textContent = "Restart failed \\u2014 try quitting and reopening Executor.";
}
});
document.getElementById("update").addEventListener("click", async () => {
status.textContent = "Checking for updates\\u2026";
try {
// Outcomes surface as native dialogs (install prompt / no updates).
await window.executor.checkForUpdates();
status.textContent = "";
} catch {
status.textContent = "Update check failed \\u2014 check your network.";
}
});
document.getElementById("export").addEventListener("click", async () => {
status.textContent = "Exporting\\u2026";
try {
await window.executor.exportDiagnostics();
status.textContent = "Diagnostics saved to Downloads.";
} catch {
status.textContent = "Export failed \\u2014 see the log file.";
}
});
document.getElementById("reset").addEventListener("click", async (event) => {
event.preventDefault();
try {
// Native confirm runs in main; on accept, state is backed up and
// the server restarts (window reloads on success). false = cancel.
const didReset = await window.executor.resetState();
if (!didReset) return;
status.textContent = "";
} catch {
status.textContent = "Reset failed \\u2014 see the log file.";
}
});
</script>
</body>
</html>`;