chore: 禁用 native auto-updater,改为引导用户从 GitHub 下载

macOS 上 ad-hoc 签名无法通过 ShipIt 的 kSecCSStrictValidate 校验,
导致热更新始终失败。在获取 Apple 开发者证书之前,暂时禁用 native
auto-updater,改为 browser-mode 检查 GitHub Releases API:

- electron/updater.ts: 注释掉 electron-updater 逻辑,initAutoUpdater
  和 setUpdaterWindow 改为 no-op
- electron/preload.ts: 注释掉 updater IPC bridge,前端不再暴露
  window.electronAPI.updater
- AppShell.tsx: isNativeUpdater 硬编码为 false,移除 native IPC 订阅
  和 native check/download/quitAndInstall 逻辑;保留 browser-mode
  的 GitHub API 检查(mount 时 + 每 8 小时),发现新版本时弹窗引导
  用户跳转 GitHub Release 页面下载

设置页 UpdateCard 保持不变:「检查更新」按钮通过 /api/app/updates
查询 GitHub,有新版本时显示「查看发布」按钮跳转下载。

TODO: 获取 Apple 开发者证书后,取消注释恢复 native auto-updater。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
7418andClaude Opus 4.6 committed 2026-02-28 11:45:36 +08:00
1 parent 819f9f401a
commit ad34fe387b
3 files changed
+45 -248

No files matched your search

+12 -111
View File
@@ -368,9 +368,12 @@ export function AppShell({ children }: { children: React.ReactNode }) {
const [checking, setChecking] = useState(false);
const [showDialog, setShowDialog] = useState(false);
const isNativeUpdater = typeof window !== "undefined" && !!window.electronAPI?.updater;
// Native auto-updater disabled — always use browser-mode (GitHub API) check.
// Users are directed to download from GitHub Releases.
// TODO: Re-enable native updater after obtaining Apple Developer certificate.
const isNativeUpdater = false;
// --- Browser-mode update check (fallback) ---
// --- Browser-mode update check ---
const checkForUpdatesBrowser = useCallback(async () => {
setChecking(true);
try {
@@ -399,130 +402,28 @@ export function AppShell({ children }: { children: React.ReactNode }) {
}
}, []);
// --- Electron native updater check ---
const checkForUpdatesNative = useCallback(async () => {
setChecking(true);
setUpdateInfo((prev) => prev ? { ...prev, lastError: null } : prev);
try {
await window.electronAPI?.updater?.checkForUpdates();
} catch {
setChecking(false);
}
}, []);
const checkForUpdates = isNativeUpdater ? checkForUpdatesNative : checkForUpdatesBrowser;
// Subscribe to native updater IPC events
useEffect(() => {
if (!isNativeUpdater) return;
const unsubscribe = window.electronAPI!.updater!.onStatus((event) => {
switch (event.status) {
case 'checking':
setChecking(true);
break;
case 'available':
setChecking(false);
setUpdateInfo((prev) => {
const releaseNotes = typeof event.info?.releaseNotes === 'string'
? event.info.releaseNotes
: '';
const newInfo: UpdateInfo = {
updateAvailable: true,
latestVersion: event.info?.version ?? '',
currentVersion: prev?.currentVersion ?? (process.env.NEXT_PUBLIC_APP_VERSION || '0.0.0'),
releaseName: event.info?.releaseName ?? `v${event.info?.version}`,
releaseNotes,
releaseUrl: `https://github.com/op7418/CodePilot/releases/tag/v${event.info?.version}`,
publishedAt: event.info?.releaseDate ?? '',
downloadProgress: prev?.downloadProgress ?? null,
readyToInstall: prev?.readyToInstall ?? false,
isNativeUpdate: true,
lastError: null,
};
return newInfo;
});
// Show dialog if not dismissed
if (event.info?.version) {
const dismissed = localStorage.getItem(DISMISSED_VERSION_KEY);
if (dismissed !== event.info.version) {
setShowDialog(true);
}
}
break;
case 'not-available':
setChecking(false);
break;
case 'downloading':
setUpdateInfo((prev) => prev ? {
...prev,
downloadProgress: event.progress?.percent ?? null,
lastError: null,
} : prev);
break;
case 'downloaded':
setUpdateInfo((prev) => {
if (!prev) return prev;
return {
...prev,
readyToInstall: true,
downloadProgress: 100,
lastError: null,
};
});
break;
case 'error':
setChecking(false);
// Reset download progress so the download button re-appears
setUpdateInfo((prev) => prev ? {
...prev,
downloadProgress: null,
lastError: event.error ?? 'Update failed',
} : prev);
console.warn('[updater] Error:', event.error);
break;
}
});
return unsubscribe;
}, [isNativeUpdater]);
// Native updater check disabled — always use browser-mode check
const checkForUpdates = checkForUpdatesBrowser;
// Browser mode: check on mount + every 8 hours
useEffect(() => {
if (isNativeUpdater) return;
checkForUpdatesBrowser();
const id = setInterval(checkForUpdatesBrowser, CHECK_INTERVAL);
return () => clearInterval(id);
}, [isNativeUpdater, checkForUpdatesBrowser]);
}, [checkForUpdatesBrowser]);
const dismissUpdate = useCallback(() => {
setShowDialog(false);
}, []);
// Native download/install disabled — no-ops while native updater is disabled.
// The UI shows "View Release" (opens GitHub) instead.
const downloadUpdate = useCallback(async () => {
// Immediately show downloading state so user gets feedback
setUpdateInfo((prev) => prev ? { ...prev, downloadProgress: 0, lastError: null } : prev);
try {
await window.electronAPI?.updater?.downloadUpdate();
} catch (err) {
console.warn('[updater] Download failed:', err);
const message = err instanceof Error ? err.message : String(err);
// Reset progress so the download button re-appears
setUpdateInfo((prev) => prev ? {
...prev,
downloadProgress: null,
lastError: message,
} : prev);
}
// no-op: native updater disabled
}, []);
const quitAndInstall = useCallback(() => {
window.electronAPI?.updater?.quitAndInstall();
// no-op: native updater disabled
}, []);
const updateContextValue = useMemo(