Skip to content

Commit 78cb281

Browse files
committed
feat: ask before updating (Sparkle-style dialog); fix terminal copy mojibake
Update flow now matches what users expect from mac apps: when a new version is found, a dialog shows the release notes with Install Update / Remind Me Later / Skip This Version (skip is remembered per version, remind-later snoozes until next launch). Once downloaded, a second dialog offers Restart Now (quitAndInstall) or install-on-quit. No more silent background installs. Also: GUI apps launch with no LANG/LC_*, so pbcopy — which agent CLIs use for clipboard copy — interpreted UTF-8 as Mac OS Roman ('→ — €' pasted as ',Üí ,Äî ,Ǩ'). Adopt the login shell's LANG alongside PATH at startup, falling back to en_US.UTF-8; newly spawned PTYs inherit it.
1 parent 30fb381 commit 78cb281

1 file changed

Lines changed: 72 additions & 5 deletions

File tree

apps/desktop/src/main/index.ts

Lines changed: 72 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { execFileSync } from "node:child_process";
2+
import { readFileSync, writeFileSync } from "node:fs";
23
import { homedir } from "node:os";
34
import { join } from "node:path";
45
import { createDb, repo } from "@ateam/db";
5-
import { app, BrowserWindow } from "electron";
6+
import { app, BrowserWindow, dialog } from "electron";
67
import { autoUpdater } from "electron-updater";
78
import { type AgentStatus, type KanbanColumn, CH } from "../shared/types";
89
import { ensureNotifyScript } from "./agent-setup";
@@ -60,15 +61,81 @@ function adoptLoginShellPath(): void {
6061
}
6162

6263
/**
63-
* Auto-update from GitHub Releases (electron-updater): check at launch and
64-
* every 4 hours; downloads in the background and notifies — the update
65-
* installs when the app quits. No more manual trips to the repo.
64+
* Auto-update from GitHub Releases (electron-updater), Sparkle-style: ask
65+
* before downloading (with release notes; "Skip This Version" is remembered),
66+
* then offer "Restart Now" once downloaded — otherwise it installs on quit.
67+
* Checks at launch and every 4 hours.
6668
*/
6769
function setupAutoUpdate(): void {
6870
if (!app.isPackaged) return;
71+
autoUpdater.autoDownload = false;
72+
73+
const skipFile = join(app.getPath("userData"), "skipped-version.txt");
74+
const skippedVersion = (): string => {
75+
try {
76+
return readFileSync(skipFile, "utf8").trim();
77+
} catch {
78+
return "";
79+
}
80+
};
81+
// "Remind Me Later" = stay quiet until the next app launch.
82+
let snoozed = false;
83+
84+
autoUpdater.on("update-available", (info) => {
85+
if (snoozed || info.version === skippedVersion()) return;
86+
const notes =
87+
typeof info.releaseNotes === "string"
88+
? info.releaseNotes.replace(/<[^>]+>/g, "").trim()
89+
: "";
90+
void dialog
91+
.showMessageBox({
92+
type: "info",
93+
title: "Software Update",
94+
message: `A new version of Ateam is available!`,
95+
detail: `Ateam ${info.version} is now available — you have ${app.getVersion()}. Would you like to download it now?${notes ? `\n\n${notes.slice(0, 1500)}` : ""}`,
96+
buttons: ["Install Update", "Remind Me Later", "Skip This Version"],
97+
defaultId: 0,
98+
cancelId: 1,
99+
})
100+
.then(({ response }) => {
101+
if (response === 0) {
102+
void autoUpdater
103+
.downloadUpdate()
104+
.catch((err) =>
105+
console.warn("[ateam] update download failed:", err),
106+
);
107+
} else if (response === 1) {
108+
snoozed = true;
109+
} else {
110+
try {
111+
writeFileSync(skipFile, info.version, "utf8");
112+
} catch {
113+
/* best-effort */
114+
}
115+
}
116+
});
117+
});
118+
119+
autoUpdater.on("update-downloaded", (info) => {
120+
void dialog
121+
.showMessageBox({
122+
type: "info",
123+
title: "Update Ready",
124+
message: `Ateam ${info.version} has been downloaded.`,
125+
detail:
126+
"Restart now to apply it — or keep working, and it will install when you quit. Agent terminals survive the restart.",
127+
buttons: ["Restart Now", "Later"],
128+
defaultId: 0,
129+
cancelId: 1,
130+
})
131+
.then(({ response }) => {
132+
if (response === 0) autoUpdater.quitAndInstall();
133+
});
134+
});
135+
69136
const check = () =>
70137
autoUpdater
71-
.checkForUpdatesAndNotify()
138+
.checkForUpdates()
72139
.catch((err) => console.warn("[ateam] update check failed:", err));
73140
check();
74141
setInterval(check, 4 * 60 * 60 * 1000);

0 commit comments

Comments
 (0)