From 347e63de0cd7e5d86bdc3b6170f3c0726078bdd5 Mon Sep 17 00:00:00 2001 From: Local Dev Date: Tue, 8 Sep 2026 21:20:20 +0200 Subject: [PATCH] =?UTF-8?q?Revert=20Theseus=200.3.32=20through=200.3.34=20?= =?UTF-8?q?=E2=80=94=20back=20to=200.3.31?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bundled revert of six commits: 9bacdcb Ship 0.3.34 aef7864 0.3.34 UI (grey chrome, DnD bookmarks, chip colors) c2da8bb Ship 0.3.33 9b92224 fix(updater) verify SHA-256 4e932e0 Ship 0.3.32 4e695c4 fix(updater) --updated flag Reason: the real-install E2E test (turn N-1) showed silent update against the user's custom D:\Program Files\Theseus Navigator location returns exit 0 without upgrading anything — every flag combination tried (/S alone, --updated /S --force-run, /S /currentuser, /S /D=) exits successfully and no files change. The 0.3.32 flag fix and 0.3.33 hash-verify fix were defensive improvements but did not address the actual "browser vanished" symptom, and 0.3.34 inherits the same broken silent-update path so its UI improvements never reach anyone still on 0.3.33+ with a non-default install path. Rolling manifest back to 0.3.31 so the update chip stops appearing on installs that can't complete the update. Users on the default %LOCALAPPDATA%\Programs\theseus-navigator location are unaffected — 0.3.31 is still their canonical shipped version. package.json reset to 0.3.31 explicitly (git revert stopped one bump short on the merged diff). Screenshot 0.3.0 (8ca5ac3) preserved — unrelated parallel work. --- chrome.html | 84 ++++++++++---------------------------------------- main.js | 87 ++++++++-------------------------------------------- package.json | 2 +- preload.js | 1 - 4 files changed, 30 insertions(+), 144 deletions(-) diff --git a/chrome.html b/chrome.html index 5ca6baa..d3b597a 100644 --- a/chrome.html +++ b/chrome.html @@ -13,12 +13,7 @@ } @media (prefers-color-scheme: light) { :root { - /* Chrome strip is a soft neutral grey — flat white was too bright next - to the browsed page, and pure #ffffff tabs disappeared into the - window title bar on light Windows themes. --bg tints the whole - top strip; --surface (inactive tab) sits a hair above it; --active - (foreground tab) pops a bit brighter so the current tab reads. */ - --bg:#e6e8ec; --surface:#f2f4f7; --surface2:#eaecf0; --active:#ffffff; + --bg:#e9ecf1; --surface:#ffffff; --surface2:#f1f3f7; --active:#dbe1ec; --ink:#1a1f28; --mut:#3c4453; --dim:#697280; --faint:#98a1b0; --line:rgba(0,0,0,.18); --line2:rgba(0,0,0,.11); --hover:rgba(0,0,0,.06); /* Darker acid for light backgrounds — same hue family, ~5.5:1 @@ -298,10 +293,8 @@ padding: 6px 12px; border: 1px solid color-mix(in srgb, var(--acid) 20%, transparent); border-radius: 8px; cursor: pointer; background: rgb(from var(--acid) r g b / .08); font-size: 13px; } .logo:hover { background: rgb(from var(--acid) r g b / .16); } .logo .gear { font-size: 12px; opacity: .8; } - /* favorites bar — new-tab page only, single compact row. Chips are - tight so many fit in the row; the whole strip is 22px tall (down - from 26) so the chrome view gains a bit of vertical space. */ - .bookmarks { display: flex; align-items: center; gap: 3px; padding: 2px 10px 4px; height: 22px; overflow: hidden; } + /* favorites bar — new-tab page only, single compact row */ + .bookmarks { display: flex; align-items: center; gap: 4px; padding: 3px 10px 5px; height: 26px; overflow: hidden; } /* Ctrl+F find-in-page bar. Sits below the address bar (above tabs body), ~32px tall so it's part of the chrome view height like .tordisc / .bcnrbar. syncHeight in the tabs handler picks it up automatically. */ @@ -314,14 +307,11 @@ .findbar .findbtn { border: 1px solid var(--line); background: var(--surface2); color: var(--ink); border-radius: 6px; padding: 3px 8px; font-size: 13px; cursor: pointer; } .findbar .findbtn:hover { background: var(--surface); border-color: color-mix(in srgb, var(--acid) 35%, transparent); } - .bm { display: flex; align-items: center; gap: 5px; max-width: 130px; padding: 2px 7px; border-radius: 5px; - background: var(--surface2); border: 1px solid var(--hover); color: var(--mut); font-size: 11px; cursor: grab; white-space: nowrap; } + .bm { display: flex; align-items: center; gap: 6px; max-width: 180px; padding: 3px 9px; border-radius: 6px; + background: var(--surface2); border: 1px solid var(--hover); color: var(--mut); font-size: 12px; cursor: pointer; white-space: nowrap; } .bm:hover { background: var(--active); color: var(--ink); } - .bm.dragging { opacity: .45; cursor: grabbing; } - .bm.dropbefore { box-shadow: -2px 0 0 var(--acid); } - .bm.dropafter { box-shadow: 2px 0 0 var(--acid); } - .bm .bmfav { width: 12px; height: 12px; flex: none; object-fit: contain; border-radius: 2px; } - .bm .bt { overflow: hidden; text-overflow: ellipsis; max-width: 96px; } + .bm .bmfav { width: 14px; height: 14px; flex: none; object-fit: contain; border-radius: 2px; } + .bm .bt { overflow: hidden; text-overflow: ellipsis; } /* In-chrome prompt modal (window.prompt is disabled in Electron BrowserViews, so bookmark rename etc. use this instead). */ .promptmask { position: fixed; inset: 0; background: rgba(0,0,0,.45); z-index: 10000; @@ -354,21 +344,15 @@ @media (prefers-color-scheme: light) { .ctxmenu { background: #ffffff; border-color: rgba(0,0,0,.15); } .ctxmenu .mi:hover { background: rgba(0,0,0,.05); } - /* The old light-mode chips used the BCH dark #253A49 as their fill. - At small font sizes on light Windows the white-on-dark-navy label - fell below legible, so both .logo (⛓ Theseus) and .tor switch to - a light-grey chip with dark ink — same footprint, readable text. - Update pill picks up the same treatment. */ - .logo { background: #eef1f5; color: #253A49; border-color: rgba(0,0,0,.14); } - .logo:hover { background: #e2e6ec; } - .logo .gear { color: #253A49; opacity: .85; } - .tor { background: #eef1f5; color: #253A49; border-color: rgba(0,0,0,.14); } - .tor:hover { background: #e2e6ec; } - .tor.connecting { background: #fbe9b5; color: #5a3f00; border-color: rgba(0,0,0,.14); } - .tor.on { background: #e6d9f5; color: #3f1f6b; border-color: rgba(0,0,0,.14); } - .upchip { background: #eef1f5; color: #253A49; border-color: rgba(0,0,0,.14); } - .upchip .upcore:hover { background: #e2e6ec; } - .upchip .updismiss { border-left-color: rgba(0,0,0,.14); color: #253A49; } + /* BCH dark #253A49 as a light-mode accent so the toolbar isn't + all-white-on-white. .logo (⛓ Theseus) becomes a dark chip; the + download / update pill picks it up so both stand out. */ + .logo { background: #253A49; color: #F8FDFF; border-color: #253A49; } + .logo:hover { background: #1a2c39; } + .logo .gear { color: #F8FDFF; opacity: .85; } + .upchip { background: #253A49; color: #F8FDFF; border-color: #253A49; } + .upchip .upcore:hover { background: #1a2c39; } + .upchip .updismiss { border-left-color: rgba(255,255,255,.20); color: #F8FDFF; } } .tordisc { font-size: 11.5px; color: #d9c7f2; background: #2a1c40; border-top: 1px solid #6b3fa055; padding: 5px 14px; } .tordisc a { color: var(--acid); } @@ -809,7 +793,7 @@ const fav = b.favicon ? `` : ``; - return `
${fav}${(b.title||b.url).replace(/
`; + return `
${fav}${(b.title||b.url).replace(/
`; }).join("") : `No saved pages yet — click ☆ or right-click here to add one.`; box.querySelectorAll(".bm").forEach((el) => el.onclick = (e) => { @@ -817,40 +801,6 @@ if (e.target.dataset.x !== undefined) T.removeBookmark(bookmarks[i].url); else T.navigate(bookmarks[i].url); }); - // Drag-reorder chips — same shape as the tab strip. Drop side is chosen - // by whether the pointer is on the left/right half of the target chip. - // dragUrl is the identity we hand to bookmark-move; renderBookmarks - // fires again after the reorder, which rebinds these handlers cleanly. - let dragUrl = null; - box.querySelectorAll(".bm").forEach((row) => { - row.addEventListener("dragstart", (e) => { - dragUrl = row.dataset.url; - try { e.dataTransfer.effectAllowed = "move"; e.dataTransfer.setData("text/plain", dragUrl); } catch {} - row.classList.add("dragging"); - }); - row.addEventListener("dragend", () => { - row.classList.remove("dragging"); - box.querySelectorAll(".bm").forEach((r) => r.classList.remove("dropbefore", "dropafter")); - dragUrl = null; - }); - row.addEventListener("dragover", (e) => { - if (!dragUrl || row.dataset.url === dragUrl) return; - e.preventDefault(); e.dataTransfer.dropEffect = "move"; - const r = row.getBoundingClientRect(); - const before = (e.clientX - r.left) < r.width / 2; - row.classList.toggle("dropbefore", before); - row.classList.toggle("dropafter", !before); - }); - row.addEventListener("dragleave", () => row.classList.remove("dropbefore", "dropafter")); - row.addEventListener("drop", (e) => { - e.preventDefault(); - const targetUrl = row.dataset.url; - if (!dragUrl || dragUrl === targetUrl) return; - const r = row.getBoundingClientRect(); - const before = (e.clientX - r.left) < r.width / 2; - T.moveBookmark && T.moveBookmark(dragUrl, targetUrl, before ? "before" : "after"); - }); - }); // Backfill: older bookmarks stored before favicon-support have no icon. // If we're currently on that URL and have a favicon in hand, patch it in // once so the next render draws it. diff --git a/main.js b/main.js index 94751f9..71bba56 100644 --- a/main.js +++ b/main.js @@ -1984,51 +1984,15 @@ function installDownloadTracker() { emitUpdateAvailable(); }); item.once("done", (_ev, state) => { - if (state !== "completed") { + if (state === "completed") { + updateDownloadPath = item.getSavePath() || dst; + updateDownloadState = "ready"; + console.log(`[update] silent fetch complete: ${updateDownloadPath}`); + } else { updateDownloadState = "failed"; console.warn(`[update] silent fetch ${state}`); - emitUpdateAvailable(); - return; } - // NEVER mark "ready" without verifying the file hashes to what the - // manifest promised. Electron's DownloadItem has been observed to - // fire done/completed on truncated payloads (bad Content-Length, - // CDN cache truncation, mid-stream TLS reset the runtime swallowed), - // and 0.3.31's in-app updater then spawned a half-file as setup — - // NSIS integrity check failed silently and the browser was gone. - const savedPath = item.getSavePath() || dst; - const expected = String(updateAvailable && updateAvailable.setupHash || "").toLowerCase(); - if (!expected) { - updateDownloadState = "failed"; - console.warn(`[update] no manifest hash for ${savedPath} — refusing to arm install`); - try { fs.unlinkSync(savedPath); } catch {} - emitUpdateAvailable(); - return; - } - const crypto = require("node:crypto"); - const hash = crypto.createHash("sha256"); - const rs = fs.createReadStream(savedPath); - rs.on("data", (c) => hash.update(c)); - rs.once("error", (e) => { - updateDownloadState = "failed"; - console.warn(`[update] hash read failed: ${e.message}`); - try { fs.unlinkSync(savedPath); } catch {} - emitUpdateAvailable(); - }); - rs.once("end", () => { - const got = hash.digest("hex").toLowerCase(); - if (got !== expected) { - updateDownloadState = "failed"; - console.warn(`[update] SHA-256 mismatch: got ${got}, want ${expected} — refusing to arm install`); - try { fs.unlinkSync(savedPath); } catch {} - emitUpdateAvailable(); - return; - } - updateDownloadPath = savedPath; - updateDownloadState = "ready"; - console.log(`[update] silent fetch complete + verified: ${savedPath}`); - emitUpdateAvailable(); - }); + emitUpdateAvailable(); }); return; } @@ -3109,26 +3073,15 @@ ipcMain.handle("recheck-update", async () => { return { updateAvailable, currentVersion: app.getVersion() }; }); // One-click "Install & restart". Requires the silent pre-fetch to have -// finished (updateDownloadState === "ready"). -// -// CRITICAL — spawning the setup with just ["/S"] uninstalls Theseus but -// then FAILS to reinstall on our config (oneClick:false + perMachine:false -// + allowToChangeInstallationDirectory:true). In wizard mode NSIS expects -// UI for the install-path picker, and in silent mode with the registry -// path wiped by the just-run uninstaller, it exits without installing. -// Users hit this in 0.3.31: browser gone, nothing left. -// -// Fix: pass --updated alongside /S. electron-builder's NSIS template -// treats --updated as "this is an auto-update, reuse the existing install -// directory from registry, don't re-run the uninstaller". --force-run -// tells it to relaunch the app after install so the user isn't stranded -// even if the wizard-mode path somehow trips again. +// finished (updateDownloadState === "ready"). Launches the setup with /S +// (skips the wizard; our nsis/installer.nsh's Ariadne prompt is bypassed +// too on upgrades because the Ariadne registry key is already present), +// then quits Theseus so the installer can overwrite it. When the installer +// finishes, the user re-launches Theseus and lands on the new version. ipcMain.handle("install-update-now", () => { if (updateDownloadState !== "ready" || !updateDownloadPath) return false; try { - const p = spawn(updateDownloadPath, - ["--updated", "/S", "--force-run"], - { detached: true, stdio: "ignore" }); + const p = spawn(updateDownloadPath, ["/S"], { detached: true, stdio: "ignore" }); p.unref(); } catch (e) { console.warn("update spawn failed:", e?.message); return false; } // Give the child a moment to inherit our arguments before we exit. @@ -3772,22 +3725,6 @@ ipcMain.handle("bookmark-remove", (_e, url) => { saveBookmarks(); emitBookmarks(); return bookmarks; }); -// Reorder: pull `fromUrl` out of the list and reinsert it before or after -// `targetUrl`. Renderer picks the side by which half of the target chip the -// pointer is on, same convention the tab strip uses. A missing entry or a -// self-drop is a no-op, so noisy drag events don't corrupt the list. -ipcMain.handle("bookmark-move", (_e, fromUrl, targetUrl, place) => { - if (typeof fromUrl !== "string" || typeof targetUrl !== "string" || fromUrl === targetUrl) return bookmarks; - const from = bookmarks.findIndex((b) => b.url === fromUrl); - if (from < 0) return bookmarks; - const [moved] = bookmarks.splice(from, 1); - let to = bookmarks.findIndex((b) => b.url === targetUrl); - if (to < 0) { bookmarks.splice(from, 0, moved); return bookmarks; } - if (place === "after") to += 1; - bookmarks.splice(to, 0, moved); - saveBookmarks(); emitBookmarks(); - return bookmarks; -}); ipcMain.handle("settings-get", () => settings); ipcMain.handle("settings-set", (_e, key, val) => { if (key in SETTINGS_DEFAULTS) { settings[key] = val; saveSettings(); } diff --git a/package.json b/package.json index 12463ee..3d6d62d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "theseus-navigator", - "version": "0.3.34", + "version": "0.3.31", "description": "Theseus Navigator — a browser that follows the thread. By Silent Mode, a Deviant project.", "author": "Silent Mode", "main": "main.js", diff --git a/preload.js b/preload.js index 782bee8..c7458e0 100644 --- a/preload.js +++ b/preload.js @@ -48,7 +48,6 @@ contextBridge.exposeInMainWorld("theseus", { addBookmark: (bm) => ipcRenderer.invoke("bookmark-add", bm), updateBookmark: (url, patch) => ipcRenderer.invoke("bookmark-update", url, patch), removeBookmark: (url) => ipcRenderer.invoke("bookmark-remove", url), - moveBookmark: (fromUrl, targetUrl, place) => ipcRenderer.invoke("bookmark-move", fromUrl, targetUrl, place), onBookmarks: (cb) => ipcRenderer.on("bookmarks", (_e, d) => cb(d)), onNav: (cb) => ipcRenderer.on("nav", (_e, d) => cb(d)), onTor: (cb) => ipcRenderer.on("tor", (_e, d) => cb(d)),