A stability-and-polish release: a big memory/OOM hardening pass, automatic favicon recovery on Chromium forks, a server-side move of the Drive OAuth exchange, plus several new options (battery-power timeout, "never suspend app windows", tab-group suspend/unsuspend, reopen-scrolled-to-top) and a "What's new" screen after updates.
Highlights
- Suspended-tab favicons recover on their own after a browser restart (#474, #397/#260 lineage): the previous startup repair fired once off
chrome.runtime.onStartupplus a session-storage sentinel; on Brave / Vivaldi / Dia that pass was routinely lost (worker recycled mid-run, or tabs not restored yet) and never retried, so tabs kept the extension icon until a manual Tab Health reload. A dedicated,onStartup-independent backstop now re-checks via a self-re-armingchrome.alarmsalarm and on the first activation of a suspended tab, only standing down after two consecutive clean passes (so a slow "continue where you left off" restore isn't cut short). The #449 "Repair favicons now" debug action stays as the manual escape hatch. Verified live on Brave 152. - A rare out-of-memory crash, reproduced and fixed at the root (#464, #466, #467, #473): the log buffer moved from a single broadcast
chrome.storage.localblob to per-record IndexedDB (no cross-contextonChangedfan-out),captureLogsgrowth is bounded and trimmed on a schedule, andinitialiseSuspendedTab()is now concurrency-capped so a burst of tab restores can't spike memory. Mostly invisible unless you runcaptureLogs, but the underlying changes make the extension more resilient regardless. - Drive OAuth token exchange moved server-side to
tms-oauth-proxy(#476, #440, #437): the OAuth client secret is no longer shipped in the extension package. On browsers wherechrome.identity.getAuthToken()doesn't work (Brave, Vivaldi), auto-backup now uses authorization-code + PKCE with a long-livedrefresh_tokenrenewed by a direct token call — no tab, no ambient-session dependency — replacing the short-lived implicit-flow fallback that dropped Drive accounts after a backup or two. Existing Brave/Vivaldi users: reconnect once (Options → Backup → Connect) after updating. - Separate auto-suspend timeout for battery power (#252): a new "Suspend tabs on battery power after" select alongside the AC timeout — suspend more aggressively when unplugged without touching the plugged-in value. Defaults to "Same as when plugged in".
- "Never suspend app windows" (#154): a new option (on by default, like the pinned/audio/active protections) that keeps tabs in an app-mode window — installed PWAs, or a site opened via "Create Shortcut → Open as window" — from being auto-suspended.
- Suspend / unsuspend every tab in a tab group (#133, thanks @mherkazandjian): new page and tab-strip context-menu items plus two bindable keyboard shortcuts, acting on every tab sharing the clicked tab's group.
- "What's new" screen after an update: a one-time modal on the Settings page showing just the current version's changes, backed by a new short, user-facing
CHANGELOG_USER.mdkept separate from the detailed engineering changelog. - "Always reopen suspended tabs scrolled to the top" (#308): opt-in — the tab reopens at the top of the page instead of wherever it was scrolled to, overriding
#sectionanchors. - Opt-in: reload also unsuspends background tabs (#158): reloading a suspended tab you're not looking at (e.g. via a multi-tab selection) can now unsuspend it; off by default.
- Blinking white background when switching between suspended tabs, fixed (#168): a standalone
critical.css(plus a render-blockingcriticalTheme.jsfor explicit theme overrides) paints the background immediately instead of showing the browser default until the real stylesheets load. Reported as far back as v7.1.6.2.
Also in this release
- Debug page: "Repair favicons now" action (#449), a live power-source indicator (#252), a larger rotating buffer for the downloadable report (#444), a "reset changelog seen flag" action, and a compacted Controls layout.
- Suspended page dark-mode polish (#446): dimmed title/URL text and classic-mascot artwork; the reload hotkey link toned down from accent-blue to a subdued gray at a contrast-safe value (#478).
- Battery-specific timeout: now reacts immediately to unplugging (it needed a manual trigger before), works on Chrome below 150, and stays configurable even when the AC timeout is set to "Never".
- Multi-tab reload determinism (#158): reloading a selection of suspended tabs no longer unsuspends only a random subset.
checkQueuehardening: an uncaught exception no longer strands a concurrency slot; a job that legitimately requeues several times isn't killed by a stale timeout; a single huge-resolution favicon can't blow the check budget.- Legacy mascot artwork now uses TMS's own modified assets instead of the raw original TheGreatSuspender files, and Tab Health / the favicon backstop count both mascot-icon variants correctly.
- Repo/CI: structured GitHub issue forms replace the free-form template (#479), two dead inherited workflows removed (#479, #480), and a
js-yamlCVE + abrace-expansionDoS patched in dev deps. - Smaller: single Drive backup downloads no longer nested under
tms-backups/(#451); Health/About intro text restyled to match the other internal pages; debug log view shows the date for entries not from today.
See CHANGELOG.md for the full, fix-by-fix list.
What's Changed
- feat(tab-groups): add suspend/unsuspend all tabs in this group (#133) by @mherkazandjian in #438
- fix(gsBackup): Drive auth fallback to PKCE with refresh_token by @gioxx in #440
- feat(options): opt-in reload-unsuspend for background tabs by @gioxx in #443
- fix(tgs): retry initTab message send to suspended pages by @gioxx in #445
- fix(suspended): dim title/URL text and classic mascot artwork in dark mode by @gioxx in #447
- fix(gsBackup): don't nest single Drive backup downloads under tms-backups/ by @gioxx in #451
- fix(gsTabQueue): reset job timeout on requeue instead of letting the original deadline stand by @gioxx in #452
- feat(debug): add on-demand favicon repair action by @gioxx in #453
- fix(tgs): switch initTab retry to exponential backoff by @gioxx in #457
- feat(options): add option to disable scroll-position restore on unsuspend by @gioxx in #458
- feat(options): add separate auto-suspend timeout for battery power by @gioxx in #459
- feat(debug): larger rotating buffer for downloadable report (#444) by @gioxx in #463
- fix(gsUtils): log buffer eager load, clear-log race, captureLogs scope by @gioxx in #464
- fix: address 5 findings from Codex review of master vs v9.0.2 by @gioxx in #465
- fix(gsUtils): remove dead log-buffer duplication, cap unbounded pendingEntries growth by @gioxx in #466
- fix(gsUtils): coalesce log-append messages to fix flush-burst sluggishness by @gioxx in #467
- fix(debug): guard fetchTabInfo() against overlapping focus-triggered runs by @gioxx in #470
- fix(debug): debounce fetchTabInfo() to at most one run per second by @gioxx in #471
- fix(debug): let getDebugInfo() actually recover an unresponsive tab by @gioxx in #472
- fix(tgs): cap concurrent initialiseSuspendedTab() to prevent OOM crash on tab-restore burst by @gioxx in #473
- feat(changelog): short user-facing What's new file, separate from CHANGELOG.md by @gioxx in #475
- Drive PKCE token exchange: move client secret server-side (tms-oauth-proxy) by @gioxx in #476
- fix(suspended): prevent white background flash switching tabs (#168) by @gioxx in #477
- fix(suspended): tone down the reload hotkey link's color by @gioxx in #478
- chore(github): structured issue forms + drop stale IssueAssignment workflow by @gioxx in #479
- ci: remove stale.yml (dead probot Stale config) by @gioxx in #480
- feat(gsTabSuspendManager): never auto-suspend tabs in app-mode windows by @gioxx in #481
- fix(favicon): onStartup-independent backstop for automatic favicon repair on Chromium forks (#474) by @gioxx in #484
Additional polish merged directly to master: a js-yaml CVE + brace-expansion DoS dep patch, the "reset changelog seen flag" debug action and Controls-layout compaction, legacy mascot artwork sourced from TMS 8.1.6 instead of raw TGS, the "What's new" changelog modal itself, sectionDesc restyling on Health/About, the Drive auth-method label update for the OAuth proxy, the debug log-view date fix, the 9.0.3 version bump, and the CHANGELOG date stamp.
New Contributors
- @mherkazandjian made their first contribution in #438
Full Changelog: v9.0.2...v9.0.3