diff --git a/GOTCHAS.md b/GOTCHAS.md new file mode 100644 index 0000000..4f6a1ec --- /dev/null +++ b/GOTCHAS.md @@ -0,0 +1,121 @@ +# Theseus gotchas + +Non-obvious things sessions keep re-deriving. If you found this file because +something broke in a way that felt spooky, the answer is probably here. + +## `build.files` in [package.json](package.json) is EXPLICIT + +electron-builder ships **only what's listed** in `build.files`. Every runtime- +loaded HTML/preload/module MUST be there. A missing entry causes the +`loadFile("foo.html")` in a WebContentsView to silently open blank in the +packaged app — visually indistinguishable from "the button does nothing". + +`npm start` (dev) never catches this because it reads from the source tree +directly. Only a real `npm run dist` + install exposes it. + +Every time you add a new `WebContentsView` or `loadFile`, add its HTML and +preload to the `files` array. Sanity check after building: + +``` +node -e "const b = require('fs').readFileSync('dist-public/win-unpacked/resources/app.asar'); for (const n of ['engine-picker.html','popover.html','downloads.html','engine-picker-preload.js','popover-preload.js','downloads-preload.js']) console.log(n, b.indexOf(Buffer.from(n)) >= 0 ? 'OK' : 'MISSING');" +``` + +This has bit us once (search-picker dropdown, shipped `6bbccf9c`, blank +picker). Do not let it bite twice. + +## Building — admin terminal the first time + +`npm run dist` needs an **admin** terminal on the machine's first Theseus +build so `electron-builder`'s `winCodeSign` package can extract its +`darwin/` symlinks (requires `SeCreateSymbolicLink`). Subsequent builds +reuse the cache under `$LOCALAPPDATA/electron-builder/Cache/winCodeSign/` +and don't need admin. + +If DNS is misbehaving on the machine, pin these hosts in +`C:\Windows\System32\drivers\etc\hosts` before building so electron-builder +can fetch: `github.com`, `codeload.github.com`, +`objects.githubusercontent.com`, `release-assets.githubusercontent.com`. +Strip them after. + +## Reproducible builds + +Set both before `npm run dist`: +- `SOURCE_DATE_EPOCH` — freezes timestamps so a rebuild with no content + changes produces the same hash. Bump per release, not per rebuild. +- `CSC_IDENTITY_AUTO_DISCOVERY=false` — stops electron-builder searching + for a signing cert (we don't sign; SECURITY.md rule 2). + +## Native `` popup uses the page's `color-scheme`. When it's +`"light dark"` (both accepted), Chromium picks by the OS scheme — so a +dark-themed app on a light OS shows a light popup and vice versa. + +Fix, currently in [settings.html](settings.html): +```css +:root { color-scheme: dark; } +@media (prefers-color-scheme: light) { :root { color-scheme: light; } } +``` +`nativeTheme.themeSource` (driven by `settings.theme`) sets +`prefers-color-scheme`, so this stays in sync automatically. Do not remove. + +Chromium also respects `select option { background; color }` in the popup +on Windows — a belt-and-braces override alongside `color-scheme`. + +## The resolver in Theseus is `resolver-web.mjs`, not `.js` + +Packaged builds ship `Argus/src/lib/resolver-web.js` as `resolver-web.mjs` +(see `extraResources` in [package.json](package.json)). Renamed because +`resources/` has no adjacent `package.json` so a `.js` gets treated as +CommonJS and its `export`s fail. Dev reads the engine copy directly (Argus +is `type: module` so `.js` works there). + +## The resolver's electrum WS `directIP` fallback + +[main.js](main.js) passes `directIP: true` to `resolveHost` so the engine +can dial the chipnet electrum servers by pinned IP if system DNS is dead. +Do not remove — this is what keeps `.bch` resolution working when the +adapter DNS is broken (a real failure mode we've hit). + +## Publishing new hashes end-to-end + +1. Build (see above). +2. Update `../site/releases-manifest.json` AND + `../site/tools/index.html` AND `../site/releases/index.html` with the + fresh SHA-256s + release date. All three must match. +3. Deploy: + ``` + scp dist-public/*.exe ../site/releases-manifest.json coinspectrum:/opt/silent-mode/dl/ + cd ../Argus && node src/lib/sia-upload.js ../site bns/silentmode + ``` +4. On-chain (wallet spend, user's action): + `releases.silentmode.bch` currently publishes + `{"u":"https://dl.silentmode.st/releases-manifest.json"}` — a compact + `u` record because on-chain hashes wouldn't fit the 200-byte + OP_RETURN. Only re-publish if the URL changes or if we ever put full + hashes on-chain. + +## Sia upload from this machine fails without a `hosts` pin + +`node src/lib/sia-upload.js` fails with `getaddrinfo EAI_FAIL +coinspectrum.duckdns.org` unless the host is pinned in +`C:\Windows\System32\drivers\etc\hosts`: +`195.184.247.106 coinspectrum.duckdns.org`. This is a DNS quirk of the +machine, not a code bug — related to the strict-resolver behavior the +Ariadne daemon's EDNS fix addresses. + +## Deploy directory quirks + +- `/opt/silent-mode/dl/` is served as `dl.silentmode.st` — installers + + manifest live here. +- `silentmode.st` proxies to Sia (`bns/silentmode/`) — the HTML pages + live there. +- The `bns` gateway does NOT auto-index directories. `silentmode.st/apps/` + is a 404 (`NoSuchKey`); users must hit `/apps/index.html`. Fix upstream + in `bnsd.js` if it ever matters. + +## Firefox needs a restart after Ariadne CA install/rotation + +Firefox only reads root CAs at startup. The Ariadne installer offers a +`-CloseFirefox` task by default when Firefox is running so this doesn't +bite. Chrome/Edge pick up the new root immediately. diff --git a/PENDING.md b/PENDING.md new file mode 100644 index 0000000..994ccf8 --- /dev/null +++ b/PENDING.md @@ -0,0 +1,149 @@ +# Pending — uncommitted Theseus changes + +Working-tree state that hasn't been committed or shipped. Read this before +touching the same files. Update when you land or add work. + +Format: each group has a `session:` label so parallel sessions can see +what belongs to whom and coordinate. Naming convention: +`YYYY-MM-DD:short-slug` for date-bounded work, or `parallel:` for +work owned by a session that isn't the current one. + +Last updated: 2026-08-02. + +--- + +## session: `2026-08-02:theseus-ux-polish` + +Owner's focus: Theseus UX polish + downloads. Everything below bundles +into one commit + one Theseus rebuild + redeploy. + +### Settings — General + +- **Startup group** at the top of `#general` with "Open previous windows + and tabs" toggle (moved up from below). +- **Appearance** replaced with three visual **theme cards**: System / Light + / Dark. `System` follows `nativeTheme.themeSource = "system"` so it + tracks the OS. Legacy `settings.theme` values outside `{system, light, + dark}` fall back to `system`. +- Files: [settings.html](settings.html), [main.js](main.js) (`applyTheme` + already handles all three values). + +### Settings — new Search section + +- Sidebar gets a **Search** top-level item between General and Naming. +- Search-engine controls moved OUT of General into this section. +- Only **enabled** engines listed in the main "Additional search engines" + block, grouped by kind (`Search engines` / `AI answer engines`), + drag-reorder within a kind, toggle to disable, ✕ to delete custom. +- **+ Add search engine** button toggles a catalog panel below with + built-in engines the user hasn't enabled (each with `+ Add`) + a "Or add + a custom URL" form. +- Files: [settings.html](settings.html) (nav, section, CSS `.engcat`, JS). + +### Settings — dropdown color-scheme + layout + +- `:root { color-scheme: dark }` + `@media (prefers-color-scheme: light)` + override. Native `` groups options + with `` by kind. Drag-reorder constrained to same-kind (a + cross-kind drop would re-group on next render). + +### Chrome / toolbar + +- **Loadbar collapses to 0px when idle** (`.loadbar { height: 0 }`, + `.loadbar.on { height: 2px }`, 120ms transition). Previously reserved + a permanent 2px strip below the address bar. +- **Downloads button** (`#downloads`) between the search box and Tor + toggle. Subscribes to `onDownloads` for badge + spin/done/err class. +- Files: [chrome.html](chrome.html). + +### Downloads (new feature) + +- New files: [downloads.html](downloads.html), + [downloads-preload.js](downloads-preload.js). Both added to + `build.files` in [package.json](package.json). +- `installDownloadTracker()` in main.js hooks + `session.defaultSession.on("will-download", …)`. In-memory list only; + no cross-session persistence. +- IPC surface: `downloads-get`, `toggle-downloads`, `close-downloads`, + `downloads-resize`, `download-open`, `download-show`, `download-cancel`, + `download-clear`, `downloads-clear-all`. +- New `downloadsPop` WebContentsView, positioned via `positionDownloads()` + from `layout()`. +- Preload exposes `getDownloads`, `toggleDownloads`, `onDownloads`. + +### Preview harness + +- [_preview.html](_preview.html) — `window.DL_ITEMS` seed + + `__toggleDownloads` overlay; stub `window.theseus.getDownloads / + onDownloads / toggleDownloads`; `kind` on stub engines; LLM catalog + trimmed to Perplexity + Phind. +- [_settings-preview.html](_settings-preview.html) — `kind` on stub + engines; LLM catalog trimmed. + +--- + +## session: `parallel:collision-policy` + +Owner's focus: BCNR ↔ ICANN name collision handling. Present in the +working tree, not mine. Leave for that session to land or bundle by +explicit ask. + +### Chrome + main-process changes + +- [main.js](main.js) — big block of new IPC around collision policy + + soft-collision picker + electrum discovery. +- [popover.html](popover.html), [popover-preload.js](popover-preload.js) + — collision switcher on the site-info popover. +- [preload.js](preload.js) — `collisionSwitch` + `collisionState`. +- [settings-preload.js](settings-preload.js) — same. + +### Settings + +- Entire **Naming** section in [settings.html](settings.html) (BCNR/ICANN + collision policy radio group + remembered choices reset button). + Untouched by my changes. + +### New files (untracked in git) + +- [collision.html](collision.html), [collision-preload.js](collision-preload.js) + — the soft-collision "Open with…" prompt window (referenced from + `main.js:219`). + +--- + +## Live state + +Shipped hashes live at `../site/releases-manifest.json` and +`https://dl.silentmode.st/releases-manifest.json`. On-chain pointer at +`releases.silentmode.bch`. See [GOTCHAS.md](GOTCHAS.md) for the release +gotchas. diff --git a/downloads-preload.js b/downloads-preload.js new file mode 100644 index 0000000..4b176f4 --- /dev/null +++ b/downloads-preload.js @@ -0,0 +1,11 @@ +const { contextBridge, ipcRenderer } = require("electron"); +contextBridge.exposeInMainWorld("dl", { + onDownloads: (cb) => ipcRenderer.on("downloads", (_e, d) => cb(d)), + close: () => ipcRenderer.invoke("close-downloads"), + resize: (h) => ipcRenderer.invoke("downloads-resize", h), + open: (id) => ipcRenderer.invoke("download-open", id), + show: (id) => ipcRenderer.invoke("download-show", id), + cancel: (id) => ipcRenderer.invoke("download-cancel", id), + clear: (id) => ipcRenderer.invoke("download-clear", id), + clearAll: () => ipcRenderer.invoke("downloads-clear-all"), +}); diff --git a/downloads.html b/downloads.html new file mode 100644 index 0000000..297cce5 --- /dev/null +++ b/downloads.html @@ -0,0 +1,101 @@ + + + + + + + diff --git a/engine-picker.html b/engine-picker.html index 89054cd..9fc44a6 100644 --- a/engine-picker.html +++ b/engine-picker.html @@ -21,8 +21,7 @@