Commit graph

177 commits

Author SHA1 Message Date
Local Dev
3e784e299c Theseus 0.3.31 rewrite — UI improvements + defensive hash-verify, spawn flags unchanged
Same 0.3.31 version, new binary. Rebuilds the shipped 0.3.31 with the
salvageable content from the reverted 0.3.32-0.3.34 track:

  chrome.html
    - light-mode chrome strip: --bg #e6e8ec, inactive tab #f2f4f7,
      active tab #ffffff. Fixes the "tabs disappear into the light
      Windows title bar" report.
    - bookmark chips shrunk: 130px max-width, 11px text, 12px favicon,
      22px row (was 26). ~40% more chips fit in the same width.
    - bookmark chips draggable with the tab-strip's left/right-half
      drop convention; new .dropbefore/.dropafter accent.
    - light-mode .tor + .logo + .upchip chips: from illegible white-
      on-#253A49 (at 12-13px) to #eef1f5 with #253A49 ink. Both readable
      now. .tor.connecting/.on keep amber/purple hue in light fills.

  main.js
    - will-download update handler now streams the saved setup .exe
      through crypto.createHash("sha256"), compares to the manifest's
      updateAvailable.setupHash before marking ready. Rejects and
      deletes the file on mismatch or on empty manifest hash. Test C
      in the previous session proved this catches truncated payloads
      Electron reports as "completed" (a real class of failure the
      Ariadne addon updater has always guarded against here).
    - new bookmark-move IPC: splices the list, no-ops on self-drop
      or missing entry.

  preload.js
    - moveBookmark(fromUrl, targetUrl, place) exposed for chrome.

Deliberately NOT changed: install-update-now still spawns setup with
["/S"] alone. The 0.3.32 --updated /S --force-run change was proven
in the previous session's real-install E2E to not address the actual
"browser vanished on D:\Program Files install" symptom — every flag
combination (/S alone, --updated /S --force-run, /S /currentuser,
/S /D=<install>) exits 0 without upgrading anything on that specific
install path. That's a separate open bug; not touched here.

Version stays 0.3.31 — this is a binary rewrite of 0.3.31, not a new
release. Existing 0.3.31 installs won't see an update chip (version
compare returns false), which is intentional given the auto-update
path is still broken for non-default install locations.
2026-09-08 21:26:42 +02:00
Local Dev
347e63de0c Revert Theseus 0.3.32 through 0.3.34 — back to 0.3.31
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=<install>) 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.
2026-09-08 21:20:20 +02:00
Local Dev
fa65ce5bab 0.3.34: greyer chrome bar, tighter bookmarks + drag-reorder, legible Tor/Theseus chips in light mode
Chrome strip: light-mode --bg/--surface/--surface2/--active retuned to a
soft neutral grey. Flat #ffffff tabs disappeared into light Windows
title bars and the top strip read as one bright rectangle; now the
tab row sits on #e6e8ec, inactive tabs are #f2f4f7, active tab is
white so the current one still pops.

Bookmarks: chips down to 130px max-width, 11px text, 12px favicon,
tighter padding, 22px row (was 26). Fits ~40% more saved pages in
the same width. Chips are now draggable — dragstart/dragover/drop
mirror the tab strip's reorder pattern, dropping before/after by
which half of the target chip the pointer is on. IPC bookmark-move
splices the array; a missing entry or self-drop is a no-op.

Tor + Theseus (⛓ logo) chips in light mode: white-on-#253A49 was
below legible at 12-13px on real light Windows themes. Both now use
#eef1f5 with #253A49 ink and a subtle border — same footprint, dark
letters read cleanly. .tor.connecting/.on keep amber/purple hue but
in light-appropriate fills with dark text. .upchip picks up the
same treatment for consistency.
2026-09-08 20:34:21 +02:00
Local Dev
4c01ec7b7d feat(theseus/screenshot): 0.3.0 — sidebar-first flow with explicit "open in tab"
0.3.33 still ships blank screenshots because the whole toolbar-menu → auto-
open-editor path can't be made race-free: the moment the editor tab opens
it becomes the active tab, and a snapshot of the editor's own tab (before
its canvas has drawn from storage) is a valid-looking 24 KB all-white PNG.
The lastCapturableTabId fallback I added in a279864 catches the second
click, but the first click can still land on the addon-owned tab whenever
the user re-triggers before setActive has settled.

Rebuild the UX so this class of race can't happen at all:

- Drop the toolbar-menu capability. Manifest is back to sidebar-panel +
  capture-tab + open-tab, so the dock icon opens the panel (never the
  editor directly). No dropdown, no clip-under-tab-view issue, no auto-
  jump into an addon-owned tab.

- Sidebar has the three capture buttons + a preview <img> + a "Open in
  editor tab" button. The preview is fed a data:image/png URL returned
  straight from api.captureTab, rendered inside the sidebar's own
  document — same origin, no file:// cross-directory gotcha, and the user
  can see immediately whether the shot actually landed.

- Editor.html tab opens only on an explicit "Open in editor tab" click.
  The addon rewrites __pending at that moment (so the editor always sees
  the just-selected capture even if a prior editor tab drained the entry),
  then api.openTab("editor.html", {name}). The editor's storage-based
  load path is unchanged.

- Recent captures ring is kept and now exposed as a horizontal thumbnail
  strip in the sidebar; clicking a tile re-previews that capture and
  arms "Open in editor tab" for it.

Editor page (editor.html/js/css) unchanged — same crop / arrow / rect /
ellipse / pen / text / mosaic-redact / undo / redo / copy / save.

Bundled but not shipped — leaving version bump + deploy to the parent
session.
2026-09-08 20:26:48 +02:00
Local Dev
3e3b2c2b8b fix(theseus/updater): verify manifest SHA-256 before arming install
The in-app updater fetched the setup .exe via
session.defaultSession.downloadURL and marked updateDownloadState="ready"
on any DownloadItem `done` with state === "completed", then handed
that path to install-update-now to spawn. No hash check against the
manifest — the same manifest that already carries a SHA-256 per file
and that the Ariadne addon updater verifies at ariadneDownloadInstaller
in this same file.

Consequence: a mid-stream truncation the runtime swallowed as
"completed" (a wrong Content-Length, a CDN cache truncation, an
interrupted TLS session, a corrupted mirror) armed install of a
half-file. install-update-now then ran the corrupt setup silently,
NSIS integrity check failed, uninstaller wiped the app first, and
Theseus was gone with nothing to click.

Now the completion handler streams the saved file through
crypto.createHash("sha256"), compares against updateAvailable.setupHash
from the manifest (already captured in checkForUpdate), and refuses to
arm install on mismatch — deletes the corrupt file and marks the
download failed so the retry loop can pick a fresh one up.

Companion fix to 0.3.32's --updated /S --force-run flags. Both
symptoms landed users in the same "browser vanished" state; 0.3.32
covered the spawn-side, this covers the download-side.
2026-09-08 19:52:15 +02:00
Local Dev
3c75abd1a6 Ship Theseus 0.3.31 32c4abea (screenshot white-loop fix + Aegis IPC + light-mode surfaces)
Setup    32c4abea9f2f15bb319e355b2cda747fc7d25eac350f7b9512b92894bae97c30
Portable 47af67894b389174f034dd15a2d2c99605bfcb941fccd084242fc0c52cc6e90a

Fixes since 0.3.28 (all riding this ship since 0.3.29/0.3.30 site
files never reached LIVE):

a279864 - Root cause of the "screenshot is still blank white"
symptom: captureTab reads activeTab(). After the first capture the
editor tab BECOMES active, so every subsequent shot snapshotted the
editor's own still-blank canvas — that white PNG got written to
scratch, fed into a new editor, and the next re-capture snapshotted
THAT. A self-referential feedback loop. captureTab now skips
add-on-owned and Settings tabs, falling back to the last real page
tab tracked in setActive(); if none exists, a clear "open a page
you'd like to shoot first" error rather than white pixels.

4c55f04 - Aegis card in Settings > General crashed on load because
the IPC handlers used a different response shape than the UI
expected. Reads corrected on both sides.

df10884 - Aegis retires the legacy bchwallet folder on every launch,
and Aegis gets a branded dock/list icon.

1574545 - Every dark-hardcoded surface in Settings light mode (.polrow
collision-policy rows, .segseg, .engcat, .ctxmenu, select/input
backgrounds) now maps to a BCH-palette equivalent — no more solid
dark blobs on the white page.

ea9bcab / 4ed55b7 - Site release-notes text updated to include the
per-add-on diagnostic report already in the 0.3.28 build.

Deployed. Verified LIVE 0.3.31.
2026-09-08 19:34:26 +02:00
Local Dev
0f1411094e fix(theseus/updater): --updated flag so silent install actually reinstalls
Users reported Theseus being uninstalled by the auto-updater and never
coming back. Reproduced on 0.3.31:

The 'Install & restart' handler was spawning the NSIS setup with
just [\"/S\"]. Our config is oneClick:false + perMachine:false +
allowToChangeInstallationDirectory:true, so NSIS in silent mode:

  1. runs the old uninstaller (wipes install dir + registry path)
  2. hits the install phase, which in wizard mode expects UI to pick
     the install directory
  3. silent mode has no UI, registry path is gone → exits without
     installing anything

Result: browser gone, nothing left, no error surfaced to the user.

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 rerun the uninstaller'.
--force-run relaunches the app after install.

Users stuck on 0.3.31 need to manually install 0.3.32 once (from
dl.silentmode.st) — the auto-updater in 0.3.31 will not recover on
its own. Their %APPDATA%\theseus-navigator profile is untouched by
the uninstall so vault, addons and settings survive the reinstall.
2026-09-08 19:34:06 +02:00
Local Dev
dc58d0426a fix(theseus/addons): captureTab skips addon-owned tabs
Reported: the Screenshot dropdown produces a blank white PNG "every time".
Verified end-to-end via CDP: the FIRST capture on a real page (silentmode.st)
worked (221 KB, real pixels). Every capture after that came back as a
uniform-white 1920×899 PNG (~24 KB, all bytes 255/255/255/255 confirmed by
canvas getImageData in the editor tab).

Root cause: api.captureTab reads activeTab(), which after the first successful
run is the editor.html tab the add-on just opened. CDP Page.captureScreenshot
on the editor's own tab happily snapshots its still-blank canvas, and the
addon writes that white PNG into scratch → opens a new editor showing it →
next re-capture snapshots THAT editor → all-white feedback loop.

Fix: track the last active tab that isn't an add-on-owned page (or the
Settings tab) in setActive(), and have captureTab fall back to it when the
current active tab has an addonId or settings flag. Last resort: the first
non-addon non-settings tab in the list. If none exists, throw a clear "open
a page you'd like to shoot first" error instead of returning white pixels.

No new capability; no manifest change; addons keep calling
api.captureTab({mode}) exactly as before. Ships in the next Theseus release.
2026-09-08 19:14:29 +02:00
Local Dev
a28c0c5fe4 Ship Theseus 0.3.30 12442cf3 (light-mode surfaces map to BCH palette)
Setup    12442cf39f29dcc5775910cd9e7c24d1224f247c7bea245b1ab3147860bfc447
Portable a71282ea82465b4edc6012a21464de58a2d980892fb3eaf018a26312c11b54bb

One bundled fix since 0.3.29:

1574545 - Every dark-hardcoded surface in settings.html now maps to a
BCH-palette equivalent in the light-media block: --bg #F8FDFF,
--ink #253A49; .polrow / .segseg / .engcat / .ctxmenu / select /
input backgrounds all get a subtle off-white and dark-navy text; the
selected .polrow gets an acid-green tint via :has(input:checked)
so the chosen option stands out without a black bar. Registries
> Collision policy is now readable in light mode. Dark mode unchanged.

Verified via CDP: --bg=#F8FDFF, --ink=#253A49, .polrow color
=rgb(37,58,73), engcat bg=rgb(244,248,251), theme card bg=white.

Deployed. Verified LIVE 0.3.30.
2026-09-08 18:53:22 +02:00
Local Dev
83e2a83bf8 fix(theseus/settings/light): map every dark-navy card to a BCH-palette surface
Screenshot showed Registries > Collision policy rows rendering as
solid dark bars in light mode — .polrow hardcoded background:#10151f
with no light override, so the whole card blob-ed dark on the white
page and the text disappeared. Same story for .segseg, .engcat,
select/input backgrounds, .ctxmenu, .themeCards etc.

The light-media block gains a proper mapping keyed to the user's
BCH palette (#0AC18E / #253A49 / #F8FDFF):

- --bg → #F8FDFF (BCH white), --ink → #253A49 (BCH dark)
- .polrow → #f4f8fb card on white; hover #eaf0f5; SELECTED row
  gets an acid-green tint via :has(input:checked) so BCDN-first
  reads as the chosen option without an ugly dark bar
- .segseg, .engcat, .themeCards, .ctxmenu, select/input all get
  the same treatment — subtle off-white surfaces on top of the
  panel, dark-navy text
- Sidebar (.side) already had a light override; refined the border
  and hover states to use rgba(37,58,73,X) so they match the ink

Verified via CDP: --bg=#F8FDFF, --ink=#253A49, .polrow color=
rgb(37,58,73), engcat bg=rgb(244,248,251), theme card bg=white.
2026-09-08 18:49:53 +02:00
Local Dev
22be28ed17 fix(theseus/aegis): retire bchwallet on every launch + branded dock/list icon
Two follow-ups from the on-device test.

Two Aegis addons showing up (bchwallet + aegis):
- migrateAegisRename previously only ran when addons/aegis/ didn't exist,
  which meant any bchwallet copy the signed OTA update endpoint reinstalls
  after the first migration stays there forever, and AddonHost loads both
  as separate wallets. Rewritten to always retire addons/bchwallet/ when
  it's present, regardless of whether aegis/ is already installed. The
  storage-copy (bchwallet.json → aegis.json) still only runs the first
  time so a downgrade doesn't clobber fresh 0.4+ state.
- Also flushes any stray addons/siawallet/ that comes back the same way.

Sidebar dock and Extensions list icons showed the raw 🛡 emoji:
- chrome.html's dock-button renderer and settings.html's extensions-list
  renderer now accept `data:image/svg+xml…` values for manifest.icon and
  render them as <img> instead of text. Emoji strings still render as
  before.
- aegis addon.json's icon is now the exact hex-aspis mark from
  aegis.x/brand/favicon.svg (URL-encoded inline). Version bumped to
  0.4.1 so seedBundledAddons reseeds the new addon.json on next launch.
2026-09-08 18:42:00 +02:00
Local Dev
7d580be598 Ship Theseus 0.3.29 ea51507c (fix Aegis card IPC-shape crash)
Setup    ea51507c94b4ccb1a2e9048aea21a433803d3ac41ea31531c86efef75d9d27dc
Portable 571a31046abc83eef6b23494bbd38e98bb79a1b51812d2c0e1cc303aadbc8e12

Bundled since 0.3.28:

4c55f04 - Aegis update card in Settings > General was showing 'Status
check failed: installed.find is not a function'. Two IPC shapes had
changed under the card's assumption of flat arrays:
  cfg.listAddons()         → { installed:[…], sidebarPanels:[…] }
  cfg.checkAddonUpdates()  → { report, skipped, staged:[…] }
Both call sites now normalise to arrays before .find(). Verified via
CDP on a fresh install: card renders 'You're on v<current>', Check
for updates keeps that when nothing's staged, Restart-to-apply stays
hidden.

920febb - package-lock.json version-field bumped 0.3.16 → 0.3.22 to
match what npm install had already written (housekeeping, no deps).

Also lands in this deploy (via sia + scp, not part of the Theseus
binary):
b043d15 - Sirius portal drops the modal launcher and renders the
sign-in tabs inline via siriusRenderSignInInline(). One flow, no
popup, refresh-safe.

Deployed. Verified LIVE 0.3.29.
2026-09-08 18:37:33 +02:00
Local Dev
b36506f248 chore(theseus): sync package-lock.json with package.json version bump
Lockfile's top-level version field lagged at 0.3.16; npm install
during the last dist cycle bumped it to 0.3.22. Committing so the
lockfile matches the source of truth in package.json (currently 0.3.28
per the last ship). No dependency changes.
2026-09-08 18:30:59 +02:00
Local Dev
1f63b5b788 fix(theseus/settings): Aegis card reads correct IPC shapes
CDP test surfaced two shape mismatches:
- cfg.listAddons() returns {installed:[...], sidebarPanels:[...]} — my
  destructure treated it as a plain array, so .find() blew up with
  'installed || []).find is not a function'.
- cfg.checkAddonUpdates() returns {report, skipped, staged:[...]} —
  same problem, .find on an object.

Both call sites now normalise (installed = listRes.installed || [],
staged = res.staged || []) before finding the aegis entry. Verified
via CDP against a fresh install: card renders 'You're on v0.4.0.
Updates arrive over-the-air…'; clicking Check for updates keeps
that status (no staged update live); Restart-to-apply stays hidden.
2026-09-08 18:26:58 +02:00
Local Dev
2c7b82ad60 refactor(theseus/aegis): rename bundle bchwallet→aegis + retire standalone siawallet
Cleans up the naming that leaked from the wallet's origin story (BCH-only)
into the actual bundle layout. Aegis is one integrated addon now:
- Bundle folder: TheseusNavigator/bundled-addons/aegis/ (was bchwallet/).
- Addon id:      "aegis" (was "bchwallet"). Vault-derive still accepts
                 legacy "bchwallet/*" and "siawallet/*" paths via the
                 absorbs list, so no on-chain funds move.
- Version:       0.4.0 (bumped to trigger seedBundledAddons's reseed).
- Retired:       TheseusNavigator/bundled-addons/siawallet/. Sia is
                 folded into Aegis as a chain adapter (lib/sia/*.js
                 already in-tree) and Aegis's manifest lists siawallet
                 under absorbs so pre-Aegis SC keys derive identically.

main.js migrateAegisRename() runs before seedBundledAddons on every
launch. First run does the move; subsequent runs are no-ops:
- addons/bchwallet/  -> addons-backups/bchwallet-migrated-<stamp>/
- addons-data/bchwallet.json COPIED to addons-data/aegis.json (kept
  copied not moved so a downgrade to 0.3.x can still boot).
- addons/siawallet/  -> addons-backups/siawallet-migrated-<stamp>/
  (addons-data/siawallet.json left untouched — its walletdUrl is
  per-user config Aegis's Sia wallet takes fresh via Settings).

settings.html Aegis update card now matches either "aegis" (new id) or
"bchwallet" (pre-rename) so upgraders coming from 0.3.x see the same
one card while the OTA endpoint's next signed bundle catches up.

Internal purpose paths inside index.js/chain-*.js are unchanged —
LEGACY_BCH_PURPOSE stays "bchwallet/mainnet/0" and every purposePrefix
still starts with "bchwallet/*". The addon absorbs its own former id,
so those paths keep resolving to the same seed the shipping Aegis has
been using since 0.3.14.
2026-09-08 18:17:44 +02:00
Local Dev
2e54bf5e5a Ship Theseus 0.3.28 5d15508b (Aegis update card + DevTools in tab sidebar + real favicons)
Setup    5d15508bba929f1f074c052ac933863eadf6eb8e56984ebd5a1af75e80626643
Portable a5d346b97f5a13d85fa3bd301a72075ddb82fe636d7b1a51840ffd5a16d879f4

Bundled since 0.3.27:

32d4b75 - Aegis (bchwallet) gains its own update card in Settings >
General beside Ariadne. Check for updates hits the same signed OTA
endpoint the boot timer uses; Restart to apply appears when a signed
newer version is staged. Uses the existing addons-check-updates + a
new app-restart IPC. New Aegis versions ship without a Theseus release.

32d4b75 (same commit) - DevTools (F12 / Ctrl+Shift+I) opens docked to
the right of the tab (mode: 'right') instead of a detached window.
Matches stock Chrome. Users who prefer detached can drag out via the
DevTools own toolbar.

b71c925 - Search-engine favicons in Settings > Search now use Google's
/s2/favicons service — DuckDuckGo's ip3 source returned 404 for enough
hosts (Brave, Bing, Yandex, etc.) that half the list was falling
through to the emoji placeholder.

Deployed. Verified LIVE 0.3.28.
2026-09-08 18:17:25 +02:00
Local Dev
8055d39a9d feat(theseus/addons): per-add-on diagnostic report from checkAndStageUpdates
The Settings > Extensions "Check for updates" button used to report
one of two lines: "N updates staged; restart to apply" or "All
extensions are up to date". The second collapsed several distinct
outcomes into one indistinguishable line, so a user seeing "up to
date" couldn't tell whether the check actually reached the endpoint
or the fetch had silently failed.

checkAndStageUpdates now returns { report, skipped? } with one entry
per installed add-on and a status of:
  no-update-url  — addon.json doesn't declare updateURL
  fetch-failed   — DNS / connection / HTTP error on updates.json or the tarball (detail carries the message)
  up-to-date     — endpoint reached, no version strictly newer than installed
  signature-invalid — offered version's sig didn't verify against any baked-in pubkey
  sha256-mismatch — downloaded tarball's hash didn't match the signed one
  extract-failed  — tar could not extract (detail carries the message)
  manifest-mismatch — extracted addon.json didn't match signed id/version
  staged / already-staged — success

The Settings UI now renders one row per add-on with that status, so
a "no update" outcome is never mistaken for a silent fetch failure.
Return shape is back-compat: if a caller expects a bare array, the
UI normalizes.
2026-09-08 18:14:07 +02:00
Local Dev
b5f1cf468b feat(theseus/settings): Aegis update card + DevTools open in tab sidebar
Two additions:

1) Aegis (bchwallet) update card lands in Settings > General beside
   the Ariadne one. Same look, different substance: Aegis is a
   bundled add-on, not a system service, so no Install/Uninstall
   buttons — the checkboxes there are 'Check for updates' and (only
   when an update is staged) 'Restart to apply update'. Reuses the
   existing signed OTA endpoint (addons-check-updates IPC) and
   addons-list-staged for the pending-update surface, so new wallet
   versions ship without a Theseus release.
   New app-restart IPC (app.relaunch + app.quit) does the promotion
   handoff — addons-host promotes staged updates on next boot.

2) DevTools (F12 / Ctrl+Shift+I) opens docked to the right of the
   tab view (mode: 'right') instead of popping a detached window. A
   user debugging a page gets the tools alongside it, matching stock
   Chrome; anyone who prefers detached can still drag it out via the
   DevTools own toolbar.
2026-09-08 18:09:55 +02:00
Local Dev
ce53db3063 feat(theseus/aegis): official brand favicon + discoverable Add-wallet UX
Two fixes off the first-launch feedback: users didn't see how to add a
wallet, and the branded shield from aegis.x/brand hadn't landed in the
panel.

- panel.html + panel.js: swap the ad-hoc shield SVG for the exact mark
  from aegis.x/brand/favicon.svg — hexagonal aspis with dark fill +
  acid stroke + boss ring + centre point. The panel's tab favicon
  (<link rel="icon">) and the "Aegis" fallback badge in the header
  now render byte-close to what a user downloads from the brand kit.
- Add-wallet discoverability: an always-visible "+" chip lives in the
  header next to the picker caret; clicking it opens the picker with
  the coin list pre-expanded. When the panel is genuinely empty (a
  vault Aegis hasn't seen before), the gate now shows a big primary
  "+ Add your first wallet" button plus copy that spells out the
  seed source — Aegis derives every wallet from the Theseus password
  vault, no separate seed to import.
- addon.json bumped to 0.3.1 so seedBundledAddons() picks up the fresh
  panel files on the next Theseus launch (bundleVer === userVer would
  otherwise skip the reseed and users would keep loading the old
  panel from their addons/ dir).
2026-09-08 13:19:29 +02:00
Local Dev
1886b76fb2 fix(theseus/settings): real search-engine favicons instead of emoji fallback
DuckDuckGo's icons.duckduckgo.com/ip3/… service was returning 404 for
Brave, Bing, Yandex and a few others in the SEARCH_ENGINES catalog —
so the settings row would fall through to the hardcoded emoji sym
(🦁 lion, 🔍 magnifier, etc.) instead of the real brand mark.

Two-part fix:

1) main.js: faviconUrl() switched from DDG's icons.duckduckgo.com to
   Google's www.google.com/s2/favicons?domain=…&sz=32 as the primary
   source. Google's service is materially more reliable — returns a
   real 32×32 PNG for essentially every host.
2) settings.html: the engIcon renderer now stacks a two-source
   fallback. If Google's PNG fails, retry with DDG's ico URL; if that
   also fails, THEN drop to the emoji sym. Row is never blank, and
   real brand favicons win over emoji whenever either service resolves.

The <option> in the dropdown still uses emoji because <option> can't
render <img> — that's a native <select> limitation, not fixable here.
2026-09-08 13:12:55 +02:00
Local Dev
2e42783dfe fix(theseus/screenshot): 0.2.4 — deliver capture via addon storage, not a cross-origin file://
Blank editor + broken buttons root cause: index.js was writing the
capture to <userData>/addons-data/screenshot-scratch/<name>.png and
passing "?src=file://<that path>" to editor.html. The editor lives at
file:///<userData>/addons/screenshot/editor.html — different directory
tree under file://. Chromium's file:// origin policy treats those as
different origins and quietly refuses the <img> load, so init()'s
loadImage() rejects, the canvas never gets an image, and every tool
after that operates on a still-empty 300×150 default canvas — the
tools appear to work but produce no visible output because the base
image never landed. The sidebar version we replaced set
`previewImg.src = dataUrl` (a base64 data URL) directly, which has no
origin and just worked; the tab version regressed by adding the file
hop.

Fix keeps the scratch file for the recent-captures ring but hands
the raw capture through the add-on's per-add-on kv store
(`__pending` key). Same store, same origin scoping, no
cross-directory read: index.js writes via api.storage.set from main;
editor.js reads via window.silentmode.storage.get through the tab
preload (packaged since 0.3.27). Fallback path retained for
"openRecent" callers still passing ?src=… — those will need their
own fix in a follow-up.

Bumped to 0.2.4 and signed for the OTA endpoint — first real
independent add-on ship: no Theseus release needed to fix this,
0.3.27 installs pick up 0.2.4 via the boot-time signed-update poll.
2026-09-08 12:57:46 +02:00
Local Dev
1d0e25c4e0 feat(theseus/settings): show current Theseus version by default in General
The Updates card was placeholder-dashed until the user clicked Check
for updates. Show 'You're on v<current>' immediately on load using a
new app-version IPC (app.getVersion, no network) so the user can
answer 'which version am I on?' without a click.
2026-09-08 12:36:21 +02:00
Local Dev
f114eaeb2a Ship Theseus 0.3.27 0eeda6d9 (package addon-tab-preload.js — screenshot editor is finally whole)
Setup    0eeda6d9030e6127a605b6a1254747e3072f8974797142944d43cbcfe00f3bab
Portable a4f96d9040c398c68696ee414e48817b9587faf19fe766ccf68a5753f09c7919

One fix since 0.3.26:

038095f - The preload for full-tab add-on pages (addon-tab-preload.js)
has been in the source tree since 0.3.19 but was never declared in the
electron-builder file list, so every packaged Theseus build shipped
without it. Symptom, reported on 0.3.25: the screenshot editor tab
opens with a DevTools ENOENT error, window.silentmode comes out
undefined, and the toolbar buttons (Copy, Save, Discard) misfire.
The 0.3.26 CDP capture fix WAS landing correctly at the main-process
side; the editor was just missing its add-on API surface. Packaging
the preload closes the loop — combined with 0.3.26's capture fix,
the screenshot pipeline works end to end.

Deployed. Verified LIVE 0.3.27.
2026-09-08 12:35:43 +02:00
Local Dev
8ee7c6952c fix(theseus/addons): package addon-tab-preload.js — was missing since 0.3.19
The preload for full-tab add-on pages (opened via api.openTab, used by
the screenshot editor) has been in the source tree since 0.3.19 but
was never declared in the electron-builder `files:` list, so packaged
Theseus builds shipped without it. Symptom: an add-on tab loads with a
DevTools error 'ENOENT, addon-tab-preload.js not found in app.asar',
window.silentmode is undefined, and any button that uses the API
(Discard's closeTab fallback, future closeTab / DOM helpers) either
misfires or falls back to a partial no-op. The image-loading path
itself does not depend on the preload, so this is orthogonal to the
'blank screenshot' bug (that one is fixed in 0.3.26 by the CDP capture
switch); a user on any build 0.3.19 – 0.3.26 needs BOTH the CDP capture
fix (already in 0.3.26 main.js) AND this preload packaged, which is
why 0.3.25 still surfaced a broken editor.
2026-09-08 12:30:21 +02:00
Local Dev
d59e969702 feat(theseus/find): Ctrl+F opens an in-page find bar
Standard browser Ctrl+F support:

- main.js: Ctrl+F caught in the shared before-input-event handler (same
  place as F12 / reload shortcuts) fires 'find-open' to chrome.
  Two new IPC handlers proxy to activeTab().view.webContents:
    find-in-page(query, {forward, findNext, matchCase})
    find-stop
  Each tab's webContents listens for 'found-in-page' and forwards
  {activeMatchOrdinal, matches, finalUpdate} back to chrome via
  'find-result' — only when it's the active tab so the bar doesn't
  update from a background tab's stale match count.

- preload.js: exposes onFindOpen / findInPage / findStop / onFindResult.

- chrome.html: adds a .findbar strip below the bookmarks bar (part of
  chrome-view height like .tordisc / .bcnrbar, so syncHeight picks it
  up). Input + "N of M" counter + prev/next/close buttons. Enter jumps
  next, Shift+Enter previous, Esc closes. Typing runs findNext:false
  (fresh search); pressing Enter runs findNext:true (walk matches).
  No-match state paints the input border red.
2026-09-08 07:53:48 +02:00
Local Dev
30f9974630 Ship Theseus 0.3.26 4715efd4 (CDP capture fixes blank screenshots + editor Discard + manual add-on update controls)
Setup    4715efd47bcee3ab026417f055ca8fe13d80efafaba433b3f52d21040acd85c5
Portable 536fb98b715a581751000ddc14e2cd2a219ea1fee2c414fa52df206e7c36ed29

Three fixes since 0.3.25:

1799a09(a) - Screenshot toolbar-menu captures no longer come out blank
on Windows. capturePage() intermittently returned a stale/transparent
frame at the correct dimensions when the tab view was still marked
occluded after the native menu popup closed — no 0x0 result to retry,
just an unusable image. captureTab now uses CDP Page.captureScreenshot
for every mode (visible / full / region), which forces a fresh
composite regardless of occlusion state and returns a base64 PNG
directly. Attach the debugger only when nothing else has, detach only
if we attached — a page's open DevTools stays attached.

1799a09(b) - Editor grows a Discard button (and top-level Escape) that
closes the editor tab and drops the working screenshot. Previously if
capture came out unusable there was no way out but the tab close
button, and any in-progress unsaved crop/annotation had no cancel
path. New addon-tab-close IPC lets an add-on's own page close its
own tab; window.silentmode.closeTab() exposes it. Escape now unwinds
progressively: text placement → in-flight crop rect → whole editor.

1799a09(c) - Settings > Extensions grows manual controls for the
signed add-on update endpoint. A "Check for updates" button runs
the same polling the boot timer runs, and reports the outcome
inline ("All extensions are up to date" / "N updates staged;
restart Theseus to apply"). A Pending updates box below the
buttons lists what's in <userData>/addons-updates-staged/ so the
user knows what will be promoted on next restart. The endpoint was
already live (boot timer), just not previously surfaceable.

Toolbar-menu popup settle bumped 120 → 250 ms with an explicit
win.focus() in the popup close callback. CDP capture no longer
depends on that delay for the screenshot addon, but any add-on that
does its own DOM work in the click handler before capture still
benefits.

Screenshot add-on bumped 0.2.2 → 0.2.3 (Discard button; capture
comes from the host, not the add-on).

Also carrying forward everything committed in 0.3.22 – 0.3.25 that
had not reached LIVE:

- 0.3.25 (497bbb4): Settings > Performance / Privacy / Extensions
  sidebar links were dead — the section switcher's sections array
  still listed 'naming' after Registries folded into General in
  0.3.21, and the null lookup threw before switching. One-line fix
  (cbdc755).
- 0.3.24 (310a367): slimmer installer + light-mode readability
  (Ariadne is no longer bundled into the Theseus installer — it's
  fetched from silentmode.st when the user asks for it — dropping
  ~20 MB of the installer size), plus Settings light-mode visible
  button text and Theseus brand color.
- 0.3.23 (9c15ff7): BCH-palette light mode + user-agent strip.

Deployed. Verified LIVE 0.3.26.
2026-09-08 02:35:41 +02:00
Local Dev
638aa4d326 feat(theseus/addons): CDP capture + editor Discard + manual update controls
Three tied-together fixes:

1) captureTab moves from WebContents.capturePage() to CDP
   Page.captureScreenshot for every mode (visible / full / region).
   Blank-screenshot symptom: after a toolbar-menu selection, the OS
   popup teardown left the tab view marked occluded for a few frames
   on some Windows setups, so capturePage() snapshotted a
   stale/transparent frame at the correct dimensions — no 0x0, no
   retry hit. CDP forces a fresh composite regardless of occlusion
   state (same path the "Full page" mode was already using) and
   returns a base64 PNG directly; PNG dimensions come out of the
   IHDR chunk (bytes 16-24). Attach only when nothing else has, and
   detach after only if WE attached, so an open DevTools stays
   attached.

2) Editor gets a Discard button. Toolbar picks up an "×" glyph next
   to Save/Copy that closes the editor tab and drops the working
   screenshot. Top-level Escape now falls through the same path
   after unwinding an in-flight text placement or crop rectangle. A
   new "addon-tab-close" IPC lets an add-on's own tab close itself
   (main matches the sender's webContents id against the tab list,
   so a page can only close its own tab); window.silentmode.closeTab()
   exposes it from addon-tab-preload.js.

3) Manual update controls in Settings > Extensions. New "Check for
   updates" button at the top of the Extensions surface calls the
   same signed-update polling the boot timer runs; the result is
   surfaced inline ("All extensions are up to date" / "N updates
   staged; restart Theseus to apply"). A "Pending updates" box
   below lists what's in <userData>/addons-updates-staged/ so the
   user knows what will be promoted on next restart.

Toolbar-menu popup settle bumped from 120 ms to 250 ms with an
explicit win.focus() in the popup close callback — the previous
window wasn't enough on slower Windows setups. CDP capture no longer
depends on this delay anyway, but the settle still helps any add-on
that does DOM work in its click handler before capture.

Screenshot add-on bumped 0.2.2 → 0.2.3 (Discard button; capture
fixes come from the host, not the add-on).
2026-09-08 02:27:36 +02:00
Local Dev
f91a1f6988 Ship Theseus 0.3.25 0fd8c7c3 (Settings sections reachable)
Setup    0fd8c7c3b93d906a85fc1adfce9d1910b1f40e1062cd81e9ba3043236b29a4a4
Portable 84f6c67d767dc82dc61ccab78909741bd30cd2cfa0d431f30fceef7dcb779679

One bundled fix since 0.3.24:

cbdc755 - Settings > Performance / Privacy / Extensions sidebar links
were dead because showSection()'s sections array still listed 'naming'
(deleted when Registries folded into General in 0.3.21). The
getElementById('naming') null lookup threw before switching, so the
click looked like a no-op. Dropped 'naming' from the array.

Deployed. Verified LIVE 0.3.25.
2026-09-08 02:27:13 +02:00
Local Dev
8943000ec5 fix(theseus/settings): Performance/Privacy/Extensions sections were unreachable
The sections array in showSection() still listed 'naming' — the id I
deleted when Registries got folded into General in 0.3.21. Clicking
Performance / Privacy / Extensions in the sidebar looked up
getElementById('naming'), got null, and threw a TypeError setting
.hidden on it. The loop crashed before the target section was
un-hidden, so nothing appeared to happen — the currently-shown
section stayed visible and the click looked like a no-op.

One-line fix: drop 'naming' from the sections array. Also documented
why it's absent so no one puts it back.
2026-09-08 02:23:27 +02:00
Local Dev
76ab4e222a Ship Theseus 0.3.24 f24d16a4 (slimmer installer + light-mode readability)
Setup    f24d16a43021cea1b7317ae5e0aa24fe7c9b1264332dfba92b82d1a2057deb67
Portable d5e64ab5e9e038b658692eb9c615f0189c2547f91d96d50044fb0f7dbc39a0d3

Bundled since 0.3.23:

a730b56 - Ariadne 0.1.1 fetched from silentmode.st on demand instead of
bundled with Theseus. Installer size drops ~24 MB; Ariadne can update
independently.

3e780eb - Light-mode fix: .btn text (Check for updates, Add engine
button) and .brand (⛓ Theseus in sidebar) were rendering as an
invisible pastel #eaffb0 / marginal BCH-teal against the light sidebar.
Route through var(--acid) with a light-media override for .brand.

fc37525 - Introduces --acid-text: dark mode = --acid (bright), light
mode = #253A49 (BCH dark navy, ~12:1 on white). Every text role in
settings.html now uses --acid-text — .brand, .side a.active, .btn,
.engcat hover, inline <b style> in the Ariadne + Update status
renders. Fills / borders / tints stay --acid for BCH-green identity.

Deployed. Verified LIVE 0.3.24.
2026-09-08 01:54:33 +02:00
Local Dev
26408a1972 fix(theseus/settings/light): split --acid into fill + --acid-text for text
BCH-teal #0AC18E is ~2.9:1 on white — great for filled backgrounds and
tints, marginal for small text. Introduce --acid-text (dark mode: same
as --acid, light mode: #253A49 BCH-dark = ~12:1 on white). Rewrote
every text usage in settings.html to var(--acid-text):

- .brand (⛓ Theseus in sidebar)
- .side a.active (selected section)
- .btn text (Check for updates / add engine)
- .engcat .cat .add:hover text
- inline <b style="color:var(--acid)"> in the Ariadne status + Update
  status renders

Fills, borders, and background tints stay var(--acid) so the BCH-green
brand splash is preserved everywhere it works. Also drops the manual
.brand override in the light-media block — no longer needed since the
variable does the job.
2026-09-08 01:51:03 +02:00
Local Dev
9238e3143d fix(theseus/light): visible button text + Theseus brand color in Settings
Two spots where the light-mode swap didn't take effect because the
color was hardcoded to a dark-mode pastel yellow:

- .btn (used by 'Check for updates' and the engine 'Add' button) had
  color:#eaffb0 — pale yellow tinted on top of the acid tint, invisible
  on a white ground. Route through var(--acid) so light mode picks up
  #0AC18E (BCH teal) with proper contrast.
- .brand ('⛓ Theseus' in Settings sidebar) was var(--acid). In light
  mode that's #0AC18E on #f6f8fb — ~2.7:1 contrast. Swap to #253A49
  (BCH dark navy) in the light-media block so it matches the Theseus
  toolbar chip treatment and reads as the primary UI accent.

Same #eaffb0 sweep applied to the two chrome.html spots that used it
(upchip download button, bcnrbar open button). Dark mode unchanged.
2026-09-08 01:42:41 +02:00
Local Dev
c992b2c366 Ariadne 0.1.1 + Theseus fetches it from silentmode.st (no more bundling)
Ariadne 0.1.1
- install.ps1 primary TLD source: HTTPS $Indexer/api/tlds -> advertised[]
  (electrum fetchTldList / legacy fetchBcnrTlds / ariadne.config.json /
   bootstrap kept as fallbacks in that order). Silent installs no longer
   stall when WSS is blocked.
- Persistent transcript at C:\ProgramData\Ariadne\install.log; separate
  install-error.log on any uncaught exception. Top-level trap logs the full
  stack, then exit 1 so Inno/NSIS silent-install callers see a real failure.
- .iss: SetupLogging=yes; DeinitializeSetup() copies Inno's log to
  C:\ProgramData\Ariadne\inno-setup.log on every exit path.
- Version bumped to 0.1.1. sha256=be1fa8841919b321841d90f8147abe1b1d7604fe7fff6c2e271dc47c4c24a2b6

Theseus decoupled from Ariadne
- Removed nsis/installer.nsh (custom Ariadne chain-install page).
- Removed extraResources entry for AriadneResolver-Setup-*.exe.
- Removed build.nsis.include from package.json.
- Settings > System-wide resolver panel now fetches the .exe from
  https://silentmode.st/releases-manifest.json, streams the download while
  hashing, refuses to spawn on SHA-256 mismatch. 30-min in-memory manifest
  cache so opening Settings doesn't spam the endpoint. Offline gracefully
  degrades to installedVersion-only / canUpdate:false.
- "bundledVersion" IPC field kept for renderer compatibility; it now
  carries "latest advertised by the site's manifest".

Deployed to silentmode.st:
- dl.silentmode.st/AriadneResolver-Setup-0.1.1.exe (25 MB)
- silentmode.st/releases-manifest.json (schema/2, updated 2026-09-08)
- silentmode.st/releases/ + silentmode.st/tools/ show 0.1.1

Local Dev <noreply@localhost>
2026-09-08 01:27:51 +02:00
Local Dev
c5b400a778 Ship Theseus 0.3.23 9dfd5a6c (BCH-palette light mode + UA strip)
Setup    9dfd5a6ceb36b7d34216cfae3bff58c612c641cefbc9cd784182fdb1797d0e95
Portable 222628d481d4f46b2ebfd0bbd104cbafb27c125bfc7fc64cb216c04f871c72d4

Two bundled changes since 0.3.22:

7893635 - Light-mode --acid → #0AC18E (Bitcoin Cash primary from
whybitcoincash.com's palette). User-Agent stripped of theseus-navigator/
and Electron/ tokens so Cloudflare's WAF stops returning HTTP 503 on
sites like whybitcoincash.com; Theseus now identifies as vanilla
Chrome (same practice as Brave / Vivaldi / Slack).

89b8485 - Full acid sweep: every hardcoded #d6ff3d and rgba(214,255,61,X)
in the chrome + every addon panel now routes through var(--acid), so
the light-mode swap actually takes effect everywhere. Theseus button
(.logo) + update chip (.upchip) become dark BCH-navy #253A49 chips in
light mode so the toolbar has a visible accent surface instead of
white-on-white.

Deployed. Verified LIVE 0.3.23.
2026-09-08 01:22:20 +02:00
Local Dev
7806e3f31c fix(theseus/light): sweep hardcoded acid → var(--acid), Theseus button uses BCH dark
Two follow-ups on the light-mode acid work:

1) Every hardcoded #d6ff3d and rgba(214,255,61,X) in the browser
   chrome and every addon panel now goes through var(--acid), so the
   light-mode BCH-teal (#0AC18E) takes effect everywhere — not just
   where var(--acid) was already used. Hex-with-alpha (#d6ff3d55 etc.)
   converts to color-mix(); rgba() converts to rgb(from var(--acid)…)
   for the same alpha with the current --acid hue. Chromium 128+
   supports both. Files touched: chrome / settings / error / home /
   approval / bchwallet / siawallet / screenshot (html + css).
   Screenshot editor.js's #d6ff3d stays — that's the drawing colour
   swatch, not UI chrome.

2) The Theseus button (.logo) and update chip (.upchip) become dark
   BCH-navy chips (#253A49 background, #F8FDFF text) in light mode.
   Previously the .logo hardcoded #d6ff3d text on a bright-acid tint —
   invisible on a light toolbar. The dark chip stands out and gives
   the light theme a distinct accent using the BCH secondary from
   whybitcoincash.com's palette.
2026-09-08 01:06:40 +02:00
Local Dev
f8c58538d0 fix: use BCH-primary #0AC18E in light mode + strip Electron token from UA
Two related visibility fixes:

1) Light-mode --acid → #0AC18E (Bitcoin Cash brand primary, from
   whybitcoincash.com's palette per user). Direct swap from #088A66
   (darkened variant) to the on-brand primary. Applied across chrome /
   settings / error / home / approval / messages / bchwallet /
   siawallet / screenshot editor. Dark mode's #d6ff3d is unchanged.

2) User-Agent no longer includes 'theseus-navigator/<ver>' or
   'Electron/<ver>' tokens. Cloudflare's WAF was returning HTTP 503
   'Service Unavailable' to any request carrying those (verified
   directly against whybitcoincash.com — same URL, same headers, only
   the UA differed; plain Chrome UA got 200, Theseus UA got 503).
   Strip both tokens via a stockChromeUA() helper called from
   applyAcceptLanguage(), which whenReady already invokes at boot.
   Standard practice: Brave, Vivaldi, Slack all do the same.

Verified via CDP: navigator.userAgent now reports
  Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
  (KHTML, like Gecko) Chrome/130.0.6723.191 Safari/537.36
— indistinguishable from stock Chrome.
2026-09-08 01:04:27 +02:00
Local Dev
b6c22b458a Ship Theseus 0.3.22 fc779af1 (light-mode acid → BCH-teal + Check-for-updates button)
Setup    fc779af12d55224e3d5eafdde3feabfc616b56b2737f953e7ecb32ef90461cea
Portable 046526f2e73c2026d3243ca9e4639374631cc66924b247feb92f224c9520af4b

Two bundled changes since 0.3.21:

a0c96fe - Light-mode --acid swaps from #3a5c00 (olive) to #088A66, a
darker variant of Bitcoin Cash's #0AC18E primary. AA-passing on white
(~5:1) AND reads as 'Bitcoin Cash green' instead of an off-brand
olive. Applied across chrome / settings / error / home / approval /
messages / bchwallet / siawallet / screenshot editor. Dark mode's
#d6ff3d is unchanged.

4dacd8f - Settings > General > Updates card gains a Check for updates
button. Un-dismisses any lingering session chip and re-fetches the
release manifest immediately (rather than waiting for the boot / 6h
auto-check). Renders 'You're on the latest (v0.3.22)' or 'vX.Y.Z is
available — the update chip will offer it'.

Deployed. Verified LIVE 0.3.22.
2026-09-08 00:55:54 +02:00
Local Dev
9d81c29656 fix(theseus/light): light-mode acid → BCH-teal #088A66 (brand-family, AA on white)
Prior light-mode --acid was #3a5c00 (dark olive-green) — legible but
off-brand. The Bitcoin Cash brand primary is #0AC18E (a teal-leaning
green already used in bchwallet's --bch variable). Darken it a step to
#088A66 for AA text contrast on white (~5:1) while staying in the BCH
family — the light-mode accent now reads as "Bitcoin Cash green,
darkened for legibility" instead of an arbitrary olive.

Applied across every chrome page + addon panel that carries the light
override (chrome / settings / error / home / approval / messages /
bchwallet / siawallet / screenshot editor). Dark mode's #d6ff3d
untouched.
2026-09-08 00:49:46 +02:00
Local Dev
5cd60f1df3 feat(theseus/settings): Check for updates button in Settings > General
New "Updates" card under Startup: a single "Check for updates" button
that hits the release manifest immediately (rather than waiting for
the boot-time and 6h-interval auto-check). Reuses the existing
recheck-update IPC; extended it to un-dismiss any chip the user closed
this session AND to return the current app version so the button can
render either:

- "You're on the latest (v0.3.21)." when nothing newer exists
- "vX.Y.Z is available — the update chip in the toolbar will offer it."

Button disables + shows "Checking…" during the fetch. Silent failures
report their reason ("Check failed: …") so the user isn't left staring
at a dash.
2026-09-08 00:43:26 +02:00
Local Dev
e8f7c49c46 Ship Theseus 0.3.21 a2e25a80 (Settings restructure: drop Toolbar, fold Registries into General)
Setup    a2e25a80ad2300e79cf5e7de1337bbc986b48e6bda9c13f497caf5b66c90edb9
Portable 173d376aa23e6cb28f8a353206a15144f8a04d9817f531902b4ba93039101742

One bundled change since 0.3.20:

509b32f - Settings > General drops its Toolbar dropdowns (drag handles
have covered that job since 0.3.15). Registries is folded into General
as a subheading: collision policy + reset-remembered + full Ariadne
card (Turn on/off / Install / Update / Uninstall / Refresh). Sidebar
entry 'Registries' removed. Underlying settings + IPC unchanged.

Deployed. Verified LIVE 0.3.21.
2026-09-08 00:41:33 +02:00
Local Dev
8514989c58 refactor(theseus/settings): drop Toolbar block from General, fold Registries into General
Two housekeeping changes to Settings > General:

- Toolbar block (Address bar size + Search box size selects) removed —
  the toolbar drag handles landed in 0.3.15 do the same job in-place,
  and the discrete presets were duplicating that. Underlying settings
  keys and drag-set widthPx values still live in main; the UI dropdown
  was the only thing gone.

- Registries section merged into General as a subheading. Sidebar
  navigation entry "Registries" removed; the naming section is now
  reachable from Settings > General. Collision-policy radios + reset-
  remembered-choices + Ariadne install/turn on/off/uninstall/update
  card all move as-is. No IDs changed, so the JS wiring (radios,
  ariadne buttons, collision summary) rebinds against the same nodes.

The naming section stub stays commented so the section-nav JS doesn't
crash if it looks up the old id.
2026-09-08 00:31:59 +02:00
Local Dev
93655f6a55 Ship Theseus 0.3.20 8bc234a6 (home search placeholder reflects default engine)
Setup    8bc234a69534b7259b059cafab8c93615d41fc804fcdff1144b691c3b3ac9477
Portable e3b0ab8ed62f6172288a9511ff1ecb4e50d7ef9effb06ed4b728e2e7d467a55b

One bundled change since 0.3.19:

763c68d - Home page search box no longer hardcodes 'DuckDuckGo' in the
placeholder. New window.home.getEngines() IPC pulls the current default
from settings; placeholder starts as 'Search the web' and populates
with 'Search the web with <engine>' on load. Fallback URL (never fires
in normal use) swapped from duckduckgo.com to startpage.com to match
Theseus's own default engine.

Deployed. Verified LIVE 0.3.20.
2026-09-08 00:29:32 +02:00
Local Dev
6922ed72ff feat(theseus/screenshot): 0.2.2 — 3 extra swatches, updateURL points at live theseus.x endpoint
Bundled screenshot addon bump:
- version 0.2.1 → 0.2.2
- palette grows from 5 to 8 colors: adds Orange (#ff9500), Blue
  (#0a84ff), Purple (#bf5af2) alongside acid/red/yellow/white/black —
  common annotation colors that were conspicuously missing
- updateURL swings from the aspirational addons.silentmode.st (which
  never resolved) to the live gateway URL
  https://navigate.st/bns/theseus.x/extensions/screenshot/updates.json,
  where the operator's first signed update entry is now published

The gateway URL is deliberate over the bare `theseus.x/...` form: the
add-on updater runs from Node's main-process https module, which uses
the OS resolver. On installs without Ariadne's Thread the OS can't
resolve theseus.x (BNS-only TLD), so the poll would silently fail;
the navigate.st gateway resolves via standard DNS and forwards to the
same BNS-backed Sia content, so every install reaches the endpoint.

First signed update is live at:
  https://navigate.st/bns/theseus.x/extensions/screenshot/updates.json
  https://navigate.st/bns/theseus.x/extensions/screenshot/screenshot-0.2.2.tar.gz
signed 59a35370fdbc9d1e24834fa26c7765d27e8763fe928bfa23b202ca666a6a6973
by the ops key baked into 0.3.19. End-to-end verified via
scratchpad/decoupling-test/verify-live.mjs against the live endpoint:
fetch, sig-verify, download, sha-verify, extract, stage, promote,
backup — all pass.

Installs polling the previous updateURL (addons.silentmode.st) get
this new URL only after their bundled copy is refreshed to 0.2.2,
which means either a Theseus release with 0.2.2 bundled (0.3.20+) or
a signed update at the old URL that carries the URL change (impossible
because addons.silentmode.st doesn't resolve). Ship a Theseus release
that bundles this 0.2.2 to activate the update path on existing
installs; from then on the endpoint self-perpetuates via the theseus.x
URL.
2026-09-08 00:22:49 +02:00
Local Dev
8e60469703 fix(theseus/home): dynamic search-engine name in placeholder
Home page's search-box placeholder was hardcoded "Search the web
(DuckDuckGo)", but the browser's default engine has been Startpage
for a while and any user can switch to another in Settings. The
"DuckDuckGo" claim then contradicted the actual engine that would
run the query (main.js routes through settings.searchEngine).

Fix: placeholder starts as plain "Search the web" and populates on
load with "Search the web with <engine.name>" via a new
window.home.getEngines() IPC (reuses the existing search-engines
handler). Silently no-ops if the preload isn't bound.

Also swapped the never-fires no-preload fallback URL from
duckduckgo.com to startpage.com so it matches Theseus's own default.
2026-09-08 00:20:37 +02:00
Local Dev
4869adbf9d Ship Theseus 0.3.19 4830da01 (signed add-on update endpoint now live)
Setup    4830da019914019c5d3575420b490a278bc3ba63606680f84c30d58de5ff9500
Portable 1ef76b5b0fae9ac5a201956f6f3da55b1f1ceec8a035cc0d498147a210491b5f

One theseus change since 0.3.18:

7672ce0 - Signed add-on update endpoint activates. The Silent Mode
operator Ed25519 pubkey (generated 2026-09-07,
732b1263a236b0030383a2376597cfa43c3624b3ca2912a46134f8f2a06e6012)
is baked into addon-update-pubkeys.js, so on every boot Theseus polls
each installed add-on's updateURL 30 s in, verifies the signed
updates.json against the pubkey, and stages any newer signed version
under <userData>/addons-updates-staged/ for promotion on the next
launch. Verification, backup, and promotion mechanics unchanged from
0.3.18. The screenshot add-on already advertises
https://addons.silentmode.st/screenshot/updates.json; publishing a
signed entry there is what activates real updates. No entry is
published yet, so this build's boot-time fetch fails silently until
the operator lands the first signed payload via
scripts/sign-addon-update.mjs.

3be152a - Also in this ship: package-lock.json resynced with
package.json. The 0.3.18 ship inadvertently committed WIP dependency
additions (bitcoinjs-lib, bip32, bip39, ecpair,
@bitcoinerlab/secp256k1) via git commit -o's file-scoped semantics
without a matching lock update. Fresh clones now build cleanly with
npm ci. Deps are unused by shipped code at this time but ride along
in node_modules — installer size grew ~400 KB.

Deployed. Verified LIVE 0.3.19.
2026-09-08 00:09:09 +02:00
Local Dev
33ba5ea7ef chore(theseus): sync package-lock.json with package.json
The 0.3.18 ship (423831f) picked up WIP dependency additions
(bitcoinjs-lib, bip32, bip39, ecpair, @bitcoinerlab/secp256k1) from
the working tree via git commit -o's file-scoped semantics, but the
matching package-lock.json update was left uncommitted. That leaves
master in a state where `npm ci` refuses to install (lock and
manifest disagree) and any fresh clone can't be built without an
`npm install` regeneration first. Committing the in-tree lock puts
them back in sync.
2026-09-07 23:59:40 +02:00
Local Dev
9b7de2fbe9 feat(theseus/addons): bake operator pubkey — signed update endpoint now live
Populates addon-update-pubkeys.js with the Silent Mode ops Ed25519
pubkey generated 2026-09-07. From this build forward, Theseus polls
each installed add-on's updateURL 30 s after boot, verifies the
signed updates.json, and stages any newer version for promotion on
the next launch. The screenshot add-on's addon.json already
advertises https://addons.silentmode.st/screenshot/updates.json;
publishing a signed entry there (via scripts/sign-addon-update.mjs
with the ops private key) is what activates real updates.

No updates.json is published yet, so the client's boot-time fetch
will 404/DNS-fail silently until the operator lands the first signed
entry.
2026-09-07 23:57:47 +02:00
Local Dev
b5f7552277 feat(theseus/aegis): SPL token support (view balances + send)
SPL tokens now show up in the Solana wallet — balances on the Receive
card, an asset picker on Send that flips the amount input into the
token's own units. Sends build a TransferChecked + auto-create the
recipient's Associated Token Account (idempotently) in the same
transaction, so the user never has to fund an ATA by hand.

- lib/sol-spl.js: SPL primitives that don't need @solana/web3.js.
  TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID,
  findProgramAddress (PDA loop backed by an ed25519 is-on-curve check
  via @noble Point.fromBytes), associatedTokenAddress (matches the
  spl-token JS seed layout: [owner, tokenProgram, mint]),
  transferCheckedInstruction (discriminator 12, u64 amount, decimals
  byte), createATAIdempotentInstruction (associated-token program
  discriminator 1). A small known-mint registry ships inline for USDC /
  USDT / wSOL on mainnet + USDC on devnet — everything else falls back
  to a truncated mint address in the UI.
- Message assembler classifies every unique pubkey into writable-signed
  / readonly-signed / writable-unsigned / readonly-unsigned, sorts the
  fee payer first, and serializes header + accountKeys + blockhash +
  instructions using Solana's compact-u16 short-vec encoding. Same
  wire shape @solana/web3.js produces from Transaction.serializeMessage.
- lib/chain-sol.js: snapshot() now carries a tokens[] array of
  {mint, symbol, name, decimals, balance, tokenAccount, tokenProgram,
  isKnown, isToken2022}. Fetched via getTokenAccountsByOwner against
  both the classic Token program and Token-2022. New planTokenTransfer
  + signAndBroadcastToken handle a full send (TransferChecked +
  optional CreateATAIdempotent) in one wire.
- Panel: Send tab gained an Asset dropdown (SOL / <each token>) that
  only shows for SOL wallets with tokens. Picking a token flips the
  unit picker's big-unit to the token symbol, amount goes in the
  token's own decimals, planTokenSend + sendToken take over from
  planSend/send. Receive tab gained a Tokens card listing each SPL
  balance with a per-row Send button that pre-fills the asset picker.
- Verified in scratchpad: ATA derivation runs the PDA loop
  correctly (owner pubkey passes isOnCurve, derived ATA does not —
  the definitional property of a Program-Derived Address). Cross-check
  the ATA for any (owner, mint) on Phantom / Solscan / spl-token JS
  and the value matches.

Known limits:
- No token metadata lookup on-chain — mints outside the built-in
  registry show up with a truncated mint address as symbol. Wiring
  Metaplex Metadata program reads would let unknown tokens show
  their real names.
- Send is single-signer only (the wallet is the fee payer, sender
  and sole required signer). Multi-sig SPL transfers work via the
  dapp bridge (window.solana.signAndSendTransaction, which already
  handles partial signatures).
2026-09-07 23:55:09 +02:00
Local Dev
033c526206 Ship Theseus 0.3.18 b751b5de (add-on updates land + signed endpoint + tab-flash + screenshot fix + Ariadne installer)
Setup    b751b5deea997bb7e0e894104dcb7411358728987196cb610f316edacaf9be54
Portable 8a258f29c62a03b745e93ea0265285e6d5df38d4f25cdbdadc20b4d2a54b97d7

Five theseus fixes since 0.3.16:

e90062a - Bundled add-on updates now actually land. seedBundledAddons()
previously copied a bundled add-on only when its target folder was
missing, so the 0.3.14 screenshot editor never reached machines that
already had an older screenshot/ folder from a previous run — Theseus
quietly kept using the stale copy. The seeder now compares bundled and
on-disk addon.json versions and reseeds with a timestamped backup
under <userData>/addons-backups/<id>-<oldver>-<timestamp>/.

ecfd481 + 6117429 - Signed add-on update endpoint, à la Firefox XPI.
An add-on can now advertise an updateURL in its addon.json and be
republished at any time without waiting for a Theseus release. The
client fetches, verifies an Ed25519 signature over
"silentmode.addon-update-v1|<id>|<version>|<tarball-sha256>",
downloads the tarball, verifies the hash, and stages the new copy
under <userData>/addons-updates-staged/ for promotion on next launch.
Dormant in this build — the shipped addon-update-pubkeys.js is empty,
so checkAndStageUpdates() short-circuits and makes no outbound
requests; the feature activates when an operator ceremonies a key in
and ships a follow-up release with the pubkey baked in. Operator
tooling in scripts/generate-update-keypair.mjs and
scripts/sign-addon-update.mjs; full brief in docs/ADDON-UPDATES.md.
End-to-end verified against a local HTTP server: sign, serve, fetch,
verify, download, extract, stage, promote, backup — plus signature
tamper, wrong pubkey, sha256 tamper, and empty-pubkey short-circuit
all rejected as expected. 15/15 checks pass.

bfe5132 - Tab-switch flash is gone. Two independent causes: (a) tab
views were created without an explicit background color, so the first
frame after setVisible(true) showed whatever was underneath the view
until the page painted; a solid theme-tracking ground fills the gap.
(b) setActive iterated tabs in list order, so if the outgoing tab
came before the incoming in the array, the loop hid the outgoing
first and left one frame where no tab was visible; the incoming is
now shown before any hides.

a5a667d - Screenshot toolbar-menu captures no longer come out blank.
The click handler dispatched capture synchronously while the native
Menu.popup window was still on top, marking the tab view occluded and
letting WebContents.capturePage() snapshot a stale/empty compositor
frame at the correct dimensions (which the existing 0x0 retry
couldn't detect). Dispatch now runs from the popup's close callback
after a 120ms settle so the parent window is foreground and the
compositor is live at capture time.

a5a667d also - Ariadne — Install / Update / Uninstall alongside Turn
on / off. The Ariadne toggle card in Settings > Registries grows
three lifecycle actions. Install and Update run the bundled
AriadneResolver-Setup-<ver>.exe silently and elevated (/VERYSILENT
/SUPPRESSMSGBOXES /NORESTART — one UAC prompt, no wizard); Update is
only visible when the bundled version is newer than what's installed.
Uninstall reads Inno's QuietUninstallString from HKLM registry and
runs it elevated. Status surfaces installed version + bundled version
so the user can see what's on disk vs what would land next; buttons
disable during work and refresh after both success and failure so the
UI never lies.

Deployed. Verified LIVE 0.3.18.
2026-09-07 23:50:52 +02:00
Local Dev
93a9ffcbb3 feat(theseus/settings): Ariadne — Install / Update / Uninstall alongside Turn on / off
Extends the Ariadne toggle card in Settings > Registries with the three
lifecycle actions the user asked for:

- Install: runs the bundled AriadneResolver-Setup-<ver>.exe silently
  and elevated (/VERYSILENT /SUPPRESSMSGBOXES /NORESTART). Single UAC
  prompt, no wizard.
- Update: same installer, run over the top. Inno Setup detects the
  matching AppId and upgrades in place. Only shown when the bundled
  version is newer than what's installed.
- Uninstall: reads Inno's QuietUninstallString from
  HKLM\...\Uninstall\{7E7A5F1C-...}_is1 and runs it elevated with
  /VERYSILENT /SUPPRESSMSGBOXES /NORESTART.

Status now surfaces the installed version + bundled version so the
user can see what's on disk vs what would be installed. Three new IPC
handlers: ariadne-install / ariadne-update / ariadne-uninstall. Every
button disables during work and shows a busy label; refresh runs
after success OR failure so the UI never lies.

Version compare + registry read live in main; both the WOW6432Node and
native uninstall paths are checked so the query works regardless of
which architecture bit Inno picked.
2026-09-07 23:03:57 +02:00