Commit graph

226 commits

Author SHA1 Message Date
Local Dev
7a71b08cf7 fix(aegis): 0.9.1 — an unset custom RPC no longer becomes the text "undefined"
Mounting an imported TRX/ETH/SOL wallet read the optional custom RPC as
String(stored || undefined), so a wallet with no override got the literal
"undefined" as its server: every history and token fetch went to
"undefined/v1/accounts/…" and the panel showed "undefined" under the
balance. Only a real https URL overrides the network default now, and the
adapter itself rejects anything that does not look like one.
2026-09-23 00:24:42 +02:00
Local Dev
8174fccba0 feat(theseus+aegis): WizardConnect auto-detection — wiz:// links + page scan
Completes the three detection paths. The injected provider shipped in
0.8.8; these two needed host support, because nothing in the add-on API
could reach the active tab's content (captureTab is pixels, not DOM).

wiz:// links (main.js)
  A click on a wiz:// anchor is intercepted in will-navigate and in the
  window-open handler (target="_blank" lands there instead), and routed
  to the wallet with the offering page's origin attached, so the
  approval names the real site. The tab never navigates. This needs
  nothing from the dapp beyond rendering the URI as a link, so it works
  for third-party dapps that will never adopt a Silent Mode API.

scan-page capability (addons-host.js + main.js)
  New capability backing api.scanActiveTabForUris({scheme, limit}).
  Deliberately NOT a "read the page" API: the host runs the match and
  returns only the URIs found, so an add-on holding this still cannot
  see page text, markup or form values. It sits well below page-inject
  on the trust ladder — it learns that a page offers a wiz:// code and
  nothing else. Scheme is validated against [a-z][a-z0-9+.-]* and the
  result count is capped.

  The matcher also accepts WizardConnect's QR-alphanumeric spelling
  (WIZ://%3FP%3D…), which is frequently the only form present when a
  dapp renders its pairing code as a QR, and decodes it. Verified
  against the SDK: decodeKeyExchangeURI accepts standard, QR-raw and
  QR-decoded alike.

  Regex sources are built host-side and passed as JSON rather than
  assembled inside the injected string — hand-escaping backslashes and
  quotes through two levels of literal was both wrong on the first
  attempt and unreviewable.

Aegis
  Declares scan-page, adds the wcScanPage handler and a "Scan page"
  button next to Connect. A scan fills the URI field and stops there
  rather than pairing outright: the user still chooses which wallet
  signs and still presses Connect, because a scan that silently paired
  would carry far more consequence than the button implies. Older hosts
  without the capability get a clear "update Theseus" message instead of
  a dead button.
2026-09-23 00:16:49 +02:00
Local Dev
64bc26ecf6 chore(aegis): 0.8.9 — ETH/SOL imported history + tokens, centred setup screen
Completes the parity work 0.8.7 started for Tron. Imported ETH and SOL
wallets showed a native balance and nothing else, because the JSON-RPC
endpoints they poll have no history or token concept at all.

- ETH history + ERC-20 balances via Blockscout, which needs no API key
  (Etherscan V2 does). Mainnet RPC moves off eth.llamarpc.com, which was
  answering 525 with an HTML error page — that parsed as a JSON error and
  showed as a 0 balance.
- SOL history via getSignaturesForAddress and SPL balances via
  getTokenAccountsByOwner, both keyless on the public RPC.

Three things the live testing turned up:

- A Blockscout mempool entry is {result:"pending", status:null}. Reading
  that as "not ok, therefore failed" showed pending sends as failures.
  Now carries a distinct pending state through to the row.
- History `delta` is now a number, a decimal string, or null. ETH wei
  needs the string (18 decimals overflows a JS number, and Math.abs was
  silently rounding it); Solana's signature feed carries no amount at
  all, and null >= 0 is true, so unknown amounts were rendering as a
  "+" that claimed a receive we cannot verify. Unknown now renders as a
  neutral row instead.
- A real address came back with 855 ERC-20s and 3078 SPL mints, nearly
  all airdrop spam, some with blank, zero-width or bidi-override
  symbols that render as an empty row borrowing trust from its
  neighbours. Token text is sanitised and lists are capped at 50, sorted
  so named tokens survive the cap.

Also: the first-run setup screen forced text-align:left on the form, so
its helper copy ran ragged under a centred mark, title and description.
The form now inherits the centred alignment; the mnemonic box stays
left-aligned on purpose, since centring wrapped seed words makes them
harder to check.
2026-09-23 00:05:14 +02:00
Local Dev
1b74b10fc5 chore(aegis): 0.8.8 — coin drilldown, per-address assets, WizardConnect from the page
Wallet strip:
- Clicking a coin opens that coin's page (addresses, price, totals, back
  and close) instead of only flipping the selection and leaving the list
  sitting there. The page already existed but was reachable only via the
  small count chip.
- The per-coin second action was a gear that selected the wallet and
  opened the global Settings tab — the same destination for every coin,
  so it read as a per-coin control that wasn't one. It is now Remove,
  behind a confirm, with the default/legacy wallet showing a lock
  instead since it gates legacy funds.
- Each address in the drilldown can expand to show what THAT address
  holds: TRC20/SPL via the adapter's tokens, BCH CashTokens via
  tokenBalances. walletSummary now carries both per wallet, so the view
  no longer has to borrow the selected wallet's assets.

WizardConnect — the Connect pane was effectively unusable:
- The locked-vault branch told the user to unlock and gave them nothing
  to click. It is reachable without the lock screen ever appearing,
  because a mounted imported wallet makes overallPhase read "ready".
  It now carries the same unlock form the lock screen uses.
- Imported BCH wallets were never registered with the WC manager —
  startForWallet ran only in the vault-derived mount branch. They mount
  as ready, so they appeared in the "Sign with" picker and then failed
  on pair. They now register from their stored seed. WC derives a child
  key tree, so single-key (WIF) imports genuinely cannot pair; those are
  disabled in the picker with the reason, rather than failing on click.
- Adds window.wizardconnect so a dapp can hand over the wiz:// URI it
  already generated instead of making the user copy it between tabs.
  The protocol is Nostr-relay pairing designed for phone-scans-QR, and
  the SDK has no in-page discovery at all, so this is our own surface:
  connect() + isReady(), plus a wizardconnect:announceProvider event
  shaped like EIP-6963 so several WC wallets can coexist. Pairing always
  goes through the approval modal; the URI is validated before any UI
  shows, and the wallet never reads the page to find one.
2026-09-22 23:08:16 +02:00
Local Dev
8785ecc7cf chore(aegis): 0.8.7 — imported Tron wallets get history + TRC20 tokens
Imported Tron wallets pointed at api.nileex.io, which only serves the
/wallet/* JSON-RPC family and 404s all of /v1/. That REST family is
where transaction history and the trc20 balance map live, so an
imported Nile wallet showed a native balance and nothing else. The
built-in Tron adapter was already on nile.trongrid.io, which is why
only imports were affected.

Switches the imported Nile endpoint to nile.trongrid.io and fills in
the two features that were never implemented for imported account-
model wallets:

- History via /v1/accounts/<addr>/transactions, with the signed delta
  computed by comparing owner_address against the wallet's own address
  in 41-hex form (the feed returns hex regardless of visible:true).
- TRC20 balances via /v1/accounts/<addr>, joined against token_info
  harvested from recent trc20 transfers to recover symbol + decimals.

Both are best-effort so a chain with no keyless feed can't blank a
wallet whose balance fetch succeeded. Contracts with no registry entry
render as "Unknown token" with a raw amount rather than a number
invented from assumed decimals, and named tokens sort above them so
airdrop spam can't bury real holdings.
2026-09-22 21:52:54 +02:00
Local Dev
30fbe73d21 chore(aegis): 0.8.6 — in-panel confirm/alert instead of native dialogs
window.confirm/alert render as chrome-owned, Theseus-branded OS boxes
outside the sidebar, which breaks the illusion that Aegis is one
coherent surface — and they can't carry an icon, a danger-styled
button, or formatted copy.

Adds aegisConfirm() / aegisAlert(): the same overlay shell the manage
and import modals already use, resolving like confirm() so callers
just await it. Escape cancels, Enter confirms, click-outside cancels.

Swapped at all four confirm sites (remove wallet from the picker,
remove wallet from Settings, remove PIN, sign out) and all seven
alert sites.
2026-09-22 21:44:03 +02:00
Local Dev
f3fb31e651 chore(aegis): 0.8.5 — Coin-Spectrum price parser reads body.asset.price_usd
Every Coin-Spectrum poll silently returned an empty map because we
were reading body.price_usd (top-level) while the API wraps its data
under body.asset. Every chain's Number(undefined) came back NaN, so
Settings › Prices showed "✓ 0 coins" and majority-vote reconciliation
had one fewer source than intended.

Now reads body.asset.price_usd (with a top-level fallback in case the
API is ever flattened).
2026-09-22 21:31:43 +02:00
Local Dev
e03c728116 chore(aegis): 0.8.4 — network chip on its own row + coin-catalogue search
Two follow-ups on 0.8.0's currency picker after a testing pass:

- The network label was a tiny gray suffix next to the wallet name in
  the header, so "which network am I on" wasn't obvious at a glance.
  Now it's a separate row of one clickable chip under the coin ticker;
  clicking jumps into the browse:chain view where the network strip
  actually switches network.

- Clicking the header opened a "Pick a coin" pane that only listed
  coins the user already had a wallet for — a first-time user with a
  single BCH wallet would see one row and no way to add more. Now it
  shows every supported coin behind a search box; owned coins jump to
  the wallet list, unowned coins jump straight into the create-wallet
  flow with that coin's network group pre-expanded.
2026-09-22 21:19:36 +02:00
Local Dev
b32b353db7 chore(aegis): 0.8.3 — default BCH explorer switches to bchexplorer.cash
Blockchair's BCH explorer is slow and ad-heavy; bchexplorer.cash is
the Bitcoin Cash community's own instance, faster on tx pages and
with a proper mempool view. Same /tx/ + /address/ path scheme
(address takes the bitcoincash: prefix as-is), so no other code has
to change.

Chipnet explorer stays on chipnet.imaginary.cash — bchexplorer.cash
is mainnet-only.
2026-09-22 20:44:44 +02:00
Local Dev
cb7ca53b01 chore(aegis): 0.8.2 — sectioned Settings tab
Settings grew tall enough that the user had to scroll past a dozen
cards to reach Prices, Sites or About. Split it into six named
sections (Security, Session, Wallet, Prices, Sites, About) with a
chip nav row at the top; only one section is visible at a time and
the choice persists across restarts.

Adds an About card that names the wallet, the aegis.x front-door
site and the silentmode.st umbrella, so support triage has a
one-click way to reach either from within the panel.

Includes the accumulated 0.7.x-0.8.1 wallet work that was already
shipping on OTA (CashTokens/BCMR, imported-wallet spend, siascan
integration, consolidate, currency picker, footer update chip).
2026-09-22 20:37:28 +02:00
Local Dev
f46e9112b7 chore(theseus): 0.3.47 — plug-in category + panel-driven addon self-update, aegis 0.6.31
Theseus core:
- addons-host: manifest.category ("plugin") propagates through snapshot(); new
  addon API surface checkAndStageSelfUpdate() + restartApp() so a plug-in
  can offer in-panel "update now → restart to apply" without pushing the
  user to Settings.
- main.js: wires the two new hooks into the AddonHost constructor.
- settings.html: Extensions listing filters out category==="plugin"; those
  add-ons live in Plug-ins instead, single source of truth.

Aegis 0.6.31:
- BTC picker trimmed to Signet only; testnet3 hidden (adapter kept so any
  existing wallet still loads).
- Wallet strip groups by chain, not chain:network; ticker gets a ▾ chevron
  and a dropdown listing every subnetwork with its own totals. Mainnet
  reads as the plain ticker; testnets carry a small Chipnet/Signet/Sepolia
  pill inline.
- Per-unit price sits directly under the ticker; amount + fiat mirror on
  the right — one glance covers name/price/holding/value.
- + Add and ⋯ More promoted from the strip into the header's action row,
  next to the new ✎ chip (was the redundant top ⋯). Duplicate "Manage
  current wallet" entry removed from the More menu.
- Footer update chip is a two-step flow via the new API: stage → restart.
  Falls back to opening Settings on any Theseus that lacks the hooks.
- Manifest declares "category": "plugin".
2026-09-14 02:30:51 +02:00
Local Dev
d7d127d7b4 fix(theseus/bns): failed content fetches get a real error page naming the upstream and cause
A bns:// fetch that fails after the name resolved (relay unreachable, DNS
stalling, the site's own server down) used to answer with the bare text
"Theseus error: fetch failed", which reads as a broken browser. The
handler now returns a styled page that names the host, the upstream it
tried (navigate.st, the p-record origin or the ip record), the error and
its cause code, explains the likely reason per cause (unreachable vs DNS),
and offers a retry.
2026-09-12 09:09:06 +02:00
Local Dev
1596463b70 chore(theseus): 0.3.46 2026-09-12 00:31:47 +02:00
Local Dev
3c0f13c1e5 fix(theseus/updater): run the installer only after the app has exited, via a detached batch helper with self-heal
A 0.3.44 → 0.3.45 auto-update on 2026-09-11 left the install without
app.asar and ffmpeg.dll ("ffmpeg.dll not found" at launch). The setup was
hash-verified; the old-version uninstaller had moved the whole old install
into its temp folder when both NSIS processes died ~8 s after the spawn,
and the install step never wrote a file. The killer was not identified, so
every overlap with the app's own lifetime is removed instead:

- install-update-now no longer spawns the setup; it records the path and
  quits. will-quit writes <userData>\update-helper.cmd and starts it as a
  detached cmd.exe (verified to outlive the app; not a child of ours).
- The helper waits for our PID to be gone (child powershell Wait-Process),
  gives Chromium's children a grace period, runs the setup directly, and
  runs it once more if resources\app.asar is missing afterwards — the
  installer is idempotent, so a second pass repairs a torn install. The
  helper deletes itself.
- Zone.Identifier is stripped from the verified download so nothing that
  starts it through the shell raises a mark-of-the-web prompt.

Console-less cmd.exe traps discovered and designed around (see the module):
child console programs' redirected stdout is empty (no tasklist|find
probing), `start /wait` on a .cmd hangs, a detached powershell.exe
started straight from Node does nothing, `timeout` needs a console.
Scenario tests: setup starts only after the process exits, once with
app.asar present, twice without, helper gone afterwards.
2026-09-12 00:31:46 +02:00
Local Dev
ed48646c71 feat(theseus/chrome): "Open link in new window" on the link context menu
A standalone page window on the same session (cookies, bns:// protocol,
session-wide bcnr preload) with Theseus's fingerprint + WebRTC policy and
no toolbar. Loads BCNR-first like a tab: a dotted host with a BCNR record
goes over bns://, otherwise clearnet; collision names follow the configured
policy without the "Open with…" interstitial. Cross-host navigations inside
the window stay BCNR-first; popups go to the main window's tabs. Its own
context menu offers open-in-tab / open-in-window / copy link and
back/forward/reload. Add-on page bridges (wallet inject) are tab-scoped and
don't run in these windows. openLinkWindow is exported for the test harness.

Verified in the dev app: coinspectrum.x opened as bns://coinspectrum.x with
the page title; navigate.st stayed https.
2026-09-10 22:25:19 +02:00
Local Dev
43d0021bf6 docs(theseus): add-on update channel lives on Sia, not the VPS — publish with sia-upload
The publishing steps pointed at scp to /opt/silent-mode/site/addons/, which
never existed; the screenshot channel (and now aegis) is served from
s3://bns/theseus/extensions/<id>/ through navigate.st/bns/theseus.x/….
Also: sign from a git-archive copy so uncommitted edits don't ship.
2026-09-10 22:25:18 +02:00
Local Dev
ee5e53512a docs(theseus/prompts): tool-agnostic phrasing in session-prompt templates 2026-09-10 22:21:19 +02:00
Local Dev
50eb143b0a chore(theseus): 0.3.45 2026-09-10 00:12:35 +02:00
Local Dev
c9dbcbde86 fix(ariadne): Theseus on/off toggle never reached the tasks; updater read a stale manifest; uninstall left NRPT rules
Theseus (Settings › Plug-ins › Ariadne's Thread):
- The elevated start/stop script was embedded in a double-quoted outer
  PowerShell string, so `$t` was interpolated away before the elevated
  shell saw it. It received `foreach ( in …)`, failed to parse, and the
  outer shell still exited 0 — "Turn on/off" reported success while doing
  nothing, in every shipped build. The script now goes across as
  -EncodedCommand. Off = Stop + Disable (the daemon task has an
  at-startup trigger, so a plain stop came back on reboot); on = Enable +
  Start. Exit 2 = daemon task missing, surfaced as a clear error.
- Version/update check now reads dl.silentmode.st's releases manifest,
  the same one the Theseus updater uses. The silentmode.st copy lagged a
  day behind (still listing Theseus 0.3.31), so a new Ariadne release
  published to dl would not have been offered.
- Install/update/uninstall now propagate the installer's exit code
  (-PassThru; exit $p.ExitCode) instead of always reading as success.

Resolver package (needs a new installer build to reach users):
- uninstall.ps1 removed only the ".bch" NRPT rule; install.ps1 adds one
  per advertised TLD. Sweep every "BNS .<tld> resolver" rule.

Verified: daemon resolves BNS names and passes ICANN A/AAAA through when
run unprivileged on port 15353; the encoded-command construction runs
intact and propagates exit codes 0/2 in an unelevated reproduction.
2026-09-09 23:04:23 +02:00
Local Dev
56eff58fda feat(theseus/chrome): page zoom, 80/20 address/search ratio, collapsed dock renders icon images
- Per-tab page zoom on Chrome's ladder (25–500 %) via setZoomFactor, so
  Chromium keys it per host: every tab on a site shares the level and it
  persists across navigations and restarts. Ctrl +/=/numpad+ in,
  Ctrl -/numpad- out, Ctrl 0 reset, Ctrl+wheel via zoom-changed. A
  percentage chip appears in the address bar when a tab isn't at 100 %;
  clicking it resets. Settings and add-on tabs never zoom.
- Address bar / search bar drag ratio floor lowered from 30 % to 20 %,
  so the split runs 80/20 to 20/80 (pixel floors still apply).
- The collapsed extension-dock button and its dropdown printed a data:
  URI icon as text ("data:image/svg+xml…"). One addonIconHtml() renderer
  now serves the dock buttons, the collapsed button and the dropdown.
2026-09-09 23:04:22 +02:00
Local Dev
7b8539fb8d feat(theseus/screenshot): 0.6.4 — Polaroid sounds, trash icon, centred cluster, filename footer + open-in-folder
Rolling every user report from the 0.6.3 rollout into one bundle:

Sounds — the Web-Audio synth palette matches the metaphor now:
- Screenshot: Polaroid shutter — sharp metallic tick + curtain-close click
  chained to a film-advance whir (band-passed noise sweeping 900→400 Hz).
- Copy: printer "chika-chika-chika" — three descending percussive noise
  bursts pinned by short sine ticks. Reads as a print-head sweep.
- Discard: paper crumple — three overlapping band-limited noise beds
  with per-sample random-amplitude crackle, descending centre freq. No
  more descending sine "boop".
- Save: soft "photo dispensing" hiss (Polaroid ejects) + a small click.
- Both the panel and editor share the design so nothing sounds different
  depending on which surface fired it.

UI polish:
- Discard button now carries a trash-can icon so it's obviously not the
  same as the close-sidebar X (they both used to be plain X's).
- Toolbar drawing tools centre themselves via a new .tool-cluster
  wrapper (flex:1 1 auto, justify-content:center); the Copy/Save actions
  stay right-anchored via margin-left:auto on their own tgroup. Fixes
  the maximized-sidebar case where the drawing groups all crowded the
  left with a big empty gap before Copy/Save on the right.
- Filename moves out of the topbar into a dedicated footer strip under
  the canvas board, alongside a new "Open in folder" button. The topbar
  is now flex-wrap:nowrap and holds only fixed-width window controls,
  so a long filename can never push discard / sound / max / close onto
  a second row (the filename ellipsises instead).
- "Open in folder" invokes a new "openFolder" addon message that calls
  Electron's shell.showItemInFolder() to open the OS file explorer with
  the specific scratch PNG highlighted (falls back to shell.openPath()
  on the scratch dir when no capture is named).

Version bump so the OTA update endpoint picks it up on the next tick.
2026-09-09 22:34:47 +02:00
Local Dev
8eda0433d7 feat(theseus/screenshot): 0.6.3 — per-tile delete, no Select button, text tool halo, right-anchor panel controls
Four issues from the user's report on 0.6.2:

- Recent captures had a global "clear all" but no way to drop a single
  screenshot. Each tile now grows a small × button (visible on hover;
  drops in behind the thumbnail preview so it never obstructs the
  content). Clicking the × invokes clearRecent({name}) and removes both
  the ring entry and the scratch PNG on disk. Bubble-guarded so the ×
  click doesn't also trigger the tile's "load into preview" handler.

- Select tool button removed — clicking it did nothing visible, so users
  read it as broken. The internal "select" mode still exists as the
  no-tool state; you get back to it now by clicking the same drawing
  tool a second time (toggle-off) or hitting Escape. The active-drawing-
  tool button flips its border when armed.

- Text tool made unmistakable: input paints with a 2 px acid border, a
  glowing acid halo, dark background, and the visible ink colour on the
  text itself. Focus attempt is three-layered (sync, rAF, timer) to
  outrun any Chromium build that drops the mid-pointer-event focus. Non-
  Enter/Escape keys get stopPropagation so a stray document listener
  can't steal the focus mid-typing.

- Panel header's sound / max / close cluster kept nudging inward when
  the status text was empty. The parent's `justify-content: space-
  between` distributed the row unevenly. Force-anchor the cluster with
  `#btn-sound { margin-left: auto }` so the three window-control icons
  hug the right edge regardless of what fills the middle.

Bundled but not shipped separately — parent session signs and pushes.
2026-09-09 22:01:06 +02:00
Local Dev
744574ba96 feat(theseus/screenshot): 0.6.2 — Copy/Save move to toolbar, Discard, right-anchored topbar
Layout reorganisation from user's diagram:

- Copy + Save move out of the topbar into the toolbar as their own
  right-anchored tgroup (margin-left:auto). On wide sidebars they sit at
  the end of the drawing-tool row; when the sidebar is narrow, the
  actions cluster wraps as its own row on the right instead of nudging
  the drawing tools around. Toolbar switches from justify-content:center
  to flex-start so the leading tool groups pack left and the actions
  group can find the right edge cleanly.

- Topbar right cluster is now Discard / Sound / Maximize / Close — Copy
  and Save are gone from the topbar entirely so the right edge reads
  as controls-only, not action-mixed.

- Discard button (X icon, danger red on hover) throws away the current
  capture — silentmode.invoke("clearRecent", {name}) removes it from the
  ring and unlinks the scratch file — then navigates back to the panel.
  Distinct from Back, which is non-destructive.

- Close button already existed from 0.6.1 but stays in the same
  right-edge position for continuity.

Bundled but not shipped separately — parent session signs and pushes.
2026-09-09 11:46:21 +02:00
Local Dev
8a99c0959c feat(theseus/chrome): Ariadne's Thread registry menu, address-bar overflow fix, full-width link pill
- Link-status pill: it measured its own width inside a view already
  capped at 100 px, so it could never grow and long hrefs were cut short.
  An off-screen twin now reports the natural width; main caps it to the
  tab area (never under the sidebar) and the pill ellipsises past that.
- Address bar at narrow widths: the URL input's intrinsic minimum width
  pushed the registry chips and the star out past the bar. #url now has
  min-width: 0 and the trailing controls are fixed-size flex items.
- The BCDN/ICANN segmented chips are replaced by one Ariadne's Thread
  icon (spiral + tail) at the end of the bar: acid when served from BCDN,
  blue for ICANN, caret when the name exists on both. Click opens a
  native menu (registry-menu-popup): switch registry, remember per name /
  per TLD, forget choices, collision policy, and a jump to the Plug-ins
  settings section. Reuses the existing switch / remember / policy paths
  (collision-switch body extracted to switchRegistry, open-settings to
  openSettingsTab). preload's openSettings now forwards a section slug.
2026-09-09 11:40:46 +02:00
Local Dev
c9a3db26ce fix(theseus/boot): paint the toolbar first — stop gating startup on chrome.html's load event
Users saw a blank window with a white strip across the top for seconds
on launch. Root cause: every part of startup, including session restore,
waited for chrome.html's did-finish-load. That event also waits for the
page's subresources, and the bookmarks bar loads its favicons over
bns:// — a BNS lookup plus a network fetch each — so a slow link held the
whole boot. On top of that, seven hidden overlay renderers, every restored
tab, the BNS index build and three network fetches all started in the
same tick and stalled the main thread ~1 s while the toolbar tried to
paint.

- Continue boot at chrome.html's dom-ready (toolbar scripts have run, IPC
  listeners exist) instead of did-finish-load; 8 s fallback timer.
- Window and chrome view get the toolbar's --bg for the active theme so
  the pre-paint frame is never white.
- Overlay pages (site info, engine picker, downloads, suggestions,
  password fill, link status, approval) load 250 ms after the toolbar or
  on first use; the approval modal awaits its page so a dapp request
  can't hang.
- Session restore is staggered: active tab first, then one background
  tab per 150 ms slotted into its saved strip position. Session file v2
  records the active index; v1 arrays still load (active = last, as the
  old loop effectively did).
- AddonHost gains api.whenUiReady(); Aegis 0.6.2 defers its heavy
  dependency loading (noble precompute, bitcoinjs, libauth, WizardConnect)
  behind it.
- BNS snapshot warm-up still starts right after createWindow (bookmark
  favicons need it); Sia refresh, update check and home-card fetch move
  to the post-paint phase.

Measured on a clone of the real profile with nine restored tabs: toolbar
usable at ~0.7 s instead of ~1.5 s, main-thread stall during toolbar load
down from ~1.1 s to ~0.2 s.
2026-09-09 11:40:45 +02:00
Local Dev
bf6bcfade2 feat(theseus/screenshot): 0.6.1 — text tool fix, category wrap, sidebar close X
Four user reports from the 0.6.0 rollout:

- Text tool never committed. openTextInput placed the box correctly but
  a couple of Chromium quirks stopped a normal type-Enter cycle:
  focus() called synchronously right after appendChild lost the race
  in some builds, and the input's own mousedown / click was bubbling
  through to #base and re-firing openTextInput on every subsequent
  keystroke click-through, so what looked like "nothing happens" was
  actually "a new empty box spawned on top of the last one every time".
  Now: focus after requestAnimationFrame, contain pointerdown / mousedown
  / click inside the input so they don't bubble to the canvas, track
  the font size on the state so commit uses the same one openTextInput
  measured against, and preventDefault on the base pointerdown so
  Chromium doesn't reset focus back to <body>.

- Toolbar wrapped one dot at a time when the sidebar was narrow (a
  lonely thin/medium/thick width would jump to a second row while the
  swatches stayed above it). Toolbar items are now wrapped in
  `<div class="tgroup">` per category — tools / swatches / widths /
  undo-redo — with `flex: 0 0 auto`, so a whole row wraps as a unit
  and lands cleanly under the previous one. `gap: 10px / row-gap: 6px`
  keeps the visual grouping obvious.

- No way to close the sidebar without hunting for the dock icon. Added
  an X button in the top-right of both the sidebar panel and the
  editor toolbar. Both wire through a new `silentmode.sidebar.close()`
  preload method that calls the existing `sidebar-close` IPC.

- Tightened the pointerdown text branch so preventDefault + explicit
  focus-after-frame make the click-through races impossible.

Bundled but not shipped separately — parent session signs and pushes.
2026-09-09 10:55:21 +02:00
Local Dev
35ec8a3904 fix(theseus/sidebar): visible-at-rest separator between the tab area and the sidebar
The resize grip lived along the sidebar's left edge as a 5-px transparent
hover target — you couldn't see it existed until the pointer landed on it.
Users on both light and dark backgrounds reported the seam between the
tab area and the sidebar as invisible.

Paint a 2-px semi-opaque mid-gray line (`rgba(140,150,170,.55)`) at rest so
the boundary is legible on every panel background; hover ramps to acid
green, active-drag ramps brighter. The visible band is narrower than
before (2 px vs 5 px) so it reads as a subtle divider rather than
competing chrome; the pointer-catch zone stays wide via an invisible
outline extension, so drag-to-resize still catches slack.
2026-09-09 10:50:30 +02:00
Local Dev
0f39429d63 chore: push-split helper for per-project forge repos + Windows Sandbox installer config
scripts/push-split.sh pushes one monorepo subdirectory to its matching
split repo on Hephaestus via an ephemeral git-subtree-split branch, so
history is preserved on the forge side. The remote name is derived from
the directory (Navigator/Resolver suffix stripped) or passed explicitly.

TheseusNavigator/test-installer.wsb is a Windows Sandbox profile that
maps dist-public read-only and launches the setup exe on logon, for
clean-machine installer checks.
2026-09-09 10:33:23 +02:00
Local Dev
992c02ea89 feat(theseus/aegis): 0.6.1 — in-panel vault setup/unlock, BCH wallet imports, opt-in fiat prices, WizardConnect
Aegis Wallet 0.4.4 → 0.6.1:

- Vault lifecycle from the wallet gate. The locked / not-yet-created states
  now show a master-password form (with optional BIP39 mnemonic on setup)
  instead of redirecting users to Settings › Passwords. New
  api.vault.lifecycle {status, setup, unlock, lock} in addons-host, gated by
  the existing "vault-derive" capability. api.openSettings(section) also
  added; settings.html honours a #section hash on open.
- Imported BCH wallets (design M.1a, read-only). Paste a mnemonic + BIP44
  path or a WIF; the cashaddr is derived in the add-on, the signer material
  goes to a separate wallet-imports.enc via api.vault.imports {list, add,
  remove, signer}. Argus password-vault gains createImports / unlockImports /
  saveImports with its own KDF salt so the imports key is disjoint from the
  passwords key. lib/chain-bch-imported.js is a single-address Electrum
  adapter; spend support is deferred to M.1b.
- Opt-in USD prices via CoinGecko (lib/prices.js), off by default, persisted
  in add-on storage. Fiat lines under balances, in the wallet picker, and a
  portfolio total when 2+ wallets are open. Settings tab is now reachable
  while the vault is locked so the toggle is always available.
- WizardConnect wallet-side pairing for BCH wallets (lib/wc.js, lib/wc-sign.js).
  @wizardconnect/{core,wallet} are loaded dynamically via api.import to stay
  on the right side of LGPL §4d. Sign requests go through approvalModal and
  are restricted to P2PKH inputs with SIGHASH_ALL|FORKID|UTXOS.
- DGB adapter load is now soft-fail: when Aegis runs from userData/addons the
  bundled ESM can't resolve peer deps, so DGB becomes unavailable instead of
  taking the whole add-on down.
2026-09-09 10:33:21 +02:00
Local Dev
7405e444e7 feat(theseus/screenshot): 0.6.0 — crop + mosaic redaction, right-anchored sidebar controls, real shutter+print sounds
Editor:
- Crop tool restored — drag to select, marquee sits with a dashed acid
  border and a dimmed backdrop for the area you'll discard, then the
  topbar shows Apply crop / Cancel. Applying trims #base to the rect,
  resets undo (dimensions changed), and drops back into the select tool.
  Enter / Esc keyboard shortcuts while a crop is pending.
- Blur / mosaic redaction tool back — drag a rectangle, editor
  downsamples that region of #base to ~12-block granularity and paints
  the blocks back nearest-neighbour. Commits directly (no confirm step).
- Sidebar-window controls (Back, name, Copy, Save, Sound, Maximize)
  reflow: Back + name on the left, Copy + Save + Sound + Maximize on
  the right so the "put the sidebar back to normal size" affordance
  lives where users expect it. Toolbar's drawing tools stay centred.
- Back arrow icon swapped from a chevron to a proper flat arrow
  (line + arrowhead), matching the new browser back/forward glyphs.

Sounds — modeled on Firefox Screenshots' feedback rather than beeps:
- Shutter is now a real photoshoot click: two mirror-slaps built from a
  band-passed noise burst (metallic ping) plus a very short square-wave
  thud each. Sounds like a camera, not a beep.
- Copy is a two-chirp "printer feed" — filtered noise burst on top of a
  sine chirp per beat, staccato ascending pair. Same shape Firefox Easy
  Screenshot uses for "copied to clipboard".
- Save keeps its ascending triad; Discard keeps its descending pair;
  new small ascending pair for Apply crop.

Chrome:
- Browser Back / Forward chevrons (M10 3 L5 8 L10 13 — two segments
  meeting at a point, no shaft) replaced with straight-arrow glyphs
  (line + arrowhead). Reads as a navigation arrow, not an angle bracket.

Bundled but not shipped separately — parent session OTA-signs and pushes.
2026-09-09 10:24:03 +02:00
Local Dev
882de1654f fix(theseus/net): sec-ch-ua client hints look like stock Chrome (Brave-style)
Cloudflare Bot Fight Mode / Turnstile flag 'UA claims Chrome but client
hints don't confirm it' as bot. Electron's default sec-ch-ua reads
'Chromium';v='130', 'Not(A:Brand';v='99' — no 'Google Chrome' brand
(that's closed-source Google branding open Chromium doesn't carry).
Combined with a UA that's already stripped of the Electron token
(stockChromeUA), the mismatch itself is the fingerprint. This is what
whybitcoincash.com and other CF-fronted sites tripped on: server
returned 503 to Theseus while returning 200 to any curl variant.

Brave, Vivaldi and Opera solved this the same way — ship their own
sec-ch-ua that INCLUDES Chrome-family brands so CF's allow-list catches
them. New applyClientHintsSpoof() registers a session-wide
onBeforeSendHeaders that rewrites the sec-ch-ua family on every
outbound request:
  sec-ch-ua:                'Google Chrome';v=<major>, 'Chromium';v=<major>, 'Not?A_Brand';v='99'
  sec-ch-ua-full-version-list: same trio with real Chromium version
  sec-ch-ua-mobile:         '?0'
  sec-ch-ua-platform:       actual OS name (Windows / macOS / Linux)

Major comes from process.versions.chrome so the story stays internally
consistent — nothing to fingerprint from a Chrome/version mismatch.
Runs alongside applyEmbedCookieShim which uses onHeadersReceived; the
two hooks are separate so no listener collision.
2026-09-09 03:27:41 +02:00
Local Dev
124325673f feat(theseus/settings): per-extension update info inline on the card
The Extensions page had a "Pending updates" strip at the top listing the
staged versions AND a "Check for updates" button that dumped a summary of
every extension's status into a global status blob just below the button.
Two places to look for what a single card was doing.

Fold both surfaces into the extension card itself:
- Each card grows a small update line under its description: green ↻
  "Update vX.Y.Z staged — restart to apply" when a staged tarball is
  waiting, red "Update failed" (with the addon-updater's detail) when
  the last check-updates run couldn't advance the version, plain "Up to
  date" when it could and there was nothing newer.
- The top strip is gone. The "Check for updates" button now just prints a
  one-line summary (N staged / N failed / all up to date) — the detail
  lives on each card.
- listStagedAddonUpdates fires on tab visit and after Reload, so the
  card badge reflects the background poll without needing the user to
  click Check.
2026-09-09 02:43:28 +02:00
Local Dev
0d583fb749 fix(theseus/addons): sidebar auto-restore on tab switch + more forgiving tar
Two follow-ups from user reports on the 0.5.x screenshot rollout:

- When the screenshot editor sidebar is maximized (fills the window) and
  the user hits New Tab / Settings / any address-bar nav that opens a
  different tab, the incoming tab was left invisible behind the sidebar.
  setActive now auto-restores the sidebar to its pre-max width whenever
  it detects a tab switch — the user can hit the maximize button again
  on the way back. Pure additive change, no other setActive semantics
  touched.

- The signed-add-on update pipeline failed the 0.5.0 tarball extract on
  a Windows 10 install with the built-in bsdtar: `tar --force-local -x
  -z -f …` — bsdtar doesn't recognise --force-local and errors out
  before it opens the archive. Try the extraction WITHOUT the flag
  first (safe with the posix-slash paths we already pass on every tar
  we care about — bsdtar, GNU tar, MSYS2 tar) and fall back to WITH
  --force-local only if the first invocation exits non-zero (MSYS2
  path where a bare `C:/…` gets parsed as a `host:` prefix). Original
  error message is surfaced on total failure so we can still tell what
  went wrong.
2026-09-09 02:38:32 +02:00
Local Dev
71b803e020 fix(theseus/screenshot): 0.5.1 — hide "Loading capture" for real + centre the tool bar
Two things the shipped 0.5.0 got wrong:

- `.empty { display: flex }` overrode the plain `[hidden]` attribute the
  init flow sets after the image draws, so the "Loading capture…" pill
  stayed visible on top of the finished capture. Global rule
  `[hidden] { display: none !important }` takes it out.

- Tool bar was left-aligned; older editor iterations grouped the drawing
  tools / swatches / widths / undo-redo in the centre of the bar, which
  read better in a narrow sidebar. Adds `.toolbar { justify-content: center }`;
  the topbar's back / max / sound / name / save / copy stay edge-anchored.

Version bump so the OTA update endpoint picks it up on the next tick.
2026-09-09 02:33:45 +02:00
Local Dev
c64e81a959 toolbar 30% ratio floor + placeholder-safe search + brand map for .x names
Toolbar drag handle now clamps both bars to at least 30 % of the
.urlsearch budget (URL: 30 %–70 %, search fills the rest). The
existing absolute mins (URL 220 px, search bumped from 140 → 180 px
so the 'Search' placeholder always fits) still apply — the tighter of
absolute vs 30 %-of-container wins at any width. .urlsearch also gets
margin-right: 10 px so the search bar has visible breathing room from
the trailing dock (Downloads / extensions / ⛓ Theseus).

Bookmark brand-case now uses a canonical map for multi-word Silent Mode
names so all-caps sources come out correctly cased: SILENTMODE.X →
SilentMode.X, silentmode.x → SilentMode.X, coinspectrum.x →
CoinSpectrum.X. Single-word brands (Theseus, Sirius, Deviant, Aegis,
Ariadne, Argus, Hermes, Prometheus, Hephaestus, Helios, Atlas,
Katalogos, Game, Poutakidis, Syskypo) are in the same map for
consistency. Unknown names fall back to Title-case (foo.x → Foo.X)
— the ALL-CAPS preserve rule is gone, so GAME.X → Game.X now,
matching the user's ask.
2026-09-09 02:25:12 +02:00
Local Dev
dcbe4d55f9 fix(theseus/bookmarks): brand-case .x TLD labels (theseus.x → Theseus.X)
Bookmark chip labels now normalise the .x TLD family to <Name>.X on
render:
  theseus.x      -> Theseus.X
  deviant.x      -> Deviant.X
  Sirius.x       -> Sirius.X
  foo-bar.x      -> Foo-bar.X
Names that were already ALL-CAPS keep their form so the visual weight
carries through:
  GAME.X         -> GAME.X (unchanged)
  SILENTMODE.X   -> SILENTMODE.X (unchanged)
Non-.x titles are untouched (CoinSpectrum, navigate.st, etc.). The
transformation runs after the descriptor trim, so titles like
'theseus.x — the browser…' also come out 'Theseus.X'.
2026-09-09 02:17:27 +02:00
Local Dev
8649bb97ea docs(theseus): draft wallet multi-account amendment
Amends DESIGN-integrated-wallet.md §0 ("one account per profile in v1") with
a formal path to supporting external key imports (BIP39 seeds and raw WIFs)
alongside the primary HD purpose-subtree. Motivated by the user's 15-wallet
Deviant chipnet keystore now encrypted under the same master-password model
that Theseus is designed around.

Key discipline:
- SEPARATE storage file (wallet-imports.enc), same PBKDF2/AES-256-GCM crypto,
  same master password, distinct KDF salt. Imports cannot compromise the
  primary seed and vice versa; corruption of one file does not damage the
  other.
- The imports schema mirrors Deviant's chipnet-keystore/1 shape (cashaddr /
  label / category / source / path / seed / wif) so import is a 1:1 field
  copy, not a translation.
- Every import stores the raw seed + BIP44 path (or the raw WIF) and derives
  addresses DIRECTLY via HDKey.fromMasterSeed, bypassing the vault's
  purposes/wallet HKDF subtree. This is essential: without the bypass,
  pasting a mnemonic re-hashes the seed through HKDF and produces DIFFERENT
  addresses than the source wallet (see memory
  bchwallet-vault-root-derivation).
- No bcnr.importWallet() ever; imports are settings-page only.
- Sign modal grows an account picker with category chips; per-origin
  "recently used" pre-selection with red-flag on category change.

Also introduces:
- bcnr.requestAccount({ account?, category? }) — backwards compatible
- bcnr.getAccounts({ category? })
- Stale-import detection (source-file cashaddr comparison on unlock)
- Sequencing: M.1 (generic import) → M.2 (import from Deviant keystore) →
  M.3 (API extensions) → M.4 (stale detection). M.1 is load-bearing;
  everything else composes.

Companion to Option A which shipped separately as the cross-repo fall-through
in Argus/src/lib/wallet.js.
2026-09-09 02:17:01 +02:00
Local Dev
30734847e9 fix(theseus): tab context menu goes native + bigger uniform bookmark chips with title-only labels
Two visible fixes from the same 2026-09-09 screenshot:

Right-click a tab was building a DOM menu and then growing the chrome
view height so it would fit under the tabstrip. That opened a
visible gap between the toolbar and the tab body while the menu was
up. Now the tab context menu goes through a new IPC
"tab-context-menu-popup" (main.js) that pops an OS-native Menu at
the click point, floating above every WebContentsView — no layout
change, no gap. Preload exposes tabContextMenuPopup(id, {x, y});
chrome.html's tab contextmenu handler now calls it directly and the
DOM openTabContextMenu / openGroupSubmenu / growChromeForMenu path
is bypassed for tabs. (The bookmark bar's own ctxmenu still uses
the DOM path — its short 2-3-row menus don't grow chrome enough
to be visible.)

Bookmark chips were too small (130px max-width, 11px text, 22px row).
Now every chip is a fixed 150px × 28px cell so the row reads as a
uniform grid, 12.5px text, 14px favicon. Labels drop the descriptor:
"GAME.X — Bitcoin Cash game platform" renders as "GAME.X". The
trimmer splits on the first em-dash / en-dash / hyphen that's
surrounded by whitespace, so single-word titles and hyphenated
compound names ("Foo-Bar" with no spaces) come through intact. Full
title still shows on hover.
2026-09-09 02:05:46 +02:00
Local Dev
ba806005fa fix(theseus/updater): re-add --force-run so Theseus auto-relaunches after silent install
install-update-now was spawning setup with ['/S'] alone since the
0.3.31 rewrite. That installs correctly (E2E-proven multiple times
this week) but leaves the user without a running browser after the
install completes — the setup exits, and the user has to click the
Start-menu shortcut to get Theseus back.

--force-run is electron-builder's NSIS convention for 'start the app
when the install finishes'; it makes the whole update feel like a
seamless in-place restart. --updated stays out (was proven not to
affect the install itself on our config).

Reported by user 2026-09-09 after 0.3.37 → 0.3.39 auto-update ran
cleanly but silently, with no post-install relaunch.
2026-09-09 00:58:26 +02:00
Local Dev
81d276f655 feat(theseus/screenshot): 0.5.0 — sidebar-first editor, direct save/copy, sounds
Two problems the old editor kept hitting:
- __pending drain race: opening the editor a second time (refresh, back-and-
  forth navigation) found the storage entry already consumed and bailed to
  a blank canvas silently.
- Cross-origin img loading: editor.html at file:///…/addons/screenshot/
  loading a scratch PNG at file:///…/addons-data/ counts as cross-origin
  under Chromium's file-URL policy; setting crossOrigin="anonymous" made
  the load fail outright.

Rebuilt editor v2:
- Load path is idempotent: silentmode.invoke("getBytes", {name}) → addon
  reads the scratch file and returns a data URL. No __pending drain, no
  cross-origin trickery — data: URLs are same-origin and never taint the
  canvas, so getImageData / toBlob keep working.
- Two-canvas model (#base + #over, over is pointer-events:none) so live
  previews don't cost a full re-composite per mousemove.
- Tools: cursor, arrow, rect, ellipse, pen, text. 6 swatches, 3 widths,
  undo / redo (25-deep). Copy + Save at the top bar. Back and Maximize
  buttons in the same top bar so navigation controls stay reachable when
  the toolbar wraps at narrow widths.
- Keyboard: A/R/O/P/T select tool, Esc = cursor, Ctrl+Z/Shift+Z undo/redo,
  Ctrl+S save, Ctrl+C copy.
- Toast surface for save/copy/error feedback.

Sidebar panel gains a direct raw-save path so the user can copy or save the
capture without entering the editor:
- Two-row actions: [Copy] [Save] on top, [Discard] [Edit] below.
- Copy uses navigator.clipboard.write(ClipboardItem); Save uses
  <a download> with a Blob URL — same path Chromium's will-download
  tracker already handles, so the file lands in Downloads and the chip
  updates like any other save.

Inline "clear all" confirmation replaces the native confirm() — the old
system-modal opened over the tab area (out of the sidebar's visual
context) and looked like Windows 95. Now a compact red strip appears
under the Recent header with Cancel / Delete buttons.

Sounds + a sound-on/off toggle in both surfaces:
- Web Audio oscillator-synthesized (no .wav shipped): shutter click on
  capture, two-tone bloop on copy, descending pair on discard/back,
  ascending triad on save.
- Preference stored in silentmode.storage under "soundOn" (default on),
  shared between the panel and the editor.

Simplifications:
- Dropped the addon's "arm" onMessage handler (superseded by getBytes).
- Manifest capabilities: sidebar-panel + capture-tab (no open-tab,
  no toolbar-menu).

Bundled but not shipped — parent session handles the OTA sign + push.
2026-09-09 00:56:41 +02:00
Local Dev
a65dc0a153 feat(theseus/devtools): 3-mode dock — bottom / sidebar / two-sidebars
New settings.devToolsDock (default 'bottom') read by the F12 handler
in main.js on each open. Values:
  bottom       - Chrome's own default, docked under the tab
  sidebar      - right-side dock (mode:right). Add-on sidebar tucks
                 out of the way while DevTools is up.
  two-sidebars - right-side dock with the add-on sidebar left in
                 place, so both share the right area.

Settings > General > Developer tools now hosts a 3-option radio group
(same .polrow style as the collision policy). Changes apply instantly
- the F12 handler reads settings.devToolsDock every time it opens, so
no relaunch is needed.
2026-09-09 00:51:05 +02:00
Local Dev
d7d4e7eb4e 0.3.38: brand-green scrollbars everywhere + captureTab widens the viewport when sidebar shrinks the tab
Two changes shipped together (main.js touched by both this session and a
parallel session in different regions):

Scrollbars — from the "empty white space should be grey, thumb should
be Bitcoin Cash green" ask:
  * new SCROLLBAR_CSS constant + styleScrollbars(wc) helper injects the
    theme on every dom-ready
  * thumb #0AC18E (BCH primary), track rgba(120,130,150,0.18) subtle
    neutral grey so it works on both dark and light surfaces without
    hardcoding either; 6px radius, 2px inset via background-clip:padding-box
  * modern scrollbar-color on <html> for Chromium 121+; ::-webkit- rules
    with !important as the fallback / override for sites that theme
    their own scrollbars — scrollbar-width intentionally left alone so
    a page that hides scrollbars entirely keeps that behaviour
  * hooked into every wc we own: createTab, chrome, popover, enginePicker,
    downloadsPop, addressPicker, pwFillPop, linkStatus, sidebar (so every
    add-on panel like Aegis picks it up), approvalPop
  * fires once immediately if the wc is already past dom-ready when we
    attach — fixed views load fast during startup, we'd otherwise miss

captureTab full-page — from the parallel session's screenshot work:
  * before Page.captureScreenshot with captureBeyondViewport we now
    override Emulation.setDeviceMetricsOverride to the window's full
    content width so an open sidebar (or other on-screen chrome that
    narrowed the tab view) doesn't clip the shot — capture comes back at
    the page's natural full width, not the visible width
  * attach the debugger for the call if it isn't attached, detach on
    return; clear the metrics override in finally so the tab returns to
    its normal layout regardless of success
2026-09-09 00:42:38 +02:00
Local Dev
e36d2b361c feat(theseus/toolbar): Firefox-style single drag handle, zero-sum URL/search ratio
The two independent drag handles (right edge of URL bar, left edge of
search bar) are replaced with ONE handle sitting between them, wrapped
in a new .urlsearch flex container that owns the URL-bar-plus-search-bar
budget between the nav buttons on the left and the trailing dock on the
right.

Zero-sum semantics: dragging the handle right grows the URL bar and
shrinks the search bar; dragging left inverts. Nothing else in the
toolbar moves — nav buttons, Downloads, extension dock and the
⛓ Theseus logo all sit outside .urlsearch's flex parent.

When the window shrinks below the responsive breakpoint the search
bar (and the drag handle) hide as before, and the URL bar grows to
fill the .urlsearch budget on its own (added flex: 1 1 auto in the
data-responsive rules for .urlwrap).

Verified static rendering: url=700px → search=157px, url=300px →
search=539px, url=default → 60/40 split, narrow window → search
hidden and url fills.

Old settings (urlBarSize / searchBoxSize / searchBoxWidthPx) are
ignored by chrome.html but kept in main's SETTINGS_DEFAULTS so an
older chrome.html could still read them on a downgrade. Only
urlBarWidthPx is used going forward.
2026-09-09 00:11:26 +02:00
Local Dev
71bd3004e0 feat(theseus/settings): Plug-ins section — Ariadne's Thread + Aegis moved out of General
New sidebar tab between Privacy and Extensions. The two long
system-scoped cards (Ariadne's Thread system-wide resolver, Aegis
built-in wallet) were bloating the General section; they cluster
naturally as "components that live alongside Theseus, each with
install/update/on-off controls of their own" and now have their
own home.

- Adds <a data-sec="plugins">Plug-ins</a> to nav.side
- New <section id="plugins"> with a short lede
- Ariadne + Aegis row blocks moved from General to Plug-ins verbatim
- sections array in showSection() extended with "plugins"
- Tab-switch handler clicks ariadneRefresh so status is never stale;
  Aegis card auto-loads on page-init and its "Check for updates"
  button stays user-initiated (avoid firing a network request every
  time the user opens the Plug-ins tab)
2026-09-08 23:00:41 +02:00
Local Dev
1b10afa1ca feat(theseus/aegis): canonical coin logos from cryptocurrency-icons
Replace the hand-drawn approximations with the official SVGs from
github.com/spothq/cryptocurrency-icons — the permissive-licensed set most
exchanges, block explorers, and other wallets standardised on. Users see
the same BCH / BTC / DGB / SC / TRX / ETH / SOL marks in Aegis they
already recognise from Coinmarketcap, Coingecko, Trezor, MetaMask, etc.

- BCH: green disc with the tilted Bitcoin-Cash B
- BTC: orange disc with the classic Bitcoin B glyph
- DGB: blue disc with the DigiByte D + swash
- SC:  brand-green disc with Siacoin's stylised S
- TRX: red disc with the geometric Tron triangle-net
- ETH: purple disc with the two-triangle Ethereum rhombus
- SOL: mint disc with the three-slash Solana mark

All SVGs are inlined in panel.js — no network fetches at panel load.
Bumped addon 0.4.3 → 0.4.4 so seedBundledAddons reseeds the new panel
on next launch.
2026-09-08 22:47:43 +02:00
Local Dev
344c71b315 fix(theseus/aegis): drop registerSidebarPanel icon override so dock inherits brand shield
The toolbar dock still showed the 🛡 emoji even after chrome.html learned
to render data-URI icons — because registerSidebarPanel({icon}) is the
per-panel icon that overrides manifest.icon, and Aegis was passing "🛡"
verbatim. Dropping the override lets addons-host's `icon = manifest.icon`
default kick in, so the dock button pulls the branded aegis.x/brand
shield the manifest now advertises.

Version bumped 0.4.1 → 0.4.3 to force seedBundledAddons to reseed the
new index.js on next launch.
2026-09-08 22:40:48 +02:00
Local Dev
8047d84c47 Ship Theseus 0.3.35 4a7bd82f (proves 0.3.34 self-update path E2E)
Version bump only, no code changes. Published to prove the just-shipped
0.3.34 install can auto-update itself using the reverted-to ["/S"]
spawn code.

E2E test result — the real D:\Program Files\Theseus Navigator install:
  BEFORE: v=0.3.34, hash e59d6da2..., mtime 09/08 22:02:46
  AFTER:  v=0.3.35, hash 420b7320..., mtime 09/08 22:31:18
  Registry updated at same D:\ path
  Post-install proc count 0 (no --force-run in the current code, as designed)

Second confirmation this session that install-update-now's ["/S"]-only
spawn (unchanged since 0.3.1) does the right thing against a real
install at a path with spaces.

Installer: 4a7bd82f30a00a6795670d0a48cf590832fd077d84726966d8fbea04fc23be1b
Portable:  138c03ad21cb6fb2a6a7f89cc726adee618622c11eb58177857fa24afa955e47
2026-09-08 22:36:50 +02:00
Local Dev
523832cd72 feat(theseus/screenshot): 0.4.0 — editor lives inside the sidebar, maximizable
User report: the sidebar preview lands correctly, but the moment the editor
opens in its own tab the picture is blank. Rather than chase that class of
handoff race again, put the editor in the same webContents as the panel:
the sidebar view navigates panel.html ↔ editor.html in place. Same
document object, same silentmode.storage surface, no cross-tab __pending
transfer at all.

- panel.html "Edit" button now calls silentmode.invoke("arm", …) — the
  add-on rewrites __pending with the currently-previewed capture's bytes,
  and the panel does location.href = "editor.html?name=…". Sidebar view
  loads the editor with the same preload; editor.js's storage-based load
  path pulls the pending entry out and paints.
- editor.html gains a "Back" arrow (returns to panel.html) and a
  maximize / restore icon.
- discard() now navigates to panel.html instead of closeTab() — there is
  no tab to close.
- Manifest drops the "open-tab" capability entirely (no more full-tab
  editor); keeps sidebar-panel + capture-tab.

Framework: new silentmode.sidebar.{maximize, restore, toggleMax, isMax,
onMaxChange}. main.js honours them via new sidebar-maximize / -restore /
-toggle-max / -is-max IPCs, remembering the pre-maximize width so a
restore drops back exactly. The sidebar drag-grip auto-exits maximize
mode on any user drag, so pulling the edge always lands on the pre-max
value plus/minus the delta. sidebar-preload exposes the surface;
chrome.html renderer is untouched — this is a per-panel affordance.

Editor tools (crop / arrow / rect / ellipse / pen / text / mosaic /
undo / redo / copy / save) unchanged. Save still goes through Chromium's
<a download> path, so the file lands in Downloads and appears in the
download chip like any other save.

Bundled but not shipped — leaving version bump + deploy to parent session.
2026-09-08 22:18:41 +02:00
Local Dev
1b74195298 bump theseus 0.3.34 for the real-install auto-updater E2E test 2026-09-08 22:03:04 +02:00
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