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).
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
Favicons:
- Each tab stores a favicon URL; wired via wc.on('page-favicon-updated')
to Electron's first-emitted icon URL. Included in the emitTabs
payload; the chrome renderer paints an <img class="fav"> in the
same slot the loading spinner uses (spinner while loading, favicon
once page-favicon-updated fires). No proactive clear on navigation
- mainstream browsers keep the old icon until the new one arrives,
which avoids a flash on every subpage click.
Cursor:
- .tab { cursor: default } instead of the previous 'grab'. Grab looked
like the page was always in the middle of a drag. .tab.dragging
keeps 'grabbing', so the grab hand only appears when the user
actually picks a tab up to reorder it.
Bumps version so the chip actually surfaces itself on 0.0.3 installs
(the version-newer check requires a strict semver bump — same-version
rebuilds don't trigger the chip). From this release on, whenever the
manifest names a newer Theseus, users get a one-click download.
Mechanism
- main.js checkForUpdate() fetches https://dl.silentmode.st/releases-
manifest.json on startup (5s timeout, cache: no-store) + every 6h.
Finds the theseus-navigator release, compares version to
app.getVersion() with a numeric a.b.c comparator that handles
"0.10.0 > 0.9.9" correctly.
- On a match → stores { version, setupUrl, portableUrl, setupHash,
portableHash, date } and emits update-available to chrome. Cleared
after the user upgrades + relaunches (same-version → null).
- Re-emits on chrome's did-finish-load in case the fetch beats the
chrome view.
Chip UI (chrome.html)
- Acid-yellow pill between the downloads button and the Tor toggle:
"↓ Update to X.Y.Z" + a ✕. Main body opens setupUrl in the system
browser via shell.openExternal (origin-validated to
https://dl.silentmode.st/ or https://silentmode.st/). ✕ dismisses
for the current session — you'll see it again next launch if still
behind.
Trust anchor
- No signing / no cryptographic verification of the download in this
phase. releases.silentmode.bch publishes the SAME manifest URL, so
users who want to verify can cross-check the manifest hash against
what BCNR returns. The proper auto-updater with signature checks is
the follow-on to this cheap version.
Non-goals in phase 1
- No delta downloads; the user clicks and gets a full installer.
- No auto-install; download → user runs the installer themselves.
- No "check now" button in Settings; the periodic timer suffices.
- No portable-vs-installed detection; the chip prefers setupUrl (the
installer upgrades in place). Right-click for portable is future work.
Six user-visible improvements + supporting infra, all uncommitted from
the earlier session-in-progress state. Ships together in one release.
Chrome / tabs
- Same-size tabs: flex 1 1 0 with max 200px, min 60px. Container gets
overflow: hidden so many tabs shrink evenly instead of scrolling out.
- Drag-and-drop tab reordering. HTML5 drag events on each .tab; drop
side chosen by pointer x within target (Chrome UX). New move-tab IPC
splices the tabs array + re-emits.
Address bar
- Persistent history at userData/history.json capped at 500 LRU. Ranked
by host-prefix > url-prefix > contains > title-contains > recency.
- Floating suggestions dropdown (addressPicker WebContentsView) anchored
under the URL bar. Debounced 80ms input; ArrowUp/Down forward to the
picker via address-cursor IPC; Enter fires goURL; blur closes after
160ms so click-through registers. New files address-picker.html +
address-picker-preload.js. Cleared by existing clearHistoryOnQuit.
Password autofill (A.2 MVP)
- Green key chip in the address bar appears when the vault is UNLOCKED
and the active tab's host has matching credentials (exact hostname
match for phase 1; eTLD+1 upgrade queued as A.2.5).
- Click chip → floating picker of usernames. Click a match → main.js
runs a small script in the active tab: finds first visible
input[type=password]:not([disabled]), walks the same form for a
visible text/email/tel/url/search input whose name/id/autocomplete
matches /username|user|email|login|account|id/, fills both via the
native value setter + dispatches input/change so React/Vue-controlled
inputs update. New files pw-fill.html + pw-fill-preload.js.
- emitPwAvailability fires from pushNav + vault setup/unlock/lock so
the chip's visibility + count stays accurate.
Bookmarks bar
- Right-click context menu on the favorites bar. On empty area:
"Add current page" (or "Remove current page" if already saved). On a
specific bookmark: "Open", "Edit title…" (prompt), "Remove", plus
the add/remove-current entry. Uses a shared .ctxmenu style mirroring
the settings ctxmenu (dark/light aware).
- Empty-state text updated to mention right-click.
Home page
- Larger responsive card grid: auto-fill minmax(260-280px, 1fr) with
breakpoints at 600/900/1200. Cards have a subtitle line, a colored
badge (on-chain / Sia / server / custom), and edit affordances that
reveal only in Edit mode.
- User-editable set: Edit toggle reveals per-card ✎/✕ + a dashed "+ Add
card" tile. Modal for add/edit with title / URL / subtitle / badge.
Reset-to-defaults button.
- Persisted at userData/home-cards.json. New home-preload.js exposes
window.home = { getCards, setCards, resetCards, navigate }. IPC
handlers in main.js validate sender.getURL() matches our own
home.html — third-party pages see the API shape via the preload but
can't act on the user's local cards.
- Fallback set of 2 cards renders when window.home is unavailable
(e.g. opening home.html directly outside Electron for preview) so
the grid is never blank.
Docs
- TheseusNavigator/ROADMAP-identity-wallet.md — the phased plan for
the two independent strands (password manager A.2/3, browser wallet
B.1-6). Committed earlier this session; re-listed here for context.
- TheseusNavigator/SESSION-PROMPT-identity-wallet.md — pastable
kickoff for the next session picking up either strand.
Files added to build.files: address-picker.html,
address-picker-preload.js, pw-fill.html, pw-fill-preload.js,
home-preload.js.
Three follow-up asks from the previous ship:
1. Shield "secure" colour bumped from #4fd1a5 (mint) to #3fb950 — the
GitHub-style saturated green, matches the +N/-N diff colour the user
pointed at as reference.
2. Engine-picker "Search settings…" now opens the Search section
directly instead of General. New IPC channel `focus-section` fires
from main after picker-open-settings, carried through
settings-preload as `onFocusSection`, and the settings.html sidebar
handler exposes showSection(sec) so any section can be focused
programmatically. Works for both a fresh settings tab (fires on
did-finish-load) and an already-open one (fires immediately).
3. Toggle no longer removes an engine from the list. Two-tier state:
INSTALLED (visible in the Settings list) and ENABLED (toggled on in
the toolbar dropdown). Toggling off keeps the row visible with an
.off class (dimmed 55%). Right-click any row → new context menu with
"Remove from list" is what actually removes an engine (built-ins go
back to the catalog, customs are dropped entirely).
Model changes:
- New settings.installedEngines persistent array (defaults to
DEFAULT_ENABLED). enabledEngines becomes a subset of installedEngines.
- isInstalled(id) helper; allEngines() carries `installed: bool` alongside
`enabled`.
- New IPC `remove-from-list` (right-click action); exposed as
removeFromList in settings-preload.
- set-engine-enabled now also INSTALLS when enabling (the catalog "+ Add"
flow), preserves installed state when disabling.
- add-engine (custom URL) auto-adds the new id to enabledEngines too.
- remove-engine (custom delete) prunes from enabledEngines as well.
- Never-empty invariant kept: enabledEngines falls back to ["duckduckgo"]
if everything gets removed.
Settings UI:
- Enabled list shows all INSTALLED engines (was: only enabled), rendered
with toggle reflecting enabled state; rows carry data-builtin so the
context menu picks the right remove IPC.
- Catalog panel and Discover-more pane filter on !installed instead of
!enabled — a toggled-off engine stays in the enabled list, not here.
- Ctxmenu is a floating .ctxmenu div; closes on outside click / Escape.
- .eng.off dims the row and mutes the name colour.
Preview harness stubs updated to include the `installed` field on every
engine + `removeFromList` and `onFocusSection` no-op stubs so
_settings-preview.html renders the new UI accurately.
BCDN pages now show https:// in the address bar (was bare 'host/', briefly bns://).
Rationale: BCNR replaces DNS (name resolution), NOT HTTP. Under the hood the
delivery IS HTTPS for s3/ip/p records; the on-chain h record has no transport
at all, but https:// is the least-surprising display. BCDN/ICANN badge is the
sole source-of-truth for which registry served us; scheme stays a convention.
Registry chip is now a proper segmented control:
- Two-chip toggle (collision candidates): single rounded pill, split in half
with a divider — active side filled (acid green for BCDN, blue for ICANN),
inactive side transparent + clickable. Feels like an on/off toggle.
- Single chip (pure ICANN or BCNR-unique TLD): standalone pill in the
registry's colour. No toggle affordance since there's no alternative.
Same acid-glow-green (#d6ff3d) and blue (#4c9eff) as the collision.html prompt
so the whole registry palette is consistent across chrome + interstitial.
Replaces the padlock in the address bar with a heraldic shield outline
that changes colour to communicate the connection state at a glance:
neutral (--dim) home / resolving — no site or pending
secure (#4fd1a5) BCDN chain-verified (kind:"ok") OR https:// clearnet
insecure (#f6768a) nxdomain / resolver error / plain http://
Single-path SVG with fill=currentColor, so state-class CSS toggles the
tint without touching the geometry. The shape matches the reference
image the user provided — flared shoulders at the top, concave flanks
tapering to a sharp bottom point (bounds x:2 y:1.2 w:12 h:13.8 in the
16x16 viewBox).
setBadge() gets one extra branch: for kind:"web" it now inspects
d.url's scheme so plain HTTP shows insecure red instead of the previous
neutral. The legacy .warn class is kept but unused by the standard
states — any lingering caller keeps working (orange).
Green/red match the download-tracker palette so the visual system stays
consistent across the toolbar.
Three UX fixes based on operator feedback (2026-08-02):
1) 'Open with…' is now a FULL-PAGE in-tab interstitial (was a modal window).
- loadBns loads collision.html via loadFile with query params instead of
opening a BrowserWindow.
- collision.html is navigation-based: buttons redirect to a special
bns://collision-choose/?host=…&choice=…&remember=…&resturl=… URL.
- serveBns handles that URL: persists remember=name/tld choice, then returns
a meta-refresh to the real target. For BCDN it appends ?_collision=bcnr
one-shot marker; for ICANN it redirects to https://<host><path>.
- loadBns strips and honors the ?_collision one-shot marker so BCDN
redirects don't re-trigger the prompt.
- Old modal path (collisionPromptOnce) removed.
2) Auto-switch from the address-bar chip: clicking BCDN/ICANN chip sets a
transient per-tab collisionOverride that loadBns consumes ONCE for this
navigation only, bypassing the soft-mode prompt entirely.
3) Address-bar toggle: chips stay visible during 'resolving' (no more
flash-and-reappear); active chip is colored (acid green for BCDN, blue for
ICANN — matching collision.html's palette); inactive is greyed with border,
clickable to switch. Feels like a proper toggle.
Settings > Registries copy: operator's exact wording adopted (title stays
'Registries', body uses 'BCNR-unique' term for TLDs that only exist on BCNR).
Terminology (user-facing labels now match the product/registry distinction):
- BCDN = Bitcoin Cash Domain Names (the product — what you view)
- BCNR = Bitcoin Cash Name Registry (the on-chain system that backs it)
Chrome badge, popover, Settings section and 'Open with…' prompt all show BCDN
for a resolved name. BCNR stays only where the registry itself is the subject.
'Open with…' prompt (collision.html):
- Larger window (640x520, was 480x340)
- Radio-select pattern with explicit Open / Cancel buttons (was auto-fire on click)
- Enter = Open, Esc = Cancel, keyboard-first
- Body copy per operator spec (no product-name-in-parens; blockchain-generic)
- Card titles kept short: 'BCNR / BCDN' + 'ICANN / IANA'
Address-bar chip:
- Says BCDN (not BCNR) for on-chain names; ICANN for web
- Dropped the '·.tld' suffix — TLD is already in the URL bar
- On collision candidates: shows BOTH chips (BCDN | ICANN) with active
highlighted; clicking the inactive one flips the tab (via collision-switch)
Settings section renamed Naming → Registries. Copy rewritten in the same
BCDN/BCNR frame; policy labels are now 'BCDN first' / 'ICANN first' / 'Ask
each time'.
Passive 'also on BCNR' bar copy updated to BCDN.
Verified: all preload/settings/main/chrome JS + HTML parse; no secrets in
staging.
- Address-bar security badge + popover lock redesigned to match Firefox's
padlock (shackle + rounded body + keyhole).
- Added AI/LLM answer engines to the catalog: ChatGPT, Claude, Phind, You.com
(Perplexity already present) — all accept a URL query. Off by default; enable
in Settings.
- Favicons now load from DuckDuckGo's icon service (one privacy-respecting host,
returns an icon for ANY domain) instead of guessing /favicon.ico per site,
which failed for several engines and fell back to emoji. Verified loading.
The search box's dropdown button now displays the current engine's favicon
(emoji fallback) + a caret, instead of a generic magnifier — and updates when
the engine changes.
- Custom engine dropdown as a floating overlay view (engine-picker.html) that
renders REAL favicons per engine — a native <select> can't show images.
- Larger catalog (DuckDuckGo/Google/Brave/Bing/Startpage/Yandex/Ecosia/Mojeek/
SearXNG/Wikipedia/Perplexity); Settings has a favicon checklist to choose
which appear in the dropdown (enabledEngines), plus manual add/remove.
- OpenSearch "scan": pages advertising a search engine surface an
"Add <site>'s search" entry in the dropdown.
- Toolbar search box now just a magnifier button that opens the dropdown
(no per-engine icon in the bar).
- Each search engine shows a symbol in the toolbar dropdown, the placeholder,
and Settings (🦆 DuckDuckGo, 🦁 Brave, 🔵 Google, 🔎 Bing, 🛡️ Startpage,
🔴 Yandex); custom engines take an optional symbol (defaults to 🔍).
- Fix: light-theme @media blocks for settings/popover/home were placed before
the base rules and lost the cascade (sidebar stayed dark) — moved them last.
- Light/dark/system theme (Settings > General) via nativeTheme.themeSource
driving prefers-color-scheme across chrome, settings, popover, and home.
- Search box redesigned: a magnifier icon opens the engine dropdown, the rest
is a wider typing field; styled to match the browser (was a raw <select>).
- Trimmed built-in engines to DuckDuckGo/Google/Brave/Bing/Startpage/Yandex;
custom engines still add/remove via "Add / edit engines…".
- WebRTC: the "WebRTC Network Limiter" extension can't run in Electron
(chrome.privacy API is unavailable), so its function is now a native
4-mode WebRTC IP policy in Settings > Privacy.
- Address-bar placeholder: "Ask a search engine or enter web address".
- Security popover redesigned to resemble Firefox's site-info panel:
lock/shield hero, "Connection secure" status, host, plain-language
subtitle, and a details grid; the overlay view auto-sizes to content.
- Search-engine picker returned to the toolbar with an "Add / edit engines…"
entry that opens Settings; added Ecosia, Mojeek, Presearch.
- Custom search engines: add (name + URL template with %s) / remove in
Settings > General; used by address-bar search.
- Address-bar placeholder: "Ask a search engine or enter web address".
- Performance: cache the chain index (was rebuilt on every navigation) and
warm it at startup — .bch pages open near-instantly after the first.
- Loading indicator: indeterminate bar under the toolbar, per-tab spinner,
and reload⇄stop button (driven by did-start/stop-loading + BNS resolve).
- Chrome cleanup: removed the bottom status bar and the redundant search
box; security padlock now always present at the front of the address bar;
minimal ICANN/BCNR pill at the end; favorites bar shows only on new-tab.
- Search: added Yandex; engine picker moved into Settings > General.
- Settings redesigned with a left sidebar (General / Performance / Privacy /
Anti-fingerprinting). Anti-fingerprinting now Show/Hide/Spoof/Manual for
timezone, language, AND location (geolocation coords overridden in-page).
Theseus Navigator:
- Firefox-style toolbar: SVG back/fwd/reload/home buttons
- security padlock badge in the address bar opens a floating site-info
overlay VIEW (on top of the page, never pushes content down)
- Edge-style favorites bar (shown only on the new-tab/home page)
- search-engine picker (DuckDuckGo/Google/Bing/Brave/Startpage)
- Theseus logo moved right, opens Settings; native menu removed
- address bar doubles as search; bottom resolver status line
Argus:
- BNS-only indexer: an electrum endpoint over a bare BCHN node
(watches just the beacon, caches txs so no txindex needed) + test
- registry lifecycle / portfolio / name-index modules
Site restructure (nav/apps/store/hermes/choose) + runbook notes.