diff --git a/src/constants.ts b/src/constants.ts
index 9dd52ad..9422870 100644
--- a/src/constants.ts
+++ b/src/constants.ts
@@ -2,6 +2,16 @@ import * as path from "path";
const IMAGES_PATH = path.join(__dirname, "../../images");
+// Bump when a release ships a v86/hardware/disk-image change that can't load
+// older state-vN.bin snapshots. The app will detect an orphaned older state
+// and offer to export the user's old C:\ as a mountable .img.
+//
+// That export splices the state's dirty-block overlay onto the *current*
+// windows95.img — which only works while the partition table and FAT geometry
+// stay constant across releases. If you ever resize the disk or reformat with
+// different cluster params, the recovered .img won't mount.
+export const STATE_VERSION = 4;
+
export const CONSTANTS = {
IMAGES_PATH,
IMAGE_PATH: path.join(IMAGES_PATH, "windows95.img"),
@@ -32,6 +42,8 @@ export const IPC_COMMANDS = {
// Else
APP_QUIT: "APP_QUIT",
GET_STATE_PATH: "GET_STATE_PATH",
+ GET_LEGACY_STATE_PATH: "GET_LEGACY_STATE_PATH",
+ GET_DOWNLOADS_PATH: "GET_DOWNLOADS_PATH",
GET_SMB_SHARE_PATH: "GET_SMB_SHARE_PATH",
SET_SMB_SHARE_PATH: "SET_SMB_SHARE_PATH",
PICK_FOLDER: "PICK_FOLDER",
diff --git a/src/css/start.css b/src/css/start.css
index 7d799ed..3cd15c4 100644
--- a/src/css/start.css
+++ b/src/css/start.css
@@ -80,6 +80,24 @@
}
}
+.welcome-warn {
+ background: #fff;
+
+ p {
+ margin: 0 0 8px;
+ }
+
+ .welcome-warn-buttons {
+ display: flex;
+ gap: 6px;
+ margin-top: 4px;
+
+ button {
+ height: 24px;
+ }
+ }
+}
+
.welcome-actions {
width: 130px;
display: flex;
diff --git a/src/main/ipc.ts b/src/main/ipc.ts
index e61e3c0..1e34d2e 100644
--- a/src/main/ipc.ts
+++ b/src/main/ipc.ts
@@ -2,12 +2,31 @@ import { ipcMain, app, dialog, BrowserWindow } from "electron";
import * as path from "path";
import * as fs from "fs";
-import { IPC_COMMANDS } from "../constants";
+import { IPC_COMMANDS, STATE_VERSION } from "../constants";
import { settings } from "./settings";
+const statePathFor = (v: number) =>
+ path.join(app.getPath("userData"), `state-v${v}.bin`);
+
export function setupIpcListeners() {
ipcMain.handle(IPC_COMMANDS.GET_STATE_PATH, () => {
- return path.join(app.getPath("userData"), "state-v4.bin");
+ return statePathFor(STATE_VERSION);
+ });
+
+ ipcMain.handle(IPC_COMMANDS.GET_LEGACY_STATE_PATH, () => {
+ // If the user already has a current-version state, there's nothing to
+ // rescue — either they've migrated or never had an older one.
+ if (fs.existsSync(statePathFor(STATE_VERSION))) return null;
+ // v2/v3 predate the overlay-rescue machinery and aren't worth supporting.
+ for (let v = STATE_VERSION - 1; v >= 4; v--) {
+ const p = statePathFor(v);
+ if (fs.existsSync(p)) return p;
+ }
+ return null;
+ });
+
+ ipcMain.handle(IPC_COMMANDS.GET_DOWNLOADS_PATH, () => {
+ return app.getPath("downloads");
});
ipcMain.handle(IPC_COMMANDS.APP_QUIT, () => {
diff --git a/src/main/main.ts b/src/main/main.ts
index dd78fe8..4c8729d 100644
--- a/src/main/main.ts
+++ b/src/main/main.ts
@@ -64,7 +64,10 @@ export function main() {
if (isDevMode()) {
// Renderer DevTools Protocol — connect Chrome to chrome://inspect
// or attach a debugger to localhost:9222
- app.commandLine.appendSwitch("remote-debugging-port", "9222");
+ app.commandLine.appendSwitch(
+ "remote-debugging-port",
+ process.env.WIN95_DEBUG_PORT || "9222",
+ );
}
// Set the app's name
diff --git a/src/renderer/card-settings.tsx b/src/renderer/card-settings.tsx
index fc73971..3ac7769 100644
--- a/src/renderer/card-settings.tsx
+++ b/src/renderer/card-settings.tsx
@@ -192,7 +192,10 @@ export class CardSettings extends React.Component<