Setup b08530a69d47c2525a2238bd35542d141c4cf2be09f61f7b6d9bb08166f606cf
Portable b67387c85f6d37df2d2c2055a1773954a2e9019d3d567943d8ed5a39e9ee53a9
One bundled fix since 0.3.10:
beca0fa - A ResizeObserver on .bar sets data-responsive to one of four
levels based on width. CSS reacts: search box auto-hides at level 1,
Theseus button collapses to just the gear icon at level 2, and the
extension dock folds into a single 🧩 puzzle button opening a dropdown
of installed extensions at level 3. User's explicit Address bar /
Search box size settings still win at wide widths.
Deployed. Verified LIVE 0.3.11.
A ResizeObserver on .bar sets data-responsive to one of four levels
based on width, and CSS reacts:
0 (>=1050px) wide — everything visible (default)
1 ( >=820px) tight — auto-hide the search box, URL min-width drops
2 ( >=620px) narrow — Theseus button collapses to just the gear
3 ( <) xnarrow — extension dock collapses to a single 🧩 button
that opens a dropdown listing every registered
panel (icon + name), click to open the sidebar
Puzzle dropdown reuses the same open/close pattern as the existing
bookmarks menu — click outside to dismiss, click a row to open (or
close if it's already the active panel). User's explicit
Settings > Address bar size / Search box size still win when the
toolbar is wide enough for them; responsive collapse only forces
extra hides at the tighter widths.
Verified on a running instance across 5 widths (1200/900/700/500/400):
each breakpoint flips exactly the elements it should.
Setup d9801fe6a1ea7d54132db36b2c78311cd5c77912618687fb9cf6476ce75a97f9
Portable ff6ea386752fb3ceeb9d5f385258a6f01f7266c2509f4670419ce6e44e24d442
One bundled fix since 0.3.9:
d1f3347 - The brand acid green (#d6ff3d) was ~1.3:1 contrast on
#ffffff / #f6f8fb, so it went nearly invisible any time the user
flipped Settings > Theme to Light. Every chrome page (chrome, home,
settings, error, approval, messages) now overrides --acid to #4d7300
in its prefers-color-scheme: light block — same hue family, ~5.5:1
on white. Also added the missing --acid: #d6ff3d declaration to
chrome.html's :root (was relying on var(--acid, #d6ff3d) fallbacks,
so the light override couldn't bind). Verified live via CDP.
Deployed: scp + sia-upload of both trees. Verified LIVE 0.3.10.
Two background tasks in progress (screenshot extension, Aegis
multiwallet + Tron/Nile) will land in a later release.
#d6ff3d on a #ffffff / #f6f8fb background sits at ~1.3:1 contrast — the
acid green went almost invisible any time the user flipped Settings >
Theme to light. Override --acid to #4d7300 in every chrome page's
prefers-color-scheme: light block. Same hue family, ~5.5:1 contrast
on white, still reads as the same brand color.
Also: chrome.html was missing --acid: #d6ff3d in :root entirely (every
site used var(--acid, #d6ff3d) fallbacks). Adding the real declaration
means the light override can actually take effect.
Files touched: chrome.html, home.html, settings.html, error.html,
approval.html, messages.html. downloads.html is a dark-only overlay
(hardcoded), collision.html already had a proper light-mode --bcdn.
Tint fills (rgba(214,255,61,X) at low alpha) stay as-is — the specific
hue barely matters through 8% opacity.
Verified live via CDP: getComputedStyle(--acid) returned #d6ff3d in
dark, #4d7300 after cfg.set('theme','light').
Setup cc676e62057b42c1e1221f0e9b69a55806bab90259bbbb4e6eb64701ab3d420a
Portable 1ab811f7edba74220b452763ee0f3329ba91d84c834d3e38be6426de0b04f1c7
Two changes since 0.3.8:
f1d117e - .extbtn was display:grid, which is block-level, so multiple
extension buttons inside #extbuttons stacked vertically. Switch to
inline-grid — same icon-centering, no forced line break between
siblings. Verified on a running instance: all 4 dock buttons at the
same y-coordinate.
(this commit) - Remove the static Aegis ₿ placeholder button and its
handler. Redundant now that the real bchwallet addon ships in the box
and registers its own dock entry. Also flip the dock-hidden logic to
disappear entirely on a fresh install with no add-ons registered, so
the toolbar doesn't carry an empty slot for users who never install
one.
Deployed: scp + sia-upload of both trees. Verified LIVE 0.3.9.
.extbtn had display:grid, which is block-level by default. Multiple
buttons inside #extbuttons stacked vertically because each was a block.
Switch to inline-grid — same centering behaviour for the icon inside
the button, no forced line break between siblings. Verified on a
running instance: all 4 buttons render at the same y-coordinate with
strictly increasing x.
Second bundled wallet, same shape as bchwallet:
- keys: api.vault.derive("siawallet/mainnet/0") as the seed for walletd's
KeyFromSeed(seed, index) (blake2b(seed||index) -> ed25519); addresses are
standard unlock hashes, so a future walletd seed import yields the same
addresses. Seed and keys live in memory only.
- lib/sia.js: Sia binary encoder, StandardUnlockHash, address checksum,
v2 InputSigHash ("sia/sig/input|" + replay byte 2 + transaction
semantics), transaction weight, walletd JSON. Address hashing and the
sighash were verified against real mainnet v2 transactions (signatures
from block 591853 verify under this implementation).
- lib/walletd.js: address-scoped walletd HTTP client (tip, fee, balance,
outputs with proofs, events, broadcast). The node URL is a user setting
with no default; hosted providers embed the access key in the path, so
only the origin is ever displayed or logged.
- lib/wallet.js: gap-limit discovery via events, mature/immature balance,
history deltas from v1/v2/foundation/miner events, largest-first
selection with change to the current address, fee = walletd rate x
weight x 1-3 multiplier, broadcast with the outputs' basis. A signed tx
built here was accepted structurally by a live walletd (rejected only
for the stub key not owning the parent).
- panel: Receive (QR), Send, History, Settings (node URL, derivation info,
seed reveal behind approval, connected sites); gates for locked vault,
no vault, no node URL.
- window.siacoin dapp bridge: getAddress (rememberable), signAndSend with
100/1,000/10,000 SC allowances, signMessage (ed25519 over blake2b-256 of
the message) — same approval and permission rules as the BCH wallet.
Setup b2b7819e7a5f1ae1aa7ac79dd8e150f7c11f238eb3ab98a53fae51186dd4dc5b
Portable c971931f380245e44064720b132859917039488c12e0f654a2eeb406cf465d37
Bundled fixes since 0.3.7:
b649398 - User-resizable address bar + search box. Settings > Appearance >
Toolbar now offers urlBarSize (wide/medium/compact) and searchBoxSize
(hidden/compact/normal/wide). Applied as data-attrs on .bar so the flex
basis of .urlwrap and the width of .searchbox swap live. Motivation:
the per-extension dock (0.3.7) needs room to grow as users install more.
Settings-set broadcasts settings-update to chrome so resizing is instant
without a relaunch.
ab87576 - F12 / Ctrl+Shift+I opens Chromium DevTools on the active tab
in a detached window. Wired in the same before-input-event handler that
owns reload / sidebar shortcuts. Always targets the active tab
regardless of which view received the keystroke.
Deployed: scp + sia-upload of both trees. Verified LIVE 0.3.8.
VPS archive step 7: 0.3.6 pair moved to Sia dl-archive/, only 0.3.7 +
0.3.8 remain on /opt/silent-mode/dl/ (per shipping-mirrors memory).
Two new settings under Settings > Appearance > Toolbar:
urlBarSize: wide (default) | medium | compact
searchBoxSize: hidden | compact | normal (default) | wide
Applied as data-attrs on the .bar element in chrome.html; CSS switches
the flex-basis of .urlwrap and the width of .searchbox. min-width on
.urlwrap guards against squeezing the URL invisible.
Settings-set now broadcasts settings-update to the chrome renderer, so
resizing takes effect live without a relaunch. Same channel is exposed
for future chrome-side settings.
Motivation: the extension dock grew a per-addon button per install, and
the URL bar (flex:1) had been eating all the remaining space. Users who
want more room for extensions can now shrink or hide the search box and
cap the URL bar width.
The packaged build stripped the native app menu, which took Chromium's
default DevTools accelerators with it. Wire the two everyone expects —
F12 and Ctrl+Shift+I — in the same before-input-event handler that
already owns reload / sidebar shortcuts. Always target the active tab
regardless of which view received the keystroke (chrome, overlay, tab)
so debugging is consistent with every other browser. Detach mode keeps
the tools out of the tab strip.
Setup 37fd8db5388cc2486b48d282bf38e1d5b18a40de5b7319950edcc412f3ddb683
Portable befab4c21ef78d7c92eb7d399e163d3e53e202a0bda9fe95f8d8db916db2e242
Bundled fixes since 0.3.6:
1026b08 - Per-extension toolbar dock: replaces the single sidebarbtn with
one button per registered addon sidebar-panel. Notepad (📝) and Silent
Mode Relay (🌐) appear automatically from their manifest icons; a static
Aegis Wallet placeholder (₿) marks the upcoming built-in BCH wallet.
Click a live button → open the sidebar on that panel, click active →
collapse. Preload adds openSidebar(panelId) / closeSidebar() wrappers.
622aaee - Right-click "Search for '<selection>'" in the page context
menu. Uses SEARCH() so it honours the current default engine, opens in
a new foreground tab, and truncates the label at 40 chars.
Deployed: scp + sia-upload of both trees. Verified LIVE 0.3.7.
Ops note: silentmode.st /var/log had grown to 6GB (journal + rotated
syslog), which broke the first portable upload. Vacuumed journal to
500M cap; ~5.9G free after cleanup. Old Theseus builds not touched.
Replaces the single sidebarbtn with a dock that renders one button per
registered addon sidebar-panel. Each button shows the panel's icon
(the emoji from its manifest) and opens the sidebar on that panel.
Clicking the currently-active button collapses the sidebar; clicking a
different one swaps the visible panel. Notepad (📝) and Silent Mode
Relay (🌐) appear automatically because they already register panels.
Also lands a static Aegis Wallet placeholder button (₿) next to the
live ones, styled as .soon so it reads as coming-soon. It'll come out
once the addon registers a real panel.
Preload adds openSidebar(panelId) and closeSidebar() wrappers around
the existing sidebar-open / sidebar-close IPC handlers.
The dapp send approval gains an "Afterwards" dropdown: ask every time, or
allow up to 0.001 / 0.01 / 0.1 BCH more without asking. The allowance is
stored as permissions[origin].sendTx {capSats, usedSats}; sends within the
remainder go through silently and draw it down, a larger request re-prompts
(showing what is left) and the choice made there replaces the allowance.
No unlimited option. Settings > Connected sites shows the remaining budget
and Revoke clears it. Message signing still asks every time.
Host: approvalModal accepts `select` {id, label, options}; a chosen value
comes back as "+<id>=<value>" and is validated against the offered options.
Adds a "Search for '<selection>'" item to the page context menu when
the user right-clicks with text selected. Uses SEARCH() so it honours
whichever engine the user has picked (Startpage default, or their own
via the picker), opens in a new foreground tab so the current page
isn't lost, and truncates the label at 40 chars so a long selection
doesn't stretch the menu. Ampersands in the label are doubled so
Chromium doesn't eat them as accelerator markers.
wallet-inject.js runs in the isolated world of https://*.x pages and exposes
window.bitcoincash { isTheseus, version, network, getAddress, signAndSend,
signMessage }. Every call is routed page -> addon-page-msg -> activate()
handler -> approval overlay showing the requesting origin:
- getAddress: approval with an "always allow" checkbox; grants persist in
api.storage.permissions and are listed/revocable under Settings.
- signAndSend / signMessage: approval on every call, never remembered.
signMessage returns a BIP-137 recoverable signature (verified offline).
- one pending approval per origin; page-facing errors never echo balance.
Host fix: the inject IPC assigned event.returnValue twice, so pages always
got an empty script list.
Send tab: recipient (cashaddr or legacy, testnet rejected), amount with
BCH/sat toggle and Max, 1-5 sat/B fee slider, live fee/total preview via
planSend. Sending goes plan -> approval-modal (To/Amount/Fee/Total) ->
ECDSA DER + SIGHASH_ALL|FORKID -> blockchain.transaction.broadcast, then
shows the txid with an explorer link. Confirmed coins are spent before
unconfirmed; dust change folds into the fee. Verified end to end against a
fake Fulcrum: broadcast tx re-parsed, sighash recomputed, signature checks.
Manifest declaring sidebar-panel, vault-derive, page-inject (https://*.x)
and approval-modal; registers the Wallet sidebar panel. Shows up in
Settings > Extensions and opens from the sidebar.
Three opt-in capabilities for add-ons, plus the plumbing they need:
- vault-derive: api.vault.derive("<id>/<path>") resolves once the password
vault is unlocked with a 32-byte HKDF child of the vault root under
"silentmode/addons/<path>". Path must start with the add-on id.
- page-inject: manifest "page-inject" {preload, origins}; a session-wide
preload asks main (sync, against the committed URL) which add-on bridges
apply and runs them in the isolated world with a scoped `theseus` object.
- approval-modal: api.approvalModal({title, body, origin, rows, actions,
checkbox}) shows a consent overlay over the tab area (approval.html);
resolves to the picked action id, "cancel", or "<id>+<checkbox>".
- api.onMessage/emit + window.silentmode.invoke/on for panel <-> activate()
messaging; page bridges use addon-page-msg, gated by tab + origin match.
- api.require so add-ons can share Theseus's dependency tree.
Setup e2a30a3b280448f8eb6e08efd21e208022b2a37cef14a72076b3f32b7a2fc529
Portable eca7cf3347a958307b8e2ba4f6266c81f8ec691b0c98ed6e24fdd70e65723b1e
Bundled fixes since 0.3.5:
d3c3298 - Chrome-view gap root cause: body no longer inherits the chrome
view's height, so document.body.scrollHeight now measures actual content
and syncHeight can shrink chrome back after a menu close. The growing
blank strip above the page is gone (was previously ratcheting to the
260px clamp on every menu open).
1b4a3c3 - Bookmarks: favicons on every row (backfilled on revisit for
older entries) + Edit title actually works via an in-page modal (Electron
BrowserViews disable window.prompt, which is why the previous menu item
silently did nothing).
952bf5f - Tab tooltip on hover shows title + URL, the way Chrome/Firefox
do it. Uses the url field already present in the per-tab payload.
f591475 - Error page gets a first-class "You appear to be offline" kind
that fires when navigator.onLine is false — no more false "not registered"
verdicts when you're just disconnected. Plus a "did you mean" row that
suggests near-match BCNR names (Levenshtein ≤ 2, same TLD) from the warm
shared index — no network required, works offline. Click a suggestion
to retry with the original path preserved.
b9d70e4 - 750ms self-heal on chrome-view height as belt-and-suspenders
for any future overlay path that bypasses closeAllMenus.
Deployed: scp + sia-upload of both trees. Verified LIVE 0.3.6.
Every .tab now carries a native title="<title>\n<url>" so hovering the
tab shows the page's own title and the URL (the way Chrome/Firefox do
it). Uses the url already present in the per-tab payload emitTabs sends;
no extra IPC.
Two bugs the user hit:
1) Edit title silently did nothing. window.prompt is disabled in
Electron BrowserView contexts, so prompt() returned null and the
round-trip remove-then-re-add never fired. Built an in-chrome
modal (.promptmask/.promptbox) that resolves to the trimmed
string on OK/Enter or null on Cancel/Escape/mask-click, and
swapped the ctx-menu Edit action to use it. Added a real
bookmark-update IPC (title + optional favicon merge) so the edit
no longer round-trips through remove/add — same URL, just the
title changes.
2) Bookmarks had no favicon. The bookmark data model was {title,url}
only, and the row template had no icon slot. Extended:
- Renderer tracks current.favicon from onTabs's active tab.
- Star click and ctx "Add current page" pass favicon along.
- main persists a favicon field (capped 2KB) and emits it.
- Row template shows the favicon (14×14) with an onerror
fallback so a broken data:/URL doesn't leave a broken glyph.
- Backfill: when a currently-open URL matches a stale bookmark
without favicon, the render pass patches it once via
updateBookmark. Stops itself the next render.
Older bookmarks.json files stay valid — no schema migration needed;
missing favicon just renders the empty placeholder slot.
The 750ms self-heal (b9d70e4) was a bandage. Real root cause: body had
height:100vh, so document.body.scrollHeight always equalled the chrome
view's current height (which IS the viewport). Once a menu grew chrome
via growChromeForMenu, syncHeight measured the inflated body and re-sent
the same big number — CHROME_H never shrank back.
Fix: drop height:100vh so body sizes to its content. scrollHeight becomes
the natural chrome height, and menu-close paths correctly report a value
smaller than the current CHROME_H. The self-heal stays in as insurance
for any future overlay that bypasses closeAllMenus.
Bar layout unchanged — every bar has an intrinsic height (.tabs 34px,
.bookmarks 26px, .bar auto), so body flow reflects them naturally.
overflow:hidden stays to clip any pathological overflow.
Two problems bundled into the branded error page:
1) "fetch failed" on no network — the tab kept falling through to
name-not-registered (and other "we asked and got nothing" verdicts)
because a totally offline browser can't reach the beacon to know.
Add a first-class `offline` kind that runs before every other
verdict: navigator.onLine === false wins; the page says "You appear
to be offline" and keeps the address so the user can Retry after
reconnecting.
2) Typos on BCNR names (games.x when they meant game.x) — the page
only offered Search / Register. Now the page asks main for the top
near-matches from the warm sharedIndex (Levenshtein ≤ 2, same TLD)
over an origin-gated `error-bns-similar` IPC. Up to three matches
render as chip-links; clicking one retries at that host, preserving
the original path. Works offline too — the index is local.
Origin-gate on the IPC uses the existing isErrorPageSender check, and
error-preload.js exposes only the invoke — no arbitrary index access.
The onTabs / onNav re-sync catches the common menu-close path, but a menu
that gets orphaned by a drag interruption, a focus flip, or a submenu
race can leave the chrome view taller than the natural body-scrollHeight
until the next tabs/nav event fires. Symptom: a huge blank strip between
the address bar and the page that grows and doesn't shrink until the tab
changes.
Fix: a 750ms interval that re-runs syncHeight whenever no .ctxmenu /
.grouppop is present. setChromeHeight in main.js only re-layouts when
the value actually changes, so this is a cheap no-op in the steady state.
Holding the ship: will bundle with the next batch per the slower-cadence
policy. Users on 0.3.5 keep the existing gap fix; this one lands with
the next release.
Setup 935d637ae19ea821f7e89b0f9a802b4e774b6d1ae3254a70f3e5f17f89424177
Portable bb6bea253d6f32f86e8fdd152cf4c969cf311c991329d5e94fce31215ecf7f00
Chrome-view height gap: any tabs event that fires while no menu/popover
is open now normalises the chrome-view height via syncHeight(). A leaked
menu-close path could previously leave the strip inflated; the next
tabs update guarantees it shrinks back to the natural body-scrollHeight.
Tab-group drag-and-drop: group chips are now valid drop targets in the
same drag session as tab reorder. Dragging any tab onto a chip and
dropping assigns that tab to the chip's group (which also auto-clusters
it via the existing tab-group handler in main). Chip highlights acid
green while a valid drop hovers.
Collapsed group vertical popover: click a collapsed group chip and a
floating panel opens below it, listing every tab in the group. Each
row shows the favicon + title + a ✕ to close that tab. Clicking a row
switches to the tab AND expands the group so the newly-active tab
appears in the strip (tabGroupToggle). Popover closes on outside click
or Escape; the outside-click filter also ignores clicks inside .gchip
so opening the popover doesn't immediately close it.
growChromeForMenu() and closeAllMenus() now include .grouppop in their
overlay queries so the popover contributes to chrome-view sizing and
gets cleaned up alongside the ctxmenus.
Deployed: scp + sia-upload of both trees. Verified LIVE 0.3.5.
Setup 3d6d3d6aeacf482284707f50d129315d07a593e09b5d68af852abe5aa0ed4c92
Portable 6c8c5ef212bfccb377e17404e83a18cf2f09771d0eb3e0ec86a85587efdcfc9e
Three address-bar suggestion fixes.
Per-row ✕ delete on hover. Clicks on the X call address-forget instead
of address-pick; the row disappears optimistically in the picker and
main drops the entry from history + persists. Sender-URL gated to the
picker's own file:// origin.
Enter with a highlighted suggestion now navigates to THAT url. The
URL input handler tracks a pickerHasCursor flag that flips true on
ArrowDown/ArrowUp and false on any input; Enter with cursor forwards
to the picker's own submit path via addressCursor("enter") — before
this fix, Enter always ran goURL against the typed letters, which
submitted them as a web search instead of opening the selected url.
Address bar reliably shows the picked URL. onAddressPicked now arms
an overrideUrlBarUntil = now+1500ms flag; the onTabs handler treats
that window as "force write the url", bypassing the focus-guard that
was leaving the bar blank when blur() hadn't landed yet.
Deployed: scp + sia-upload of both trees, verified LIVE 0.3.4.
Setup e016d66543976b7a4df5ac16033319d59cb0f418e54d7e838ef16de274525a83
Portable b9881a62c39ecfe22644611f5aa16a48f32f97f9ec5751b5888ccbd870338c3e
Three 0.3.2 misses fixed:
Tab context menu was clipped by the chrome view's fixed height — the
menu rendered with position:fixed inside a WebContentsView whose
bottom edge stops at CHROME_H, so items below the tab strip weren't
visible. New growChromeForMenu() measures every open menu's bounding
box and calls T.setChromeHeight(needed) so main.js grows the chrome
view to fit; closeAllMenus() calls syncHeight() to restore.
Bookmarks bar was hidden on every tab except Home, so Add-to-
Bookmarks had no on-screen feedback. Now always visible.
Tab groups now actually cluster. Assigning a color to a tab moves it
adjacent to its group-mates in the tabs array (main-side splice, no
render-only trick). The chrome renderer inserts a colored group chip
before the first tab of each group; clicking the chip toggles a
per-group collapsed state (in-memory, resets on relaunch). Collapsed
groups hide their member tabs and the chip shows the member count.
Expanded groups keep the per-tab top color stripe from 0.3.2 so the
cluster reads as one visual block.
Deployed: scp + sia-upload, verified LIVE 0.3.3 on dl.silentmode.st.
Setup 09331b2fd9ccf136e2183b7cd85354cfd56e2ed50260b7aadeed63c7ea450251
Portable 21752d0fc85fb39ec1e65192920461e9ae395a22d9a68abd27f12e638d0fdd07
Right-click a tab: floating context menu with Reload, Duplicate, Group
(submenu: None / Red / Orange / Yellow / Green / Cyan / Blue / Purple),
Add to Bookmarks, Mute (also Unmute; 🔇 shows next to the title when
muted), Close. Menus close on outside click or Escape.
Group state is per-tab. A grouped tab shows a colored dot before the
title and a matching 2-px accent stripe on the top edge, so a cluster
of same-group tabs reads visually. Palette is drawn from existing
provenance colors (err/warn/acid/srv/sia/blue).
Backend IPCs are all tab-scoped (not "active tab"): tab-reload,
tab-duplicate, tab-mute (toggle or explicit boolean), tab-group,
tab-bookmark. emitTabs payload gains muted, group, and url so the
menu can read current state.
Installer wizard branding: 164×314 sidebar BMP with the compass mark
centered + "Theseus / NAVIGATOR" wordmark under it, plus a 150×57
top-strip header with a mini compass on the right. Sharp can't write
BMP directly (only png/webp/etc), so nsis/make-icons.mjs renders raw
RGB via sharp and wraps it in a hand-rolled 24-bit uncompressed BMP
header. Uninstaller reuses the same sidebar.
Silent-install fix: nsis/installer.nsh's AriadnePageCreate now checks
IfSilent BEFORE touching nsDialogs::Create. In /S mode the flag is
zeroed and the function returns cleanly, so the installer no longer
hangs waiting for a page it will never draw. This is why 0.3.2 needed
two builds — the first hung on /S install; the fixed hash is the one
that ships.
Deployed: scp + sia-upload of both trees. Verified VPS hash matches
local 09331b2f. Fresh /S install to D:\Program Files\Theseus Navigator\
placed 0.3.2 with the correct HKCU Uninstall registry entry.
Setup fe59105d2e99a41b7000caeb86601a8e1675846d193e92204034669f5b368d60
Portable 1b6eda55b53894cf9889548116c7b6100888fb160edc84cc1592bb79f9d95b53
The update flow no longer asks the user to click Download. When
checkForUpdate detects a newer version, autoDownloadUpdate() kicks off
session.defaultSession.downloadURL against the setup URL immediately.
will-download recognises the update URL and routes the file to a
fixed %TEMP% path (bypassing the visible downloads panel entirely),
streams updateDownloadReceived/Total into the chip via
emitUpdateAvailable, and flips updateDownloadState to "ready" when
the transfer finishes.
Chip states:
idle first render before the fetch starts — clickable to
trigger the manual download (kept as a fallback).
downloading "↓ 42% — 0.3.2" — no click, just progress.
ready "✓ Install 0.3.2 & restart" — one click.
failed fall back to the pre-0.3.1 explicit-download click.
install-update-now IPC: spawns the cached setup with /S (detached,
stdio ignored), then app.quit() 400ms later so the installer can
overwrite the running exe. Our nsis/installer.nsh detects an existing
Ariadne install via the HKLM registry and skips its Ariadne prompt on
upgrades, so the /S run is fully unattended.
The one-click flow eliminates two long-standing sources of confusion:
- "Download opens a different browser" — Theseus's default session
fetches the installer itself, not a URL handoff to shell.
- "Update requires multiple wizard clicks" — /S skips them.
Extensions aren't touched by this. The framework lives in
addons-host.js + sidebar-preload.js; add-ons themselves live in
%APPDATA%\Theseus Navigator\addons\<id>\ and are a separate layer.
New extensions ship by drop-a-folder, no browser release required.
Deployed: scp + sia-upload, verified 200 + 0.3.1 in the manifest.
Setup bb9d8dec124b8e2a976642ed77051b04edd1d03185581f99db845ef168919836
Portable 1e2d02aea13656574c374440b0c41374290f1bbf85ac6313cec075292cfc34f8
Home cards decoupled from the installer. Theseus now fetches
https://dl.silentmode.st/home-cards.json at boot and every 6h, caches
into <userData>/home-cards-remote.json, and applies it as the default
tier. Priority in loadHomeCards() is:
1. <userData>/home-cards.json (user edits — unchanged, always win)
2. <userData>/home-cards-remote.json (last successful fetch)
3. DEFAULT_HOME_CARDS (code fallback for offline first-boot)
On a successful refresh, main pushes the new list to every home tab
via the home-cards IPC — but only when the user has NO local edits.
The user's edit mode remains authoritative.
Content updates now happen by editing site/home-cards.json and running
scp + sia-upload. No browser build required.
Prometheus.X copy fix: "Decentralized App Marketplace" (was
"marketplace for BCDN-hosted apps" — the marketplace isn't BCDN-
specific). Applied to both DEFAULT_HOME_CARDS (fallback) and
site/home-cards.json (canonical live copy).
Deployed:
- scp installers + manifest + tools/ + releases/ + home-cards.json
to /opt/silent-mode/dl/ and /opt/silent-mode/site/
- sia-upload of both site trees
- verified home-cards.json served 200, manifest 0.3.0 live
Existing installs of 0.2.5 will surface 0.3.0 in the update chip and
also pull the new home-cards.json — so the "Decentralized App
Marketplace" wording lands on ANY current install (0.3.0+) the moment
this commit deploys, without waiting for anyone to install 0.3.0.
Wait — 0.3.0 is what CARRIES the fetch logic. So the auto-pull benefit
only kicks in from 0.3.0 onward. Users on 0.2.5 or earlier need to
install 0.3.0 once; from then on every home-card edit reaches them
without a new browser release.
Setup 50be20d6e3811445817e35c560dce1a4bbcc62004d6b0480848a211a654319ea
Portable 021afe629c61f2f49e95f936261649bdcff58c8b79bd0d903a8d10e6009740b0
Home page card grid gets a brand pass. Each title's TLD suffix (.X,
.bch, ...) is now styled in acid (--acid) with a soft text-shadow
glow. styledTitle() splits the domain on the last dot so capital
labels like "Theseus.X" render as ink + acid.
Card copy tightened per name:
hello.bch A small page on the blockchain itself.
siatest.bch A page with no server, backed by Sia.
SilentMode.X Infrastructure development for a decentralized web.
Theseus.X The Web Navigator - this browser's own address.
Sirius.X Register and manage BCDN names.
Hephaestus.X The forge - Silent Mode's code host.
Prometheus.X An app store - a marketplace for BCDN-hosted apps.
Helios.X Search engine for the decentralized web (in design).
Hermes.X Messaging - end-to-end encrypted over Nostr.
Badges: dropped the generic ".x" tag; each .X card carries its role
label instead. Palette assigns each role a distinct hue drawn from
the existing provenance colors, so the grid reads as families without
adding new brand values:
Infrastructure / Registrar acid
Navigator blue
Code host sia purple
App store srv teal
Search warn amber
Messaging err coral
Descriptions brighten from --mut to --ink on card hover so the ink
color reads as the "acid touch" the user asked for without adding
literal green blocks to every card.
Deployed: scp installers + manifest + tools/ + releases/ pages to VPS,
sia-upload of both trees, verified HEAD 200 + manifest 0.2.5.
Setup 7fd323a87bd32b780e147de18e16ecd82f89960bbd8e9a619c5d25d374597cd2
Portable 3166e64cf56badd7b26c4c793dc79bbed6f9d6c48fbd467d97f845385b91b1dd
Home cards: DEFAULT_HOME_CARDS replaced with the .x sibling grid the
user asked for -- hello.bch, siatest.bch (the "types of BCDN" pair),
then silentmode.x / theseus.x / sirius.x / hephaestus.x /
prometheus.x / helios.x / hermes.x. Existing installs with a saved
home-cards.json keep their edits (defaults only seed fresh profiles).
Search engine picker sync: user reported the toolbar dropdown listed
engines as active that Settings > Search showed differently. Root
cause: settings.searchEngine could be pointing at an id not in the
currently-enabled set (stale settings.json after DEFAULT_ENABLED
changes across versions). loadSettings now normalizes on boot -- if
searchEngine isn't enabled, fall back to enabled[0]; and
installedEngines gets unioned with enabledEngines so the two lists
can't disagree in ways that make toolbar and Settings render
different rows.
Proxy auth support in the framework: setSessionProxy accepts
`{ proxyRules, auth: { username, password } }` or an inline
`socks5://user:pass@host:port` URL. When creds are present, the
handler strips them from the URL, installs a session#login listener
on the default session that answers with them, then calls setProxy.
Chromium's SOCKS5 client doesn't consume proxy auth (known Chromium
limitation), but HTTP proxies work; SOCKS-based extensions need to
gate by IP allowlist at their server. Log line masks the password.
Update chip note: the "download opens in a different browser" was
0.2.0-era behavior. 0.2.1 rewired it to session.downloadURL. Anyone
still seeing it needs to install 0.2.1+ once.
Deployed: scp + sia-upload both trees, verified HEAD 200 + manifest
0.2.4 live.
Setup 3abaeff73afcecc9e4f05f749765e168a97a377890211dbae4345654c84ce2f1
Portable 71017563d6ba107cb25e24be240abcb78e34491d8f7aa42e095421edbc482a85
Brand: the red-N compass from theseus.x is now the taskbar / titlebar /
File Explorer icon everywhere. Source SVG lives at
site-theseus-x/assets/favicon.svg so brand + browser icon stay in sync.
nsis/make-icons.mjs renders it to build/icon.png (512x512) and
build/icon.ico (multi-resolution: 16/24/32/48/64/128/256). Wired into
package.json: build.win.icon, build.nsis.installerIcon + uninstaller
+ header; the ico ships as an extraResource so main.js's BrowserWindow
also uses it at runtime. Icons live in build/ which is gitignored -
run `node nsis/make-icons.mjs` when the SVG changes.
Sidebar: multi-panel picker strip. When 2+ extensions register sidebar
panels, sidebar-preload.js injects a 32-px tab strip at the top of
every panel's document. Click a tab -> ipcRenderer sidebar-open ->
loadFile switch. Preload also injects box-sizing:border-box + a
33-px body padding so height:100% panels don't overflow. Solo-panel
case is unchanged (strip only appears when panels.length >= 2).
Search: Startpage is the new default. Both the default id and the
enabled-list ordering put it first. DDG stays enabled by default too.
Deploy: scp installers + manifest + tools/ + releases/ to VPS,
sia-upload of both trees, verified HEAD 200 and manifest 0.2.3.
Icons regenerated from theseus.x's favicon.svg; the .svg itself
shipped in the 0.1.x window when the theseus.x site went live.
Setup 972f6209639122f32f032d5f2f9fc5a4808e0d4a810f88ae38ec9a1275ac52ac
Portable a9771f054ec36b9aff6ddee958cecf7e84cdacd4d7932aa8385c445aab4d29be
User-visible rename: the Settings tab and its labels say "Extensions"
now instead of "Add-ons". Internal identifiers (disabledAddons, the
addons/ folder, IPC channels, capability strings) stay put — code
churn wasn't worth it, and users only see the user-facing text.
Draggable sidebar. sidebar-preload.js now injects a 5px grip strip
along the LEFT edge of every panel document. mousedown+mousemove
streams delta-x px to main via sidebar-drag IPC; main clamps to
[200, 800] and debounces a save to settings.sidebarWidth. Width is
restored on next launch. The default is still 340. Faint acid-green
highlight on hover so the affordance is discoverable.
New extension capability: session-proxy. An extension whose addon.json
declares "session-proxy" gets api.setSessionProxy(rules) which routes
to session.defaultSession.setProxy — the same primitive Tor already
uses under the hood. Rules can be a string ("socks5://host:port") or
an object matching Electron's setProxy shape; null clears. The
capability is opt-in: an extension without the declaration gets an
error if it tries to call setSessionProxy. This is the framework
surface a private 3-VPS relay extension would build on (extension
folder stays on the operator's disk only; nothing about it appears in
the public build).
Deployed: scp installers + manifest + tools/ + releases/ pages to
VPS, sia-upload of both trees, verified HEAD 200 and manifest 0.2.2.
Setup 67e3cda1b76a6dba966d91a43e78fdb52378f860c0f75a7775d11b96e1b4f5e3
Portable 415c804f75df6fab5072650fbdc3cffa4124ed02f8ff53a91281ebd2dc4775c3
Update chip: the Download button used to hand the URL to the system
browser (shell.openExternal) - user opens Theseus, gets prompted to
update, clicks Download, watches ANOTHER browser wake up and start
the transfer. That's the "why did a different browser open?" report.
Fix: session.defaultSession.downloadURL(url) - triggers the same
will-download handler our own downloads panel already listens on, so
the file lands in the user's Downloads folder AND appears in
Theseus's downloads chip with progress + Show-in-folder. Rejected
protocols unchanged; only dl.silentmode.st and silentmode.st URLs
survive the allowlist.
Ctrl+B toggles the add-on sidebar (matches VS Code). Verified end-
to-end against a fresh <userData>: bundled Notepad was seeded,
Ctrl+B opened its panel, typed text autosaved to
<userData>/addons-data/notepad.json, restart re-mounted and the
text loaded back before the append could clobber it.
Deployed: scp installers + manifest + tools/ + releases/ to VPS,
sia-upload of both trees, verified HEAD 200 and manifest 0.2.1.
Setup c5202ddba5a4bf4cd8d71c665c72bdd996ced761f9a7aae295cb960e17988f47
Portable 9142764f78e41c6a6220960d5f7278e0abe6c1c91e5033871d95225355d8feda
0.1.x -> 0.2.x — two new subsystems land together. 0.1.3 (which had
only the error pages) is retired; those hashes never went live, so
we jump 0.1.2 -> 0.2.0 for clean version->hash 1:1.
Add-on framework:
- Discovery scans <userData>/addons/<id>/; each add-on carries an
addon.json manifest and an activate(api) CommonJS entry. Nothing
about a private add-on ships in the public build - drop the
folder, restart, it's live.
- Bundled 'Notepad' reference add-on ships in resources/bundled-addons/
and is seeded into the user's addons dir on first boot. Right-
sidebar textarea, autosave, char/word counter.
- Extension point in this rev: sidebar-panel (WebContentsView on the
right, SIDEBAR_W=340). Toolbar toggle appears only when at least
one add-on registers a panel.
- Settings gains an Add-ons tab: list installed, per-add-on enable/
disable toggle (settings.disabledAddons persists), Show folder /
Open add-ons folder / Reload buttons, trust-model warning.
- Origin-gated per-addon storage: main derives the add-on id from the
sender file:// URL, so a panel can only touch its own kv store
under <userData>/addons-data/<id>.json.
Branded error page:
- did-fail-load on every tab -> error.html with kind = name-not-
registered (BCNR host + ERR_NAME_NOT_RESOLVED) | name-unreachable
(non-BCNR host + NAME_NOT_RESOLVED) | unreachable (conn refused/
reset/timeout) | tls (cert range) | generic.
- Actions per kind: Retry + Home always; Search for '<host>' and
Register-on-Sirius where a host is present; Tor guide link on
unreachable.
- Address bar keeps the failed URL (refreshTabUrl already skips
file://) so the user can edit and retry.
- Ignorable codes (-3 ABORTED, -20 BLOCKED_BY_CLIENT, subframe
errors, internalNav) skipped so normal user actions don't paint
an error page.
Deployed:
- scp installers + manifest + tools/ + releases/ pages to VPS
- sia-upload of ../site (silentmode.bch) and ../site-theseus-x
- verified HEAD 200, manifest reads 0.2.0 2026-08-31
Existing 0.0.6/0.1.2 installs will surface 0.2.0 in the update chip
on next launch.
New subsystem for extending Theseus with folders on disk. Each add-on
lives at <userData>/addons/<id>/ with an addon.json manifest and a
CommonJS entry that exports activate(api). Nothing about a private
add-on ships in the public installer - drop the folder, restart, it's
live. Bundled reference add-ons ride in the packaged app under
resources/bundled-addons/ and are seeded into <userData>/addons/ on
first boot; the framework treats seeded and drop-in add-ons the same.
Files:
- addons-host.js Loader + api.registerSidebarPanel() + per-
addon storage on <userData>/addons-data/.
Kept at the CommonJS-scoped top level (lib/
is ESM-scoped via its own package.json).
- sidebar-preload.js Runs in every sidebar panel. Exposes
window.silentmode.storage.{get,set,all} +
onVisibility. Main-side handlers derive the
add-on id from the sender file:// URL, so a
panel can only touch its own store.
- bundled-addons/notepad/ Reference add-on: addon.json, index.js,
note.html. Autosaving textarea with char /
word count.
main.js:
- Extension point: sidebar-panel. One right-anchored WebContentsView
(SIDEBAR_W=340) hosts the current panel; layout() shrinks the tab
views by the sidebar width when visible. First registered panel
wins for MVP; picker for multiple panels lands later.
- initAddons() at app.whenReady(): seedBundledAddons, then
AddonHost.discoverAndActivate.
- IPC surface: sidebar-toggle / sidebar-open / sidebar-close /
sidebar-state, addons-list / addons-set-enabled / addons-reveal /
addons-open-dir / addons-reload, and origin-gated
addon-storage-get/set/all.
- Settings gains `disabledAddons: []` — off-toggled ids persist and
the loader honours them without a restart (discoverAndActivate
runs again on toggle).
chrome.html: toolbar sidebar-toggle button, hidden until at least one
add-on has registered a sidebar panel.
settings.html: new "Add-ons" section under privacy. Lists installed
add-ons with icon / name / version / description / capabilities;
per-add-on enable/disable toggle + Show folder button; page-level
Reload and Open add-ons folder buttons; warning note about the trust
model.
package.json: build.files gains sidebar-preload.js + addons-host.js.
extraResources gains bundled-addons/ so the packaged app carries the
reference notepad for the first-boot seed.
Verified: `npm start` boots, addons-host discovers the notepad,
activates it, registers one sidebar panel. Log confirms
"1 installed, 1 enabled, 1 sidebar panels". Actual sidebar rendering
+ notepad UI need clicked-through validation on a real install.
Not shipped yet - deploy still blocked on the fail2ban VPS SSH ban.
Ships as 0.2.0 once SSH clears (this is a new subsystem, not a fix).
Setup f2afc14efc63008cbb9dad44176e94146386db4c0afda4459f1d4eb929172b6d
Portable 5d08b1415526934db8de780949a610896064fe9567aa0e5e1702ebabd7eb7df2
Chromium's default 'This site can't be reached' replaced with a Theseus-
themed error page. did-fail-load on every tab's webContents (main frame
only, non-ignorable code) routes the tab to error.html with the
attempt URL, host, error code, and description as query params. The
page keeps t.url pointing at the failed URL so the address bar shows
what the user typed and they can edit + retry - refreshTabUrl's
existing file:// skip means the error page's own path never leaks
back into the bar.
Five kinds, chosen by pickErrorKind(code, host):
name-not-registered BCNR-eligible host + ERR_NAME_NOT_RESOLVED.
Says "no BCDN record on chain, no clearnet host
either." Offers Register on Sirius + Search +
Retry + Home.
name-unreachable ERR_NAME_NOT_RESOLVED on a non-BCNR host. DNS
failed - offers Retry + Search + Register +
Home.
unreachable CONN_REFUSED/RESET/TIMED_OUT/CLOSED/NETWORK_CHANGED.
Offers Retry + Tor guide + Home.
tls ERR_CERT_* range (-200..-299). Offers Retry +
Home.
generic Everything else.
home-preload.js gains `window.errorpage` alongside `window.home`. Both
APIs are sender-URL-gated in main - a random page seeing the shape
can't invoke them (isErrorPageSender / isHomePageSender). The external-
open handler additionally allowlists Silent Mode domains only.
package.json build.files gets error.html + error-preload.js so
electron-builder actually bundles them (GOTCHAS rule: an unlisted
runtime-loaded file silently opens blank).
Ship pages (releases-manifest.json, tools/index.html, releases/index.html,
site-theseus-x/index.html) updated to 0.1.3 with the new hashes.
DEPLOY STATUS - blocked on VPS SSH: my IP was hit with a full-port ban
mid-turn (likely fail2ban from the burst of scp during the 0.1.0-0.1.2
iterations). Site pages/manifest/installers are committed locally but
NOT yet on dl.silentmode.st or the Sia mirror. Live still reads 0.1.2.
User needs to unban 195.184.247.106 on their end, or wait for the ban
to expire, before the ship pages match reality.
Setup b8cc85ec0f70844e4ce14a70b0ff89b9d9720be2f0e5568e56c51ecef706b14d
Portable 6540b4c67906046cd2c5303a9ccaa4e00a39b3daa5792b71e16c4f141f498220
Copy-only change to the installer's Ariadne page: names the mechanism
BCDN — Bitcoin Cash Domain Names — in the body text instead of listing
example TLDs. Reads more clearly to a first-time visitor who might not
know that ".bch" and ".x" are the same registry.
Everything else from 0.1.1 rides along: dedicated wizard-page checkbox
for Ariadne's Thread (pre-checked, skipped on upgrades), uninstall
symmetry, Startpage POST-form fix.
Deployed: scp installers + manifest + site pages to VPS, sia-upload of
both trees, verified 200 + manifest 0.1.2 2026-08-31.
Setup 2a2784943006b0c4f52e22cc2ec51a43e8007497d90da022798e739d83f805f0
Portable 1d9cfa6467d66604ef2f672969afdc288f46608913c35658f9c7466820ab01df
Ariadne install UX: promoted from an end-of-install MessageBox popup to
a dedicated wizard page. nsis/installer.nsh replaces the MessageBox
customInstall with a `Page custom` (nsDialogs) that shows FIRST in the
install flow (electron-builder's INCLUDE hook is placed above its own
MUI_PAGE_* inserts and NSIS processes page directives in file order —
that is the earliest hook we have without editing the template).
Framed as "Options" so it reads naturally as a preamble.
The page:
Header: "Optional add-ons"
Body: A 4-line explanation of Ariadne's Thread and the trade-off.
Checkbox: "Install Ariadne's Thread (recommended)" — pre-checked.
Footer: Notes the UAC prompt and that Theseus install continues.
Skipped entirely (Abort) if Ariadne is already installed. State is
saved from AriadnePageLeave into $InstallAriadneFlag; customInstall
runs the chain-installer iff BST_CHECKED.
Uninstall side unchanged (still MessageBox — a full custom uninstall
page would be overkill for one Y/N during a rare event).
Also carries 1e5d670: don't re-route same-origin navigations through
navigateTab. Was silently breaking every site whose in-page form
POSTs — Startpage's search box submits to /do/search via POST, and
navigateTab -> loadURL always GETs, dropping the body. Same-origin
navigations now stay on Chromium's native path.
Deployed: scp + sia-upload of both trees. Verified HEAD 200 on the
installer, live manifest reads 0.1.1 2026-08-31, VPS hashes match.
0.1.0 (never deployed for long — same-day iteration) is preserved
in _prev/ for rollback.
Startpage's in-page search form POSTs to /do/search. Our will-navigate
rewriter was calling navigateTab(id, url) which loads via loadURL(url)
- always a GET, no body. So the second search from within Startpage
always landed on /do/search with no query and no results.
Google's search form GETs, so 0.0.5's query-preservation fix was
enough for it. DDG uses history.pushState and never fires
will-navigate at all. Startpage POSTs, so it needs a different fix:
just don't intercept.
Only intercept CROSS-ORIGIN navigations for BCNR re-lookup. A form
submit or subpage link on the current site (same hostname) belongs to
Chromium natively - the site is already loaded from clearnet, its
subsequent navigation stays on clearnet. Preserves POST bodies for
every site, not just Startpage: any login form, comment submit, or
checkout flow that stayed on-origin was silently broken by the same
bug.
Setup 510f81fd5e9b4287a55817aaf5080e5d46005eecb5359eb06892040cf8d10d87
Portable 96bfb469f2d9dfe11606aa10db92febdfce73df980eec475ab285f2334925158
Bundled AriadneResolver-Setup-0.1.0.exe (9ab725be, unchanged 0.1.0)
Version 0.0.9 -> 0.1.0 marks the "Silent Mode = one install" milestone:
Theseus and the system-wide Ariadne resolver now ship together.
nsis/installer.nsh (electron-builder `nsis.include`) hooks two macros:
customInstall -- If Ariadne's Thread is NOT already installed,
MessageBox MB_YESNO|MB_DEFBUTTON1 asks whether
to install it now. On Yes, chain-invokes the
bundled Inno installer with
/VERYSILENT /SUPPRESSMSGBOXES /NORESTART
(Ariadne raises its own UAC because Inno declares
PrivilegesRequired=admin). Ariadne being present
already suppresses the prompt on upgrades.
customUnInstall -- Reads Ariadne's UninstallString from HKLM 64-bit
Uninstall\{...ARIADNERSLVR}_is1. If present,
symmetric MessageBox asks whether to remove it
too, then ExecWaits the string with the same
silent flags. Skips silently if Ariadne isn't
installed.
Registry probe uses SetRegView 64 (Ariadne installs 64-bit per
ArchitecturesInstallIn64BitMode=x64compatible in its .iss). Reset to
`lastused` after each probe to leave electron-builder's own state
unchanged.
Package changes:
- version 0.0.9 -> 0.1.0
- build.extraResources adds build/AriadneResolver-Setup-0.1.0.exe
(unpacked to $INSTDIR/resources/); build/ stays gitignored - the
binary is regenerated by copying from AriadneResolver's Inno output
- build.nsis.include -> nsis/installer.nsh
Size: installer 122 MB (+25 MB for bundled Ariadne), portable 122 MB.
Portable also carries the Ariadne exe as a side effect of extraResources
being global; portable can't invoke an installer, so the 25 MB is dead
weight there - future rev could scope extraResources per-target.
Site updates: tools page + releases page + theseus.x landing all
reflect the 0.1.0 hashes, sizes, and the new "Ariadne's Thread bundled"
line. tools page's "Coming to the Windows installer" footnote is
rewritten past tense because it landed.
Deployed:
- scp installers + releases-manifest.json to /opt/silent-mode/dl/
- scp tools/ + releases/ index pages to /opt/silent-mode/site/
- sia-upload of ../site and ../site-theseus-x
- verified HEAD 200, manifest reports 0.1.0 2026-08-31, VPS hashes
match local
Existing 0.0.6 (or newer) installs will surface 0.1.0 in the update
chip on next launch.
Setup 5452a34f211176cf04b7ea77a70fb838f0031b6ea0faed2cd270eae989b20c60
Portable ee602a016caf022452b2096ca683cf4bb4cea93ded1352192910c581a962d9ae
Version bumped 0.0.8 -> 0.0.9 because the prior 0.0.7 and 0.0.8
"Ship ..." commits (f464de6, 1a3b232, ed9ec18) never actually
deployed - the live manifest at dl.silentmode.st still served 0.0.6
until this commit. Bumping the number preserves version->hash 1:1:
this 0.0.9 is the FIRST post-0.0.6 binary that ever went public.
Cumulative content:
- 0.0.7 warm-start from bundled BNS snapshot + 30-s background delta
refresh + Sia snapshot pull on boot (first .bch page opens
near-instantly, index stays fresh while browser runs).
- 0.0.8 window.bcnr read-only dApp API on every page (resolveName,
isRegistered, getBcnrTlds, getRecordVersion). Permission
origins now scope to eTLD+1 via the Public Suffix List
(same rule Chromium uses for cookies/storage).
- 0.0.9 Address-picker paints the picked URL in the address bar
immediately (was leaving the typed prefix while the target
loaded). Reload keys wired end-to-end: F5 / Ctrl+R soft,
Ctrl+Shift+R / Ctrl+F5 hard, Shift-click the toolbar reload
does hard too.
Deployed:
- scp installers + releases-manifest.json to /opt/silent-mode/dl/
- scp tools/ + releases/ index pages to /opt/silent-mode/site/
- sia-upload of ../site to bns/silentmode/
- verified: dl.silentmode.st HEAD 200 on the installer, manifest
reports 0.0.9 2026-08-31, VPS hashes match, both silentmode.st and
silentmode.bch tools pages show 0.0.9 buttons.
Existing 0.0.6 installs will surface the update chip on next launch.
Address-picker fix:
Picking a suggestion from the address dropdown loaded the URL but
left the address bar showing the 3-4 letters the user had typed.
Root cause: onTabs's focus guard
if (document.activeElement !== $("url")) $("url").value = d.url
skipped its write while the URL input still held DOM focus, and
clicking a sibling WebContentsView doesn't always deliver the blur
to the chrome renderer in time. Fix: address-pick sends an explicit
address-picked IPC to the chrome, which force-blurs and writes the
full picked URL before the tabs event arrives.
Reload keys:
None of the standard reload accelerators worked (Menu.setApplicationMenu(null)
drops Chromium's default menu accelerators, and hard-reload was never
wired at any layer). Now:
F5 / Ctrl+R -> soft reload
Ctrl+F5 / Ctrl+Shift+R -> hard reload (reloadIgnoringCache)
Shift-click on the toolbar reload button -> hard reload
Same before-input-event hook that carries Ctrl+Shift+M; always targets
the active tab regardless of which view got the key, and skips the
Settings tab. Toolbar tooltip updated to advertise Shift-click.
Merges a parallel session's work with the multi-source BNS story from 0.0.7.
The dApp side (parallel session)
--------------------------------
* bcnr-preload.js — installs `window.bcnr` on every page via contextBridge.
Read-only surface: resolveName(name), isRegistered(name), getBcnrTlds(),
getRecordVersion(name), plus getPermissionOrigin() for diagnostics. All
Promises; a missing name returns null (not throw). No signing, no wallet
unlock — that surface is designed but deliberately out of scope for 0.0.8
(see TheseusNavigator/DESIGN-integrated-wallet.md).
* bcnr-origin.js — pure function that computes the eTLD+1 permission origin
for a URL. ICANN suffixes via `psl` (same PSL Chromium uses, handles
.co.uk / .github.io / etc); BNS names key off the on-chain TLD list so
foo.wallet becomes a public suffix as soon as `wallet` appears there.
Match browser cookie / MetaMask semantics: a grant on pay.merchant.com
covers account.merchant.com but not evil.com.
* dev/bcnr-selftest.js, dev/origin-selftest.mjs — self-tests, no I/O.
* main.js wires bcnr-preload.js into session.defaultSession.setPreloads() so
it runs BEFORE per-WebContentsView preloads; adds bcnr:* IPC handlers.
* preload.js + chrome.html — small hooks so the shell picks up window.bcnr
the same way regular content does.
* package.json — psl dep, bcnr-preload.js/bcnr-origin.js in `files`.
Also included
-------------
* AriadneResolver/mobile/.../UpdateCheck.java — in-app update-check for the
Android app; already active in the shipped 0.11 APK (build.ps1 -Recurse
picked it up), formalising the source now.
* TheseusNavigator/snapshots/bns-name-snapshot.json — refreshed bundled
starter (73 beacon txs, root c37b8596…c54e414ba).
* Site pages + manifest updated to point at 0.0.8.
TheseusNavigator-Setup-0.0.8.exe 95.4 MB
21939743eafdfe8742a6b7c4b987bd2782384d7bc41289cb80a7e08019dc9f02
TheseusNavigator-0.0.8-portable.exe 92.7 MB
2aa429fe39dc0fa4ac040fc6d6eb31b0f890c8a83175c49fcb50f052c480d39d