Nouveautés

Chaque version, de la plus récente à la plus ancienne — les mêmes notes que l’app affiche quand elle se met à jour. Les téléchargements se trouvent sur la page des versions. Les versions plus anciennes sont affichées en anglais.

La nouvelle icône s’affiche enfin correctement sur macOS 26. En style sombre, la flèche et l’anneau ne se fondent plus en taches pleines, et la tête et les oreilles du chat ont des bords nets au lieu de bords crénelés.

Fermer l’établi libère désormais la mémoire utilisée par ses notes de version. Auparavant, une page de notes de version ouverte continuait de tourner en arrière-plan jusqu’à ce que vous quittiez DuoUpdater.

Une nouvelle icône. Un chat siamois enroulé sur lui-même, dont la queue forme la flèche d’actualisation. Sur macOS 26 et ultérieur, elle suit votre style d’icônes clair, sombre ou teinté.

Les vérifications en arrière-plan attendent tant que vous êtes en mode données faibles ou sur une connexion limitée, comme un partage de connexion iPhone. Elles s’exécutent dès que vous retrouvez un réseau normal. La vérification manuelle et l’installation des mises à jour fonctionnent comme avant.

Les vérifications qui échouent à cause d’un raté du réseau sont relancées une fois, deux minutes plus tard. Avant, les lignes en échec et l’avertissement restaient jusqu’à la vérification programmée suivante, six heures plus tard par défaut.

Sous le capot. Les images des notes de version prennent beaucoup moins de place sur le disque, le panneau Requêtes ne compte plus deux fois une requête revalidée, et la vérification de Muse ne télécharge plus sa page de connexion.

Les apps Homebrew qui s’installent avec leur propre script d’installation, comme Quark Cloud Drive, se mettent désormais à jour en un clic. Avant, chaque tentative se terminait par une erreur indiquant qu’aucun paquet d’installation n’avait été trouvé.

Les apps Homebrew dont l’installateur doit être lancé par vous affichent désormais leur mise à jour avec un lien, au lieu d’échouer. Avant, DuoUpdater téléchargeait tout l’installateur puis s’arrêtait sur une erreur.

Davantage d’apps Homebrew sont reconnues. Les apps que Homebrew installe sous un autre nom, comme Visual Paradigm Community Edition, sont désormais vérifiées, et une app au nom proche n’est plus confondue avec elles.

Les apps dont le cask Homebrew a été retiré ne se voient plus proposer une mise à jour que Homebrew refuse d’installer. Elles sont vérifiées à la place via le propre flux de mises à jour de l’app, quand il existe.

Les notes de version de VS Code s’affichent de nouveau.

Sous le capot. Réglages › Diagnostic n’avertit plus en permanence au sujet d’Antigravity et d’OpenLens quand leurs mises à jour sont trouvées par un autre moyen.

Blender téléchargé depuis blender.org reçoit désormais ses mises à jour, en un clic. Avant, seule une copie installée avec Homebrew était vérifiée.

Les versions alpha, bêta et release candidate (RC) de Blender suivent leur propre canal. DuoUpdater reconnaît le type de version que vous avez et vous prévient quand une version plus récente du même type sort. Une alpha ne se voit jamais proposer une version stable, ni l’inverse.

Les mises à jour de Muse s’affichent de nouveau. Depuis que Muse demande une connexion sur son lien de téléchargement, sa ligne affichait une erreur au lieu de la nouvelle version.

Sous le capot. La fenêtre de la barre des menus et l’établi s’ouvrent un peu plus vite la première fois après le lancement, et duo check liste désormais les apps dont la vérification a échoué au lieu de dire que tout est à jour.

DuoUpdater parle désormais italien, chinois traditionnel, portugais (Brésil) et turc. Cela fait onze langues. En allemand, en espagnol et en japonais, les textes erronés ou tronqués ont été corrigés. Réglages → Dossiers affiche désormais le nom des dossiers comme le Finder dans votre langue.

Les apps installées avec Homebrew sont désormais mises à jour par Homebrew. Cela concerne les apps installées avec brew qui ont aussi leur propre outil de mise à jour. Auparavant, DuoUpdater les mettait à jour directement sans que Homebrew le sache, et le brew upgrade suivant retéléchargeait et réinstallait la version que vous aviez déjà.

Les fenêtres s’ouvrent dans le Space où vous êtes. Auparavant, rouvrir les Réglages ou une autre fenêtre de DuoUpdater après l’avoir fermée pouvait vous ramener dans le Space où elle était affichée la dernière fois.

Une mise à jour, une notification. Certaines apps sont vérifiées par deux sources, qui pouvaient annoncer la même nouvelle version encore et encore.

Le Journal des versions n’affiche plus de versions datées dans le futur. Si le flux d’un développeur indique une date postérieure au moment où DuoUpdater a vu la version pour la première fois, le journal utilise ce moment-là.

Quand le disque de sauvegarde est débranché, la fenêtre de l’établi tient de nouveau dans l’écran, et « Copier maintenant » vous dit pourquoi la copie est impossible. Auparavant, la fenêtre pouvait devenir plus haute que l’écran, si bien que les listes ne défilaient pas jusqu’au bout, et « Copier maintenant » ne faisait rien, sans rien dire.

Les bêtas et versions candidates de Xcode se mettent désormais à jour en un clic. Connectez-vous une fois à votre compte Apple Developer dans Réglages → Xcode, et DuoUpdater télécharge et installe les nouvelles bêtas et RC comme n’importe quelle autre mise à jour. Auparavant, il pouvait seulement vous signaler qu’une nouvelle version était sortie.

Installez n’importe quelle version de Xcode à côté de celles que vous avez. Réglages → Xcode liste toutes les versions de Xcode, regroupées par version, avec le groupe de votre macOS déjà ouvert. « Installer » place celle que vous choisissez dans Applications comme une copie à part — par exemple Xcode-26.6.app — sans rien remplacer ; ou enregistrez seulement l’archive (.xip). Quand vous êtes connecté, la liste d’Apple elle-même est incluse, si bien que les nouvelles versions apparaissent en quelques minutes.

Votre connexion Apple Developer se maintient toute seule. Apple met fin à une session développeur au bout d’environ huit heures ; DuoUpdater en obtient maintenant une nouvelle en arrière-plan — sans fenêtre ni mot de passe — tant qu’Apple reconnaît encore ce Mac. Vous pouvez désactiver cela dans Réglages → Xcode.

Les nouvelles versions de Xcode apparaissent plus tôt. En semaine, aux heures où Apple publie habituellement, DuoUpdater cherche un nouveau Xcode toutes les cinq minutes.

Quelques apps fonctionnent de nouveau après des changements de leurs développeurs. CapCut bêta et Superconductor nightly sont de nouveau trouvées et installées, et Superconductor garde son identité d’app actuelle. VLC 3.0.24 et JetBrains Air affichent de nouveau leurs notes de version.

Qoder CN IDE est désormais pris en charge. L’édition pour la Chine continentale de l’IDE de Qoder a la vérification des mises à jour, l’installation en un clic et ses notes de version dans la fenêtre. Qoder CN, l’app de bureau, affiche aussi désormais ses notes de version.

Qoder IDE ne change plus d’avis sur la dernière version. Qoder déploie ses mises à jour progressivement, et DuoUpdater pose désormais la question de la même manière que votre copie de l’IDE, si bien qu’il obtient toujours la même réponse. Auparavant, la version proposée pouvait alterner entre deux versions, et une installation en un clic pouvait s’arrêter en cours de route parce que la réponse avait changé.

Les apps Sparkle dont la mise à jour téléchargée est devenue obsolète peuvent de nouveau être mises à jour. Si une app qui se met à jour elle-même via Sparkle a téléchargé une version et qu’une plus récente est sortie ensuite, DuoUpdater supprime maintenant l’ancien téléchargement et installe la dernière. Auparavant, « Mettre à jour » répétait qu’une installation maintenant serait annulée, et la ligne ne changeait jamais.

duo install vous prévient quand la dernière version attend déjà. Si le programme de mise à jour d’une app a déjà téléchargé la dernière version, il le dit maintenant et propose de quitter l’app ou de lancer duo restart. Auparavant, il affirmait à tort que l’app pouvait seulement être vérifiée, pas installée.

搜狗输入法 se met à jour en un clic. DuoUpdater applique la mise à jour comme la méthode de saisie le fait elle-même — le bundle installé reste en place — et copie d’abord votre dictionnaire et vos réglages, pour qu’une restauration les rende aussi.

Les sauvegardes sur un autre disque gardent désormais le dictionnaire et les réglages d’une méthode de saisie. Auparavant, seule l’app elle-même était déplacée sur le disque de sauvegarde, si bien qu’une restauration depuis ce disque laissait en place les données de la version plus récente.

Fini les mises à jour qui ne peuvent jamais s’installer. JetBrains Air affiche désormais la version que Toolbox propose réellement. Une app de l’App Store restée sous son ancien nom après que son développeur l’a renommée indique maintenant quelle copie l’App Store met à jour, au lieu de proposer une mise à jour qui ne fait que réinstaller l’autre copie.

Les notes de version de davantage d’apps s’affichent mises en forme. Les apps qui publient leurs notes en Markdown ont désormais la même liste native que les autres. Auparavant, elles s’affichaient en texte brut.

Relancer n’entre plus en concurrence avec l’installeur de l’app. Quand une app a téléchargé sa propre mise à jour et que sa sauvegarde de restauration doit aller sur un disque externe, cette copie attend désormais la fin de l’installeur. Auparavant, elle se faisait pendant les quelques secondes que macOS lui laisse pour travailler.

Les sauvegardes de restauration peuvent désormais vivre sur un autre disque. Une sauvegarde est une copie entière d’une app, et sur le volume de démarrage elles s’accumulent. Réglages → Sauvegardes liste les disques connectés avec l’espace libre de chacun, déplace les sauvegardes que vous avez déjà et écrit les nouvelles là-bas en arrière-plan : débranchez le disque et vous aurez un délai, pas un point de restauration manquant. duo backups gagne disks, sync, verify et probe.

千问输入法 est désormais pris en charge. DuoUpdater vous signale la sortie d’une nouvelle version et met à jour la méthode de saisie comme elle se met à jour elle-même.

Les notes de version ne restent plus bloquées sur la version précédente. Quand un développeur publie une mise à jour quelques minutes avant que sa page de changements n’en parle, les anciennes notes étaient classées sous la nouvelle version et conservées indéfiniment. CleanShot X affichait les notes de 5.0 sous 5.0.1 depuis le jour de sa sortie.

Supprimer une sauvegarde libère maintenant l’espace annoncé. Les sauvegardes prises par d’anciennes versions de DuoUpdater étaient écrites dans une forme que macOS refuse de supprimer : Nettoyer laissait l’essentiel de la copie sur le disque tout en la comptant comme récupérée.

Nettoyer s’ouvre immédiatement. Auparavant, chaque sauvegarde enregistrée était remesurée de zéro à chaque clic.

WorkBuddy affiche de nouveau sa version la plus récente. Son service de mise à jour répond par l’étape suivante d’une chaîne de mises à jour plutôt que par le build le plus récent, si bien que les quatre éditions de WorkBuddy avaient deux versions de retard.

Sous le capot. Une app qui n’a jamais déclaré quel binaire elle exécute — Muse, de Meta, en fait partie — livre désormais quand même ses frameworks et son SDK.

Les mises à jour terminées avec Relancer peuvent désormais être annulées. Quand une app a déjà téléchargé sa propre mise à jour et que vous cliquez sur Relancer, DuoUpdater enregistre d’abord la version actuelle : la mise à jour apparaît alors dans Restauration comme les autres. Auparavant, seules les mises à jour installées par DuoUpdater lui-même pouvaient être annulées.

Voyez ce qu’une mise à jour a changé dans une app. Pour toute app dont une version précédente est enregistrée, l’établi propose désormais une vue Différences du bundle à côté de Notes de version : signature et autorisations, macOS minimal, éléments d’arrière-plan et d’ouverture de session, bibliothèques intégrées, ainsi que les fichiers ajoutés, supprimés ou redimensionnés. duo diff fait de même dans le Terminal pour deux copies quelconques d’une app.

Relancer vous prévient quand le programme de mise à jour d’une app n’a pas appliqué la mise à jour. Si l’app se ferme et que la mise à jour n’arrive jamais, sa ligne l’indique désormais et propose toujours Relancer. Auparavant, l’indicateur s’arrêtait sans un mot.

Cherry Studio affiche de nouveau sa version la plus récente. Après que Cherry Studio a renommé ses téléchargements Mac, DuoUpdater prenait une version plus ancienne pour la dernière : les copies récentes apparaissaient à jour et les plus anciennes se voyaient proposer cet ancien build.

Les mises à jour de l’App Store ne restent plus bloquées derrière un assistant qui ne répond pas. Quand l’assistant de DuoUpdater cessait de répondre, la mise à jour restait à 0 % et toutes les mises à jour App Store en file d’attente patientaient jusqu’à ce que vous quittiez DuoUpdater.

Tout mettre à jour ne relance plus les apps que vous avez ignorées. Avec « Relancer automatiquement les applications mises à jour » activé, la fin d’un lot pouvait quitter et rouvrir une app ignorée, ou une app dont vous aviez ignoré la version téléchargée.

Tinycast et SuperCmd sont désormais pris en charge. DuoUpdater vous signale la sortie d’une nouvelle version de Tinycast ou de sa bêta, et reconnaît désormais le SuperCmd open source d’origine en plus de SuperCmd 2. Les notes de version de Kimi Code s’affichent aussi désormais.

Les notes de version correspondent à la version proposée. La dernière page de notes de version de VS Code s’affichait vide, et juste après la sortie d’une nouvelle version, le volet des notes pouvait montrer celles de la version précédente.

Le Journal des versions n’ajoute plus la même version à chaque lancement. Des apps comme Claude, Raycast et Cline recevaient une entrée en double à chaque démarrage de DuoUpdater.

La barre latérale de l’établi est divisée en onglets Applications, Brew et Restauration. Cliquez sur un onglet ou faites glisser le pointeur sur les onglets pour changer ; la recherche filtre les trois à la fois.

Sous le capot. Relancer et Revenir en arrière sur une même app ne se marchent plus dessus ; un flux de mises à jour ne peut plus amener DuoUpdater à supprimer des fichiers hors de son dossier de téléchargement ; les vérifications en arrière-plan ne risquent plus que macOS demande l’accès aux données d’autres apps ; un très grand nombre dans le filtre Requêtes ne fait plus quitter l’app ; et la barre des menus respecte désormais une demande d’administrateur que vous avez refusée dans duo install.

Les mises à jour d’iStat Menus sont correctement détectées. Quand iStat Menus republiait une mise à jour, DuoUpdater pouvait continuer à la proposer après son installation, et cliquer de nouveau sur Mettre à jour se terminait par une erreur.

Memoh Desktop est désormais pris en charge. DuoUpdater vous signale la sortie d’une nouvelle version et peut la mettre à jour en un clic.

Tout mettre à jour ne vous demande plus de relancer une app de l’App Store déjà rouverte. Quand l’App Store ferme une app et la rouvre sur sa nouvelle version, sa ligne l’affiche aussitôt comme mise à jour, au lieu d’indiquer « Relancer maintenant » jusqu’à la fin de tout le lot.

Une app qui a déjà téléchargé sa propre mise à jour ne la télécharge plus deux fois. Certaines apps récupèrent une mise à jour discrètement en arrière-plan, puis attendent que vous les relanciez. Cliquez sur Mettre à jour dans DuoUpdater : il installe désormais la copie déjà présente sur votre disque, la mise à jour se fait en quelques secondes et sans aucun téléchargement. Auparavant, DuoUpdater retéléchargeait la même version.

Cua Driver et Petex sont désormais pris en charge. DuoUpdater vous signale la sortie d’une nouvelle version de l’une ou l’autre, et Cua Driver se met en plus à jour en un clic et affiche ses notes de version.

La même mise à jour ne vous est plus signalée encore et encore. Quand le serveur d’un développeur alternait entre deux versions, chaque vérification ressemblait à une nouvelle mise à jour et envoyait une nouvelle notification.

Un paquet qui vient d’être installé ne propose plus de s’installer à nouveau. Sa ligne continuait d’indiquer que le paquet téléchargé serait rouvert.

DuoUpdater nécessite désormais macOS 15 Sequoia ou version ultérieure. Un Mac encore sous macOS 14 conserve sa version actuelle et ne se voit plus proposer de mises à jour ; tous les Mac Apple silicon peuvent passer à un macOS pris en charge.

Sous le capot. Les vérifications régulières ne résolvent plus les liens de téléchargement à l’avance, ce qui pouvait masquer brièvement un bouton Mettre à jour pourtant fonctionnel quand le serveur de téléchargement d’un développeur ne répondait pas à temps.

Aside est désormais pris en charge. DuoUpdater vous signale la sortie d’une nouvelle version du navigateur Aside et affiche ses notes de version.

Les mises à jour que votre macOS ne peut pas exécuter ne sont plus proposées, et la ligne indique maintenant pourquoi. Quand un développeur précise les versions de macOS prises en charge par une version, DuoUpdater s’y conforme : après une mise à niveau de macOS, Little Snitch ne propose plus une version plafonnée en dessous de votre système ; Xcode ne propose plus une version qui exige un macOS plus récent que le vôtre ; et un paquet d’installation dont l’app exige un macOS plus récent est refusé, au lieu d’installer une app qui ne s’ouvrira pas. Les lignes qui n’affichaient qu’un tiret vide indiquent désormais « Pas encore pour ce macOS » ou « Nécessite un macOS plus récent », avec les détails à portée de clic.

Voyez avec quel SDK chaque app a été compilée. Cliquez sur la marque à côté du nom d’une app : ses détails indiquent désormais, par exemple, « Compilée avec le SDK macOS 27.0. » — pratique pour repérer les apps déjà recompilées pour le dernier macOS.

Les apps Homebrew publiées en deux paquets — l’un pour les anciens systèmes, l’autre pour le plus récent — sont maintenant lues depuis le bon. OnyX est découpé ainsi pour macOS 27, et DuoUpdater ne regardait que le paquet destiné aux anciens systèmes : soit OnyX n’apparaissait pas du tout, soit il était jugé à jour par rapport à une version que Homebrew refuse d’installer sur 27. DuoUpdater suit désormais celui des deux que vous avez installé.

Les bêtas TestFlight ne perdent plus leur mise à jour au lancement de TestFlight. Une bêta avec un nouveau build en attente pouvait repasser à « à jour » et y rester jusqu’à ce que vous rouvriez TestFlight.

Les mises à jour en un clic de Dropbox et ToDesk téléchargent le bon fichier. Sur les Mac Apple silicon, Dropbox téléchargeait la version réservée aux Mac Intel, que le contrôle de sécurité refusait ensuite ; ToDesk se voyait proposer la version en accès anticipé réservée à une partie des utilisateurs, au lieu de la version générale.

Relancer termine immédiatement la mise à jour de Spotify. Quand Spotify avait déjà téléchargé sa propre mise à jour, Relancer tournait pendant plusieurs minutes avant que la mise à jour s’applique.

Les versions bêta passent à leurs versions finales. Une bêta d’Xcode se voit proposer sa version candidate au lieu d’apparaître à jour ; les bêtas de CotEditor voient ses versions candidates ; et une bêta de Carbon Copy Cloner dont le cycle de test est terminé se voit proposer la version qu’elle est devenue, au lieu d’une vérification en échec.

Les notes de version correspondent à la version que vous avez. Blender 5.2 affichait les notes de la 5.1, et Raycast 1.x celles de la 2.x. « Ouvrir la page » de Gemini ouvre désormais la page actuelle de la version de bureau de Google au lieu d’une erreur.

Les Réglages expliquent chaque option juste à côté. Les longues notes sous des sections entières sont remplacées par une courte ligne sous chaque commande, et les menus ne décrivent que l’option choisie.

L’app écrit désormais son nom DuoUpdater, comme le site web.

Les paquets Homebrew issus de taps non approuvés réapparaissent. Depuis Homebrew 6, brew ignore discrètement les paquets des taps non approuvés quand il liste ce qui est installé ; ils disparaissaient donc de DuoUpdater sans explication. Ils sont désormais affichés comme « Non vérifié · tap non approuvé », avec la commande brew trust prête à copier — et dès que vous l’avez lancée (ou une mise à niveau) dans le Terminal, la fenêtre se met à jour quand vous y revenez.

Les apps qui demandent un mot de passe administrateur pour se mettre à jour ne sont plus mises à jour deux fois. Quand une app comme Tailscale avait déjà téléchargé sa propre mise à jour et attendait un redémarrage, DuoUpdater ne le voyait pas et proposait quand même Mettre à jour, au risque d’entrer en collision avec l’installateur de l’app. La ligne propose désormais Relancer, et Tout mettre à jour la laisse de côté.

La section Homebrew peut maintenant mettre à jour Homebrew lui-même. Quand une nouvelle version de Homebrew sort, une ligne en haut propose de lancer brew update pour vous. Elle reste masquée si vous avez défini HOMEBREW_NO_AUTO_UPDATE.

Une mise à niveau Homebrew qui échoue affiche maintenant la véritable erreur de brew. La ligne montrait auparavant le conseil que brew affiche après l’erreur, ou rien du tout, si bien qu’un message comme « vos Command Line Tools sont trop anciens » ne vous parvenait jamais. Mettre à niveau plusieurs paquets à la fois n’annonce plus non plus la fin avant qu’elle soit atteinte.

L’icône de la barre des menus compte au-delà de 50. Avec plus de 50 mises à jour en attente, elle restait bloquée à 50.

Notes de version : celles de Claude sont regroupées en New, Improved et Fixed, comme dans Claude lui-même ; celles de Mac Mouse Fix s’affichent en texte plutôt que dans une page intégrée ; et l’app officielle de Homebrew a maintenant ses notes.

duo check ne dit plus « Everything is up to date. » quand il n’a pas pu vérifier. Il le signale désormais quand il n’a pas pu lire TestFlight ou quand l’analyse des apps a été abandonnée.

Les notes de version s’affichent désormais dans votre langue quand une app les publie en plusieurs langues. Certaines apps traduisent leurs notes à chaque publication ; DuoUpdater retenait celle que l’app citait en premier ou en dernier, si bien que les notes d’une app s’affichaient en allemand pour tout le monde et que celles d’une autre changeaient de langue d’une version à l’autre.

Les apps qui ont ajouté une version Mac ne sont plus marquées « Non pris en charge sur ce Mac ». Une app iPhone ou iPad que vous utilisez sur Apple silicon était signalée à tort dès l’instant où son développeur publiait une véritable version Mac — le seul changement qui rend la mise à jour plus accessible, pas moins.

Une app de l’App Store que vous testez aussi en bêta n’est plus prise pour une version TestFlight. Quand un développeur promouvait une bêta telle quelle, les deux portaient le même numéro de build et votre copie achetée était confiée à TestFlight — l’App Store ne pouvait donc jamais lui proposer de mise à jour.

Une mise à jour de l’App Store qui exige un macOS plus récent que le vôtre le dit désormais. Avant, la rangée proposait quand même de l’installer et l’App Store refusait à la dernière étape, sans rien afficher pour expliquer pourquoi.

La fenêtre « Requêtes » indique désormais jusqu’où remonte réellement son journal, et signale les périodes qu’elle ne peut pas couvrir entièrement. Avant, choisir « 30 derniers jours » sur un journal qui ne remontait qu’à quelques heures donnait exactement le même résultat que « Dernières 24 heures », sans rien à l’écran pour expliquer pourquoi.

Vous choisissez ce que DuoUpdater fait des bêtas TestFlight, dans Réglages → Général. « À l’actualisation » lit ce que TestFlight sait déjà et lui demande une réponse fraîche quand vous appuyez sur le bouton d’actualisation ; « Garder à jour » laisse en plus DuoUpdater demander de lui-même, si bien qu’une bêta TestFlight installée en arrière-plan ne reste plus un point d’interrogation jusqu’à votre prochaine actualisation, et qu’un build qui vous attend ne passe plus inaperçu derrière un « à jour » ; « Désactivé » ne lit rien et l’indique sur ces rangées au lieu de deviner. Les Mac qui avaient déjà l’accès complet au disque démarrent sur « À l’actualisation », les autres sur « Désactivé ».

Ouvrir TestFlight vous-même suffit désormais à ce que DuoUpdater remarque ce qu’il a installé. Une bêta que vous installiez via TestFlight restait un point d’interrogation jusqu’à l’actualisation suivante — et sur macOS 27, où l’avis « Prêt à tester » de TestFlight n’arrive plus pour les apps que vous avez déjà, cela pouvait durer des heures.

Cline reçoit désormais ses mises à jour, sur sa version stable comme sur sa bêta, et affiche ses notes de version. Jusqu’ici, sa rangée affichait un point d’interrogation au lieu d’une version : il ne publie aucun flux de mise à jour que DuoUpdater sache lire, et il n’existe pas de paquet Homebrew pour lui. DuoUpdater interroge maintenant la même adresse que l’outil de mise à jour de Cline, si bien que la mise à jour proposée est celle que Cline aurait installée lui-même, et la bêta reste sur la piste bêta.

Les notes de version qui regroupent les changements sous des titres comme « Added » ou « Fixed » conservent désormais ces titres. Avant, tous les groupes étaient fondus en une seule liste, impossible de distinguer les nouveautés des corrections de bugs.

Mac Mouse Fix propose désormais ses bêtas si vous avez activé « Get Beta Versions » dans ses propres réglages Général. Avant, DuoUpdater ne voyait que les versions ordinaires de Mac Mouse Fix, et une bêta passait inaperçue jusqu’à la publication de la version ordinaire suivante.

Les apps dont le numéro de build est un simple compteur ne masquent plus leurs propres versions correctives. Pour une app annonçant une version comme 12.10 avec le build 282987, une version 12.10.1 se lisait comme « déjà à jour ».

Un nouveau build d’une app qui garde le même nom de version est de nouveau annoncé. Une fois qu’un build avait été annoncé, tous les suivants portant ce nom arrivaient en silence — la rangée s’allumait, la pastille les comptait, mais aucune bannière n’arrivait jamais.

« Tout mettre à jour » ne compte plus que les apps réellement mises à jour. Une app qui ouvre le programme d’installation d’Apple pour que vous terminiez était comptée comme faite alors que sa fenêtre était encore ouverte, si bien que « 2 apps ont été mises à jour » pouvait ne rien vouloir dire.

Une mise à jour qui a abouti mais a laissé un résidu est désormais signalée comme installée, et non par une demande de « Gestion des applications ». La nouvelle version tournait déjà pendant que la rangée vous envoyait dans les Réglages Système.

Arrêter « Tout mettre à jour » arrête désormais le téléchargement en cours. Avant, un transfert de plusieurs gigaoctets continuait jusqu’au bout, réessayait jusqu’à cinq fois, et ne s’apercevait qu’ensuite qu’il avait été annulé.

Les notes de version ne sont plus mélangées entre deux apps qui partagent une même page de changelog, et restent à jour après une mise à jour pour les apps dont les notes vivent sur une page par version. Antigravity et Antigravity IDE pouvaient afficher les notes l’une de l’autre pendant un quart d’heure ; Thunderbird, WeChat, Opera et quelques autres continuaient un moment d’afficher les notes de la version précédente après la mise à jour.

La recherche dans la liste des apps ignore les accents, comme le faisait déjà la recherche des Réglages. Taper « cafe » trouve maintenant « Café ».

La page « Diagnostic » affiche une ligne d’état par canal de publication. Une règle bêta ou preview cassée se cachait jusqu’ici derrière sa voisine stable en bonne santé.

Une réponse « interdit » de GitHub n’est plus signalée comme une limite de requêtes. Un dépôt devenu privé ou un jeton auquel il manque une autorisation vous incitait à ajouter un jeton qui n’aurait rien changé.

« Relancer » n’est plus proposé pour une app qui se met à jour elle-même quand le build en attente est plus ancien que celui qui tourne.

Sous le capot. Les installations, les sauvegardes et les vérifications de paquets ne monopolisent plus les ressources dont le reste de l’app a besoin : le menu reste réactif pendant l’une d’elles, et fluide pendant un gros téléchargement ; le « Journal des versions » compte toutes les publications qu’un éditeur livre sous un même nom de version ; une sauvegarde de restauration est refusée plutôt que conservée quand il lui manquerait l’exécutable de l’app ; le premier lancement sur un Mac neuf ne consigne plus d’erreurs de base de données sans objet ; duo verify et duo reconcile signalent désormais un changelog dont les entrées se sont effondrées et une adresse d’installation en échec depuis des jours ; une commande duo bloquée abandonne son analyse au bout de vingt secondes au lieu de rester suspendue.

Certaines apps qui se mettent à jour elles-mêmes ne semblent plus à jour alors qu’une version plus récente existe. Pour les apps dont les informations de mise à jour se trouvent derrière un serveur de téléchargement lent à se rafraîchir, DuoUpdater pouvait continuer à voir une version plus ancienne pendant des jours après une publication.

Les notes de version de Kimi apparaissent désormais dans DuoUpdater.

Les mises à jour de CodeEdit apparaissent désormais. Une version plus récente de CodeEdit laissait sa rangée sur un point d’interrogation au lieu de proposer la mise à jour.

Sous le capot. La liste Homebrew du menu se remplit plus vite, et les commandes duo démarrent plus vite.

« Vérifier à nouveau » sur une bêta TestFlight donne désormais la vraie réponse. Avant, la rangée devenait un point d’interrogation jusqu’à la prochaine actualisation.

Les bêtas TestFlight gardent leur réponse pendant que le bouton d’actualisation interroge TestFlight. Avant, elles pouvaient toutes devenir des points d’interrogation pendant quelques secondes.

super.engineering est désormais pris en charge : vérification des mises à jour, notes de version et installation en un clic. Un nouveau nightly apparaît avec ce qui y a changé, et « Mettre à jour » l’installe pour vous.

Microsoft Edge Beta pouvait vous proposer un build stable d’Edge. Pendant la brève période où le flux bêta de Microsoft était vide, la rangée indiquait une version stable, et mettre à jour l’aurait installée par-dessus votre bêta.

Les bêtas TestFlight affichent désormais les mises à jour que TestFlight leur propose, y compris les bêtas d’apps iPhone et iPad. Le bouton d’actualisation interroge TestFlight en arrière-plan, une mise à jour ne disparaît plus quelques minutes après que vous l’avez trouvée, et le bouton TestFlight ouvre la page de cette bêta.

Quand DuoUpdater ne peut pas savoir si une bêta TestFlight est à jour, il le signale. La rangée affiche un point d’interrogation au lieu de la présenter comme à jour — par exemple quand vous vous êtes déconnecté de TestFlight ou que vous ne testez plus cette bêta.

L’accès complet au disque est désormais expliqué, et plus rien ne vous importune sans lui. Sans cet accès, DuoUpdater ne déclenche plus les avertissements de macOS sur la lecture des données d’autres apps ; si une bêta TestFlight ou CotEditor en a besoin, il vous explique une seule fois pourquoi et où l’accorder.

« Relancer » disparaît dès qu’une app mise à jour a été quittée. Une app qui laissait tourner un processus auxiliaire continuait de demander à être relancée longtemps après que sa mise à jour avait pris effet.

Une demande de confidentialité de macOS restée sans réponse ne bloque plus la vérification des mises à jour. Elle se poursuit sans le réglage de cette app.

Les notes de version de Rockxy et d’Ollama sont de nouveau complètes. Celles de Rockxy remontent le fil de ses versions récentes au lieu de s’en tenir à la plus récente, et la dernière version d’Ollama n’est plus laissée de côté.

duo, le compagnon optionnel en ligne de commande, gère mieux TestFlight. --refresh-testflight fonctionne que TestFlight soit ouvert ou non, sans s’emparer de votre écran, et duo check ne dit plus qu’une bêta est à jour quand TestFlight a annoncé un build plus récent.

Telegram Desktop est de nouveau suivi pour les mises à jour. Telegram a renommé le fichier qu’il publie, et la rangée n’y trouvait plus de version — elle affichait donc un échec de vérification à la place de la mise à jour qui attendait derrière.

Une app iPhone ou iPad installée via TestFlight est reconnue comme telle. DuoUpdater la prenait pour un achat sur l’App Store : la rangée désignait donc le mauvais gestionnaire, tandis que le store était interrogé sur une fiche qui n’existe pas — à chaque vérification, aussi longtemps que l’app restait installée.

Une bêta TestFlight porte l’icône de TestFlight lui-même. Les rangées dont s’occupe l’App Store portaient déjà l’icône du store ; celles dont s’occupe TestFlight en écrivaient le nom en toutes lettres, si bien que le même genre de rangée était signalé de deux façons différentes.

L’en-tête de la fenêtre Réseau ne bouge plus quand vous changez d’onglet. Ses deux onglets plaçaient leur titre à des hauteurs légèrement différentes, de sorte que passer de l’un à l’autre donnait l’impression que la fenêtre tressautait.

Le défilement de toute la liste des apps est de nouveau fluide. Un défilement rapide dans la liste complète perdait des images ; chaque ligne indique désormais sa hauteur sans devoir être construite d’abord.

Les notes de version d’une app de l’App Store viennent maintenant toujours de l’App Store. Quand la recherche du store pour une app n’aboutissait pas ou échouait, la fenêtre pouvait se rabattre sur les notes de l’autre canal de distribution de cette app — une autre version, avec ses propres numéros — et décrivait donc une publication que votre copie n’allait jamais recevoir.

Windscribe sur son canal Beta ou Guinea Pig se voit proposer les versions de ce canal. DuoUpdater lit le canal de mise à jour que vous avez choisi dans les réglages de Windscribe, si bien qu’une copie suivant une ligne de préversion ne s’entend plus dire qu’elle est à jour alors que cette ligne a du plus récent. La fenêtre affiche aussi les notes de ces préversions, qu’elle ne listait auparavant que pour les versions stables.

Windscribe est désormais suivi pour les mises à jour, avec ses notes de version. Une copie sur une version ancienne est listée avec la version vers laquelle elle peut aller et ce qui y a changé ; auparavant, DuoUpdater n’avait aucun moyen de voir la version de Windscribe. La mise à jour passe toujours par l’installateur de Windscribe, qui configure aussi des éléments situés hors de l’app.

Une mise à jour n’est plus appliquée à une app qui a disparu pendant que vous cliquiez. Si l’app est désinstallée, remplacée ou devient illisible entre le clic et le début de l’installation, DuoUpdater s’arrête et le dit, au lieu d’installer quand même à cet emplacement.

duo, le compagnon optionnel en ligne de commande, ne dit plus qu’une installation par paquet est terminée avant qu’elle le soit. Installer une app livrée en .pkg ouvre l’installateur de macOS et vous laisse la suite, mais le récapitulatif la comptait comme installée — « 1 installed » alors que rien n’avait encore été remplacé. Les deux sont maintenant comptés séparément. Sa sortie --json étiquette également chaque ligne avec ce qui est arrivé à cette app, si bien qu’un script n’a plus besoin de lire l’explication en anglais pour distinguer un échec d’un saut délibéré.

Sous le capot. La revérification juste avant l’installation qui protège une mise à jour en un clic protège maintenant aussi duo install ; et les contrôles qu’un téléchargement doit passer avant de remplacer une app tiennent en un seul endroit pour les deux chemins qui s’en servent.

Cliquer sur « Mettre à jour » ne reste plus sans effet lorsqu’une source de mises à jour se contredit. Si la vérification lancée au moment du clic renvoie une version plus ancienne que celle proposée dans la ligne, DuoUpdater le signale désormais et conserve la mise à jour. Auparavant, l’app était déclarée à jour et disparaissait de la liste, et la même mise à jour réapparaissait à la vérification suivante.

Les mises à jour de Fork sont de nouveau proposées lorsque Fork est réglé sur son canal Develop. DuoUpdater lisait à l’envers le réglage de canal de Fork et suivait son flux Stable, nettement en retard : une copie Develop était donc annoncée à jour alors que Fork proposait déjà une version plus récente.

Mac Performance Monitor affiche enfin ses notes de version. L’app les publie dans son dépôt plutôt que dans le flux que nous lisons, si bien que la fenêtre n’avait rien à afficher.

CotEditor est désormais pris en charge, sur sa ligne de versions finales comme sur sa ligne bêta. La ligne suivie par une copie découle de la version installée et du réglage propre à CotEditor « Update to prereleases when available » : une copie bêta se voit donc proposer la bêta suivante plutôt qu’une version finale qui la ferait reculer.

Une app installée depuis l’App Store ne se voit jamais proposer un téléchargement venu d’ailleurs. Lorsque la requête adressée à la boutique échoue ou revient vide, la ligne indique désormais que la boutique s’en occupe, sans numéro de version. Auparavant, la vérification pouvait se rabattre sur l’autre canal de distribution de l’app — une compilation différente, avec sa propre numérotation — et proposer de l’installer par-dessus la copie de la boutique.

Aucune app ne se voit proposer une mise à jour qui la ramènerait à une version antérieure. Certains flux placent une version finale au-dessus d’une préversion en réalité plus avancée : l’installer aurait fait reculer l’app.

Une erreur longue sur une ligne ne repousse plus le reste de la liste vers le bas. Elle tient en deux lignes, le texte complet s’affichant au survol.

Quatre apps de plus sont prises en charge : WhatCable, Qoder IDE, Qoder et Yaak. Chacune bénéficie de la vérification des mises à jour et d’une installation en un clic, et ses notes de version sont chargées dans la fenêtre sous forme de texte plutôt que de page intégrée.

Les deux apps Mac de Qoder sont désormais distinguées. L’IDE et l’app de bureau partagent un nom et une page de téléchargement mais paraissent sur des lignes de versions séparées ; chacune est maintenant suivie pour elle-même.

Les versions beta de WhatCable et de Yaak sont suivies sur leur propre canal. Une copie exécutant une beta n’avait aucune source et restait sur « Échec » ; la beta suivante lui est désormais proposée, avec des notes de version distinctes de celles des versions finales. Pour WhatCable, cela inclut aussi la version finale en laquelle une beta finit par passer — l’accepter fait basculer la copie sur le canal final.

Vérifier vos apps de l’App Store consomme une fraction du réseau qu’elle consommait. Chaque vérification redemandait la page produit de chaque app de l’App Store ; les pages sont désormais conservées une heure et la boutique est interrogée sur toutes vos apps en quelques requêtes au lieu d’une par app. Avec un intervalle de vérification de cinq minutes, cela représente environ un tiers de trafic en moins au total ; avec l’intervalle par défaut de six heures, les pages expirent toujours entre deux vérifications, l’économie y est donc moindre.

Revérifier une seule app ne recharge plus toutes les apps de l’App Store. Un simple « Vérifier à nouveau » jetait toutes les pages produit conservées, si bien que la vérification planifiée suivante les payait toutes ; il n’actualise désormais que l’app sur laquelle vous avez cliqué.

Vérifier les apps distribuées via GitHub coûte une fraction du réseau que cela coûtait. Chaque vérification retéléchargeait la description complète de chaque version même quand rien n’avait été publié ; GitHub est désormais interrogé pour savoir si la version a changé depuis la dernière fois, et rien n’est téléchargé si ce n’est pas le cas. Une fois par jour, chaque version est relue intégralement, de sorte qu’une version retirée est remarquée en moins d’un jour.

Les apps suivies sur un canal beta ou nightly de GitHub demandent maintenant une version au lieu d’une page entière. La version la plus récente est la réponse presque à chaque fois, et la page complète n’est récupérée que lors des tours où elle ne l’est pas.

La vérification des mises à jour de Vorssaint ne passe plus par une redirection. Son dépôt a été renommé, et suivre l’ancien nom faisait silencieusement basculer la requête sur la limite anonyme de GitHub ; la vérification s’adresse désormais directement au nouveau nom.

Sous le capot. L’artefact de version est désormais compilé, signé et notarisé sur un Mac hébergé par GitHub, avec une provenance de build que chacun peut vérifier, et le journal des requêtes distingue une réponse issue du cache d’une réponse venue du réseau.

Les journaux de requêtes que vous exportez ne contiennent plus votre nom de compte. Pour une app installée dans votre dossier personnel, chaque ligne indiquait le chemin complet ; elle affiche désormais ~, quelle que soit la façon dont vous sortez le journal.

L’onglet « Requêtes » indique désormais ce qu’il couvre et ce qu’il ne couvre pas. Il enregistre les requêtes que DuoUpdater effectue lui-même. Une page de notes de version charge ses propres images et polices, et les mises à jour de l’App Store et de Homebrew sont effectuées par des outils distincts : rien de tout cela n’y figure, et la fenêtre le dit maintenant au lieu de vous laisser le supposer.

« Copier l’URL » échappe désormais l’adresse qu’elle vous donne. Les chemins comportant une espace — ceux des téléchargements de Firefox, Thunderbird et Bartender, entre autres — étaient copiés tels quels : un navigateur le corrige, la ligne de commande non.

La ligne beta de CapCut ne signale plus une vérification en échec. Entre deux betas — une fois l’une passée en version finale et avant que la suivante n’ouvre — son éditeur ne publie rien sur ce canal. Cela apparaissait comme une ligne rouge et un « Réessayer » qui ne pouvait pas aboutir. La ligne n’a désormais simplement pas de réponse de cette source, jusqu’à l’arrivée de la beta suivante.

Audacity affiche désormais la marque indiquant avec quoi elle est conçue. Elle démarre par un petit lanceur qui passe la main au vrai programme placé à côté, et la marque était lue sur le lanceur, qui ne lie rien du tout.

Les notes de version de l’App Store arrivent maintenant dans votre langue. Elles étaient toujours récupérées dans la langue par défaut de la boutique, si bien qu’un Mac en chinois ou en japonais les lisait toujours en anglais.

Les mises à jour de DuoUpdater lui-même apparaissent maintenant à son nom dans la fenêtre « Réseau ». Sa vérification de version, ses notes de version et son téléchargement y figuraient avec une colonne d’app vide.

Sous le capot. Un identifiant présent dans le chemin d’une adresse web est désormais retiré avant l’enregistrement de la requête, comme l’était déjà celui d’une chaîne de requête.

La fenêtre « Download Traffic » s’appelle désormais « Réseau » et comporte un second onglet. « Téléchargements », c’est le relevé que vous aviez déjà : ce que chaque mise à jour a coûté en tant que fichier. « Requêtes » est nouveau : chaque requête que DuoUpdater effectue pour vous, son objet, l’app à laquelle elle se rattache et ce qu’elle a coûté, avec un champ de filtre pour interroger le journal plutôt que le faire défiler. Les chiffres du haut répondent à ce que vous avez filtré, pas au total de toujours.

Vérifier les mises à jour de Spotify ne consomme presque plus de réseau. Spotify ne publie aucun fichier de version, la vérification lit donc le numéro dans un installeur allégé de deux mégaoctets — et le téléchargeait en entier à chaque fois, jour et nuit. Elle demande maintenant si ce fichier a changé et ne le télécharge pas quand ce n’est pas le cas.

PDF Expert trouve désormais ses mises à jour et indique ce qui a changé. Il lisait une liste de versions que son éditeur n’alimente plus depuis 2022 : il se déclarait donc à jour quelle que soit la version installée. Il suit maintenant la liste utilisée par le programme de mise à jour de l’application elle-même, et affiche désormais aussi les notes des versions précédentes, et non plus seulement de la dernière.

Les préversions d’UTM reçoivent désormais leurs propres mises à jour, s’installent en un clic et affichent les notes correspondantes. Une copie en préversion était auparavant comparée au canal final et déclarée à jour sans autre explication ; elle suit maintenant sa propre lignée et revient au canal final dès qu’elle en reçoit la version finale.

Sous le capot. Les requêtes enregistrées ont rejoint le même stockage que le relevé de téléchargements, si bien que les deux comptes d’un même téléchargement ne peuvent plus diverger. Votre relevé existant est repris tel quel.

Quinze applications de plus sont surveillées, et toutes sauf une s’installent en un clic. AgentsView, AnythingLLM, Chatbox, ChatGPT Classic, DSH Desktop, FluidVoice, GitHub Copilot, Kun, Meetily, Microsoft 365 Copilot, OpenLogi, OpenSuperWhisper, Paseo, T3 Code — sur ses deux canaux, alpha et nightly — et Vorssaint. L’exception est ChatGPT Classic : la vérification est faite pour vous, mais l’app fournit un programme d’installation qui la met à jour lui-même ; cette mise à jour reste donc la vôtre à lancer.

Huit applications affichent désormais leurs notes de version dans DuoUpdater au lieu de vous renvoyer vers une page web. Xcode, Antigravity, Antigravity IDE, AnyDesk, AnythingLLM, Chatbox, Headlamp et Helium. Pour trois d’entre elles, il n’y avait nulle part où vous renvoyer : la page d’AnyDesk répond par un test anti-robot, les auteurs de Helium ne publient aucune page de notes, et Antigravity IDE n’avait aucun lien.

Les bêtas de Xcode disent ce qui a changé dans chaque bêta. La ligne proposait un numéro de version interne et un lien ; elle liste maintenant les notes d’Apple pour la bêta que vous utilisez et pour toutes les bêtas précédentes de cette même version.

Word, Excel, PowerPoint, Outlook et OneNote voient enfin que leur mise à jour est installée. Ces cinq applications continuaient à proposer de rouvrir un programme d’installation que vous aviez déjà terminé, sans jamais passer au redémarrage — attendre ou revérifier n’y changeait rien.

Une ligne en attente de redémarrage s’explique à nouveau, dans les deux fenêtres. Quand une application devançait ce que publie son éditeur tout en attendant un redémarrage, la ligne au-dessus du bouton décrivait tout autre chose ; pour les lignes en attente d’un redémarrage après « Tout mettre à jour », la fenêtre et le menu se contredisaient aussi.

Les étiquettes d’état n’écrasent plus le nom de l’application en russe. Quelques étiquettes empruntaient par ailleurs des formulations à des textes sans rapport, dans toutes les langues traduites.

Les notes de version apparaissent maintenant pour les applications dont l’éditeur date une version sans l’horodater. Ces publications ne laissaient auparavant aucune trace.

Une page de notes de version que nous refusons d’ouvrir en donne maintenant la raison. Elle restait blanche, ce qui ressemblait exactement à une application ne publiant aucune note.

Les notes de version Nightly de WeChat DevTools ne sont plus vides.

Sous le capot. Le traitement des versions et des dates de publication a été regroupé, de sorte qu’un numéro de build ne peut plus être lu comme une version commerciale, et la chronologie des publications n’invente plus une heure que l’éditeur n’a jamais donnée.

Les vérifications en échec sont désormais visibles dans la fenêtre. La fenêtre n’affichait rien pour une ligne dont la vérification avait échoué — ni pour celles que vous aviez ignorées, celles dont vous aviez passé la version, ni celles gérées par l’App Store, Toolbox ou TestFlight. Cela ressemblait exactement à « à jour ». Les deux fenêtres disent maintenant la même chose de la même application, et le bouton de nouvelle tentative existe des deux côtés.

« Vérifier à nouveau » interroge, sur n’importe quelle ligne, cette seule application. La liste des applications en cours d’exécution est relue au passage : c’est le moyen le plus rapide de corriger un point vert qui semble faux.

Passer une version et ignorer une application s’annulent maintenant depuis le menu contextuel de la fenêtre. Les deux lignes invitaient à faire un clic droit pour annuler, dans une fenêtre dont le menu ne proposait rien de tel.

La vérification en arrière-plan ne vous retire plus les notes de version que vous êtes en train de lire. La vérification horaire jetait toutes les notes déjà chargées, si bien qu’un volet ouvert repassait à l’indicateur de chargement. Seule une actualisation que vous demandez repart de zéro.

Les téléchargements interrompus sont vérifiés avant d’être déclarés complets. Un serveur qui renvoyait tout le fichier, comme un serveur qui s’arrêtait trop tôt, était cru sur parole ; l’ennui apparaissait une étape plus loin, sous la forme d’une installation à partir d’une archive abîmée. Les téléchargements derrière certains proxys, qui échouaient définitivement, aboutissent maintenant.

Mettre à jour une application ne relit plus toutes les applications de votre disque. Chaque clic effectuait deux balayages complets de vos applications, uniquement pour examiner celle que vous aviez désignée.

Les notes de version de Chrome ne peuvent plus se figer. Une simple refonte du blog de Google suffisait à les bloquer plusieurs minutes ; elles se chargent désormais rapidement, quelle que soit l’allure de la page.

Un programme d’installation déjà téléchargé n’est plus jeté puis récupéré à nouveau. Lorsqu’un éditeur écrivait la même version de deux façons (v1.2.3 et 1.2.3), le paquet en attente n’était pas reconnu, et « Relancer » pouvait attendre un remplacement déjà effectué.

Une installation administrateur qui échoue n’est plus prise pour une annulation de votre part. Aucune erreur n’était affichée, et l’application cessait discrètement de proposer la mise à jour en un clic jusqu’à ce que vous redemandiez les droits administrateur depuis le menu de sa ligne.

Le point vert « en cours d’exécution » repère maintenant toutes les applications. macOS n’annonce jamais l’ouverture ou la fermeture de certaines d’entre elles, et leur point restait faux jusqu’à ce qu’un événement sans rapport le rafraîchisse.

« Tout mettre à jour » ne clignote plus pendant une actualisation, et une application mise à jour en cours d’actualisation n’est plus ramenée à l’état où elle proposait la mise à jour déjà installée.

Si la vérification échoue au moment où vous appuyez sur Mettre à jour, cela vous est dit au lieu d’être classé comme « rien à faire ».

Sous le capot. Les dates de publication écrites dans des formats inhabituels sont lues correctement, le contrôle d’adresse des pages de notes de version couvre toutes les écritures équivalentes, et la tenue de registre courante ne touche plus au disque chaque fois qu’une application s’ouvre ou se ferme sur votre Mac.

La marque de Docker décrit désormais l’interface de Docker et non son service d’arrière-plan. La ligne indiquait « native » ; or Docker Desktop est une app Electron. Cette marque est lue dans le bundle de l’app, et le bundle de Docker n’est qu’une enveloppe : le programme qu’il désigne est un service d’arrière-plan écrit en Go, il n’embarque aucun framework, et l’app qui dessine réellement les fenêtres se trouve un niveau plus bas. Tout était lu correctement — simplement dans le mauvais fichier. DuoUpdater regarde maintenant dans l’app imbriquée, mais uniquement lorsque celle de l’extérieur n’apporte rien d’elle-même et qu’elle contient exactement une app de ce type capable de prouver avec quoi elle est construite ; un processus d’assistance livré à côté d’une vraie interface ne peut donc toujours pas prêter son identité à son hôte. Docker se lit comme Electron 42.5.0 et, sur les cent quarante-six apps de la liste de la machine où ceci a été écrit, c’est la seule ligne qui change.

Les notes de version de CleanShot X sont à nouveau lisibles — y compris celles de la 5.0. CleanShot a publié sa plus grosse mise à jour depuis des années et en a profité pour reconstruire sa page de notes : la date est passée au-dessus du numéro de version, deux niveaux sont apparus autour de lui, et une version de fonctionnalités glisse désormais une introduction et deux liens vidéo entre la version et sa liste de changements. La règle de lecture qu’utilisait DuoUpdater ne correspondait plus à rien de tout cela. Pire qu’un volet vide : il n’avait pas l’air vide. Les notes déjà enregistrées pour la version précédente restaient à l’écran sous le titre de la nouvelle — le volet affichait « 5.0 » au-dessus des changements de la 4.8.10, et rien nulle part ne le signalait.

Les notes enregistrées avant la publication d’une version sont désormais relues plutôt que crues indéfiniment. C’est l’autre moitié de la même histoire. DuoUpdater a su que la 5.0 existait six minutes avant que CleanShot n’en publie le contenu, a enregistré la page telle quelle et l’a classée sous 5.0 — et à partir de là, chaque vérification trouvait quelque chose d’enregistré et n’allait plus jamais voir. Les notes enregistrées sont maintenant confirmées auprès de l’éditeur une fois par session avant d’être tenues pour définitives : une version dont les notes arrivent en retard se complète d’elle-même à la visite suivante, au lieu de rester fausse.

Ce que vous ouvrez depuis la barre des menus s’ouvre maintenant au premier clic. Choisir « Nouveautés » sur une ligne — ou les Réglages, ou le journal des versions — ne faisait absolument rien la première fois, et ne fonctionnait qu’à partir du second clic. Rouvrir le menu ramenait chaque tentative au rang de « première », si bien que pour qui ouvre le menu, clique une fois et attend une fenêtre, cela n’a jamais fonctionné. Le premier clic dans le menu servait à passer DuoUpdater au premier plan, au lieu de faire ce qu’il visait. La fenêtre ouverte est en outre maintenue au premier plan : elle y était amenée puis repoussée dans le même instant, l’autre manière dont tout cela ressemblait à un clic sans effet.

Une app qui laisse son propre nom vide en reçoit désormais un quand même. Eudic (欧路词典) figurait dans la liste avec une icône, une version, et rien du tout à l’emplacement du nom. Son bundle déclare bien un nom d’affichage — et le laisse vide, parce que les vrais noms se trouvent dans les traductions de l’app — et DuoUpdater prenait cette réponse vide pour la réponse au lieu de poser la question suivante. Il se rabat maintenant sur l’autre nom de l’app, puis sur le nom du fichier de l’app, si bien qu’aucune ligne n’est plus sans nom. Une app sur cent cinquante était concernée ici ; l’important est que l’information était déjà là et qu’elle était ignorée.

Le redémarrage vous dit maintenant que l’app a refusé de quitter, au lieu de ressembler à un clic sans effet. Si une app a une fenêtre qui vous attend — une demande d’enregistrement, une feuille de connexion, un dialogue quelconque —, macOS ne la laissera pas quitter, et ce côté-ci n’y peut rien : c’est la fenêtre de l’app. DuoUpdater tournait auparavant pendant trente secondes puis remettait le même bouton sans explication, ce qui ressemble exactement à un bouton cassé — alors on appuie de nouveau. La ligne dit maintenant ce qui s’est passé et vous renvoie vers l’app pour vous occuper de cette fenêtre. Rien n’a été modifié et la nouvelle version est déjà installée, il ne reste donc vraiment que le redémarrage — et si vous quittez simplement l’app vous-même dans les dix minutes qui suivent, DuoUpdater s’en aperçoit et la relance dans la nouvelle version sans que vous ayez à cliquer.

Les notes de version de 欧路词典 correspondent de nouveau à une version, et non à seize ans de versions. L’app publie tout son historique — chaque version jusqu’à la 2.5.0 — à l’intérieur des notes de la version la plus récente, si bien que le volet de détail affichait le tout sous le titre « 26.9.0 » et qu’il fallait faire défiler une décennie pour trouver ce qui venait de changer. Chaque version a maintenant sa propre entrée dans la liste, comme pour toutes les autres apps.

La marque qui indique avec quoi une app est construite exige désormais une preuve pour Tauri, et non une ressemblance. Tauri ne laisse rien à trouver dans un bundle — ni framework, ni dossier à lui —, si bien que cette marque-là était déduite de la façon dont l’app est empaquetée, plus du fait qu’elle lie la vue web d’Apple. Longbridge correspond à tout cela et n’est pas du Tauri : elle dessine ses propres fenêtres avec le même moteur de rendu que Zed, et n’intègre une vue web que pour un coin de son interface. DuoUpdater lit maintenant l’empreinte propre de Tauri dans le binaire avant de l’affirmer ; une app est donc appelée Tauri lorsqu’elle en est une — et Longbridge se lit comme ce qu’elle est : une app Mac native.

CapCut ne passe plus au rouge parce que les serveurs de ByteDance ont eu une mauvaise demi-seconde. Le point d’accès auquel DuoUpdater demande la version de CapCut répond par un code de succès puis, environ une fois sur cinquante, par un objet d’erreur au lieu de la réponse — un dépassement de délai interne à l’infrastructure de ByteDance, environ 390 octets là où 436 kilooctets étaient attendus. Rien de ce côté ne permettait de distinguer cela d’un changement de forme de la réponse de CapCut, et la ligne indiquait donc que la vérification avait échoué — ce qui se lit comme « c’est cassé et quelqu’un doit le réparer » pour quelque chose qui se règle tout seul à l’essai suivant. Cette forme précise est maintenant reconnue pour ce qu’elle est : la requête est réessayée immédiatement, et elle n’est signalée comme un vrai problème que si elle persiste pendant cinq jours.

Chaque app de la liste dit désormais avec quoi elle est faite. La ligne d’une app de l’App Store a toujours porté la marque de la boutique, et toutes les autres se ressemblaient : une app Sparkle, une app Electron et une app native étaient impossibles à distinguer. Chaque nom porte maintenant la marque de la technologie elle-même — cliquez pour en voir le nom et une phrase, survolez pour l’infobulle : Electron, Tauri, Flutter, Qt, Java, Chromium, Mac Catalyst, une app iPhone sur Apple silicon ou une app Mac native — avec la version de l’environnement là où elle se lit comme un fait (Electron 42.4.1, Qt 6.2, le Chromium que l’app embarque, le Tauri avec lequel elle a été construite). Tout cela est lu dans le paquet lui-même — le framework que l’empaqueteur a dû livrer, l’environnement dont son lanceur a besoin, les bibliothèques que le binaire lie — c’est donc un fait sur ce qui est installé, et non une supposition tirée du nom. Quand un nom long ne laisse pas de place, le symbole s’efface plutôt que de renvoyer le nom à la ligne : la ligne appartient au nom. Tout cela se désactive dans Réglages → Général.

LibreOffice n’annonce plus un retour en arrière vers la version que vous avez déjà. Son index de téléchargement publie des versions en trois parties (26.8.0) alors que la copie installée en annonce quatre (26.8.0.3) ; compléter la partie manquante par un zéro faisait paraître la copie installée plus récente — la ligne affichait donc une note discrète « l’éditeur est en retard sur vous » à propos d’une app parfaitement à jour. Une source qui publie moins de parties que l’app n’en annonce est désormais lue comme décrivant la même version, et non une plus ancienne ; un vrai retour en arrière le dit toujours.

Un réglage ajouté par une mise à jour se signale désormais une fois. Une nouvelle préférence au milieu de la fenêtre des Réglages est une préférence que personne ne trouve. Après la mise à jour qui l’a ajoutée, l’engrenage de la barre des menus porte une pastille bleue, la page qui l’héberge en porte une dans la barre latérale, et le réglage lui-même en porte une jusqu’à ce que vous l’ayez regardé. Uniquement pour celles et ceux qui ont réellement fait la mise à jour : une installation neuve n’est pas accueillie par des pastilles sur des fonctions qui font simplement partie de l’app qu’elle vient de découvrir.

Les apps Electron ajoutées à la version précédente peuvent enfin être mises à jour d’un clic. 0.3.75 a appris à DuoUpdater à lire le fichier que ces apps portent en elles, et il le lisait bel et bien : il en tirait la nouvelle version, le téléchargement adapté à votre Mac, la somme de contrôle pour le vérifier — puis n’avait nulle part où envoyer tout cela. Le bouton d’installation n’apparaissait jamais, et duo install expliquait son refus par un motif qui n’était pas le vrai. Cette version raccorde le chemin d’installation. En pratique, vous ne verrez peut-être aucune différence : cette lecture se place derrière toutes les règles écrites à la main, elle ne parle donc que pour une app que rien d’autre ne couvre — et aujourd’hui, sur la machine où ceci a été compilé, il n’y en a aucune. Cela comptera pour l’app que vous installerez demain et pour laquelle personne n’a encore écrit de règle.

Un téléchargement qui vous ferait quitter une version native est désormais refusé. Apple Silicon peut encore exécuter des apps Intel par traduction : un téléchargement uniquement Intel passait donc le contrôle « est-ce que cela tourne sur ce Mac ? » et s’installait proprement — vous laissant avec une copie traduite d’une app qui tournait jusque-là nativement, en silence, et recommençant à chaque mise à jour suivante. Toute installation sur place compare maintenant ce que vous avez à ce qui est arrivé et refuse cet échange. Dans l’autre sens, ou d’une version universelle vers une version Apple Silicon, c’est normal et toujours autorisé.

Quand il ne peut pas prouver l’architecture d’un téléchargement, il décline au lieu de deviner. Certains éditeurs publient une version Apple Silicon à côté de leur téléchargement par défaut, et le seul moyen de savoir que le défaut est la version Intel est de remarquer que l’autre existe. Si cette seconde vérification ne revient pas proprement — le serveur de l’éditeur la refuse, la connexion tombe, ou les deux ne s’accordent pas sur la version — DuoUpdater ne traite plus ce silence comme une réponse. Il vous donne la version et ne propose pas d’installation : c’est le résultat honnête.

Une règle cassée ne peut plus disparaître du Diagnostic. Pour les apps couvertes à la fois par une règle écrite à la main et par la nouvelle lecture — la plupart, délibérément — un échec de la règle était annulé par la réussite de la lecture juste après, si bien qu’une app dont la règle était réellement cassée continuait de paraître saine. Les deux sont désormais enregistrés séparément. La nouvelle lecture signale aussi ses propres échecs pour la première fois : sur la machine où ceci a été compilé, trois apps pointaient vers des adresses qui renvoient « introuvable » depuis un certain temps, et rien ne l’avait dit à voix haute jusqu’ici.

Les lignes qui voient une mise à jour sans pouvoir l’installer proposent maintenant la même chose aux deux endroits. La barre des menus affichait un bouton « Ouvrir » qui ouvrait le Finder, tandis que la fenêtre n’affichait rien du tout pour la même ligne.

Les applications conçues avec Electron sont désormais reconnues sans que quiconque ait à les inscrire au préalable. Bon nombre d’applications Mac embarquent un petit fichier indiquant où se trouvent leurs mises à jour. Jusqu’ici, DuoUpdater ne connaissait que celles pour lesquelles une règle avait été écrite à la main : toutes les autres figuraient dans votre liste sans numéro de version, sans aucun moyen de vous signaler qu’une nouvelle version était parue. Il lit maintenant ce fichier directement, exactement comme il lit celui de Sparkle depuis toujours. Une application de ce type est donc prise en charge le jour où vous l’installez, et non le jour où quelqu’un s’en occupe.

Les applications qui disposaient déjà d’une règle écrite à la main ne changent pas. Le nouveau mode de lecture se place derrière elles : il ne peut que combler un vide, jamais reprendre la main sur ce qui fonctionnait déjà.

Deux détails déterminent si le téléchargement proposé est le bon, et tous deux ont été tranchés en examinant de vraies applications plutôt qu’en supposant. Certains éditeurs désignent une version Intel comme téléchargement « principal » alors même qu’ils publient une version Apple Silicon à côté ; d’autres donnent à la version Apple Silicon un nom de fichier impossible à distinguer de celui de la version Intel, si bien que le nom ne révèle rien. DuoUpdater choisit selon l’architecture, et lorsqu’il ne peut pas garantir qu’un téléchargement fonctionnera sur votre Mac, il vous indique la version sans proposer l’installation — plutôt que de vous remettre quelque chose qui s’installe parfaitement puis refuse de s’ouvrir.

Si vous utilisez la version bêta, la release candidate ou une version nightly d’une application, DuoUpdater surveillait discrètement la mauvaise branche. Il détermine votre branche en retrouvant votre build dans la liste des versions publiée par l’éditeur — mais une préversion conserve le plus souvent le même numéro de version publique que la version stable dont elle est issue, ce qui est le comportement normal d’une préversion. La correspondance tombait donc sur l’entrée stable. L’erreur était silencieuse : rien d’anormal n’apparaissait à l’écran, vous n’entendiez simplement plus parler du build suivant de votre propre branche, et les notes de version affichées appartenaient à la ligne stable. C’est en installant les vraies préversions de Supacode et de TypeWhisper et en observant le résultat que le problème est apparu ; toutes deux suivent désormais la branche sur laquelle elles se trouvent réellement.

La bêta de CapCut affichait une version que vous n’aviez pas. La ligne indiquait « 9.3.4545 → 9.4.0-beta6 » alors que CapCut lui-même, le Finder et tous les autres outils de mise à jour appelaient votre copie 9.4.0-beta5. Certaines applications inscrivent leur vraie version dans un champ différent de celui qu’utilisent la plupart, et DuoUpdater lisait, de votre côté de la flèche, celui qui paraissait le plus propre, et du côté de l’éditeur, le vrai. La mise à jour proposée était toujours la bonne — seule l’étiquette était fausse. Les deux moitiés de la ligne proviennent désormais du même endroit, pour CapCut comme pour les sept autres applications conçues ainsi.

MacWhisper, GitHub Copilot for Xcode, TypeWhisper et OpenUsage affichent maintenant leurs notes de version. Ces quatre applications avaient un panneau de notes vide : leurs flux de mise à jour n’en contiennent aucune, ce qui n’a été remarqué qu’en confrontant chacune à ce que l’éditeur publie réellement. DuoUpdater lit désormais la page de notes de version de MacWhisper, le fichier de changelog de Copilot et le site de changelog de TypeWhisper, et renvoie OpenUsage vers sa liste de versions.

Helium se met désormais à jour via son propre service, ce qui apporte son canal bêta et des téléchargements bien plus légers. Il était jusqu’ici suivi via la liste publique des versions, où seules les versions stables apparaissent — celles et ceux qui utilisaient la bêta d’Helium recevaient donc la stable. Son service publie aussi des correctifs différentiels : une mise à jour courante pèse environ 40 Mo au lieu d’un nouveau téléchargement de 124 Mo. Vérifié avec une version stable et une version bêta, et le téléchargement est contrôlé avec la clé de signature contenue dans votre copie installée avant tout remplacement.

Les versions bêta, développeur et nightly de Firefox et Thunderbird sont correctement suivies désormais — jusqu’à aujourd’hui, aucune de ces cinq voies de publication n’avait jamais signalé la moindre mise à jour. Elles étaient lues depuis le fichier de versions public de Mozilla, qui ne publie que la version affichée, et l’installation d’une bêta en retire le « b5 » : une bêta de Firefox s’appelle 155.0 pendant tout le cycle, la seule question posée était donc « 155.0b5 est-il plus récent que 155.0 ? », et la réponse est non. Nightly était pire — Mozilla en publie un chaque jour et ils s’appellent tous 157.0a1, si bien qu’un cycle de quatre semaines ne donnait exactement rien. DuoUpdater interroge maintenant le service de mise à jour de Mozilla lui-même, l’adresse qu’utilise l’updater intégré de Firefox et que l’application indique en son sein, et compare l’identifiant de build que les deux côtés portent. Vérifié avant publication contre les téléchargements réels des cinq voies : l’identifiant que ce service annonce est octet pour octet celui qui se trouve dans votre copie ; une bêta en retard d’un build affiche désormais sa mise à jour, et un nightly construit plus tôt le même jour aussi. Les versions stable et ESR n’ont jamais été concernées et restent inchangées. Une limite qu’il vaut mieux énoncer clairement : ce service ne publie aucune date de publication, donc pour ces cinq voies le journal des versions enregistre toujours le moment où DuoUpdater a vu un build pour la première fois, et non celui où Mozilla l’a publié.

Wispr Flow, AionUi et Devin se mettent à jour en un clic désormais, au lieu de simplement signaler qu’une nouvelle version existe. Les trois voyaient déjà leurs mises à jour ; aucun ne pouvait en appliquer une, au motif annoncé que l’éditeur publie des versions distinctes pour Intel et Apple Silicon et que DuoUpdater n’avait aucun moyen de choisir. Mesurée plutôt que supposée, cette raison ne tenait pas : les points d’accès dont ces trois-là sont lus sont déjà ceux d’Apple Silicon, et DuoUpdater ne fonctionne que sur Apple Silicon — il n’y a jamais eu de choix à faire. Chaque téléchargement a été récupéré et vérifié avant d’être branché : la bonne application à l’intérieur, signée par le même développeur que votre copie, notarisée par Apple, et celui d’AionUi confronté à la somme de contrôle que son propre manifeste publie. Chacun a ensuite été réellement installé par-dessus une copie plus ancienne, et est revenu sur la nouvelle version.

Grok Bot est désormais suivi — nouvelles versions et mises à jour en un clic. L’application de bureau de xAI est compilée et signée par Anysphere, l’entreprise derrière Cursor, et elle se met à jour via le service de publication de Cursor. C’est précisément pourquoi aucune des voies habituelles ne répondait pour elle : pas de flux Sparkle, pas de fiche sur l’App Store, pas de dépôt public de versions, et un cask Homebrew qui renvoie la mise à jour à l’application elle-même. DuoUpdater lit à la place le point d’accès de version du fournisseur. Deux autres points d’accès existaient et ont tous deux été écartés pour des raisons précises : celui qui se cache derrière le bouton de téléchargement sur x.ai ne publie aucun numéro de version, et celui qu’utilise le propre updater de l’application répond par un corps vide dès que vous êtes à jour — un silence impossible à distinguer d’un point d’accès en panne. Le téléchargement a été vérifié avant d’être branché : l’image disque contient la bonne application, signée par le même développeur que votre copie et notariée par Apple. Une chose qu’il n’offre délibérément pas : les notes de version. xAI n’en publie aucune pour cette application, et le seul changelog qu’elle publie concerne un autre produit.

Comet et Msty Studio se mettent aussi à jour en un clic, et une nouvelle vérification surveille les applications qui le pourraient et ne le font pas. C’étaient les deux dernières du lot à voir leurs mises à jour sans pouvoir les appliquer, et aucune n’a eu besoin de quoi que ce soit de nouveau — seulement d’un examen plus attentif de ce que l’éditeur envoie réellement. Le lien de téléchargement de Comet est signé et expire au bout d’une heure ; le bouton de mise à jour pointe donc vers la passerelle de Perplexity elle-même, et le lien est fabriqué au moment où vous cliquez plutôt que des heures plus tôt, lors de la vérification. Msty publie quatre téléchargements dans un seul fichier, la version Intel en tête, et l’empreinte servant à vérifier le téléchargement était prise sur cette première entrée ; elle est maintenant liée à la version Apple Silicon réellement récupérée — ce qui fait aussi qu’une version publiée entre la vérification et le clic est le plus souvent détectée au lieu d’être installée en silence. Les deux ont été téléchargées et passées par les vraies barrières d’installation avant publication. La leçon la plus large ne concerne ni l’une ni l’autre : rien dans DuoUpdater ne pouvait remarquer qu’une application restait en simple détection pour une raison devenue fausse. Le balayage nocturne des recettes le signale désormais lorsqu’une application seulement surveillée nous tend déjà un installeur.

QQ音乐 est suivi maintenant — nouvelles versions, mises à jour en un clic et ses notes de version dans la fenêtre. Aucune des voies habituelles ne fonctionnait pour lui. Il ne publie aucun flux Sparkle ni même le framework Sparkle ; son cask Homebrew renvoie la mise à jour à l’application elle-même ; et le point d’accès de mise à jour indiqué dans son propre binaire répond 200 avec un corps vide à toutes les requêtes possibles — un silence impossible à distinguer d’un point d’accès en panne, il a donc été écarté. DuoUpdater lit à la place le fichier de données sur lequel repose la page de téléchargement de l’éditeur : cette page est livrée vide et se remplit à partir de ce fichier, qui est aussi le seul endroit où les notes de version existent — il n’y a ni blog, ni flux appcast, ni page par version. Les notes sont donc lues directement dedans et affichées dans la propre fenêtre de DuoUpdater, et la mise à jour installe l’image disque notariée nommée dans cette même réponse. Un piège à signaler : ce fichier contient encore une seconde entrée Mac, vieille de six ans, à côté de l’actuelle ; les deux règles s’appuient donc sur le nom de fichier versionné du téléchargement Mac plutôt que sur le mot « Mac ». Et une limite qu’il vaut mieux dire clairement : le fichier publie la version affichée, jamais le numéro de build sous-jacent, si bien qu’une republication qui garde le même nom de version est invisible ici. DuoUpdater ne peut pas inventer une mise à jour qui n’existe pas — il ne voit simplement pas ce cas précis.

TimeMachineEditor est suivi maintenant — nouvelles versions et mises à jour en un clic. Aucune des voies habituelles ne fonctionnait pour lui : pas de flux Sparkle (l’application ne porte ni adresse de flux ni le framework qui s’en servirait), pas de fiche sur l’App Store, pas de dépôt public de versions, et un cask Homebrew qui renvoie la mise à jour à l’application elle-même. Ce qu’il a en revanche, c’est un petit site du fournisseur dont l’unique lien de téléchargement indique la version dans son propre texte — la même page, lue de la même façon, sur laquelle s’appuie le propre contrôle de version de Homebrew ; c’est donc la source prévue par l’éditeur, et non une supposition. La mise à jour s’installe comme le propre paquet d’installation du fournisseur plutôt que par un simple échange d’application, et c’est délibéré : le téléchargement place aussi un planificateur en arrière-plan, un outil en ligne de commande et un démon de lancement en dehors de l’application elle-même, donc remplacer seulement l’application laisserait une copie neuve à côté d’un planificateur obsolète, sans rien pour remarquer le décalage.

Little Snitch est suivi maintenant, sur ses deux lignes de publication, stable et nightly. Object Development publie un fichier de version sur lequel son propre programme de mise à jour se rabat — le même que lit Homebrew — et DuoUpdater le lit directement, parce que Little Snitch ne publie pas de flux Sparkle et que son cask renvoie la mise à jour à l’application. Les deux versions partagent une seule identité, ce qui les rend normalement impossibles à distinguer ; celle-ci se trahit dans la chaîne de version, où un build nightly écrit le mot en toutes lettres (« 6.5 nightly (7301) ») tandis que le build stable se lit comme un simple « 6.4.1 ». Il vaut la peine de préciser ce que cela ne fait délibérément pas : cela n’installera pas la mise à jour à votre place. Little Snitch fait tourner une extension système et un service en arrière-plan privilégié aux côtés de l’application, et personne n’a vérifié sur une vraie machine si le simple échange de l’application les laisse intacts — donc DuoUpdater vous dit qu’une nouvelle version est sortie et vous envoie vers le téléchargement du fournisseur lui-même, plutôt que de deviner avec un filtre réseau.

Carbon Copy Cloner est suivi maintenant, et il n’essaiera pas de vous faire passer d’une version majeure à l’autre. Bombich maintient trois générations vivantes en même temps — CCC 5, 6 et 7 — qui déclarent toutes la même identité au système, ce qui rend « y a-t-il quelque chose de plus récent ? » une question plus piégeuse qu’il n’y paraît : 7.1.6 se classe réellement au-dessus de 6.1.13, mais passer de l’une à l’autre est un achat séparé, et CCC 7 exige un macOS plus récent que celui qu’une machine sous CCC 5 fait peut-être encore tourner. Répondre au seul numéro de version aurait dit à chaque propriétaire de CCC 5 et 6 qu’une mise à jour gratuite l’attendait, pour toujours, et cela aurait été faux à chaque fois. DuoUpdater lit donc chaque génération à sa propre adresse et n’offre jamais que la prochaine version au sein de la génération que vous possédez réellement. Les versions bêta sont récupérées aussi, pour qui a activé cette option dans CCC. Détection seulement pour l’instant — CCC installe un assistant privilégié aux côtés de l’application, ce qui engage bien plus que les mises à jour en un clic déjà proposées ici — et la raison pour laquelle rien ne pouvait voir ces mises à jour auparavant vaut la peine d’être notée : le propre flux de mise à jour de l’application répond avec succès à chaque requête, avec une page entièrement vide.

Une mise à jour que votre Mac ne peut pas réellement exécuter n’est plus téléchargée puis installée. Chaque bundle d’application indique le plus ancien macOS sur lequel il se lancera, et certains fournisseurs indiquent aussi le plus récent — « ce build n’est pas pour un OS aussi récent », ce qui est la façon dont une application qui n’a pas encore rattrapé macOS 27 le dit. DuoUpdater ne lisait ni l’un ni l’autre. Pour les applications suivies via un flux Sparkle, le plancher était déjà respecté, mais c’est une minorité : parmi les applications d’un Mac typique, celles lues depuis le propre point de terminaison d’un fournisseur ou depuis les releases GitHub forment la plus grande moitié, et une release GitHub ne publie nulle part une exigence de macOS. Donc une application déjà passée à un macOS plus récent que le vôtre pouvait vous être proposée, téléchargée en entier, mise en place — puis refuser de s’ouvrir. DuoUpdater lit maintenant l’exigence directement dans l’application téléchargée, juste à côté du contrôle déjà existant qu’elle est bien compilée pour votre processeur, et refuse l’échange plutôt que de remplacer une copie qui fonctionne par une qui ne démarrera pas. La borne supérieure indiquée par le fournisseur est respectée elle aussi, là où un flux en publie une, donc un build que le développeur a marqué comme n’étant pas pour votre macOS n’est tout simplement pas proposé. Trois limites qui valent la peine d’être dites clairement. Lire l’exigence dans le téléchargement signifie que le téléchargement a déjà eu lieu — cela évite une installation cassée, pas le trafic, parce que pour la plupart des applications il n’y a nulle part de plus tôt où demander. Une application dont votre Mac ne peut pas exécuter la version la plus récente continuera de montrer cette mise à jour et de refuser de l’installer ; le refus nomme désormais la version de macOS qu’elle exige, mais DuoUpdater ne se souvient pas encore de la réponse pour arrêter de la proposer. Et le contrôle couvre les routes où DuoUpdater échange lui-même le bundle de l’application — un paquet d’installation remet le fichier à macOS, qui applique les exigences propres au paquet, et Homebrew et l’App Store choisissent leurs propres builds ; les applications venues de la section iPhone et iPad de l’App Store sont délibérément ignorées, puisque la version qu’elles indiquent est une version iOS, et la comparer à macOS serait pire que de ne pas vérifier. Une chose qu’il ne dit pas encore à voix haute : là où un développeur a marqué un build comme n’étant pas pour votre macOS, cette mise à jour n’est tout simplement pas proposée, et l’application se lit comme à jour plutôt que d’expliquer pourquoi. Pour un Mac plus ancien, cela se résout de soi-même le jour où vous mettez macOS à jour. Pour un Mac trop récent, non, et une meilleure réponse que le silence y est due.

百度网盘 est désormais suivi — nouvelles versions, mises à jour en un clic et notes de version dans la fenêtre. Aucune des voies habituelles n’était ouverte. Il ne publie pas de flux Sparkle ; le cask Homebrew ne peut pas répondre pour une copie installée à la main ; et le manifeste de mise à jour indiqué par son propre bundle est hors service — ce fichier, son jumeau arm64 et le répertoire qui les contient répondent tous 404. DuoUpdater lit donc le point d’accès sur lequel repose la page de téléchargement de l’éditeur, et installe l’image disque arm64 notariée indiquée dans cette même réponse. Les notes de version arrivent par le même chemin : la page « 版本更新 » a un onglet Mac版, mais elle est livrée vide et se remplit depuis une API ; DuoUpdater lit donc directement cette API et affiche les quarante dernières versions dans sa propre fenêtre. Une limite qu’il vaut mieux dire clairement : ce flux publie la version affichée, jamais le numéro de build sous-jacent, si bien qu’une republication qui garde le même nom de version est invisible ici. DuoUpdater ne peut pas inventer une mise à jour qui n’existe pas — il ne voit simplement pas ce cas précis.

Une vérification qui a échoué le dit désormais, au lieu d’afficher un tiret vide. Pour une app dont seul le point d’accès de l’éditeur peut donner la version, il n’existait qu’une façon de dire « pas de réponse » : un tiret vide — exactement ce qu’affiche une app que rien ne couvre. Un point d’accès d’éditeur qui expirait, ou qui changeait d’adresse, se lisait donc exactement comme « DuoUpdater ne suit pas cette app » — un verdict d’apparence définitive, sans bouton Réessayer et sans rien dans le décompte « apps n’ont pas pu être vérifiées ». Ces cas sont désormais traités pour ce qu’ils sont, des vérifications échouées : un bouton Réessayer, une place dans le décompte et la raison indiquée. Pas tous, délibérément : une situation à laquelle votre Mac ne peut tout simplement rien — aucune recette pour la piste de publication que vous suivez, un point d’accès qui exige une identité que cette machine n’a pas — reste le tiret discret qu’elle a toujours été, et une vérification en échec trois tours de suite quitte toujours la bannière au lieu d’y rester épinglée indéfiniment. Une app installée par JetBrains Toolbox garde aussi son bouton « ouvrir Toolbox » quand la lecture de sa version échoue, puisque ouvrir Toolbox était la réponse dans tous les cas.

Le rappel « relancer pour l’appliquer » disparaît maintenant une fois que vous avez relancé. Quand le programme de mise à jour d’une app avait téléchargé un build en arrière-plan, DuoUpdater vous le signalait et proposait un bouton Relancer dans la notification. Le bouton fonctionnait — l’app redémarrait sur le nouveau build et affichait « 1.0 est maintenant en cours d’exécution. » — mais le rappel qu’elle remplaçait restait en dessous dans le Centre de notifications, à vous demander encore de relancer ce que vous veniez de relancer. DuoUpdater attendait que le rappel cesse d’être pertinent, et le seul moment où il vérifiait était justement celui qui avait déjà été pris en compte. Il retire désormais le rappel dès qu’aucune relance n’est en attente, ce qui efface aussi celui laissé par une app qui a appliqué sa propre mise à jour pendant que DuoUpdater ne tournait pas.

Les apps qui publient plusieurs builds sous un même numéro de version sont désormais traitées correctement — partout. Une app Mac porte deux chaînes de version : celle qu’elle vous montre (« 1.0 ») et un numéro de build, qui, lui, augmente réellement. La plupart des apps font avancer les deux. Certaines ne font avancer que le build : Amp a publié dix builds en une seule journée, tous appelés 1.0 ; Surge a publié quatre versions distinctes sous le numéro 6.9.0 ; les builds de préversion de JetBrains font de même. Pour décider « est-ce que ça a changé ? », DuoUpdater comparait la version affichée à une douzaine d’endroits, et pour ces apps cette comparaison ne pouvait répondre que « non » — ou, là où la question était « est-ce la même ? », « oui » — quoi qu’il se soit réellement passé. Voici ce que cela a cassé. C’est une seule et même erreur, découverte parce qu’Amp l’a rendue visible.

Relancer ne semble plus bloqué pendant trois minutes avant de signaler un échec qui n’a pas eu lieu. Cliquer sur Relancer pour une app dont le programme de mise à jour avait un build en attente faisait tourner l’indicateur d’activité pendant trois minutes, puis annonçait un échec — alors que la mise à jour avait en réalité été appliquée en une ou deux secondes et que l’app avait déjà rouvert sur le nouveau build. DuoUpdater attendait de la version affichée un changement qui n’allait jamais venir. Mesuré sur Amp : 189 secondes d’indicateur d’activité pour un échange qui a pris moins d’une seconde. L’opération se termine désormais en bien moins d’une seconde, et un véritable échec est toujours signalé comme tel.

Relancer ne vous propose plus un build déjà dépassé. Quand le programme de mise à jour d’une app avait téléchargé un build et que le développeur en avait publié un autre depuis, DuoUpdater proposait quand même Relancer — vous relanciez et vous retrouviez aussitôt avec un build de retard, exactement ce que cette vérification devait empêcher. Ces lignes proposent désormais Mettre à jour à la place, qui récupère le build actuel.

Ignorer une version ne réduit plus une app au silence pour toujours. C’est le changement à retenir. « Ignorer cette version » sert à refuser une version et à laisser passer la suivante. Seule la version affichée était enregistrée : pour une app qui garde le même nom de version d’un build à l’autre, ignorer une seule fois revenait à refuser toutes les versions futures — définitivement, même après un redémarrage, sans rien à l’écran pour signaler que l’app était devenue muette. Ignorer une version enregistre désormais le build refusé. Une conséquence de la correction : une version ignorée par une version antérieure de DuoUpdater vous est proposée une fois de plus, car l’ancien enregistrement ne dit pas de quel build il s’agissait. L’ignorer à nouveau l’enregistre correctement.

Restauration revient pour les mises à jour qui semblaient n’avoir rien changé. L’établi masque une restauration qui ne ferait rien — or, pour ces apps, toute restauration semblait ne rien faire : la ligne disparaissait donc après une vraie mise à jour, alors qu’une sauvegarde complète restait sur le disque sans aucun moyen d’y accéder.

Le rappel de relance est de nouveau annoncé une fois par build, et survit à la publication d’un autre build par le développeur. 0.3.69 avait remplacé un rappel répété toutes les cinq minutes par un rappel émis une seule fois par build préparé — mais il identifiait le build par son nom, si bien que pour ces apps il annonçait le premier puis restait muet pour tous les suivants. C’est corrigé. Par ailleurs : si une app refuse de quitter parce qu’elle a du travail non enregistré, DuoUpdater garde une note pour la rouvrir une fois que vous avez répondu. Cette note était jetée si le développeur publiait un autre build pendant que vous décidiez, et l’app restait fermée après l’échange sans rien pour la rouvrir. Elle suit désormais le nouveau build.

Un échec de mise à jour de l’App Store n’est plus enregistré discrètement comme un succès, et un paquet d’installation téléchargé n’est plus pris pour celui actuellement proposé quand il s’agit d’un build plus ancien. Les deux problèmes venaient de la même comparaison. L’historique des versions comptait aussi dix builds d’une app comme une seule version ; il les compte désormais séparément, mais l’historique déjà enregistré ne peut pas être reconstitué.

La ligne indique elle-même quel build une relance appliquera. Elle affichait « 1.0 → 1.0 » — une ligne qui ne montre aucune différence. Elle affiche désormais « 1.0 (129) → 1.0 (130) », et seulement quand c’est le build qui a changé ; lorsque les noms de version diffèrent déjà, la ligne ne change pas. La même correction s’applique aux info-bulles de Relancer, à la notification, à la note expliquant pourquoi une installation a été reportée, et au refus de duo install.

微信输入法 et 豆包输入法 peuvent de nouveau être mises à jour en un clic — et de la même façon qu’elles se mettent à jour elles-mêmes. La mise à jour en un clic des méthodes de saisie avait été retirée en 0.3.25, le jour même de sa sortie, après la disparition des réglages de méthode de saisie d’un utilisateur. Le problème tenait à la façon d’installer : elle remplaçait l’app entière, comme le fait un installeur lors d’une première installation. Une méthode de saisie est enregistrée auprès de macOS par l’emplacement de son app, et ces deux apps se mettent à jour sans toucher à cet emplacement — elles conservent l’app et en remplacent le contenu. DuoUpdater fait désormais de même : l’app enregistrée reste la même app après la mise à jour, et un échec, à quelque étape que ce soit, laisse la copie que vous utilisiez exactement là où elle était. Ni l’une ni l’autre ne vous demande plus votre mot de passe, non plus.

Avant la mise à jour de l’une ou l’autre, tout ce qu’elle a appris est d’abord copié. Votre dictionnaire, vos réglages et l’état de votre compte ne se trouvent pas dans l’app, donc la copie de restauration que DuoUpdater conservait déjà ne les couvrait pas. Ils sont désormais sauvegardés en instantané avant chaque mise à jour de méthode de saisie, puis remis en place avec la restauration, et la copie ne coûte presque rien — les 578 Mo de l’une d’elles prennent un dixième de seconde et quasiment aucun espace disque. C’est un filet de sécurité, pas une réparation : ce qu’une app décide de faire de vos données au démarrage suivant relève de son propre code, et rien ne peut s’interposer. Mais désormais, il y a quelque chose auquel revenir.

Une mise à jour ne retire plus discrètement à une app sa capacité à se mettre à jour elle-même. Quand DuoUpdater avait besoin d’un administrateur pour remplacer une app, il rétablissait le propriétaire de l’app mais pas les permissions avec lesquelles elle avait été installée — or un téléchargement se décompresse normalement avec des permissions plus restreintes que celles que définit un installeur. Pour ces deux méthodes de saisie, c’est toute la différence entre un programme de mise à jour capable de mener à bien sa prochaine mise à jour et un programme incapable de faire le ménage derrière lui. Les permissions d’origine d’une app sont désormais reportées sur la copie qui la remplace.

DuoUpdater cesse de vous demander de relancer la même app toutes les cinq minutes. Une app qui se met à jour elle-même dépose la nouvelle version sur le disque et attend que vous la quittiez. DuoUpdater le remarquait à chaque vérification et publiait un rappel à chaque fois, si bien qu’un build que vous aviez décidé de ne pas encore relancer continuait de vous harceler tant que vous le laissiez en attente. Chaque build n’est désormais annoncé qu’une fois : relancez-le, ignorez-le, ou ignorez l’app, et il ne se manifeste plus ; le build suivant s’annonce normalement.

Une app en attente de relance compte comme une mise à jour, et une app ignorée ne compte plus du tout. Une nouvelle version déjà présente sur le disque est une mise à jour — simplement téléchargée en avance — elle est donc désormais comptée dans la pastille et dans la ligne « N mises à jour disponibles », au lieu de figurer dans un décompte séparé à côté. Les apps ignorées ont suivi le chemin inverse : une app que vous aviez ignorée pouvait allumer la pastille alors que sa ligne n’affichait qu’une étiquette grisée « Ignoré » et aucun bouton, si bien que le chiffre désignait quelque chose sur quoi vous ne pouviez pas agir. Ignorer une app et ignorer une version ont désormais le même sens sur les trois surfaces — le rappel, la pastille et la liste.

搜狗输入法 est désormais suivi — en interrogeant son propre programme de mise à jour plutôt qu’en lisant son site web. La page de journal des modifications de Sogou publie des numéros de version à trois segments alors que la copie installée en porte quatre : comparer avec elle aurait obligé à tronquer d’abord la vraie version. Son propre contrôle de mise à jour, lui, répond avec la numérotation du bundle. DuoUpdater interroge ce point d’accès comme le fait l’app et en extrait la version, avec ses quatre segments, si bien qu’une republication qui ne change que le dernier est visible. Il s’agit ici de détection uniquement : le programme de mise à jour de Sogou fait bien plus que remplacer l’app — il réenregistre un générateur QuickLook, déplace vos données vers un nouvel emplacement et force la méthode de saisie à quitter — la mise à jour elle-même lui est donc laissée. Une chose à savoir, et c’est le fait de Sogou, pas le nôtre : leur point d’accès répond en fonction de la version de macOS qui l’interroge, et un Mac sous macOS 28 qui pose la question pour son propre compte reçoit un build de 2023. DuoUpdater ne pose pas la question pour le compte de votre Mac, donc la version affichée est la version actuelle sur tous les Mac.

Les notes de version qu’une correction ultérieure aurait extraites correctement sont désormais relues, au lieu de rester fausses pour de bon. Les notes sont mises en cache par version, en partant du principe que les notes d’une version publiée ne changent jamais. C’est vrai des notes, mais pas de ce que DuoUpdater parvient à en extraire : une app dont les notes sortaient brouillées le restait pour cette version, quel que soit le nombre de corrections d’analyse publiées ensuite. Chaque entrée du cache enregistre désormais la génération de la logique d’extraction qui l’a écrite, et une entrée écrite par une génération plus ancienne est récupérée de nouveau. Les deux caches le font — journaux des modifications des apps et notes des formules Homebrew.

Une vérification qui échoue sur le CDN d’un tiers est retentée une fois avant d’être considérée comme cassée. 502, 503 et 504 signifient tous qu’un intermédiaire n’a pas pu joindre le serveur situé derrière lui : la requête n’est jamais arrivée, et la même requête un instant plus tard aboutit en général. C’est exactement ce qui a fait échouer la vérification de Headlamp — GitHub a répondu 504, sans le moindre en-tête de limite de requêtes. Ces trois codes ont désormais droit à une nouvelle tentative, après huit dixièmes de seconde. Seulement ces trois, délibérément : un 500 signifie que le serveur lui-même échoue, et répéter la requête ne fait le plus souvent que reproduire l’échec ; quant à réessayer après une limite de requêtes, cela consomme le quota même dont elle se plaint.

Les notes de version d’une formule Homebrew suivent la version à laquelle elles appartiennent. Les notes étaient mémorisées par formule et jamais par version : une fois les notes d’une formule chargées, chaque consultation ultérieure affichait celles de cette première version pendant tout le reste de la session — y compris après l’apparition d’une version plus récente. Leur lecture occupait aussi la file d’attente dont dépendait le reste de la liste des formules, si bien qu’un brew info lent pouvait bloquer la liste autour de lui.

Faites un clic droit sur une app dans la barre latérale de l’établi pour l’ouvrir. Le même Ouvrir que proposent depuis toujours les lignes de la barre des menus, dans la fenêtre où vous en aurez le plus probablement besoin.

Supprimer un installeur téléchargé efface aussi l’erreur qu’il avait laissée. Supprimer un paquet préparé remettait déjà la ligne sur Mettre à jour, mais un échec en rouge issu de la tentative que vous veniez d’annuler y restait affiché — et rien ne l’aurait jamais effacé, puisqu’une erreur n’est retirée qu’une fois la ligne à jour, ce qui n’arrive jamais à une ligne qui propose encore une mise à jour. Elle disparaît désormais avec le téléchargement.

duo, le compagnon optionnel en ligne de commande, ne se décrit plus de manière inexacte. --timeout a disparu — il était accepté, documenté, et lu par rien du tout. --budget est documenté pour la première fois, et le seul message qui le mentionne indique désormais un vrai nombre de minutes au lieu de toujours « 15 ». --max-calls annonçait une valeur par défaut de 20 alors qu’elle est de 6. Une option numérique qui reçoit autre chose qu’un nombre provoque désormais une erreur : duo verify --max-concurrency 1x était auparavant ignoré, et le balayage tournait avec la valeur par défaut de quatre — l’inverse de ce que veut quelqu’un qui ralentit volontairement un balayage. Et duo verify compte les requêtes qu’il a réellement envoyées : un flux qui répond 502 puis réussit à la nouvelle tentative n’affiche plus un ok impeccable alors qu’il a discrètement été interrogé deux fois. -h fonctionne partout où --help fonctionne.

Quatre apps de plus sont suivies, plus deux canaux de publication, et chacune se met à jour sur place. CapCut, Canva, et WorkBuddy sur les deux sites qui le distribuent — le site international et le site chinois suivent des calendriers de publication indépendants, si bien qu’une installation ne se voit jamais proposer que la version et les notes de son propre site. Termius et VSCodium gagnent leurs canaux Bêta et Insiders, en plus des builds stables déjà couverts. La deuxième piste de CapCut est la plus délicate : elle se choisit avec un commutateur dans CapCut même et n’apparaît nulle part dans le numéro de version ; la piste que vous suivez est donc lue sur la copie présente sur le disque, au lieu d’être devinée d’après le build que vous exécutez à ce moment-là. Bon à savoir si vous cochez cette case : DuoUpdater vous proposera la bêta la plus récente dès qu’elle existe, parfois avant que le déploiement progressif de CapCut ne vous l’ait apportée.

Les canaux de préversion d’Android Studio ne vous proposent plus un build plus ancien que le vôtre. Google liste ses versions dans l’ordre de publication plutôt que par numéro de version, et DuoUpdater parcourait cette liste trois fois séparément — une fois pour la version, une fois pour la date, une fois pour le téléchargement — si bien qu’une release candidate publiée après une Canary plus récente pouvait fournir la version d’une entrée et le fichier d’une autre. Le 26 août, le canal Canary a répondu 2026.1.4 RC 2 alors que 2026.2.1 Canary 2 était déjà sortie. Ces trois réponses doivent désormais provenir de la même entrée.

Une version republiée n’installe plus la copie qu’elle devait remplacer. Quand un projet recompile une version sans changer son numéro, les deux fichiers restent sous le même tag — KeePassXC publie KeePassXC-2.7.11-1-arm64.dmg à côté de l’original KeePassXC-2.7.11-arm64.dmg — et DuoUpdater prenait celui qui apparaissait en premier dans la liste. Cet ordre est alphabétique : il a placé la recompilation en premier cette fois-ci, mais l’aurait placée en dernier la fois suivante. Rien de tout cela n’était visible : la version affichée sur la ligne était correcte, seul le fichier derrière elle était le mauvais. Le bon fichier est désormais choisi d’après ce qu’indique son nom.

Les builds nightly et snapshot sont reconnus comme les préversions qu’ils sont. Le nightly de VLC, le snapshot de KeePassXC et Freelens nightly s’installent tous sous le nom et l’identifiant de bundle de l’app stable, si bien que leur chaîne de version est le seul indice qui les trahit — et elle n’était pas lue. Ils étaient comptés comme des installations stables, et c’est ainsi qu’un nightly se voyait proposer une version ordinaire pour s’écraser lui-même. Le nightly de DB Browser for SQLite est identifié d’après le nom de fichier de l’app pour la même raison, et là le problème était bien réel mais caché : sa version figée se classe au-dessus de la version stable actuelle seulement jusqu’à ce que la stable la rattrape ; à partir de là, chaque installation nightly se serait vu discrètement proposer un build stable.

Relancer une app indique ce qui s’est réellement passé. Quelques apps embarquent une seconde app dans leur propre bundle — Surge y range son Tableau de bord — et quand seule cette app interne avait besoin de redémarrer, DuoUpdater annonçait que l’app principale avait été relancée alors qu’elle ne l’avait pas été. Il indique désormais le résultat propre à l’app interne, et n’affiche plus de notification de relance pour une relance qui n’a jamais eu lieu.

Une mise à jour déjà téléchargée le signale, et peut être abandonnée. Une ligne contenant un paquet d’installation entièrement téléchargé n’affichait qu’un bouton bleu Installer — rien n’indiquait que le téléchargement était déjà terminé, ni que le bouton rouvre l’installeur au lieu de recommencer la mise à jour, et il n’y avait aucun moyen de changer d’avis. C’est désormais indiqué sur la ligne elle-même plutôt que caché dans une info-bulle, et Supprimer le programme d’installation téléchargé, dans le menu contextuel de la ligne, supprime le téléchargement et remet la ligne sur Mettre à jour. Supprimer un paquet pendant qu’une installation de la même app était déjà en cours pouvait aussi supprimer un paquet qui venait de finir de se télécharger ; ce n’est plus possible.

Les boutons de notes de version qui pointaient vers des pages retirées ouvrent de nouveau des pages existantes. Microsoft a renommé les pages de notes de version d’Edge pour les entreprises et Termius a déplacé son journal des modifications : trois canaux d’Edge et Termius vous envoyaient donc vers une page qui n’existait plus. Rien n’avait jamais vérifié que ces pages existaient encore, et c’est pourquoi elles pouvaient se périmer indéfiniment pendant que tout le reste semblait en bon état — elles sont désormais vérifiées à intervalles réguliers. Le canal Dev d’Edge n’a plus aucun bouton : Microsoft a cessé d’en publier les notes, et toutes les pages qui existent encore appartiennent à une autre ligne de publication.

Raycast est suivi jusqu’à sa version 2, et uniquement sur les Mac capables de l’exécuter. Raycast 2 exige macOS Tahoe et Apple silicon. Un Mac qui ne remplit pas ces conditions reste sur la piste de la version 1 et n’est plus averti d’une version qu’il n’aurait jamais pu installer. Les deux pistes ont aussi désormais leurs propres notes de version : une installation de la version 1 affiche l’historique de la version 1, et non celui de la version 2.

Les notes de version s’affichent dans la fenêtre de DuoUpdater pour davantage d’apps. BetterDisplay sur ses trois pistes, Shotbase, et WorkBuddy sur ses deux sites. Les notes de BetterDisplay ne se terminent plus par le balisage brut de son bouton de téléchargement, et ne répètent plus la liste de ses contributeurs à chaque version.

duo, le compagnon optionnel en ligne de commande, refuse une ligne de commande qu’il ne comprend pas. Une option mal saisie était auparavant ignorée, et une option ignorée revient à une option que vous n’avez jamais passée — si bien que duo verify --githubb vérifiait discrètement toutes les recettes au lieu de celle que vous aviez demandée. Les options inconnues, une option privée de sa valeur et les arguments superflus provoquent désormais des erreurs qui indiquent ce que la commande accepte réellement, et --help fonctionne après n’importe quelle commande.

Les préversions et les builds internes de BetterDisplay sont désormais proposés à ceux qui les ont demandés. BetterDisplay regroupe ses trois lignes de publication dans un seul flux de mise à jour et choisit entre elles au moyen de deux commutateurs dans ses propres réglages. DuoUpdater ne pouvait que deviner votre ligne d’après le build que vous exécutiez à ce moment-là, ce qui ne dit rien d’un commutateur activé mais pas encore mis à profit — si bien qu’un utilisateur ayant activé les deux commutateurs, mais encore sur un build stable, s’entendait dire qu’il était à jour alors que le programme de mise à jour de BetterDisplay lui proposait déjà une version quatre publications plus loin. Votre choix réel est désormais lu dans BetterDisplay, y compris le cas où activer les builds internes laisse aussi arriver les préversions ordinaires. Ses préversions réservées à Apple silicon sont délibérément exclues, pour qu’un Mac Intel ne se voie jamais proposer un build qu’il ne peut pas exécuter.

Changer deux fois de suite le canal de publication d’une app ne fige plus la ligne sur l’ancienne réponse. Basculer un commutateur de canal pousse DuoUpdater à revérifier cette app, et un second basculement survenant pendant que la première vérification était encore en cours était auparavant ignoré — la ligne continuait de proposer une bêta à quelqu’un qui venait de désactiver les bêtas, jusqu’à ce qu’un événement sans rapport déclenche une autre vérification. Le basculement le plus récent prend désormais le relais du précédent, et une vérification interrompue en cours de route marque les apps qu’elle n’a pas atteintes pour le passage suivant, au lieu de les enregistrer comme traitées. Les lignes passent aussi plus tôt à l’état de vérification après un basculement, ce qui réduit le laps de temps pendant lequel la réponse affichée a déjà été invalidée par votre commutateur.

Une app qui vit à l’intérieur d’une autre app est désormais fermée et rouverte avec elle. Quelques apps embarquent une seconde app complète dans leur propre bundle — Surge y range son Tableau de bord. macOS la traite comme une app distincte, si bien que rien ne la fermait quand une mise à jour était appliquée à l’app qui la contient : elle continuait d’exécuter la version qui venait d’être remplacée, depuis une copie qui ne se trouvait plus là où elle le croyait, et ne pouvait donc plus communiquer avec l’app à laquelle elle appartient. Ces apps sont désormais fermées avec l’app qui les contient et rouvertes après elle, et la fenêtre dans laquelle vous travailliez réellement est celle qui revient au premier plan. Seules les apps que vous auriez pu ouvrir vous-même sont traitées ainsi ; les processus auxiliaires invisibles qu’une app exécute pour son propre compte ne sont pas touchés.

Les points de restauration qui avaient discrètement cessé d’être créés le sont de nouveau. Une app peut verrouiller l’un de ses propres fichiers pour que rien ne puisse le supprimer, et la copie conservée pour la restauration héritait de ce verrou — elle ne pouvait donc jamais être remplacée par la suivante, et une seule tentative interrompue pouvait laisser derrière elle une copie que rien ne parvenait à effacer. Dès lors, chaque mise à jour de cette app se faisait sans retour possible, ce que signalait une simple ligne sans donner aucune raison. Sur le Mac du développeur lui-même, une app était restée dans cet état pendant deux jours. Les copies conservées pour la restauration ne portent plus le verrou, l’app installée reste exactement telle que son développeur l’a configurée, et une copie restée coincée ne peut plus bloquer celle qui doit la remplacer.

Une mise à jour qui a réussi ne signale plus un échec. macOS peut mettre une nouvelle version en place puis échouer en supprimant celle qu’elle a remplacée. Cet échec était pris au pied de la lettre : DuoUpdater affirmait qu’une app n’avait pas été mise à jour alors qu’elle l’avait été, ou qu’il n’existait aucun point de restauration alors qu’une copie complète se trouvait dans la réserve de sauvegardes — et dans le premier cas, il vous envoyait accorder une permission que vous aviez déjà accordée et qui, de toute façon, n’y aurait rien changé. Ce qui s’est réellement passé sur le disque est désormais vérifié avant de signaler quoi que ce soit.

Les lignes de version ne répètent plus les chiffres que le numéro de version contient déjà. Quand une app attend d’être relancée, la ligne affiche la version que vous exécutez et celle qu’une relance installera. Les deux côtés portaient un numéro de build, ce qui rend la différence lisible quand un développeur publie plusieurs builds sous un même nom de version — mais n’ajoute que du bruit quand les versions diffèrent déjà. La ligne de Chrome épuisait sa largeur à afficher « 151.0.7922.174 (7922.17… » et s’interrompait avant les chiffres qui avaient réellement changé. Les numéros de build n’apparaissent désormais que lorsque ce sont eux qui ont changé.

Un seul mot désormais pour rouvrir une app afin de terminer sa mise à jour. Une app dont le programme de mise à jour avait déjà mis la nouvelle version en place vous demandait de la « Redémarrer » ; une app qui garde la nouvelle version de côté jusqu’à ce que vous la quittiez vous demandait de la « Relancer ». Cette différence était réelle en coulisse, mais n’en faisait aucune pour vous : le même clic dans les deux cas, et le même résultat si vous ne cliquez jamais, puisque la mise à jour s’applique de toute façon la prochaine fois que vous quittez l’app. C’est désormais « Relancer » partout — y compris dans les notifications, les info-bulles et le réglage qui s’en charge à votre place — et c’est aussi le mot que Chrome, Claude et la plupart des apps qui se mettent à jour elles-mêmes vous présentent. Seul l’anglais a jamais eu deux mots pour cela ; l’allemand, le japonais, le russe et le chinois n’en ont toujours utilisé qu’un, et l’espagnol et le français adoptent le terme qu’ils employaient déjà ailleurs.

Une mise à jour qui a besoin d’un administrateur en demande maintenant un, au lieu d’échouer et d’accuser une permission. Pour savoir si l’échange nécessitait un mot de passe, DuoUpdater regardait le dossier où se trouve une app plutôt que l’app elle-même. Tout ce que macOS avait installé en tant que root — chaque app de l’App Store, et toute app mise en place par un paquet d’installation — passait ce test, empruntait la voie qui ne demande aucun mot de passe, et ne pouvait en aucun cas aboutir : supprimer l’ancienne version exige un accès en écriture aux répertoires qu’elle contient. macOS signale ce refus avec le même code que pour un refus de l’autorisation Gestion des applications, si bien que l’échec se présentait comme une demande d’accorder la Gestion des applications, ce qui ne pouvait jamais aider, puisque l’obstacle était le propriétaire des fichiers. Sur un Mac ordinaire, cela concernait chaque app de l’App Store et une poignée d’autres, et c’étaient les comptes administrateur qui étaient touchés — les comptes standard empruntaient déjà la bonne voie. Ces mises à jour prennent désormais la voie qui fonctionne, et l’app conserve son propriétaire au lieu de devenir discrètement la vôtre.

Les apps de l’App Store ont désormais un point de restauration, comme toutes les autres. Les sauvegardes les ignoraient, en partant du principe que l’App Store peut toujours récupérer un build précédent. C’est faux — l’App Store ne propose que la version actuelle d’une app — si bien qu’il restait la seule voie qui appliquait une mise à jour sans moyen de l’annuler. Ces apps sont désormais sauvegardées avant une mise à jour comme les autres, et comme la copie est faite par clonage, elle n’occupe presque aucun espace disque tant que la mise à jour n’a pas réellement remplacé l’original. Restaurer l’une d’elles affiche ce qui est propre à l’App Store : la mise à jour réapparaît aussitôt dans la liste Mises à jour, et se réapplique d’elle-même si les mises à jour automatiques des apps sont activées. Et quand une mise à jour de l’App Store n’allait de toute façon jamais s’appliquer — une app iPhone exécutée sur un Mac, un titre non vendu dans votre région — plus aucun point de restauration n’est créé, si bien qu’une ligne ne peut plus proposer de revenir à la version qu’elle exécute déjà.

Longbridge Desktop est maintenant suivi, sur ses deux lignes de publication. Stable et Aperçu bénéficient chacune de la détection de version, de l’installation en un clic du build officiel pour Apple silicon et de notes de version affichées dans la fenêtre de DuoUpdater, illustrations comprises.

Les notes de version de WhatsApp s’affichent désormais pendant que sa vérification sur l’App Store est encore en cours. La page App Store affichée dans cette fenêtre avait été enregistrée sous un nom que la recherche ne pouvait jamais retrouver, si bien que le volet des notes restait vide au lieu de l’afficher.

L’en-tête du menu en montre plus dans moins d’espace. La version de DuoUpdater s’affiche désormais à côté de son nom, et un clic dessus ouvre ses notes de version. « Tout mettre à jour » est passé sur sa propre ligne, où un libellé traduit a la place d’être lu en entier, et les actions en bas du menu sont des icônes. La bannière qui annonçait que DuoUpdater se mettait à jour a disparu — c’est l’étincelle à côté de la version qui s’allume à la place, et elle reste allumée jusqu’à ce que vous ayez lu ce qui a changé. Une ligne d’état trop longue pour le menu se termine désormais par des points de suspension au lieu d’élargir le menu.

Les Réglages ne tronquent plus les options de mise à jour qu’ils proposent. Les deux menus qui déterminent la façon dont une mise à jour est appliquée coupaient leurs propres libellés dans plusieurs langues. Les libellés sont désormais plus courts, et passent sur une deuxième ligne lorsque le texte l’exige encore.

Nouveautés indique la date de sortie de chaque version. Chaque version de la colonne latérale affiche désormais sa date de publication.

Les mises à jour propres à une architecture choisissent désormais le build que ce Mac peut réellement exécuter. Quelques apps publient deux fois la même version dans un même flux Sparkle — une fois pour Apple silicon, une fois pour Intel — et DuoUpdater les départageait autrefois selon l’adresse de téléchargement qui arrivait en tête du tri. Il lit désormais l’exigence matérielle indiquée dans le flux et, quand l’éditeur la laisse vide, l’architecture figurant dans le nom du fichier. Le build natif l’emporte systématiquement, et un build que ce Mac ne peut pas lancer n’est pas proposé. Les versions GitHub bénéficient du même traitement, sans qu’une recette parfaitement saine soit déclarée cassée simplement parce que son artefact le plus récent cible une autre architecture.

Les vérifications de mise à jour de ChatGPT suivent désormais la piste de déploiement associée au compte. OpenAI maintient parfois les comptes professionnels et d’entreprise sur un build de bureau plus ancien pendant qu’un nouveau build atteint d’abord les comptes grand public. DuoUpdater omettait l’abonnement du compte dans cette vérification, ce qui sélectionnait discrètement la piste prudente pour tout le monde : il pouvait affirmer que la copie installée était on ne sait comment en avance alors que ChatGPT téléchargeait déjà un build plus récent, ou proposer un build que le programme de mise à jour de l’app remplacerait ensuite. Il envoie désormais le libellé de l’abonnement, tiré de l’état de connexion ChatGPT/Codex, avec la même requête de mise à jour que celle de l’app. Si ce libellé n’est pas disponible, il conserve le comportement prudent ; les identifiants eux-mêmes ne figurent jamais dans la requête ni dans les diagnostics.

Une relance à laquelle macOS ne répond jamais ne peut plus bloquer toutes les mises à jour suivantes. Launch Services accepte parfois une demande de réouverture d’une app mise à jour sans jamais donner suite. La ligne restait alors indéfiniment sur « Relance en cours… », son bouton Redémarrer restait désactivé, et la mise à jour de DuoUpdater lui-même attendait derrière. Un lancement resté sans réponse au bout d’une minute est désormais abandonné et considéré comme un échec : la ligne se rétablit et le reste du programme de mise à jour continue de fonctionner.

Le Journal des versions reste rempli quand on fait glisser rapidement sa barre de défilement. L’ancienne pile à chargement différé pouvait être distancée par un long saut, laissant brièvement une fenêtre vide pendant que les lignes étaient créées autour de la nouvelle position. Le journal utilise désormais une liste à recyclage qui peut sauter directement à destination. La commande d’actualisation garde aussi le même encombrement quand elle passe de sa flèche à son indicateur d’activité, si bien que la ligne du bas ne tressaute plus au début d’une vérification.

Trafic de téléchargement signale désormais les mises à jour qui ont utilisé un correctif binaire. Les nouveaux téléchargements enregistrent la voie qui a réellement abouti — et pas seulement le fait qu’un correctif ait été proposé — et portent une étiquette Delta dans leur historique. Les téléchargements de correctif de la 0.3.62, reconnaissables à leur taille bien plus petite, sont aussi identifiés, bien qu’ils aient été enregistrés avant que le registre du trafic ne comporte un champ pour la voie.

Les mises à jour ne téléchargent désormais que ce qui a changé, quand le développeur les publie ainsi. Certaines apps publient un petit correctif à côté de chaque version — de quoi transformer la version que vous avez en la nouvelle, sans tout récupérer à nouveau. DuoUpdater ignorait ces correctifs et téléchargeait le paquet complet à chaque fois. Il prend désormais le correctif quand l’un d’eux correspond exactement au build que vous utilisez. La dernière mise à jour de ChatGPT a pesé 1,9 Mo au lieu de 605 Mo ; celle de Docker, 87 Mo au lieu de 582 Mo. Le résultat est une application identique dans les deux cas — même signature, mêmes octets, ce qui a été vérifié par comparaison avec le téléchargement complet avant la sortie de cette version. Quand aucun correctif ne correspond à ce que vous avez, ou qu’un correctif ne s’applique pas, le téléchargement complet a lieu comme avant : rien ne peut donc échouer à s’installer à cause de ce changement.

DuoUpdater ne télécharge plus une mise à jour qu’une app est déjà en train de télécharger elle-même. Beaucoup d’apps se mettent aussi à jour elles-mêmes, et quand nous allions chercher tous les deux le même fichier de 600 Mo en même temps, vous le téléchargiez deux fois. DuoUpdater repère désormais un téléchargement en cours et le laisse faire, en l’indiquant sur la ligne au lieu de rester inactif sans rien dire. Si ce téléchargement s’avère abandonné, il cesse d’en tenir compte au bout de dix minutes, pour que rien ne reste bloqué.

Une mise à jour qu’une app a déjà préparée n’est plus écrasée. Les apps qui se mettent à jour elles-mêmes téléchargent souvent en arrière-plan, puis attendent que vous les quittiez pour mettre la nouvelle version en place. Installer par-dessus l’une d’elles semblait fonctionner, puis était annulé dès que vous quittiez l’app — et quand la version en attente de l’app était plus ancienne que celle que DuoUpdater venait d’installer, vous vous retrouviez plus en retard qu’au départ. Ces mises à jour peuvent désormais aller à leur terme, quelle que soit la version qu’elles apportent.

Les mises à jour de DuoUpdater lui-même sont aussi plus légères. Ses versions sont désormais publiées avec le même type de correctif : la mise à jour depuis une version récente récupère quelques centaines de kilooctets au lieu de onze mégaoctets.

Les explications laissées par une mise à jour s’effacent désormais d’elles-mêmes. Quand DuoUpdater confie une app à son propre programme de mise à jour, la ligne l’indique — « l’a mis au premier plan pour que son propre programme de mise à jour applique la mise à jour ». Cette phrase restait là pour de bon : seul le lancement d’une autre mise à jour de la même app pouvait la retirer, si bien qu’elle restait affichée sous la ligne longtemps après l’installation de la mise à jour, décrivant quelque chose qui s’était terminé des heures plus tôt. Elle disparaît désormais dès que l’app est à jour. L’avertissement signalant qu’une mise à jour a été appliquée sans point de restauration est délibérément conservé, car il décrit la mise à jour déjà effectuée et ne prend son importance qu’une fois celle-ci terminée.

Une mise à jour refusée s’explique désormais dans votre langue. Quand une autre installation est déjà en cours — DuoUpdater qui traite un lot, ou duo dans un terminal — la ligne vous le signale. Ce message n’existait qu’en anglais, dans une fenêtre par ailleurs traduite, et se terminait par un numéro de processus : utile dans un terminal, mais inexploitable dans un menu. Il est désormais traduit, et indique quoi faire plutôt que qui détient le verrou. L’outil en ligne de commande affiche toujours le numéro de processus, là où vous pouvez en faire quelque chose.

La ligne sur le rythme des publications, et son horloge, suivent désormais vos réglages régionaux. Journal des versions → Tendances résumait tout par « Publie le plus souvent le vendredi, vers 18 h ». Les langues qui déclinent les noms de jours ne peuvent pas le formuler avec le jour inséré au milieu de la phrase, et obtenaient la mauvaise forme du mot — le russe affichait « Чаще всего выходит пятница » là où il faut « по пятницам ». C’est désormais une étiquette : « Pic : vendredi, vers 18 h », correcte dans toutes les langues. L’heure suit le même principe — si votre Mac affiche l’heure au format 24 heures, cette ligne aussi, tout comme l’axe du graphique.

La recherche des Réglages comprend désormais les mots affichés à l’écran. Le champ de recherche au-dessus de la barre latérale des Réglages s’appuyait sur une liste de termes supplémentaires rédigée en anglais et jamais traduite : « rollback » menait à Général, tandis que « Zurücksetzen » et « 回滚 » ne menaient nulle part. Ces termes existent désormais dans toutes les langues de DuoUpdater. Les termes anglais fonctionnent toujours, quelle que soit la langue, car la documentation dont ils proviennent est en anglais.

Activer « Tout afficher » ne fait plus hésiter le menu. La liste complète de toutes vos apps était mesurée intégralement à chaque affichage — sur un Mac avec 127 apps, cela représentait environ une seconde de travail, presque entièrement consacrée à la mise en page de lignes situées bien en dessous de celles que vous voyez. Ce coût se payait à chaque bascule, pas seulement à la première. Seules les lignes réellement à l’écran sont désormais construites.

Une explication laissée par une mise à jour échouée ne survit plus à l’échec. Quand une mise à jour ne pouvait pas être appliquée — parce qu’une autre installation était déjà en cours, par exemple — la ligne en indiquait la raison, en rouge. Rien ne retirait jamais ce texte : une fois la mise à jour installée et la ligne revenue à une coche, l’ancienne explication restait affichée en dessous, et y demeurait à chaque nouvelle vérification jusqu’au redémarrage de DuoUpdater. Elle disparaît désormais dès que l’app est à jour. Les raisons liées aux mises à jour encore en attente ne sont pas touchées, pour qu’une explication que vous n’avez pas encore lue ne puisse pas être effacée par une vérification en arrière-plan.

Le bouton « Tout mettre à jour » ne change plus de taille avec la longueur de la liste. Quand seules quelques mises à jour étaient en attente, il s’affichait une taille en dessous de la bonne, avec quatre-vingts points d’espace vide à côté, puis reprenait sa taille normale dès que la liste s’allongeait. Il garde désormais la taille prévue.

Trafic de téléchargement indique désormais vers quel build une mise à jour est passée, et pas seulement vers quelle version. Beaucoup d’apps publient plusieurs builds sous un même nom de version — Surge en a sorti quatre distincts sous « 6.9.0 » — si bien que ces lignes affichaient « 6.9.0 → 6.9.0 » sans rien vous apprendre. Elles affichent désormais « 6.9.0 (12028) → 6.9.0 (12030) », et seulement quand le nom de version ne suffit pas ; quand la version a déjà changé, le numéro de build ne serait que du bruit et il est omis.

Le build enregistré est celui qui a réellement été installé, lu sur l’app elle-même une fois la mise à jour en place. Et non le numéro annoncé par le flux de mise à jour du développeur — les flux se trompent parfois, et cette méthode fonctionne aussi pour les sources qui ne publient aucun numéro de build : GitHub, Homebrew et l’App Store. Une mise à jour qui attend encore dans la fenêtre d’installation de macOS n’est jamais devinée ; rien n’est enregistré à son sujet tant qu’elle n’est pas effective.

Un téléchargement qui n’a rien changé est désormais signalé comme tel. Il arrive qu’une mise à jour récupère et installe le build déjà présent sur votre Mac — un numéro de version incohérent chez le développeur, un miroir qui sert ce que vous avez déjà. C’est de la bande passante réellement consommée pour rien, et la fenêtre du trafic est précisément l’endroit où vous voudriez le voir. Ces lignes portent désormais une étiquette « aucun changement ». Les téléchargements enregistrés avant cette version n’ont pas de numéro de build à comparer ; ils sont donc laissés tels quels plutôt que devinés : inconnu ne veut pas dire inchangé.

DuoUpdater vous montre désormais ce que la mise à jour de vos apps a réellement coûté en téléchargements. Il comptait, à l’octet près, chaque mise à jour récupérée pour vous — mais ce décompte n’avait aucun endroit où s’afficher, et le chiffre dormait dans un fichier que personne ne pouvait lire. Une fenêtre Trafic de téléchargement s’ouvre désormais depuis le bouton en forme de graphique en bas du menu, et le chiffre du mois en cours est affiché à côté de ce bouton, pour que la question la plus fréquente trouve sa réponse sans rien ouvrir. À l’intérieur : le total, les trois derniers mois côte à côte avec l’évolution de l’un à l’autre, la répartition des octets selon leur provenance, et chaque app classée selon ce qu’elle a coûté — cliquez sur l’une d’elles pour voir chacune de ses mises à jour, de quelle version à quelle version elle est passée, et la taille de ce téléchargement.

Le total dit honnêtement ce qu’il ne peut pas voir. Homebrew, l’App Store et les apps qui se mettent à jour via leur propre outil intégré récupèrent eux-mêmes leurs octets, et DuoUpdater n’y touche jamais — le chiffre est donc un minimum, pas un décompte complet. Cela a toujours été vrai ; ce qui change, c’est que la fenêtre l’indique en permanence, et plus seulement sur l’écran vide qui s’affiche avant le premier enregistrement.

Les apps que vous avez renommées ou supprimées depuis conservent leur historique. Le trafic est enregistré selon l’emplacement de l’app sur le disque, ce qui permet de garder séparés deux canaux de la même app — Android Studio Canary et Beta, par exemple — au lieu de les additionner. La contrepartie : renommer une app laisse son historique sous un nom qui n’existe plus. Quand OpenAI a renommé Codex en ChatGPT, 30 Go de téléchargements se sont retrouvés répartis entre deux entrées qui ressemblaient à des doublons. Ces entrées sont désormais regroupées et grisées en bas de la liste, sous un titre qui explique ce qu’elles sont. Rien n’est supprimé, et le total les inclut toujours.

Une app installée depuis l’App Store ne se voit plus proposer le téléchargement direct du développeur. Beaucoup d’apps sont publiées à deux endroits à la fois — sur l’App Store et en téléchargement direct sur le site du développeur — sous la même identité, mais sous forme de builds réellement différents. Le téléchargement direct a généralement de l’avance, car il n’attend pas la validation de l’App Store. Pour une app installée depuis l’App Store, DuoUpdater interroge d’abord l’App Store, mais quand cette vérification échouait pour une raison quelconque — une connexion coupée, une vitrine qui ne répondait pas — il se rabattait discrètement sur le site du développeur et vous proposait ce qui s’y trouvait. WhatsApp affichait ainsi « 26.32.75 → 26.33.19 » : une vraie version, mais venue du mauvais endroit. L’accepter aurait remplacé votre copie App Store par une copie que l’App Store n’aurait plus jamais pu mettre à jour. Les apps installées depuis l’App Store sont désormais vérifiées auprès de l’App Store et nulle part ailleurs.

Changer le canal de mise à jour d’une app depuis cette app est désormais pris en compte immédiatement. Certaines apps vous laissent choisir entre leurs versions normales et leurs bêtas — Surge, Tailscale, Fork, OrbStack, IINA, Alfred et d’autres — et DuoUpdater suit votre choix pour ne jamais vous proposer un build que vous n’avez pas demandé. Il ne remarquait le changement que lorsque vous quittiez l’app ou ouvriez l’une des fenêtres de DuoUpdater. Aucun de ces deux cas ne correspond à ce que l’on fait réellement : désactiver le réglage, laisser l’app ouverte et jeter un œil à la barre des menus. Pire, les apps enregistrent ce réglage sur le disque quand bon leur semble, et non au moment où vous cliquez — Surge a mis cinq minutes ici —, si bien que même après avoir quitté l’app, le réglage pouvait être lu trop tôt. DuoUpdater surveille désormais le changement du réglage lui-même et revérifie cette app en une seconde ou deux. Remettre Surge sur ses versions normales retire désormais immédiatement la bêta de sa ligne, au lieu de l’y laisser jusqu’à une heure.

Une vérification qui n’a rien pu joindre ne ressemble plus à un bilan de santé parfait. Quand toutes les sources échouaient — pas de réseau, ou un proxy qui refusait discrètement les connexions alors que l’icône Wi-Fi indiquait que tout allait bien — les apps en échec étaient masquées et le panneau affichait « 127 applications · à jour ». C’est exactement l’écran qui s’affiche quand tout est vraiment à jour, ce qui rendait une vérification échouée impossible à distinguer d’une vérification réussie. Le panneau indique désormais combien d’apps il n’a pas pu joindre, montre ce qui s’est mal passé, et propose de revérifier celles-là — uniquement celles-là, sans toucher à tout ce qu’il a réussi à vérifier.

A helper macOS wouldn't switch on no longer sends you to reset your whole Mac. App Store updates install through a small background item macOS asks you to approve once. When that approval was refused, DuoUpdater had exactly one explanation for it: the system's record of the item is damaged, and repairing it takes a Terminal command that clears the background-item approvals of every app on your Mac. That is one cause among several, and macOS never says which one applies — the ordinary one is that the switch is simply off. The message now leads with that instead: turn DuoUpdater on under "Allow in the Background" in Login Items & Extensions, and DuoUpdater opens the pane for you. The Terminal reset is still written down, as the fallback for when DuoUpdater isn't listed there or switching it on changes nothing. The message also stopped running off the edge of its card.

Two Settings options read on one line again. The two options under Install routing — how App Store updates install, and what happens to apps that ship their own updater — used to put their name to the left of the menu, the way options do everywhere else on macOS. Adding six languages moved both names above their menus instead, because a German or Russian option can be long enough to run off the end of the line, and the safe layout was applied to every language at once. Each row now decides for itself: the name stays beside the menu as long as the menu leaves room for it, and only moves above when the text genuinely needs the width. In English, Japanese and Chinese both rows are back on one line; in German and French they stay stacked, which is the only way they fit without being cut off.

DuoUpdater now speaks Russian, Simplified Chinese, Japanese, German, French and Spanish. It follows whatever language your Mac is set to, and switches with it — there is nothing to turn on. If you would rather read it in a language your Mac isn't set to, macOS can do that per app: System Settings ▸ General ▸ Language & Region ▸ Applications. Everything the app writes itself is translated: the menu-bar panel, every Settings page, the setup window, the notifications, the alerts, and the small print under each option. Counts are handled the way each language actually handles them rather than by bolting an "s" onto the end, which matters most in Russian, where "1 update", "2 updates" and "5 updates" take three different endings — and in Chinese and Japanese, where they take none.

Two things stay in English on purpose. Release notes are the vendor's own words, so they arrive in whatever language the vendor wrote them in — translating them would mean rewriting what a developer said about their own release. And the duo command-line tool stays English, the way command-line tools generally are.

An App Store app that was open when you updated it comes back again. Last release drew a line in the wrong place. It was fixing something real — an update that failed, or that you cancelled, could bring an app back to life minutes after you had closed it yourself — but it decided whether to reopen by asking whether someone had answered a quit prompt. Almost no App Store update shows one: the prompt only appears on a route DuoUpdater stopped using a while ago. So from 0.3.53, updating an App Store app that was running closed it and left it closed, with nothing on screen to say why. The question it asks now is whether the update actually landed, which is the thing that decides whether a quit is coming at all. This is verified against a real App Store update rather than reasoned about: the store terminates your app to replace its files and never brings it back — despite its own prompt promising that it will.

DuoUpdater now tells you when App Store is waiting on you. The store cannot replace an app while it is open, so it puts up a "cannot be open during installation" prompt and waits — with no time limit, holding the update and a download slot for as long as it takes. That prompt is a small panel inside App Store's own window, which may be sitting on some entirely unrelated page; App Store bounces its Dock icon a few times and gives up; and DuoUpdater lives in the menu bar with no Dock icon to bounce. An update could sit there indefinitely with nothing anywhere telling you a click was needed — one took four and a half minutes here, ending only because someone thought to look. The row now says what is being waited for, from the moment the update starts.

The dot that marks an app as open no longer lags behind. macOS does not reliably announce that an app has launched — some apps never trigger it at all, while quitting is always announced. DuoUpdater listened only for those announcements, so a row could insist an app was closed while its window sat in front of you, and only correct itself when some unrelated app happened to open or quit. It now re-derives which apps are running whenever it rescans, which includes the moment you open the menu.

Two things a review caught before you did. The warning that an update was applied without a rollback point was being erased before it could be read: restarting an app cleared the whole note, and restarting after an update is the default. It is now retracted only by whoever wrote it. And Update All could refuse to restart an app — telling you its own updater had a version staged and waiting — when nothing was staged at all: it compared what was on disk now against a build number recorded before the install, so an app whose version name had not changed looked like a conflict.

An app that already downloaded its own update is no longer asked to download it again. Plenty of apps fetch their next version quietly in the background and hold it until you next quit them — that's the "relaunch to update" state you see inside Claude, TablePlus and others. DuoUpdater has always recognised that state in Electron apps and offered you Relaunch instead of an Update, because the bytes are already on your disk. Apps built on Sparkle, which is most of the rest, were invisible to it: TablePlus sat there with a 133 MB download and an unpacked 382 MB copy of 26.9.11 in its cache, while its row offered to fetch 26.9.11 for you all over again. Those apps are now recognised too — the row offers Relaunch, and nothing is downloaded twice.

One thing it deliberately won't do is offer Relaunch for an older build. An app can be holding a version behind the one you have, which happens when a vendor releases to some people before others and DuoUpdater installed the newer one first. Relaunching there would quietly move you backwards, so the row doesn't offer it — and DuoUpdater won't restart the app for you either, because that restart is the exact signal the app's own installer is waiting for.

Three ways an update could go wrong that a review caught before you did. An App Store update that failed, or that you cancelled, could bring the app back to life minutes later — you would quit it yourself and it would reopen, because DuoUpdater had noted "this app may need reopening" before anything had actually closed it. It now only reopens an app when a quit was genuinely asked for. Separately, the check added last release to stop an app's own updater undoing ours compared only the version name: a vendor that ships several builds under one version number slipped straight past it, which is the same failure it was written to prevent. It now compares the build number too. And an app's own updater is no longer assumed to be waiting just because a downloaded copy is sitting in its cache — Sparkle leaves those behind for ten days after an interrupted install, which could have left a Restart button that did nothing but explain itself.

Same changes as 0.3.51, reissued so it can actually reach you. 0.3.51 went out carrying the same internal build number as 0.3.50. That number, not the one in the version name, is what an update check compares — so anyone already running 0.3.50 was told they were up to date and never offered it. This release carries the changes below under a build number that is properly newer. If you are reading this on 0.3.51, nothing about the app changed between the two.

An update that kept coming back. ChatGPT would offer a new version, install it, restart — and a minute later the same update was waiting again. The install was never the problem: the new version really did land on disk. What happened next is that ChatGPT's own updater put a different one back. There are two lists involved, and DuoUpdater was reading the wrong one. The first is everything the vendor has published; the second is what the vendor is actually handing out to your Mac today, which can be an earlier build while a release is still rolling out. DuoUpdater was reading the published list — the same address ChatGPT itself is configured with, which is what made it look right — and offering you a build the vendor was still holding back. ChatGPT had meanwhile downloaded the build it was being offered and parked it, waiting for the app to close. Restarting to apply our update is what closed it. DuoUpdater now asks the same question ChatGPT's own updater asks, so the two agree on what the current version is.

Restarting an app no longer applies somebody else's update. That collision isn't unique to ChatGPT. A lot of apps download their next version quietly and install it the instant you quit them — the "relaunch to update" state you've seen in Claude, TablePlus and others. They'll wait hours for that quit; one was observed holding on for nearly seven. When DuoUpdater restarts an app to put its own update into effect, that restart is exactly the signal they're waiting for, and theirs runs second. Before restarting, DuoUpdater now checks whether anything is waiting, and what version it holds. If it's the same version — which is the common case, and harmless — nothing changes. If it's a different one, the app isn't restarted: the row says what's waiting and leaves the choice to you, rather than quietly swapping in a build you didn't pick.

An App Store update no longer leaves your app closed. Updating an app you have open through the App Store means closing it — the store's own installer quits it to replace the bundle, and doesn't open it again afterwards. DuoUpdater knew to reopen it, but only if you'd answered its own "quit to finish updating" prompt. Answer the identical prompt in the App Store window instead, or take an update that raises no prompt at all, and nothing remembered that your app had been open. It updated correctly, said "Updated ✓", and your app was simply gone — with no restart offered, because by then there was no running app to restart. What decides now is whether the app was running when the update started, which is the thing that was actually true, rather than which window you happened to click in.

豆包输入法 now gets checked, and shows its release notes. It was in the list — DuoUpdater looks inside /Library/Input Methods — but nothing anywhere knew where to ask about it, so the row sat blank forever and read like "nothing to do". It now reads the same endpoint the vendor's own download button reads, and compares the same build number the vendor versions by — so even a re-release that keeps the version name unchanged shows up, rather than passing as the version you already have. The release notes come from the feed the input method's own updater polls, laid out as a proper list rather than a link to a page that doesn't exist. As with 微信输入法, DuoUpdater will tell you a new version is out but will not install it for you: an input method is registered with the system by its installer, not merely copied into place, and quietly swapping the bundle is how you lose your personal dictionary.

Zed's release notes come back instead of an error. DuoUpdater asks GitHub about a lot of apps, and GitHub lets an unidentified caller ask only sixty questions an hour from one network — a budget every GitHub-hosted app on your machine shares. Zed's notes were the ones losing that race, and the panel showed a failure rather than the notes. Those requests now carry the GitHub token you saved in Settings ▸ GitHub, or the one the gh command-line tool already holds if you use it, which lifts the limit far out of the way. Without a token nothing gets worse: Zed's notes now come from a single, smaller source that covers both its channels, where before each one fetched its own web page.

Notion's release notes are about the app you have. They were being read from Notion's product announcements — the page that introduces features as they launch. Those posts are titled by feature, not by version, so nothing on that page ever lined up with the version number on Notion's row, and the notes for the update you were being offered were never there to find. They now come from Notion's own "What's new" page for the Mac and Windows app, where the versions are the ones you can actually compare against.

Some release notes were quietly incomplete, and no longer are. A release's final line could go missing from ChatWise's notes. Two of Postman's releases were cut off mid-sentence — both at the exact point where the text contained a quotation mark. Six apps' notes are now read from the same data the vendor's own site is built from, rather than picked out of the finished page, which is both sturdier and how those two ended up whole. HBuilderX is the one trade-off: its notes now come from the official release document, which covers the HBuilderX editor itself and not the bundled uni-app and uniCloud module logs, so its entries are shorter than before — the same releases, in the vendor's own words, minus the parts about other products.

Release notes that arrive inside an app's update feed are laid out properly. A good number of apps ship their notes as a small piece of a web page tucked inside the feed their updater reads. DuoUpdater used to hand that straight to the system's HTML renderer, which produced a serif font nothing else in the app uses, bullets indented into the margin, and — the part that mattered — a long list could be cut in half, with everything after the cut silently absent. Those notes are now read into the same list layout the rest of the panel uses: right font, right indentation, and nothing dropped. Where the markup is too tangled to be sure of, DuoUpdater leaves it to the old renderer rather than risk showing you part of a list as if it were all of it. TablePro benefits most — its notes had stopped being found at all.

Four more apps show their release notes properly, instead of an embedded web page. Alcove, Docker, Kiro and Waku each publish their notes somewhere a program can read them — Alcove and Docker on their own sites, Kiro as a feed, Waku on GitHub — but DuoUpdater was showing you the web page instead, which meant the vendor's fonts, the vendor's navigation, and no way to move between versions. They now read as proper entries in the list, the same as everything else. Kiro's feed covers three separate products; only the notes for the app you have installed are shown.

A release whose notes are written as sentences no longer vanishes. Some releases don't have a bulleted list of changes — they have a line or two of prose, sometimes only "no public-facing changes in this release". DuoUpdater understood lists and nothing else, so those releases were skipped entirely: if you happened to be running exactly that version, the panel had no entry for it at all, as though your own build had never shipped. They're kept now. Where the notes are laid out in a way that still can't be read cleanly — a table, mostly — the page is shown as before rather than half-converted into something misleading.

Antigravity IDE gets checked. It's a separate app from Antigravity, with its own version, and it was in your list but nothing ever checked it — the row just sat there with no version to compare against and no way to find out. It's checked now. DuoUpdater won't install it for you; it will tell you when a new version is out and where to get it.

DuoUpdater tells you when it updated itself, and what changed. It installs its own updates quietly, on purpose — it waits until you're away from the machine and swaps itself without asking, because a tool that interrupts you to talk about itself is getting in the way of the work it's supposed to protect. The cost was that you'd end up on a new version you never agreed to and never saw the notes for: every other app in your list has a "what changed" panel, and the one app that changed under you in silence was this one. Now the menu says so once, and opens its release notes. It's shown until you read it rather than for a set time — the update this is for is the one that landed while you were asleep. A fresh install doesn't get told it was updated, because it wasn't, and going back to an older build on purpose doesn't either.

And you can read those notes any time. The ✨ button at the bottom of the menu opens every release DuoUpdater has ever shipped, with the one you're running marked in the list.

Switching an app's update channel in that app is noticed straight away. Some apps let you choose between their stable and pre-release builds in their own settings — Tailscale, Fork, Surge, OrbStack, TablePlus, CleanShot, IINA, Alfred, DuoPaste. That choice lives in the app's own preferences, where nothing tells DuoUpdater it has changed, so switching from a beta track back to stable left the row still comparing you against the beta — and still offering it — until the next scheduled check, up to an hour later. DuoUpdater now re-reads that choice when one of those apps opens or quits, and when you come back to its own window, and re-checks just the app that changed.

Tailscale's Release Candidate track is one of the choices DuoUpdater understands. Tailscale publishes three: stable, release candidate, and unstable. Only two were known here, so a Mac opted into release candidates was quietly checked against stable instead, and reported up to date whenever a candidate build was newer than the stable one. All three are now checked against the track you actually chose.

Confirming a quit late no longer leaves the app updated but closed. Some apps guard their own quit with a dialog — Claude, for one, asks about an active conversation — and that dialog could land in the middle of a Relaunch. DuoUpdater rightly refuses to sit there while you decide (and it still won't force the quit past your unsaved work), but once it stepped aside it also stopped listening. Answer the dialog a minute later and the quit went through, the app's own updater swapped in the new version — and then nothing happened: some updaters deliberately don't reopen the app after installing, DuoUpdater was no longer watching, and you were left staring at an app that had simply closed. It now leaves a note for itself when it steps aside: if you do confirm that quit within the next few minutes, it waits for the update to finish landing and then brings the app back, in front if that's where it was. The note expires after a few minutes, so a quit hours later is just you closing the app, and stays that way.

The same late answer now works for a plain Restart. A save prompt could block the Restart button (and the automatic restart that follows a one-click Update) in exactly the same way, with a worse ending: the new version was already on disk, so when you finally dismissed that prompt and the app closed, DuoUpdater's next look around decided there was nothing left to restart and quietly dropped the badge too — an app closed, an update half-applied, and no trace that anything had been asked for. Answering a save prompt within a few minutes now finishes the restart it belonged to, and the app comes back on the new version.

App Store updates tell you they're waiting, and don't leave the app closed if you answer late. When the App Store finishes downloading an update for an app you have open, it asks for that app to be closed before it can install — and DuoUpdater waits, indefinitely and on purpose, for you to say when. Until now that request lived only inside the menu: if you never opened it, an update sat downloaded-but-not-installed all night, and background checks waited with it. It now also arrives as a notification with a Relaunch button, so you can answer it without hunting for the row. And if your app puts up a save prompt of its own after you tap Relaunch, answering it minutes later no longer strands the app closed — the update lands and the app is reopened, the same as if it had quit right away.

The list holds still while you are clicking down it. Every finished update used to re-sort the list on the spot: the app that just landed left the pending group, or picked up a Restart badge and jumped to the top, and everything below it slid up a row — under the pointer of anyone working down a list of Update buttons. Click the top one, go for the next, and the next one had moved. Now the order is held from the first click until the whole round is done: an app that finishes shows its confirmation in place, nothing else moves, and the list settles once at the end, when the finished apps drop away as they always did.

One less version number on a row that needs a restart. An app with an update waiting and an earlier update still needing a restart tried to print all three versions on one line — installed, available, and the older one still running. On four-part versions like Chrome's it did not fit, and the line was cut off exactly where the digits started to differ, so the part left visible said nothing at all. The line now sticks to the comparison that matters — what you have and what is offered — and the running version moved to the row's tooltip, where it fits.

No more Dock icon. DuoUpdater is a menu-bar app — everything it does starts from the icon up there — but it also held a Dock slot, and the only thing that slot ever did was open the same window the menu bar opens. It now runs from the menu bar alone. If you would rather keep the Dock icon, Settings ▸ General ▸ "Hide the Dock icon" turns it back on, and with it the badge that shows the number of pending updates; hidden, that count lives on the menu-bar icon instead.

An app you ignored is no longer checked at all. Ignoring an app hid its row, but every check still asked its vendor after it — one network request per app per round, spent on an answer nothing would ever be said about. On an unauthenticated GitHub budget of sixty requests an hour, those were requests taken from the apps you do watch. Ignoring now means not asking, which is what "hide an app from update checks" always claimed. Naming an app on the command line still checks it, and so does asking for hidden rows, since both are you asking about that app specifically. Skipping a version is unchanged and still checked — whether the version on offer is still the one you skipped can only be known by asking. And un-ignoring re-checks that app on the spot, instead of leaving the row blank until the next round comes due.

An app you ignored stops notifying you. An app that updates itself leaves a "Relaunch to apply it" reminder in Notification Center and repeats it every few minutes until you act on it. That reminder never consulted the ignore list, so an app you had ignored went on sending it — hidden in DuoUpdater's own list, still arriving every five minutes, with nothing on screen to explain where it was coming from. Ignoring an app now silences those reminders and clears any already waiting in Notification Center. Skipping a version does the same for that version.

A download no longer squeezes the app's name or its version off the row. While an app was downloading, the progress bar and its percentage claimed enough of the row that a long name wrapped onto a second line, a long date-style version was clipped at both ends to something unreadable, and at 100% the percentage itself broke across two lines. The row now measures what the name and the version actually need and fits the progress readout into what's left: the bar gives way to a compact ring, and the percentage stays. Nothing is given up until there is genuinely no room for it.

An update no longer looks like it fired twice. With one update pending, installing it briefly emptied the list: the row dropped out the moment the new version reached the disk, the "Everything is up to date" placeholder took its place and jumped the window's height, and then the row reappeared saying "Relaunching...". Nothing was actually wrong underneath — the app still had to be restarted to run the new code — but it read as though something had happened twice. The row now stays where it is from the click through to the relaunch. The step that used to announce "Done" while the app was still being restarted says "Installed" instead; "finished" is left for the confirmation at the end, where it belongs.

The workbench sidebar follows the arrow keys again. Holding an arrow key walked the selection off the edge of the list and left it there, moving through apps that were never drawn and not catching up when the keys stopped. The selected app stays in view.

Moving through that sidebar is quicker. Every keypress was re-deriving, once per app per row, a fact about the whole list that had not changed — on a machine with 124 apps that came to about fifteen thousand redundant filesystem-path lookups per keystroke. It is derived once now. Fast key repeat can still outrun the list; there is more to do here.

An App Store update says "Update", not "Get". When the background helper has not been approved there is no way to install an App Store update in place, so the row hands off to the App Store app instead — but the button for that read "Get", which is what the store says about an app you do not own yet. Every row that reaches it is an app you already have, with an update waiting. It says "Update" now, and when the helper is what is missing the tooltip says so, since approving it in Settings is what turns those updates into one click.

The action column lines up. A checkmark or a small badge at the end of a row was centred in its slot while a wide button sat flush against the row's edge, so the right-hand column read as ragged — and visibly out of line with the Homebrew row pinned below it. Everything ends on the same edge now.

WeType (微信输入法) now reports the version you actually have. Its version was being read off the name of the vendor's installer file, which turns out to carry the installer's version rather than the app's — the installer is a small downloader that fetches the real app separately, and the two numbers drift apart. DuoUpdater now reads the same manifest the vendor's own installer reads, so the version matches your copy and new releases show up when they ship. WeType still has to be updated with the vendor's installer rather than in place: replacing the bundle skips the input-method registration step and was found to lose settings.

A beta build can never arrive on the stable channel. The fix in 0.3.44 looks further back through an app's releases when the newest one has no Mac build attached. That wider search could also see the developer's beta and release-candidate builds, which the normal check never shows you — so an app that happened to publish a release without its Mac download could have offered you a beta. Nothing had actually hit this, and now nothing can: the wider search only ever considers finished releases.

Notion's release notes are readable again. Notion restyled its releases page and DuoUpdater could no longer pick the posts out of it, so the notes fell back to showing the raw web page. They render as proper entries again.

PureMac's updates are visible again. The developer publishes a separate command-line tool from the same place as the app, and its release was being read as if it were the app — as version 1.0.0, which looks older than what you have installed, so the app reported itself up to date and every real update stayed hidden. It now reads only the app's own releases.

An update that only ever existed for phones no longer sits in your list. Some apps share one version number across Mac, Windows, Linux and mobile, and sometimes a release goes out to the phones alone — the version number moves, but no Mac build is ever made. DuoUpdater was reading that as a Mac update, which left an update you could never install and that never went away. It now looks for the Mac download itself rather than trusting the version number, so those releases are correctly ignored. LocalSend was the app affected; its row now reads as up to date, which it is.

LocalSend installed from its own website updates in one click. Now that the right release is identified, its Mac disk image can be installed in place like the rest.

An App Store copy is never replaced with a build from elsewhere. A few apps are published both on the Mac App Store and as a download from their developer, under the same identity — LocalSend is one. Those are genuinely different builds, and the App Store's copy has to keep updating through the App Store. DuoUpdater now leaves those copies to the store instead of ever offering the developer's build over them.

Updates that the wider ecosystem never picks up get flagged for us. Our nightly recipe sweep could only tell whether an app's version could still be read, not whether the answer made sense for a Mac — which is why the LocalSend problem had to be spotted by hand. It now also compares against Homebrew, and raises a flag when we are reporting a version that nobody else has packaged long after it was published. Nothing about this is visible on your Mac; it is how this class of mistake gets caught by machine next time.

Package updates are read more thoroughly before they are opened. The check added in 0.3.41 asks an installer package where it installs, and refuses one that will not say. It was reading only the summary the package publishes about itself; it now also reads the package's own file list, which is what the installer actually follows. That means a package that keeps quiet in its summary is still understood instead of turned away. Every app that updates this way was re-checked against its real installer, and none of them changed.

A download link that stays broken now gets noticed. When a vendor's server has a bad minute, DuoUpdater waits it out rather than crying wolf — but that was letting a download link that had been broken for good slip by unremarked, because it looked the same as a bad minute on any single check. It now tells the difference: brief trouble is still ignored, trouble that lasts is flagged and fixed. Nothing changes on your Mac; this is about broken apps getting repaired sooner instead of quietly staying broken.

Release notes can't be pulled down to an insecure page. A vendor's notes page is loaded over a secure connection, but nothing stopped that page from redirecting itself to an insecure one. Now it can't.

Updating OneNote no longer installs the whole of Microsoft Office. OneNote's update was being fetched from Microsoft's combined Office installer, which puts Word, Excel, PowerPoint, Outlook and OneDrive on your Mac along with it. If you keep OneNote on its own, that was five applications you never asked for. It now downloads Microsoft's standalone OneNote update, which installs OneNote and nothing else.

Package updates are checked more strictly before they are opened. An update that arrives as a macOS installer package now has to say where it installs, and has to name the app you are updating. A package that will not say is refused rather than let through. Every app that updates this way — Office, Edge, Teams, OneDrive, Tailscale, ToDesk, AweSun and the rest — was checked against its real installer first, so this should never fire on a normal update.

Telegram's one-click update stops vanishing when Telegram's servers hiccup. Working out where to download Telegram from needs one extra request to their servers, and those servers were intermittently refusing it — a few minutes at a time, then fine again. When that happened the update was still detected, but the Update button quietly disappeared for that check and you had to go to the website yourself. DuoUpdater now retries before giving up, so a brief hiccup no longer costs you the one-click install.

Package installers are checked against the app they claim to update. Some updates arrive as a macOS installer package, which runs with administrator rights the moment you confirm it. Until now the only check was that the package came from the same developer as the app being updated — which would have let any package from that developer through, not just the right one. DuoUpdater now also reads where the package says it will install and refuses it if that is not the app you are updating. Nothing changes for a normal update; this only ever fires on a package that does not belong.

Release notes only open over a secure connection. The notes pane loads a vendor's own page for some apps, and one of those pages was still being fetched over plain http. Those pages now have to be https, and a handful of other malformed addresses are refused outright rather than loaded.

Fewer apps can go silently missing after a vendor renumbers. Zotero's jump to 10.0 in 0.3.37 exposed a whole class of this: an app disappears from the update list, with no error, because the vendor changed how many numbers are in its version. Twenty-one apps — among them VS Code, Discord, Obsidian, Figma, WhatsApp and GIMP — no longer depend on that staying the same. The rest were checked and deliberately left alone, because for those a looser check would risk reading the wrong number off the page.

The download percentage no longer spills out of its row. While an update downloaded, the number next to the progress bar sat too far right — clipped by the edge of the list instead of lining up with everything else in the column — and there was more empty space between the bar and the number than there needed to be. Both are fixed; the percentage still holds a fixed width, so the row stays steady as it counts up to 100%.

Zotero 10 shows up as an update again. Zotero numbered its new major release 10.0 — two numbers where every previous release had three — and DuoUpdater's check for it quietly stopped recognising the version. Nothing looked wrong: no error, no failed check, Zotero simply never appeared in the list, so anyone still on 9.0.6 was never offered the upgrade. It is recognised again, and the one-click install is unchanged.

A package update that leaves the old copy running now offers to restart it. Some updates install as a package handed to macOS's own installer, and when that finished it left the previous copy still running the old version — with no prompt, so you had to notice and quit it yourself. DuoUpdater now spots that and offers a Restart, the same as it already does for other kinds of update. It only offers one when a copy that was open before the install is genuinely still running the old code — if the installer (or you) already relaunched the app, or it wasn't open, nothing is shown.

WeChat DevTools (微信开发者工具) is checked for updates now — Stable, RC and Nightly each on their own track. It used to sit there as "unknown": since version 2.02 the app reports Electron's stock identity on disk, calling itself version 36.6.0, and all three channels look identical from the outside. DuoUpdater now reads the real version and channel out of the app's own configuration, so whichever track you installed is the only one you are offered — a Nightly install is never handed a Stable build, or the other way round. Updates install in one click, and the release notes for the exact build show up in the window.

App Store updates stop breaking every time DuoUpdater updates itself. Replacing the app left the background helper from the previous copy running, and macOS then never started the new one — so the helper looked switched on while every App Store update failed talking to a copy that no longer existed. Only a restart cleared it. The helper now steps aside when it has been idle for a minute, which means a replaced app heals itself by the next update. For a Mac already in that state there is a Restart Helper button in Settings → Diagnostics and on the update that failed; it asks for an administrator password and takes effect immediately, no restart.

Diagnostics can tell you whether the helper actually works. "Enabled" only ever meant "switched on", and the difference between that and "answering" showed up as a failed update. A Check button now says which one you have, in those words.

Backups: choose what to delete. "Clean Up Now" only removed backups belonging to apps you had uninstalled, so on most Macs it deleted nothing and said nothing while the size stayed put. It now opens a list — every backup with its app icon, the update it would roll back, its size and date — with everything selected and anything you want to keep unselectable. The button says how much the selection frees. Backups whose records had gone missing were previously counted in the total but impossible to see or remove; they are listed too, marked unusable.

A silent self-update no longer leaves DuoUpdater sitting in front of you. When it applied its own update in the background, macOS brought back the windows that had been open — and bringing a window back also brings the app forward, so an update nobody asked for landed on top of whatever was being worked on and stayed there. DuoUpdater now notes which application was in front before it replaces itself, and gives the front back to it on the way in. Windows still return exactly as they were.

Docker updated to the version it said it would. Docker publishes its releases in an order that puts an older one first, and DuoUpdater read the newest version from that list while taking the download link from the top of it — so it fetched 574 MB, kept a backup, installed 4.86.0 over the 4.86.0 already there, and went on offering 4.87.0. Downloads are now matched to the version each entry declares for itself, whatever order a vendor lists them in.

An update that changed nothing is no longer reported as done. The check that runs immediately after installing already knew Docker hadn't moved; it was overruled by a success message and an "Updated ✓". When an update we applied ourselves leaves the app exactly as it was, that is now shown as the failure it is, naming what was installed and what is still on disk.

Silent self-updates no longer wait for an empty screen. With the switch turned on, DuoUpdater would hold its own update back while any of its windows were open — which, for a window people leave open, meant waiting until the app was quit. Open windows no longer delay it (macOS brings them back after the restart), while a DuoUpdater you are actually using still does: it waits for the keyboard and mouse to go quiet before restarting itself.

Installing DuoUpdater's own updates silently now actually is silent. The switch introduced in 0.3.30 downloaded the new version in the background and then still asked before applying it — the one thing it was meant to spare you. It now applies the update itself, at a moment when doing so interrupts nothing: no check or install running, nothing waiting to be relaunched, no DuoUpdater window open, and you working in another app. It restarts itself there, without a prompt. Until such a moment arrives it simply waits, and if none ever comes the update is still applied when you quit — so the wait can delay a version, never lose one. Leaving the switch off is unchanged: you are asked, as before.

An App Store update no longer blames you for a permission you already gave. When DuoUpdater is replaced while it is running — by its own update, or by a rebuild during development — the previous copy of its background helper keeps holding the slot the system reserves for it, while macOS still reports the helper as switched on. Every App Store update then failed with a red line telling you to go turn it on in Login Items, where you would find it already on, and the button offered beside that message quietly did nothing. That state is now recognised and named for what it is, along with the one thing that clears it. DuoUpdater no longer tries to repair it by re-registering the helper: that was measured to switch the background item off and leave it unable to be switched back on.

DuoUpdater can now update itself without asking. Settings → Updates has a new switch for installing DuoUpdater's own updates in the background, taking effect the next time it restarts. It stays off unless you turn it on, and the prompt-and-wait behaviour is unchanged for everyone who leaves it alone.

Its own updates are noticed within the hour. DuoUpdater checked for its own new versions once a day, so a release could sit unseen for most of a day. It now checks hourly.

Eight more AI desktop apps are tracked. OpenCode Desktop and OpenChamber follow their GitHub releases; Wispr Flow, Granola, Comet, Windsurf, AionUi and Msty are read from their vendors' own version endpoints.

Installer packages stay the same package from verification to macOS Installer. DuoUpdater now seals the selected installer before closing or replacing any existing Installer window, checks it again immediately before opening, and refuses the hand-off if another local process changed the file in between. This preserves Sparkle's signature guarantee all the way to the package you see in Installer without making the menu-bar UI pause while large packages are checked.

Multi-installer disk images handle more real-world package names without guessing. Versioned beta, release-candidate, Apple Silicon, and universal package names are recognized when they identify one unique product, while similarly named helpers and sibling products remain excluded. Older bundle-style macOS installer packages are supported by the same integrity checks.

Failed installer downloads are cleaned up immediately. A bad signature, unreadable disk image, cancelled download, or rejected package no longer leaves a full installer sitting in temporary storage until the next day's cleanup.

Signed Sparkle updates that arrive as installer packages now work. A few apps publish a perfectly valid, cryptographically signed .pkg instead of an app archive. DuoUpdater offered those updates, downloaded them, and then tried to unpack the package as though it were a zip — an update that could never finish. They now go to macOS's own Installer, after DuoUpdater verifies both the Sparkle signature on the download and the installer identity inside it.

A disk image containing several installers is no longer allowed to make a guess. Some vendors put a main installer, helpers, and sibling products in one image. Matching on a fragment of the filename could pick a helper simply because its name contained the app's name. DuoUpdater now opens a package only when it is the sole choice or can be identified uniquely; otherwise it stops and leaves the decision to you instead of presenting the wrong installer.

The App Store helper is more tightly scoped to your login session. The privileged helper now takes the account identity directly from macOS's authenticated XPC connection and refuses a request whose claimed user does not match. Normal App Store updates behave exactly as before; the change closes off a signed client from redirecting the helper into another user's session.

Release notes show their formatting instead of its punctuation. Notes that come from a project's GitHub release were rendered exactly as written — **bold** with the asterisks, links as [text](url). Bold is now bold and links are links. This affected every app whose updates come from GitHub, which is most of the open-source ones.

Arrow-keying down the app list no longer crawls. Holding an arrow key felt like moving one row at a time through mud, and long release notes made it worse. Three things were doing it: a permission check on every app in the list ran again for every row drawn; the notes for whichever app you passed through were re-parsed on each keypress; and a long set of notes — one project's runs to 54,000 characters — was laid out in a single pass, which froze the window for about two seconds. The check is now computed once per list, parsed notes are kept, and long notes are laid out only as far as you have scrolled. Worst measured stall went from ~2.1 s to under 0.6 s, and what remains is the deliberate pause before the detail pane catches up rather than a freeze.

Input methods are never updated by replacing the app, and 微信输入法 (WeType)'s one-click from 0.3.25 is withdrawn. Settings were lost on a Mac during the work that added it. What we can show is that the copy in the protected system folder was never actually replaced by DuoUpdater — but an older copy of the input method was installed and launched elsewhere on that machine while testing, inside the window where the settings were rewritten. Nothing here is proven, and an input method's dictionary is not something to test a theory on: WeType now reports its version and sends you to the vendor's installer, which registers the input source with the system — a step that replacing the app bundle skips, and the likely reason that Mac then appeared twice in WeType's own device list.

The refusal is not specific to WeType: DuoUpdater no longer offers a one-click for anything installed as an input method, whichever vendor it comes from. Those apps still report their versions and link out.

Three more apps now report their updates, and all three install with one click. Hidden Bar, XQuartz and EasyFind were sitting in the list as a grey "unknown".

Hidden Bar is the interesting one: it ships with an update feed configured, so from the outside it looked like it was already covered. The feed answers, and is well-formed, and contains no releases at all — which is indistinguishable from a healthy feed until you look inside it. Its version now comes from its release tags instead. EasyFind ships no updater at all, so a copy installed from the vendor's site had no way to learn about new versions.

XQuartz installs through the system installer rather than by replacing the app, because it is not just an app: it lays down a whole X11 stack, and swapping only the app bundle would leave the rest at the old version. macOS asks for the administrator password itself, as it does for any package.

Thirteen more apps now report their updates, twelve of them with one click. GIMP, MongoDB Compass, Meld, Emacs, Tor Browser, Zotero, GrandPerspective, TigerVNC, qBittorrent, Opera, LibreOffice, pgAdmin 4 and Telegram Desktop were all sitting in the list as a grey "unknown" — installed, with nothing to say about them. Each was worked out by downloading the vendor's actual build and reading its identity out of it, so a one-click only appears where the download is signed by the same developer as the copy you already have. The exception is qBittorrent: its own build isn't signed by an identified developer at all, so it reports its version and sends you to the project's page.

Opera, LibreOffice and pgAdmin 4 nearly joined that exception. All three publish nothing but a directory listing, and listings sort alphabetically — "100" comes before "99" — so the newest release is not the first one on the page. Reading the version was never the problem; building a download link was, because the obvious way to build one would have picked whichever release happened to be listed first. They now download the release that was actually compared. That is the one mistake a signature check cannot catch for you: an older build of the right app, signed perfectly.

1Password and Inkscape now install with one click too, and both were previously written off. 1Password's official download turns out to be a small installer program rather than the app — signed and notarised by 1Password, so every safety check passes it, and installing it would have replaced your password manager with its own installer. DuoUpdater now fetches the package that installer itself downloads. Inkscape's download page hands out its file through a one-time link that changes with every release; the same file also sits at a plain, predictable address, which is what gets used.

微信输入法 (WeType) now installs with one click. It lives in a folder only an administrator can write to, which is why it used to only report its version. It now goes through the same administrator prompt as any other app in a protected location.

Release notes for Opera, Inkscape and 1Password. Opera publishes one page per major version, Inkscape one wiki page per release, and 1Password a feed — all three now render as proper change lists in the app instead of a link out. 1Password's version and its notes both come from that feed now, which is a published interface, rather than from scraping the page beside it.

Discord's version check works again. Discord moved its downloads to a different server and the check was still looking at the old address, so DuoUpdater quietly reported "no version" for Discord Stable while everything else kept working. It now keys off the part of the address that names the release channel, which is the part that actually has to be right.

Fifteen more apps now report their updates, and all but one install with one click. Rancher Desktop, Cherry Studio, RedisInsight, Upscayl, WailBrew, Wave Terminal, Lens, Termius, Unity Hub, iStat Menus, Inkscape, Google Gemini, Antigravity, AnyDesk and Kiro were all showing as a grey "unknown" — installed, with nothing to say about them. Each one was worked out by reading the vendor's own build rather than trusting a download page: the version now comes from wherever that app's own updater looks, and a one-click only appears where the download is signed by the same developer as the copy you already have. Three of them (Google Gemini, Antigravity, Kiro) publish nothing a download page can be scraped for; their real update services answer the same questions their own updaters ask, so that is what DuoUpdater asks too.

AnyDesk in particular was written off and shouldn't have been. Its download and changelog pages both refuse anything that isn't a person with a browser, so an earlier sweep concluded the app was unreachable. The plain-text changelog on the same server answers fine — and it is what AnyDesk's own Homebrew entry has always read.

Updating an app in a location that needs an administrator password now asks, once. Most apps live in /Applications, which you can write to; a few — input methods, for one — live where only an administrator can. Those used to show an Update button that could never work. Now the button asks for the password, and if you dismiss that prompt DuoUpdater takes the hint: the row switches to Open and stops asking on every release. "Ask for administrator access again" in the row's right-click menu brings the button back. The choice is remembered for that copy of the app specifically, so declining for one install doesn't silence another.

An up-to-date Xcode beta no longer claims the vendor is behind it. Under "Show all", a row whose vendor has fallen behind what you have installed shows a muted note saying so — you're ahead, nothing to do. Xcode was getting that note while sitting on exactly the build Apple was offering: it publishes a build number plus a human label ("27.0 beta 5"), and comparing that label against the plain "27.0" the bundle reports made a release look newer than its own beta. The note now settles on the build whenever both sides have one, so the same release is recognised as the same release however it is labelled. A vendor that has genuinely fallen behind is still called out.

44 more apps now report their updates. Apps that publish on GitHub but ship no update feed of their own used to sit in the list as a grey "unknown" — DuoUpdater could see them installed and had nothing to say about them. Bruno, UTM, kitty, KeePassXC, Godot, Bitwarden, VSCodium, draw.io, Podman Desktop, Anki, Raspberry Pi Imager, LuLu, MarkEdit, Clash Verge, Freelens, Tabby, Espanso, Moonlight, SwiftBar, Sequel Ace, balenaEtcher, DB Browser for SQLite, OpenLens, Headlamp, OpenMTP, Goose, Caffeine, noTunes, KeepingYouAwake, MiddleClick and a dozen more now show a real version, and 36 of them install with one click like any other app. Which ones was decided by downloading each vendor's actual build and reading the identity out of it, so a one-click only appears where the download is signed by the same developer as the copy you already have. Seven — Alacritty, Flameshot, MarkText, darktable, OWASP ZAP, BlueBubbles and Wine — publish builds Apple hasn't notarised, so those report their version and send you to the vendor rather than installing anything. LocalSend is report-only for a different reason, corrected here after this version shipped: its builds are notarised, but its newest release attaches no macOS download at all, so there is nothing to install until the project starts publishing one again.

Apps that already carry a Sparkle feed needed nothing: they were checked as part of this sweep and were already working, which is why names like Rectangle, Maccy, iTerm2 and Telegram aren't in the list above.

An update that your Mac couldn't run is now refused rather than installed. Where a developer publishes one download per processor, DuoUpdater picks between them by the file's name — and names are not always honest: three of the apps above ship an Apple silicon build under a name that says nothing about it, or says the opposite. Before an app is replaced, its new version is now checked against the processor in your Mac, read out of the program itself instead of its name. If it can't run here, the update stops and your working copy is left exactly as it was. Nothing about a normal update changes; this is the case that used to end with an app that no longer opened.

An unanswered permission prompt no longer leaves the update check hanging. To tell a TestFlight build apart from an App Store one, DuoUpdater reads TestFlight's own database, and macOS keeps that behind the "access data from other apps" permission. Until that was answered the read didn't fail — it waited, indefinitely, for a prompt that might be sitting behind another window or might never be answered at all, and the scan behind it simply never finished. Nothing timed out and nothing said why. It now waits a few seconds and then carries on without TestFlight's side of the story; the only thing missing in the meantime is whether those particular apps came from TestFlight, and it sorts itself out on the next scan once the permission is granted.

Homebrew updates work behind a proxy. If your Mac reaches the internet through a proxy, upgrading brew packages failed with curl: (28) Failed to connect while every other update went through fine. Homebrew shells out to curl, which — unlike the rest of DuoUpdater's networking — doesn't read the proxy you configured in System Settings; it only reads proxy environment variables, and an app launched from the Dock or at login has none. DuoUpdater now passes your system proxy settings down to Homebrew itself. Nothing changes on a machine with no proxy configured, and a proxy you've already exported in your own shell still wins.

Claude's updates now show up while they're still rolling out. Anthropic releases Claude in stages: a build goes to a fraction of Macs at a time, and the public download page only catches up at the end. DuoUpdater was reading that public page, so for the whole of a rollout — most of a day, in the case of 1.30096.5 — it told you Claude was up to date while Claude itself had already quietly downloaded the new version and was waiting for a relaunch. It now also asks the same endpoint Claude's own updater asks, which answers for your Mac specifically, and offers whichever of the two is further ahead. Nothing about which build you're offered has changed: it is either the public release or the one your Mac was already allocated. Claude also gains real publication times, so its releases now appear in the Release Log with the moment Anthropic shipped them rather than an estimate.

A superseded package update no longer leaves its window sitting there. Updates that go through macOS's own installer — Microsoft Office, AweSun, ToDesk — open an Installer window and then wait for you. If you left one open and a newer release came along, installing that one opened a second window, and they stacked up. The older window is now closed once its replacement is ready, and its download cleaned up with it. A window that's mid-install, or asking for your password, is left strictly alone.

duo says which copy is which when two apps share a name. Naming an app that is installed twice — two Xcode betas, say — printed both candidates as a bare "Xcode" and told you to name one exactly, which matches both again. The listing now carries each copy's version, and when the matches genuinely share a name it asks for the path instead of repeating advice that cannot work.

"Open download page" no longer downloads a file. On apps whose page DuoUpdater knows — ToDesk and UU Remote among them — that button handed your browser the installer package instead of opening anything: the link it used was the same one the updater downloads from, so clicking it started a download you didn't ask for. The page and the package are now kept apart, and the button opens the vendor's actual download page. Where a source only ever publishes a package and no page at all — a bare Sparkle feed — there is now no button rather than one that downloads something.

The app list responds to the arrow keys again. Opening the workbench window left the keyboard focus nowhere in particular, so ↑ and ↓ did nothing until you clicked a row — and after clicking into the release notes on the right, or switching to another app and back, they stopped working again. The list now takes the keyboard when it opens and takes it back at the points it used to lose it. Typing in the search box is untouched: a search you've started keeps the caret.

The Brew section starts collapsed. Casks and command-line formulae are a side channel for most people, and having that tree open by default pushed your actual apps up the sidebar every time the window opened. It now starts closed and remembers however you leave it.

Xcode betas and release candidates are now detected, and two copies can be told apart. Xcode was a grey "v27.0" with no update information at all, and if you keep more than one build around — a current beta beside the previous one — they were indistinguishable: same name, same version, same icon. Each row now reads its real build, so an update shows as "27.0 beta 1 (27A5194q) → 27.0 beta 5 (27A5237l)". Which track a copy belongs to is worked out from Apple's published builds rather than guessed from what you named the folder, and you'll only ever be pointed at something at least as finished as what you have — a beta can be superseded by a beta, a release candidate or the finished release, never the other way round. Updating still means going to Apple: the downloads need you signed in with your Apple ID, so the row links to Apple's download page and its release notes.

Cursor's release notes are shown properly instead of an embedded web page. Cursor writes its changelog as dated posts rather than numbered releases, so the notes pane fell back to loading the website. Each post is now shown as its own entry — its date, its headline and its changes — the same as every other app with readable notes.

duo check now shows what changed when the version number doesn't. Updates that keep the same version and only move the build — Surge, the JetBrains previews — printed as "6.9.0 → 6.9.0" on the command line, which was accurate and told you nothing. It now shows the builds, matching what the menu bar has always shown.

Apps that ship their own updater are now updated directly by default. These are the ones like Chrome, VS Code, Cursor and the Electron apps — and because they are also the apps you tend to leave running all day, the old default of stepping aside while they were open meant they were almost never updated at all: the row offered to open the app and left the rest to you. DuoUpdater now downloads the vendor's own installer and applies it whether or not the app is running, then quits and relaunches it so the new version takes effect. Anything that installs background components alongside the app — Tailscale, Office — ships a package that macOS's own installer handles, so those pieces are still put in place properly. If you would rather nothing was touched while an app is open, Settings → General → Self-updating apps still has the old behaviour, and changing it back does not affect anything already installed.

An app whose developer changed its update signing key can be updated again. Apps that update through Sparkle sign each release with a key, and the copy you already have carries the matching public key to check it against. If a developer generates a new key and ships it without a hand-over release signed by the old one, that check fails for everybody — the app's own updater is just as stuck as DuoUpdater was, and the update sits there refusing to install with a signature error. DuoUpdater now recognises that specific situation: when the new download carries a different key of its own and the release was signed with it, it stops trusting the signature and falls back to the same checks it uses for apps that publish no signature at all — the download must be validly signed by Apple's developer certificates, and by the same developer as the app it is replacing, for the same app. A download that fails any of that is still refused, as is a bad signature that isn't explained by a key change. Mirage Beacon 1.3.0 was the first to hit this.

Update All no longer says a running app is finished before its restart. When an update had already replaced an app on disk but Update All was still busy with other installers, the row briefly showed a green checkmark and disappeared even though the old version was still running. The app now stays visible with its running and installed versions, explains that it is waiting for the batch restart, and offers Restart now. The completion checkmark appears only when the update is actually in effect.

Apps installed by a .pkg can now be rolled back. DuoUpdater keeps a copy of the previous version before it updates an app, so a bad update can be undone. Apps that install through macOS's own installer — Microsoft Office, AweSun, ToDesk and the like — never got that copy: the rollback was skipped for them entirely, so the one kind of update DuoUpdater can't watch land was also the one you couldn't back out of. They're now backed up like everything else.

Rollback no longer refuses apps that write inside their own bundle. Some apps keep working files in amongst their own program files — ToDesk stores its settings database and logs there, and doing so breaks the seal Apple puts on an app. DuoUpdater checked that seal before restoring a backup, so for those apps it declared a perfectly good backup damaged and refused to put it back. It now checks the copy against a fingerprint taken when the copy was made, which is the thing that actually matters: that what's being restored is exactly what was saved. Tampering with a stored backup is still caught, and still refused.

When a backup isn't possible, it says so instead of failing quietly. A few apps keep program files that your account simply can't read — EasyConnect is one — and no copy of those can be made. Rather than attempting it and reporting a failure part-way through an update, DuoUpdater now checks first, tells you which file is in the way, and updates anyway; you just don't get a rollback point for that one app.

The same app no longer appears several times over. Some apps leave a dated copy of themselves behind every time they update — DuoPaste, for one, parks a DuoPaste.backup-20260716-183428.app next to the real thing on each self-update. Those copies are complete, working app bundles as far as anything on disk can tell, so DuoUpdater listed each one as its own app: three identical DuoPaste rows, each offering the same update. Worse, taking one of those offers would have installed the new version into the backup, leaving the app you actually use untouched and creating another stray copy. Backup and duplicate bundles are now recognised for what they are and left out of the list, as are exact clones of an app found in two places. Genuinely separate installs that happen to share an identity — Firefox alongside Firefox Beta, two versions of Android Studio kept side by side — still each get their own row.

The list now reliably notices apps appearing and disappearing. DuoUpdater watches your Applications folders so that an app updating itself in the background, or one you drag to the Trash, is reflected within a few seconds. That watch could quietly stop working — nothing crashed, nothing was reported, it simply stopped hearing about changes, and the list then went stale until you reopened the window. It's now rebuilt periodically and after your Mac wakes from sleep, with a fresh scan each time, so a watch that dies recovers on its own instead of staying dead for the rest of the session.

An app that gets restarted after an update no longer jumps in front of what you're doing. When DuoUpdater updates an app that's currently running, it quits and reopens it so the new version actually takes effect. Reopening it also pulled it to the front — so an update to something sitting quietly in the background could drop a window on top of the thing you were typing into. The app's position now survives the restart: whatever was in front comes back in front, and whatever was in the background comes back in the background, still there and still updated, just not in your way. The same applies to apps DuoUpdater reopens after an App Store update. Apps that weren't running at all are, as before, updated on disk and left closed — updating an app never starts it up.

Fixes AweSun's update failing with "the server returned HTTP 404". DuoUpdater worked out where to download AweSun's installer by building the filename itself from the version number. Oray then renamed the file — the same 16.6.0 build, one letter's difference — and every attempt at the update hit a dead link. It now takes the filename straight from Oray's own download listing rather than guessing at it, so a future rename won't break it again.

An installer you've already downloaded no longer downloads again. Some apps update through an installer package that macOS opens for you to confirm. If you closed that window without finishing — or quit DuoUpdater and came back — the row went back to offering "Update", and taking it fetched the whole package a second time. ToDesk's is 375 MB. The download was on your disk the entire time; nothing was pointing at it. Those rows now offer "Install" instead, which just re-opens the file you already have. If the installer window is still open it comes forward rather than opening a second one, and the offer stands until either the download is gone or a newer version comes out — at which point the old package would be the wrong one, so the row goes back to a normal "Update".

Homebrew packages that aren't apps now show up. DuoUpdater tracked outdated Homebrew formulae, and left casks alone on the grounds that a cask installs an app, which already gets its own row. That holds right up until a cask installs no app — a command-line tool like codex, a font, a driver. Those had no row anywhere: nothing for the app list to find, and not a formula either. codex sat three versions behind without a word. They're now part of the Homebrew panel, which reads "packages" rather than "formulae" to match. Casks that do install an app are still managed per-app exactly as before, and apps that update themselves are still left to their own updater.

"Update All" now includes apps that install from a package. A handful of apps — ToDesk and AweSun among them — ship their update as an installer package rather than something DuoUpdater can swap into place on its own. Those were quietly left out of "Update All" and had to be updated one row at a time; if such an app was the only other update pending, the button disappeared altogether rather than acting on just one. They're now part of the batch, and they run at the very end: everything that updates unattended finishes first, so nothing opens a window or asks for your admin password until the rest is already done. One caveat worth knowing — DuoUpdater can't tell when macOS's installer has finished, so if two package updates come up in the same batch, both installer windows open one after the other rather than waiting in line.

Fixes updates going unnoticed for days at a time. DuoUpdater re-uses the answers it gets from each app's version feed so it isn't re-downloading the same file every few minutes. The problem was how long it trusted a stored answer: when a vendor's server doesn't say how long its reply stays valid, macOS guesses — and it guesses longer the longer that feed has gone unchanged. So the very feeds that had been quiet for a while were exactly the ones DuoUpdater stopped re-reading, and a new release could sit there for days with the app still reporting "up to date" and no error to show for it. Every version check now always asks the server whether anything changed, while still skipping the download when nothing has. OrbStack 2.2.2 is the release that surfaced this; the same blind spot applied to most apps checked directly against their vendor, including Chrome, Cursor, Claude, ChatGPT, Warp, Spotify, and Visual Studio Code.

Homebrew-managed apps no longer get stuck at the version they were on when DuoUpdater started. The catalog DuoUpdater reads to learn the latest version of a Homebrew app was loaded once per launch and never refreshed, which is invisible if you quit the app daily and wrong if you leave it running for weeks. It now refreshes periodically. As a bonus, machines with no Homebrew casks installed no longer download that 5 MB catalog at all.

Uses less memory and does less work in the background. This release is entirely under the hood — nothing about what DuoUpdater does has changed, only what it costs to leave running. Every update it downloaded used to leave a small amount of memory behind that was never reclaimed; harmless once, but it adds up over the weeks a menu-bar app tends to stay open. Separately, while the main window was open DuoUpdater re-read every installed app from disk every 15 seconds and started a system process each time to see what was running — that now happens every three minutes, since the filesystem watcher already notices a real change the moment it happens. Recording the release history after each check also used to save its file once per app rather than once per check, and release notes could be fetched more than once when the same page was already on its way in.

No more beachball while an app is relaunching. Clicking Update on another app while one was being quit and relaunched could freeze DuoUpdater for a moment — the spinning rainbow cursor, an unresponsive window, a click that seemingly did nothing. Relaunching an app now happens in the background instead of on the interface, so the rest of the list stays live and clickable throughout. The same freeze could show up when opening an app from a row's right-click menu, or when handing an update off to an app's own updater; both are fixed too.

Backups from uninstalled apps are now cleaned up automatically. DuoUpdater keeps one backup of an app's previous version so an update can be rolled back. Backups for apps you've since uninstalled or moved were never reclaimed and could quietly pile up gigabytes of disk space over time. They're now deleted automatically during the regular update check. Settings shows how much space backups are currently using, with a toggle to turn off the automatic cleanup and a "Clean Up Now" button to run it on demand.

JetBrains Toolbox apps no longer show a stuck or incorrect "update available." Version checks for Toolbox-managed apps (IntelliJ, Android Studio, Fleet, Air, and others) now always ask live rather than sometimes falling back to a local cache that could never actually report a new version — it fixes both a status that lingered after Toolbox had already installed the update, and one that never appeared in the first place.

Claude Desktop's release notes are now shown in DuoUpdater. Update entries for Claude Desktop now include Anthropic's own per-version changelog instead of a generic notice.

Update All now also relaunches apps that were only waiting on a restart. If an app had already downloaded its update and just needed a relaunch to finish — Claude, for instance — clicking Update All used to skip it, leaving a stray "Relaunch" button behind. It now relaunches those too, in the same pass, whenever automatic restart-after-update is on.

App Store updates recover from a receipt hiccup instead of just failing. Occasionally a Mac App Store update downloads in full but the very last install step trips over a "receipt" error — a transient App Store glitch that a second attempt usually clears. DuoUpdater now retries once automatically. If it still doesn't take, the row offers an "Open App Store" button to finish the update from the App Store's Updates page, instead of leaving a raw error on screen.

ToDesk update detection fixed. A change to ToDesk's download page stopped DuoUpdater from reading its latest Mac version, so ToDesk updates went unnoticed. Detection now reads the version reliably again.

App Store updates no longer show a scary error for an app that's already up to date. If the Mac App Store had quietly updated an app in the background — TestFlight, say — DuoUpdater's row could go stale and, on Update, try to reinstall the version that was already there. macOS's installer rejects that with an alarming red "The upgrade failed", even though nothing was actually wrong. DuoUpdater now confirms an App Store app really is behind before reinstalling, and treats a no-op reinstall as "already up to date" — settling the row quietly instead of showing an error.

App Store updates now ride out network hiccups. A brief connection drop mid-update — a flaky link, or a proxy resetting the connection — used to fail an App Store update outright with a "could not connect to the server" error. Those updates now retry automatically a few times before giving up, so a momentary blip no longer strands an update that a second attempt lands cleanly. Clicking Update again after a failure also clears the old error immediately, instead of leaving it on screen next to the spinner.

Apps that update themselves clear from the list faster. When an app like Chrome finishes updating itself in the background while an App Store update is running, its "update available" row now clears promptly — it no longer lingers until the rest of the queue finishes.

One-click updates for four more apps. HBuilderX, JetBrains Toolbox, and Microsoft Edge's Beta and Dev channels now update in place with a single click, instead of only telling you that an update exists. HBuilderX also now reads its version straight from DCloud's own release feed, so it picks up new builds sooner and more reliably.

Self-updating apps stay in their own lane. A running app that ships its own Sparkle updater is now handed off to that updater — the same courtesy DuoUpdater already gave other self-updating apps — instead of being replaced underneath it, unless you've chosen "Always replace" in Settings.

Fixes

  • The running-app dot and "Relaunch" badge no longer briefly lose track of an app right after an in-place update, when macOS keeps its process pinned to the temporary swap location for a moment.
  • When you restart an app yourself after it updated in the background, the "Relaunch" badge now clears the moment the app comes back up — instead of lingering until the next background check.

Fixes

  • When you restart an app yourself after it updated in the background, the "Relaunch" badge now clears the moment the app comes back up — instead of lingering until the next background check.

See when your apps actually ship. DuoUpdater now keeps a Release Log: a running timeline of every release the apps you track put out, each stamped with its publish time. Open it from the clock icon at the bottom of the popover.

Release-habit heatmap. A new Patterns view charts releases by weekday and hour, so you can see when an app tends to ship — pick any single app for its own pattern and version history, or view all of them together. History is backfilled from each app's update feed, so the heatmap is useful right away instead of starting empty.

Honest about what it can't time. Apps that publish an exact release date (Sparkle, GitHub, Alcove) are timed to the minute. Apps that only expose a version number get a clearly-marked "≈" estimated window — bounded by when DuoUpdater last saw the old version and first saw the new one — and never skew the heatmap.

Fixes

  • ToDesk update checks no longer report an older grayscale build; they now track the version actually offered for download.

Passwordless App Store updates. Updating Mac App Store apps no longer interrupts you for your password every time. DuoUpdater now installs a small, signed privileged helper (one-time approval) and bundles mas, so App Store updates apply directly in the background.

Cleaner "Restart to finish" lines. When an app updates itself on disk while it's still running, the pending-restart line now shows the real marketing version on both sides — e.g. 1.8.x (build) → 1.9.0 (build) instead of a bare build number on the left.

Fixes

  • Fixed a build issue on Xcode 26.5 (changelog extractor name collision).

Apps that update themselves now clear correctly. If an app updated through its own updater (for example, Chrome via "About Chrome") while DuoUpdater was busy installing other updates, it could keep showing a stale "update available" row long after it was already current. DuoUpdater now re-checks the moment the installs finish, so the row clears right away instead of lingering.

"Update All" shows the whole queue. Every app in an "Update All" run now shows a "Queued" state immediately, instead of leaving the ones further down the list looking idle with a clickable Update button. Clicking Update on an app that's already queued can no longer start a second install of it.