diff --git a/addon-updater.js b/addon-updater.js index 873341c..8b0c085 100644 --- a/addon-updater.js +++ b/addon-updater.js @@ -53,12 +53,16 @@ function readAddonJson(dir) { // Called BEFORE seedBundledAddons at boot. Any staged folder whose version // beats the currently installed copy is promoted; older or matching stages // are cleaned up so they don't loop on every boot. -function promoteStagedUpdates({ addonsDir, backupsDir, stagedDir, logger }) { +// `only(manifest)` limits the promotion to some staged entries (the live +// "Install update" path applies extensions in place but leaves plug-ins for +// the next launch). Returns the list of { id, version } actually promoted. +function promoteStagedUpdates({ addonsDir, backupsDir, stagedDir, logger, only }) { const log = logger || (() => {}); - if (!fs.existsSync(stagedDir)) return; + const promoted = []; + if (!fs.existsSync(stagedDir)) return promoted; let entries; try { entries = fs.readdirSync(stagedDir, { withFileTypes: true }); } - catch (e) { log("promote: readdir failed:", e?.message); return; } + catch (e) { log("promote: readdir failed:", e?.message); return promoted; } for (const de of entries) { if (!de.isDirectory()) continue; const from = path.join(stagedDir, de.name); @@ -68,6 +72,7 @@ function promoteStagedUpdates({ addonsDir, backupsDir, stagedDir, logger }) { try { fs.rmSync(from, { recursive: true, force: true }); } catch {} continue; } + if (typeof only === "function" && !only(manifest)) continue; const target = path.join(addonsDir, manifest.id); const currentVer = readAddonJson(target)?.version; if (currentVer && cmpVer(currentVer, manifest.version) >= 0) { @@ -82,13 +87,14 @@ function promoteStagedUpdates({ addonsDir, backupsDir, stagedDir, logger }) { try { fs.renameSync(target, backup); } catch (e) { log(`promote: backup ${manifest.id} failed, keeping staged for next boot:`, e?.message); continue; } } - try { fs.renameSync(from, target); log(`promote: ${manifest.id} -> ${manifest.version}`); } + try { fs.renameSync(from, target); log(`promote: ${manifest.id} -> ${manifest.version}`); promoted.push({ id: manifest.id, version: manifest.version }); } catch (e) { // Cross-drive rename can fail on Windows; copy then rm. - try { fs.cpSync(from, target, { recursive: true }); fs.rmSync(from, { recursive: true, force: true }); log(`promote: ${manifest.id} -> ${manifest.version} (via copy)`); } + try { fs.cpSync(from, target, { recursive: true }); fs.rmSync(from, { recursive: true, force: true }); promoted.push({ id: manifest.id, version: manifest.version }); log(`promote: ${manifest.id} -> ${manifest.version} (via copy)`); } catch (ee) { log(`promote: move ${manifest.id} failed:`, ee.message); } } } + return promoted; } // ---------- HTTP helpers -------------------------------------------------- diff --git a/chrome.html b/chrome.html index 8c8ce46..80179fd 100644 --- a/chrome.html +++ b/chrome.html @@ -55,6 +55,7 @@ matter how many tabs are open; the row scrolls (wheel) once tabs hit their minimum width, like Chrome. */ .tabs > .newtab { flex: none; margin-left: 2px; } + .tabrow > .newtab { flex: none; align-self: center; margin-left: 2px; } /* Firefox-style overflow: once tabs hit their minimum width the row scrolls, the earliest tabs slide out on the left, and an arrow at each end moves the row (they only appear when there is something to scroll). */ @@ -492,10 +493,11 @@ +
- +