Commit graph

253 commits

Author SHA1 Message Date
Local Dev
d07f2ff757 Theseus 0.3.126: Claude connector detects Microsoft Store install of Claude Desktop
The Store install of Claude Desktop lives under
%LOCALAPPDATA%\Packages\Claude_<publisher-id>\, and its "AppData\Roaming"
is virtualised to LocalCache\Roaming inside that package. The classic
%APPDATA%\Claude\ folder is never read by the Store app, so a
claude_desktop_config.json dropped there is invisible to it; Theseus's
old existence check against path.dirname of that classic path was both
false-negative (nothing in classic, Store present) and false-positive
(empty classic folder left over, Store the real install) — the user saw
"Not installed on this computer" with Claude Desktop clearly running.

desktopConfigPath now looks for a Claude_<id> package first and uses
its LocalCache\Roaming\Claude path when present; otherwise it falls back
to the classic path. Added a desktopInstalled() helper that treats any
of: the config dir, a Store package, %LOCALAPPDATA%\AnthropicClaude,
%LOCALAPPDATA%\Programs\Claude, or Program Files\Claude as proof of an
install. register() mkdirSyncs the chosen path so the Store case
succeeds on first write.
2026-10-27 22:46:22 +02:00
Local Dev
f3a8d883e2 Theseus 0.3.125: Claude connector gets a simultaneous-session cap
New row in the connector panel: Simultaneous sessions. Three radios —
1 only / Multi / No limit — and a number input next to Multi for the
exact cap (clamped 1-100). Default stays at no limit, so existing users
see no behaviour change until they pick a value.

On the server side, initialize counts live sessions first (a GC pass over
expired ones runs so an abandoned tab doesn't permanently hold a slot)
and refuses any that would push past the cap with 429 and a message the
client surfaces to the user ("Theseus is at its simultaneous-session
cap (<N>). Disconnect a client, or raise the limit..."). Lowering the
cap below the live count is non-retroactive: no one gets kicked, but the
next connect fails until one goes away.

Settings surface widened: publicState() carries sessionLimit, and a new
set-session-limit message writes it (persisted in the add-on's storage
alongside token / port / allowEvaluate).
2026-10-27 22:30:23 +02:00
Local Dev
1916d6adfe Theseus 0.3.124 (cont'd): Shield panel gets its own close button
Shield is a right-side add-on panel (no `side` in the manifest). Unlike
left panels, right-side ones get no shared chrome from Theseus — the
panel-header with Maximize/Close only draws over left panels. So the
Shield panel had no visible close button and the user had to re-click
the Shield icon in the dock to toggle it off.

Added a × button in the add-on's own header that calls
window.silentmode.close() (sidebar-preload's close IPC). Minimal CSS
with a hover tint that matches the panel-header's own close.
2026-10-27 22:02:23 +02:00
Local Dev
aea158ab05 Theseus 0.3.122 followups: AI engines page, Pick-AI edit button, Pithos panel, Did-you-mean on DNS failures, LLM picker UI polish, real-brand icon preference
Shipped on top of the 0.3.122 Settings restructure commit.

AI engines settings page. New top-level nav entry "AI engines" with its own
Default picker, Enabled list, catalog, discover filter and + Add AI engine
form. The Search page is now LLM-free — ENGINE_KINDS is `["search"]`, the
Search catalog filters out kind="llm" entries, and the Search custom-URL
form only adds kind="search" engines. add-engine IPC now accepts a kind:
"llm" field (sets defaultLlmId instead of searchEngine for LLM customs).

Pick-AI picker. Borders removed, corners rounded (16px), heavier shadow;
"Pick AI engines…" footer row dropped. Edit button (pencil icon) added to
the header; opens the new AI engines settings page via `llm-picker-settings`,
which now routes to the "ai-engines" slug (openSettingsTab falls through to
"search" for legacy profiles that lack the section).

Icon priority flipped. allEngines() now prefers a fetched favicon (the
site's own brand mark, cached per profile) over the bundled generic tile.
Bundled tiles still carry the first paint while the fetch runs, and the
emit after fetch swaps in the real brand. Offline profiles see the tile
indefinitely — same reliability as before.

Pithos sidebar panel. bundled-addons/pithos/addon.json declares a `panels`
block so sidebarLeftPanels() returns Pithos's panel BEFORE the add-on's
on-demand activation. Previously, the Sidebar settings' Theseus native
apps card was missing Pithos: it only appeared after first launch, when
the add-on's own registerSidebarPanel call ran. Hermes already did this.

Did-you-mean on DNS failures. The error page's "Did you mean" row now
merges BCNR warm-index matches with ICANN alternative-TLD swaps + history
base-name matches. For my.mynymbox.com the suggestions are my.mynymbox.io,
mynymbox.io, my.mynymbox.net, mynymbox.net — the subdomain-strip is
interleaved so a mistake like typing my.mynymbox.com when the real site
is client.mynymbox.io still surfaces mynymbox.io near the top. Both paths
are local-only; no network, no leak of what the user is browsing.

Sidebar settings tightened. "How panels open" collapsed to one row with
two side-by-side option cards; "Reset panel widths" and "AI engine in the
sidebar" are one-liners now.
2026-10-27 20:50:40 +02:00
Local Dev
9095a5ecf9 Theseus 0.3.112: AI picker chevron fixed, home polish, performance toggles
Three home-page tweaks:
- Removed the YOUR LINKS and SILENT MODE section headings; the two
  panels now stand on their own without labels.
- The + Add card cell now matches the real cards' size and shape so
  it reads as a peer of the grid rather than a short dashed strip.
- Empty slot cells in the left grid are invisible by default and
  only reveal their dashed outline when you hover the strip or drag
  a link over them. The + add-link cell stays visible as the
  discoverable entry.

AI engine picker:
- The chevron badge on the AI button is now a plain span with the
  button role, not a nested <button> inside the main AI button.
  Chromium flattened the invalid nesting so the chevron's own click
  handler never fired; the picker now opens from the chevron and
  from keyboard Enter / Space as well as right-click.

Performance (Settings > Performance > Startup):
- Pithos ships with activation: on-demand; its control server for
  s3d no longer boots at launch. Wakes on first panel open or a
  pithos.sia navigation.
- Hermes relay auto-restore (1.5 s after launch) is now gated by a
  new setting hermesAutoRestore (default on). Turn it off to skip
  background Nostr relay connections for users who don't live in
  Hermes.
- New setting pithosAtLaunch (default off) mirrors the existing
  walletAtLaunch so users who do want Pithos ready at launch can
  opt back in.
- The Lightest preset now also turns off pithosAtLaunch and
  hermesAutoRestore.
2026-10-24 14:20:20 +03:00
Dev
a920737c3c Claude connector 0.2.0: connect Claude Code and Claude Desktop from the panel
Setting the connector up meant copying a command with a token into a
terminal, and since 0.3.107 the token rotates whenever the connector
stops, so a configured client silently lost access after any extension
toggle and had to be set up again.

The panel now has a Connect button per app. Claude Code is registered
through its own CLI (claude mcp add-json, user scope), so its config is
written by Claude Code itself; Claude Desktop gets only the theseus entry
in claude_desktop_config.json, with a backup and no write to a file that
does not parse. Apps connected this way are re-registered after every
start and every Revoke when the address or token no longer matches. The
panel opens by itself the first time the extension is turned on. The
copy-a-command route stays under "Set up by hand".
2026-10-24 00:32:06 +03:00
Local Dev
7f70779f1c Theseus 0.3.107: two-section home + Claude connector hardening
Home page splits into two self-contained panels so the left-column
links no longer scale with the Silent Mode cards. The slot grid is
narrower, the icons default closer to Windows desktop-shortcut size,
and each section carries its own subtle panel background and heading.

Claude connector hardening (the opt-in MCP add-on from 0.3.106):

- Pin the approved origin to the TabDriver on every Controller.use()
  and re-check the tab's current URL before each CDP read / input
  (isolated, snapshot, screenshot, clickAt, insertText, press,
  setFiles, evaluate). A meta-refresh or soft-nav to an unapproved
  origin between approval and the call now throws instead of leaking
  content or steering input to the new site.
- Rotate the bearer token on every stop() so toggling the connector
  off (toolbar chip, panel switch, deactivate) invalidates existing
  credentials. Re-enabling issues a fresh token; the panel's install
  strings update on the next start. Matches the mental model where
  "off" means "the keys change" instead of "the server stops".
- click without a ref now resolves the element at (x, y) through
  DOM.getNodeForLocation and refuses if it's a password / one-time-
  code field. Previously only ref-based click ran isSecretField; raw
  coordinates let focus land on a password field before FOCUS_GUARD
  kicked in to block typing.
2026-10-23 19:12:52 +03:00
Dev
c06557e957 Theseus: Claude connector, an opt-in MCP server for the signed-in profile
Claude sessions could not work inside the user's own profile: the desktop
app's browser lost synthetic pastes and typing in Medium's editor, and a
browser-wide --remote-debugging-port would hand every session to any local
process. The connector is a built-in extension, off until turned on in
Settings > Extensions, that serves MCP on 127.0.0.1 behind a per-install
token and drives one tab at a time through that tab's webContents.debugger.

- Host: a "tab-control" capability (built-in add-ons only) for listing,
  opening, navigating, closing and focusing tabs, handing out web tabs'
  webContents (never Settings, extension or home tabs), and a toolbar chip
  plus tab outline while a client is connected; the chip's X stops it.
  Built-in add-ons can ship "defaultEnabled": false.
- Tools: list_tabs, open_tab, navigate, activate_tab, close_tab, screenshot,
  read_page_text, snapshot (accessibility tree with refs), click, type
  (insertText + real Enter), press_key, paste_html / paste_text (system
  clipboard + webContents.paste, clipboard restored), upload_file
  (DOM.setFileInputFiles), wait_for, and evaluate behind its own switch.
- Safety: first use of each site asks the user; password and one-time-code
  fields are refused; uploads only from folders the user added; requests
  from web pages or foreign Host headers are refused; every action is
  logged with a timestamp in the panel and actions.log.
- Claude Desktop runs stdio-shim.cjs through the Theseus executable in Node
  mode.
- Tests: unit (protocol, auth, policy, shim) and an end-to-end run on a
  throwaway profile that types, pastes HTML with a heading and a link, and
  uploads a PNG on a local page.
2026-10-23 17:45:02 +03:00
Local Dev
93e54ca348 translate 0.1.6 -> 0.1.7: translate as you type, and say what was detected
Typing never triggered a translation. The input handler was wired only to the
language detector, so nothing happened until Enter, the Translate button or a
language change -- the panel looked broken to anyone who simply typed and
waited. Translation now runs 500 ms after the text settles.

Each request carries a sequence number. Typing outruns the network, and
without that guard a slower earlier response paints its stale text over a
newer one.

Detection already worked, but wrote its answer only into the text of the
collapsed "Auto-detect" option, which a closed select hides -- so it read as
"detection is broken" when it had in fact succeeded. Name the language in a
row under the selects, and lower the 12-character floor to 5, since short
phrases never cleared it. With translate-as-you-type on, skip the standalone
detect call: the translation response already carries the detected language,
so asking twice only doubled the load on a public mirror.

Two of the three fallback mirrors were dead, checked by posting to both
endpoints: translate.plausibility.cloud answers 405, and lingva.ml serves an
HTML page because it is not a LibreTranslate API at all, so it could only ever
produce the "HTML instead of JSON" failure. Drop both and add
silentmode.st/libre, which stays a fallback rather than the default because it
covers six languages against disroot's fifty.

Auto-translate sends text to a translation server as it is typed, so it is a
visible toggle rather than silent behaviour. Default on.
2026-10-22 15:59:09 +03:00
Local Dev
3b2cad491d hermes: ship the browser side of the Theseus feature set
Fixes the "unknown invoke: fetchCloudBackup" dead-end on mobile sign-in
and the empty hooks the Settings UI depended on. The shim now implements:

- Local wrap: on signup it generates a BIP-39 mnemonic (@scure/bip39),
  derives the Nostr sk via PBKDF2+HKDF with purpose "messenger/0" (same
  chain Theseus runs), scrypt+AES-GCM wraps the mnemonic (@noble/hashes
  scrypt matching HERMES_SCRYPT N=2^15 r=8 p=1), stores it in
  localStorage.hermes.wrap. hasBackup/getBackup use that wrap, so a
  password sign-in now works on the same device.

- Cloud backup: publishCloudBackup / fetchCloudBackup / removeCloudBackup
  / hasCloudBackup matching Theseus's dtag format
  (hermes.backup.v1/<sha256(bareName)[:32]>). Password unlocks the local
  wrap, re-wraps for the cloud copy with a fresh salt, publishes a
  kind:30078 to every relay, remembers the event id for later retract
  via NIP-09.

- Phone discovery: setPhone / clearPhone / findByPhones with the same
  hermes.phone/<base64url(sha256(E.164))[:32]> d-tag Theseus uses, so a
  vCard import on the browser surfaces the same matches a Theseus user
  would see.

- contactsUpdate / contactsRemove rounded out so the panel's contacts
  menu is fully wired.

Also:

- Default relay list bumped to [wss://hermes.x, wss://relay.silentmode.st,
  wss://nos.lol] in both the Theseus host and the web shim, so every
  publish/fetch hits our own strfry on the VPS and the cloud backup lives
  somewhere we control.

- Theseus host: addons-host.js + main.js now understand a `width` field
  on sidebar panels, so the Hermes panel declares width:500 and opens at
  a Telegram-ish width by default (user can still drag; saved per-panel).

- Panel + web messenger: forced color-scheme:dark (the brand mark has
  hard navy cutouts that stand out as "black inside the envelope" on a
  light background; dark everywhere is cheaper than theme-aware marks).

- Password fields: 👁 toggle appears on every <input type="password">
  via a tiny JS enhancer in both the panel and the web messenger.

- Settings/signin tabs: Sign in / Sign up persistent pill, drag-to-resize
  contacts/thread splitter (persisted per device), 2-column always.
2026-10-22 15:33:07 +03:00
Local Dev
b2fef43607 Theseus 0.3.103: sidebar panel context menu + Hermes icon framing
Right-click on a sidebar panel (WhatsApp, Telegram, LLMs, add-on panels
like Hermes) now opens a native menu with Copy image / Save image as /
Open link in new tab / Copy / Back / Forward / Reload. Previously the
sidebar views had no context-menu listener attached, so sites like
WhatsApp Web that intercept right-click left the user with no way to
copy an image.

Hermes mark in the sidebar strip now zooms to the V-fold and wings;
envelope body partially visible. The original viewBox had ~43% empty
space top-and-bottom, so the glyph rendered at ~15 px inside the 26 px
icon frame.
2026-10-22 13:48:09 +03:00
Local Dev
c944952f04 hermes panel: mirror the Sign in / Sign up tab bar from the web
Theseus's sidebar panel.html had the pre-redesign flow (two primary buttons
+ Create a new account toggle + Name+password/Seed-phrase chip switcher).
Replaced with the same persistent pill tab bar the web messenger uses:
Sign in / Sign up visible together, active one filled, inactive outlined;
tapping an inactive tab swaps the form below with no back step. "Recover
with seed phrase" is a quiet link that opens its own form (with ← Back).

The Theseus-only "Open with Theseus ID" quick path now lives inside the
Sign in tab's form and hides entirely when the vault is locked — no more
disabled button + hint about unlocking the vault cluttering the signin
screen. Bumped the bundled addon to 0.2.9.
2026-10-22 13:28:47 +03:00
Local Dev
bbe5d3d298 hermes: cloud-wrapped backup (opt-in B) + mobile site polish
Users can now sign in with name + password on a device that has never seen the
account by opting into a cloud backup at account creation. The seed phrase is
locally re-wrapped with scrypt + AES-GCM keyed by the password and published
as a NIP-78 kind:30078 event under d-tag `hermes.backup.v1/<sha256(name)>`.
Relays only ever see opaque ciphertext; the password is the only decryption
key, so backup strength is password strength.

Signin tries the local wrap first (fast, no network) and falls back to the
cloud copy if the device hasn't been used before. Settings → Backup now has
"Back up to cloud" / "Re-upload" / "Remove cloud backup" controls that reuse
the Reveal-seed password field as the key.

Site: added @media breakpoints to shared.css so the header collapses cleanly
on narrow screens (icon-only brand under 380px, hidden "Sign in" label under
640px), the hero mark drops to 84px, h1 scales down, and buttons shrink to
touch sizes. Also fixed a stale reference to the removed `mnemonicBox` id in
the Create-account toggle that was throwing a TypeError on mobile.
2026-10-22 03:46:45 +03:00
Local Dev
6b4654231b hermes settings: scrollable modal + Address book vCard import
Two Settings-pane fixes:

1. .modal was clipped on short viewports (mobile landscape, small
   laptop screens): place-items:center + fixed max-width with no
   max-height meant the content below Phone discovery / Backup fell
   off the bottom. Add max-height: calc(100vh - 24px) + overflow-y:
   auto so the whole thing scrolls inside the backdrop. This is why
   the user couldn't see Phone discovery on mobile.
2. Address book section between Phone discovery and Backup: 'Import
   contacts from vCard' triggers a hidden file picker (<input
   type=file accept=.vcf>) that reads the file client-side, extracts
   FN + TEL per VCARD block, hands the phone list to findByPhones,
   and auto-adds the matched Hermes identities as contacts with the
   vCard name as nickname.

Lives in both the Theseus addon panel and the hermes.x web messenger.
Phone discovery was already in Settings — the modal clipping just hid
it on smaller viewports.
2026-10-22 03:12:28 +03:00
Local Dev
5984d39253 hermes signin: one Sign in button + two chips, nav + mobile dark bg
Signin screen (both the Theseus addon panel and hermes.x/messenger):
- Open with Theseus ID and Create a new account stay as top-level
  actions (unchanged).
- Beneath them, a 'Sign in' divider + two chips [Name + password]
  [Seed phrase] drive one unified Sign in button. Toggle swaps the
  input area between the password form and the mnemonic textarea.
  The old 'Sign in with name + password' and 'Open an existing
  account' secondary buttons are gone.

Site nav restructure (site-hermes-x/):
- Header now: Hermes.X brand + Overview + Sign in icon (opens
  /messenger). Messenger tab, Branding tab, and Get Theseus pill are
  all removed from the header.
- Footer carries Branding + Open Messenger + Get Theseus links as
  secondary nav. Branding is 'here' on the brand kit page.

Mobile dark bg fix (shared.css):
- color-scheme: dark on :root so mobile browsers don't flip the
  page into a light theme that makes the sky-blue mark unreadable.
- html { background: var(--bg) } so the pre-body paint is dark too
  (Safari / Firefox mobile briefly show the html bg before body css
  loads).
2026-10-22 03:08:40 +03:00
Local Dev
975edba88f hermes signin: hide the hermes: scheme + add name+password sign-in
Scheme form "hermes:alice" was leaking into the UI (default display
mode + hero copy + placeholders). Drop it as a visible option: the
display-mode picker now offers bare / dotted / email and defaults to
bare so users just see "alice" in chat lists and settings. The
hermes: URI scheme stays available as an input form (parseHandle
still accepts it) — just not surfaced in the UI.

New sign-in path: a "Sign in with name + password" button on the
signin screen opens a two-field form that calls getBackup({password})
to unwrap the locally-saved mnemonic, then init({mnemonic, handle})
in one shot. This covers the "come back to the same device" case
without typing the full seed every time. From a new device the seed
phrase path is still there — the form hint says so.

Applied to both the desktop addon panel (TheseusNavigator/bundled-
addons/hermes/panel.html) and the hermes.x web messenger
(site-hermes-x/messenger/index.html) so they stay in step.
2026-10-22 02:27:23 +03:00
Local Dev
47af393f22 hermes brand kit: inner V-fold now reads on every surface
Before: the on-sky lockup had a dark mark with dark cutouts — the fold
V-shape disappeared because the cutouts matched the mark colour instead
of the sky backdrop. Same on cream.

Now three per-surface mark variants, cutouts coloured to match the
expected background so it shows through:
  mark.svg          sky body  + navy cutouts   → dark panel
  mark-on-sky.svg   navy body + sky cutouts    → sky-blue surface
  mark-on-light.svg navy body + cream cutouts  → light surface

Logo lockups rebuilt the same way: logo-horizontal-on-sky.svg uses the
dark+sky mark variant, logo-horizontal-light.svg uses the dark+cream
mark variant, same for stacked.

Branding page's on-sky / on-light preview cells repointed at the new
variants. addon.json bumped to 0.2.6 (same mark, re-emitted from
pipeline for byte parity with the sites).
2026-10-22 00:14:54 +03:00
Local Dev
df994c2bdf hermes: tighter viewBox + bump sidebar strip icon size 20→26
Two tweaks so the mark reads at sidebar size.

- addon.json/mark.svg (and every mirror of mark.svg across the sites):
  rebuild with ZERO padding around the content bbox so the icon fills
  the slot vertically — before it was centred in a square viewBox that
  wasted ~45% of pixels. Version bumped to 0.2.5 so Theseus re-seeds.
- quicklinks.html: .icon svg, .icon img goes from 20×20 to 26×26
  (container stays 34×34; same breathing room, bigger glyph). Ships
  with the next Theseus release — can't be hot-patched into the asar.

Deploy state: site-hermes-x is live on the VPS and in bns/hermes.x/ via
the silentmode-sia-sync systemd timer, which was extended to include
hermes-x alongside sirius-x and bergamot. Future rsyncs of site-hermes-x/
to the VPS auto-sync to Sia within 5 minutes.
2026-10-21 23:02:32 +03:00
Local Dev
b013eebd5c hermes: use the vector mark everywhere, retire the raster paths
User supplied the real vector source at Hermes/Icons/file.svg. Dropped the
background rectangle, kept the sky-blue foreground + dark inner detail
cutouts, squared the viewBox around the content bbox with a small margin.
Result: ~6.6 KB SVG, pixel-perfect at every size — no more 60x downscale
blur.

- bundled-addons/hermes/assets/mark.svg: tight-cropped vector
  (viewBox centres the icon in a square so 1:1 slots don't crop).
- bundled-addons/hermes/assets/mark-64.svg: same, pre-normalised to a
  0..64 viewBox for legacy consumers that assume that range.
- bundled-addons/hermes/addon.json: version 0.2.4; manifest icon is now
  the SVG as a data:image/svg+xml;base64 URI (8.8 KB vs the previous
  16 KB PNG data URI).
- bundled-addons/hermes/panel.html: both img tags point at mark.svg at
  24 and 72 px.
- home.html / home-brand/hermes-mark.svg: Hermes.X tile uses the vector.
- site/hermes/{favicon,branding/mark}.svg: both now the user's artwork.
- site-hermes-x/assets/{favicon,mark}.svg: same.
- All /hermes site HTML img tags swapped from mark.webp to mark.svg.

Installed bundle + user-data cache hot-patched to 0.2.4 so this takes
effect on the running Theseus without a reinstall.
2026-10-21 22:52:18 +03:00
Local Dev
2abd4d9616 hermes: crop the mark to the icon area, ship 128/256 px PNGs
The 1461x720 webp downscales badly to 24 px (sidebar strip) and 72 px (signin
header) — browser is doing a ~60x reduction and the thin wing lines turn to
mush. Pre-crop around the icon's content bbox, make it square with a small
breathing margin, resize to 128 px and 256 px, drop transparency on the dark
backdrop. Addon manifest icon is the 128 PNG as a data URI (16 KB vs the
26 KB uncropped webp), and the panel pulls mark-128.png / mark-256.png at
the two sizes it needs. Also home.html's Hermes.X tile now points at the
cropped PNG so the home card isn't blurry.

Version bumped to 0.2.3 so seedBundledAddons picks it up on a release
bundle swap. The installed bundle + user-data cache were hot-patched
too so the fix is visible immediately in the running app.
2026-10-21 22:14:00 +03:00
Local Dev
8c4572e329 hermes: use the user's own mark.webp as the icon, drop the SVG attempts
User-authored artwork wins. mark.webp is the main icon; two sibling variants
(mark-wings-both.webp, mark-variant.webp) ship alongside for brand uses.

- bundled-addons/hermes/addon.json: version 0.2.2, icon/panels[0].icon are
  now data:image/webp;base64,... from the main mark.
- bundled-addons/hermes/assets/mark.webp: served by the host via the panel
  page's relative path (seedBundledAddons' fs.cpSync recursive carries it).
- bundled-addons/hermes/panel.html: both top-bar and signin inline SVGs
  become <img src="assets/mark.webp"> at 24 and 72 px.
- site/hermes/index.html: hero SVG → <img> at 120 px.
- site/hermes/branding/{index.html,mark.webp,mark-wings-both.webp,mark-variant.webp}:
  branding kit now carries the three webp files; the inline hero SVG uses
  the main one.
- site-hermes-x/{index,branding,messenger}/index.html: same SVG → <img>
  swap with the appropriate assets/ relative path.
- site-hermes-x/assets/mark{,-wings-both,-variant}.webp: sibling of the
  existing favicon.svg and mark SVGs (kept for backward refs that still
  point at them).

Legacy mark.svg + mark-stroke.svg + favicon.svg stay in place for any
external references; nothing in-repo points at them for the primary icon
slots anymore. favicons still point at the SVG files — safe to leave;
flipping those to webp is a one-liner if you want it.
2026-10-21 21:32:14 +03:00
Local Dev
e4a9a2cea9 hermes: addon 0.2.1 — bump so Theseus re-seeds today's user-data cache
The seedBundledAddons() version check is strict less-than: a cached v0.2.0
in %APPDATA%\Theseus\extensions\hermes\ wouldn't be overwritten by a bundle
also at v0.2.0, even if the files inside changed. Bumping to 0.2.1 forces
a reseed on the next restart so all of today's panel + API work (three-form
parser, Settings panel, kind:0 profiles, phone discovery) ships without a
manual cache wipe.
2026-10-21 19:06:56 +03:00
Local Dev
dd754c030b hermes: "on-chain registered name", not ".bch name"
Hermes handles are not tied to the .bch TLD — the user's names live on .x
today and the planned Hermes TLDs are .erm/.tel — so the hermes.x site,
the silentmode.st Hermes page and the add-on's description and panel now
say "on-chain registered name" and use alice.x / bob.x as examples.
Add-on wording ships on its own OTA; no version bump here.
2026-10-21 18:39:37 +03:00
Local Dev
5e27a1b53d hermes: phone discovery (opt-in), lookup contacts by number
Users can link one or more phone numbers to their Hermes identity by
publishing a kind:30078 claim event whose d-tag is a SHA-256 hash of the
E.164 number. The number itself never leaves the device. Add-contact and
message-send now also accept a +phone input directly — the client hashes it
and queries relays for the matching Hermes identity.

- lib/hermes.js: normalisePhone(str) strips separators + a leading 00
  into E.164, rejects anything that doesn't fit +[country][7-15 digits].
  hashPhone(str) → base64url-truncated-to-32 SHA-256 digest, used as the
  d-tag suffix under PHONE_DTAG_PREFIX. buildPhoneClaimEvent /
  buildPhoneRetractEvent emit the signed kind:30078 / NIP-09 kind:5.
- main.js: _hermesAPI.getPhone / setPhone / clearPhone / findByPhones.
  Plaintext phone persists in the identity meta (locally only) so the
  user can see what's linked and retract it; event ids are kept so a
  retract can reference the exact wire event. hermesResolveTo takes a
  phone-shaped input and does the discovery lookup transparently, so
  contactsAdd and send accept phones without a new entry point.
- panel.html: Settings → Phone discovery (link / unlink + privacy note),
  add-contact placeholder now lists +phone alongside the other forms.

Privacy stance stated in the UI: "anyone who already knows your number
can find you — same tradeoff as number-based messengers." No PSI tricks
yet; plain hash. Users who don't want it just don't link, which is the
default. Future slice can add a pepper if operators want to narrow the
brute-force window.
2026-10-21 17:21:16 +03:00
Local Dev
b5b3e5c1b2 hermes: Nostr kind:0 profiles — display name, picture, about
Peers' chat-list labels now cascade: contact nickname → kind:0 display name →
BNS handle → pk preview. Avatars render as a URL picture when kind:0 carries
one, with initials as fallback. Profiles are fetched on demand (background,
non-blocking) when a new peer pk shows up in the inbox or contact list, and
cached on disk so a cold start renders instantly.

- lib/hermes.js: buildProfileEvent({sk, displayName, picture, about}) emits
  a signed kind:0 with `name` + `display_name` set together (clients vary
  on which they prefer). parseProfileContent(content) handles both.
- main.js: profile cache at <userData>/hermes/profiles.json; auto-fetch
  from HERMES_DEFAULT_RELAYS with a 4 s per-relay cap. hermesPublishEvent
  centralises relay publish (used by profile save; send() retains its
  inlined copy for the DRY-up later). hermesRecord() kicks off a background
  profile fetch the first time a peer is seen; result fires on the
  hermes-profile bus event.
- main.js: _hermesAPI.updateProfile / getProfile. Addon proxies both.
- panel.html: Settings → Profile editor (display name, picture URL, about);
  publishes on save, pre-fills from the cache. Picture validated as http(s).
  labelFor() + avatarFor() centralise the display cascade. Profile state
  lives in state.profiles.
2026-10-21 17:18:07 +03:00
Local Dev
cee34c47e5 hermes: name+password signup, Settings panel, seed backup gated by password
Third signin option on the panel: enter a bare name + password, Hermes mints
a 12-word BIP-39 mnemonic locally, derives the Nostr key, password-wraps the
mnemonic for later Settings → Backup, and persists the sealed sk the same
way the other paths do. Save-forever still handles routine signin — the
password is only used to reveal the seed phrase and only from Settings.

- main.js: hermesWrapMnemonic / hermesUnwrapMnemonic via scrypt (N=2^15) +
  aes-256-gcm. Wrapped blob at <userData>/hermes-identity/mnemonic.wrapped.json,
  plaintext JSON — the wrap itself is the protection. On sign-out the blob
  is nuked alongside the sealed sk.
- main.js: init() now takes { create: true, handle, password }. Handle is
  validated (1-32 chars, kebab-friendly) and stored as `<name>.erm` so a
  mainnet free-manifest reservation lands on the same canonical form later.
  Mnemonic-path init optionally takes a password too — "promote this
  seed-phrase session to a password-protected backup" in one step.
- main.js: new _hermesAPI.getBackup({password}) and .hasBackup. status() now
  returns handle + source so the panel can label the restored session.
- panel.html: "Create a new account" button on signin reveals handle +
  password + confirm. ⋯ menu adds Settings… showing account info, display
  mode picker (hermes:alice / alice.erm / alice@hermes.tel — persisted via
  silentmode.storage), and the gated seed-phrase reveal. Reveal lays words
  out 12-across with 1-indexed numbering so a user copying to paper doesn't
  miscount. Backup section hides for vault / mnemonic sessions.

Still off-chain only — handles created this way are local labels until the
mainnet mint of the free manifest lets us register them against the
`hermes.erm` signed-records store (see [[hermes-name-scheme-plan]]).
2026-10-21 17:14:26 +03:00
Local Dev
4133153f32 hermes: three-form handle parser, hermes: scheme display, save-forever signin
Panel + standalone window now accept all three handle forms as synonyms, and
the UI defaults to the hermes:alice scheme form. Signin is persistent across
restarts via safeStorage-sealed identity; the ⋯ menu adds Sign out.

- lib/hermes.js: parseHandle(input) → {kind, value} canonicalises any of
  hermes:alice, alice.erm, alice.bch, alice@parent.tld, npub1…, or raw hex.
  renderHandle(name, mode) formats a .erm name as hermes:alice (default),
  alice.erm (dotted), or alice@hermes.tel (email). Non-.erm names always
  render dotted so a .bch handle can't masquerade as a sub-identity.
- main.js: hermesResolveTo() unifies contacts-add + send + their panel-API
  twins behind one path. Sub-identity (alice@parent.tld) resolution returns
  a crisp "not available yet" until the mainnet mint of the parent name's
  signed-records manifest lands — the parser accepts the form today so UI
  copy and placeholders can show it.
- main.js: safeStorage-sealed identity at <userData>/hermes-identity/,
  auto-restored on app ready. New _hermesAPI.signOut wipes it. init() takes
  { remember: false } for a one-shot session (default: persist). A
  hermes-restored event fires on auto-restore so the panel skips the
  signin screen.
- panel.html: renderHandle() mirror client-side; ⋯ menu with "Signed in as
  hermes:alice" header + Sign out; placeholders show all three forms; the
  signin hint tells users they stay signed in.

On-chain `.erm` and `hermes.tel` mints are deliberately deferred to mainnet
per user direction — the parser and display paths are tld-agnostic, so a
mainnet switch is one constant change in lib/hermes.js (HERMES_TLD /
HERMES_EMAIL_PARENT) plus the panel's mirror of them.
2026-10-21 12:32:59 +03:00
Local Dev
8777b1fc56 hermes: in-panel messenger with Theseus ID signin, spread-wings mark
The sidebar panel used to be a launcher that opened the standalone Messages
window; now it IS the messenger — signin screen with "Open with Theseus ID"
(derives the Nostr key from the unlocked vault seed) or "Open an existing
account" (12/24-word mnemonic fallback), then a contacts + thread view with
a narrow-width single-column fallback. The ⧉ button still pops the standalone
window out, so the Ctrl+Shift+E flow keeps working.

- main.js: expose a global._hermesAPI with status/canUseVault/init/inbox/
  send/markThreadRead/contacts* so the addon can proxy panel calls without
  granting it ipcRenderer or crossing the HERMES_ONLY sender gate.
  hermesEmit also fans out on an in-process __hermes_bus so the panel gets
  live inbox/status pushes decoupled from hermesWin's lifetime.
- bundled-addons/hermes/index.js: proxies each allow-listed method onto
  global._hermesAPI, forwards bus events to api.emit for the panel.
- panel.html: signin + app screens, mobile-style single column under 540px.
- Mark updated to the spread-wings variant: envelope sized up (34×22),
  three tapered trails extending outside the viewBox so the wings don't
  bunch at the back of the envelope at any size. Applied to the addon
  icon (manifest base64), the panel header, both /hermes sites, and
  site-hermes-x's favicon + mark SVGs.
2026-10-21 03:00:17 +03:00
Local Dev
6001686f09 hermes: propagate M v2 tapered-trails mark + sky-mid everywhere
Earlier iterations left the nested site/hermes/* on the superseded winged-
helmet design and the Theseus addon on acid-green despite the branding
tokens moving to sky-mid. This brings every surface to the same mark + colour:

- TheseusNavigator/bundled-addons/hermes/addon.json: both icon fields
  (toolbar + panel declared) swap from acid-green helmet to sky-mid
  (#38BDF8) tapered-trails envelope. Picks up on next addon re-copy.
- TheseusNavigator/bundled-addons/hermes/panel.html: inline SVG swapped
  from helmet dome paths to the tilted-envelope + 3 tapered trails. Uses
  currentColor so the panel's own colour token drives it.
- site/hermes/branding/mark.svg + mark-stroke.svg: standard (3 trails) +
  simplified 16-20px (1 trail) variants match site-hermes-x/assets/.
- site/hermes/branding/index.html: six inline mark cells (hero + 5 size
  cells) swapped in bulk.
- site/hermes/index.html: hero mark SVG swapped.

Grep confirms all seven surfaces now carry 'rotate(-22 32 32)' — the
tapered-trails signature. Nothing left on the old helmet.
2026-10-21 02:38:46 +03:00
Local Dev
4a7667c06e hermes.x: standalone site + sidebar addon side:left + mark v2 (tapered trails)
New site-hermes-x/ — standalone .x site (own nav, own assets, own OG tags),
sibling to site-theseus-x and site-sirius-x. Internal nav stays on hermes.x:
Overview, Messenger (preview + UI mockup), Branding (brand kit). The only
cross-link is 'Get Theseus' pointing at theseus.x where appropriate.

Mark redesigned: tilted winged envelope with three tapered speed-trails on
the back-left (top longest, bottom shortest). Default colour sky #38BDF8 —
swappable via --sky in site-hermes-x/assets/shared.css. Alternate orange
palette documented but not applied by default. Mark propagated to:
  - site-hermes-x/assets/mark.svg + mark-stroke.svg (16-20px variant)
  - site/hermes/{index.html, branding/{index.html, mark.svg, mark-stroke.svg}}
  - TheseusNavigator/bundled-addons/hermes/{addon.json, panel.html}

Theseus addon moves out of the top-right extensions dock and into the
left-strip sidebar: panels[].side = 'left' + registerSidebarPanel({side:'left'}).
Appears alongside Mail/Pithos/Telegram, excluded from rightPanels() so the
extensions dock no longer lists it. Verified via sidebarState() CDP query —
hermes:main is no longer in the right-panels list.

site/hermes/ (the nested silentmode.st/hermes page) also updated to the new
mark for consistency; both the sovereign hermes.x and the silentmode-nested
page now show the same winged envelope.
2026-10-21 02:19:58 +03:00
Local Dev
8eae448dde Hermes: Ermis shortcut (Ctrl+Shift+E), sidebar add-on, vCard import, brand kit
Shortcut: Ctrl+Shift+M -> Ctrl+Shift+E. Chrome owns Ctrl+Shift+M as
'switch profile' and E matches the Greek spelling (Ermis).

Sidebar discoverability: new bundled add-on at bundled-addons/hermes/
registers a left-strip icon + launcher panel. The panel is a thin chrome
(mark + 'Open Messages' + shortcut hint) that forwards clicks through
api.onMessage -> ipcMain.emit('hermes-open-request') -> openHermesWindow.
All real messaging code stays in main.js — add-on is purely for discovery.

Address book: opt-in vCard (.vcf) import. Dialog in the Add Contact modal
lets the user pick a file; main.js parses BEGIN:VCARD blocks for X-BNS-NAME
/ X-NOSTR-NPUB / X-NOSTR-PUBKEY plus .bch names and npubs mentioned in
NOTE fields. Candidates are previewed per-contact with checkboxes; nothing
is added until the user confirms. Non-matching vCards are returned too (so
the user can still add manually) rather than silently dropped. Nothing is
uploaded; parsing is local.

site/hermes: status badge flipped from 'designed - not yet built' to
'MVP - desktop'. New 'What ships today' grid covers threaded chat, send by
name, address book, local history (all live) and mobile + Tor (next /
planned). Hero carries the new Ctrl+Shift+E shortcut and a link to
/hermes/branding.

site/hermes/branding: new page. Mark SVG (winged envelope, two variants
for 16-20px and 24-160px display sizes), palette (reuses Silent Mode
tokens + an amber accent that's distinctly warm-yellow, not Hermes-orange
— so it never collides with Hermès the fashion house), name explanation
(English Hermes / Greek Ermis), voice notes, do/don't table, MPL-2.0
attribution.

Hermes/MOBILE-RECOMMENDATION.md: analysis of three mobile paths (inside
Ariadne / standalone / hybrid). Recommendation is Option 1: ship as a
screen inside Ariadne. Reuses the wallet seed, aligns with the design
doc's 'one seed many purposes' architecture, lowest total cost.
2026-10-21 00:45:25 +03:00
Local Dev
eac7020820 Aegis 0.32.3: WizardConnect waits between relay reconnects
When the relays were unreachable (after a sleep, or a relay offline) the
relay client reconnected with no delay at all, re-signing the queued
wallet_ready on every lap. On Theseus's main thread that spun a core for an
hour, grew the process to 2.5 GB and froze the browser. connect() now waits
2 s, 4 s ... up to 60 s between tries, and starts over once a connection
has held for a minute.
2026-10-07 19:17:25 +02:00
Local Dev
a33854a926 Pithos 0.3.23: rename S3 users 2026-10-07 00:17:32 +02:00
Local Dev
9d46e47eb1 Pithos 0.3.22: s3d is stopped gently and never mid-upload; stuck waiting files can be repaired 2026-10-06 20:30:22 +02:00
Local Dev
c2bc27b0a1 Pithos 0.3.21: clearer Share dialog with pithos.sia/l links, restart prompt after in-place updates 2026-10-06 00:13:56 +02:00
Local Dev
62c2f269af Pithos 0.3.20: drive mode chip and Share, pithos.sia/app, Linux built on Hephaestus 2026-10-05 23:52:35 +02:00
Local Dev
1e45428dec Aegis: a BNS site and a web site of the same name are different sites
Wallet permissions were filed by the origin Theseus reports, which is
https://name for both registries. Whoever registered a colliding name in
BNS inherited the real site's connection and its silent-payment allowance,
and the other way round. A page served from BNS is now filed, and named on
every approval, as bns://name.

Grants saved before this stay under https://name: a saved connection only
discloses an address and everything else still prompts, so the BNS site of
that name simply asks again. Payment allowances are reset once, because
nobody can say which registry's site an old one was granted to.

Needs a host that reports the registry; older ones behave as before.
2026-10-05 23:40:16 +02:00
Local Dev
bf92548267 Aegis 0.32.2: no transaction is marked replaceable
Start of the next batch; 0.32.1 is published.

Bitcoin inputs were given the BIP125 sequence that opts in to
replace-by-fee. Aegis does not replace transactions on any chain and has
no way to bump one, so advertising a payment as replaceable only told the
recipient to distrust it until confirmed. Inputs are final again.
2026-10-05 22:54:25 +02:00
Local Dev
a1eceb444a Aegis 0.32.1: the PIN pads follow the vault PIN's length
Since Theseus 0.3.80 the vault PIN can be 6 to 8 digits, but Aegis's
pads still submitted at six, so anyone with a 7- or 8-digit PIN got
"wrong length" from every Aegis prompt and had to use the master
password. The lock-screen, transaction and reveal pads now draw as many
dots as the host reports (pinLength) and submit at that length; a
wrong length is explained instead of shown as a wrong PIN. Aegis's own
PIN on older hosts stays at six.
2026-10-05 22:43:05 +02:00
Local Dev
dbef930d45 Pithos 0.3.19: open Pithos in a browser, from the app or the pithos.sia website 2026-10-05 01:47:37 +02:00
Local Dev
4ff75d312a Pithos 0.3.18: JSON key export, Linux desktop builds
Export JSON… gives scripts and agents one file with endpoint, key, secret
and drive. The desktop app now ships for Linux too (AppImage, .deb,
tar.gz), using per-user s3d paths there.
2026-10-04 22:49:48 +02:00
Local Dev
29ab1a5b9b Pithos 0.3.17: Windows desktop app with update notices; accounts named after your Sia Storage email 2026-10-04 22:02:15 +02:00
Local Dev
6225e79d9b Pithos 0.3.16: public links at navigate.st/sia, and the Pithos name opens Overview
Files in your own Sia account can now be shared with anyone through a
navigate.st/sia link that keeps working with this computer off; the
navigate.st service is live, so the buttons can ship.
2026-10-04 18:27:05 +02:00
Local Dev
e8723c29e4 Theseus: bundle Pithos 0.3.15 2026-10-04 16:18:17 +02:00
Local Dev
39ebd87d9d Theseus: bundle Pithos 0.3.14 2026-10-04 15:56:01 +02:00
Local Dev
f2913691aa Theseus: bundle Pithos 0.3.13 2026-10-04 14:39:45 +02:00
Local Dev
b99d3a6e54 Merge branch 'master' into claude/goofy-dubinsky-1f8f33 2026-10-04 04:32:44 +02:00
Local Dev
70b35e2520 Aegis: the PIN pads use the one Theseus PIN when the host offers it
On a host with api.vault.pin, Aegis no longer keeps a PIN of its own:
its lock-screen, reveal and transaction pads send the digits to the
Theseus vault PIN, which is checked in main against the one strike
counter Settings, the unlock prompt and Pithos also use. The vault is
opened there, and the panel receives a single-use proof (two minutes)
where it used to receive the master password; vaultUnlock, revealSecret
and pinGateSatisfied accept it, still bound to the request it was
entered for. The master password no longer passes through Aegis or its
panel for a PIN entry.

An existing Aegis PIN moves to the vault PIN on its first correct entry.
If Theseus already has a different PIN, the user is asked once which
one to keep. Setting and removing the PIN act on the vault PIN, and
Settings says that it is shared. Hosts without the API (Theseus
0.3.74-0.3.76) keep Aegis's own PIN exactly as before.
2026-10-04 04:19:38 +02:00
Local Dev
77f90dfa64 Aegis: smaller hardening from the 0.32 audit
- Electrum: a reply larger than 8 MB ends the connection; a server
  streaming without newlines used to grow the buffer without bound and
  re-parse it on every chunk, on the Electron main thread.
- Overlay amounts are formatted from integer strings: 0.1 ETH read
  0.100000000000000006, and 1 ETH + 1 wei read 1.
- The panel escapes a broadcast txid shown without an explorer link.
- A TPM refusal hands back only its own PIN attempt, not the count
  before it, which could undo guesses made in parallel.
- BCH WIF imports must carry this network's version byte and a valid
  compression flag; a 64-byte Solana keypair must have a public half
  that matches its secret half.
- WizardConnect: the overlay shows the network fee (exact, as
  SIGHASH_UTXOS commits to the inputs), marks outputs to this wallet's
  own addresses, lists every token input and every output instead of
  "... and N more" (more than 30 is refused), and a very high fee or
  token inputs get the danger button.
- DAI permits: expiry 0 reads "never expires", and the allowed flag is
  read the way the encoder signs it.
2026-10-04 04:09:45 +02:00
Local Dev
001fce02e7 Theseus: bundle Pithos 0.3.12
New installs carry the same Pithos the extension channel serves.
2026-10-04 04:06:04 +02:00