refactor(theseus/aegis): rename bundle bchwallet→aegis + retire standalone siawallet

Cleans up the naming that leaked from the wallet's origin story (BCH-only)
into the actual bundle layout. Aegis is one integrated addon now:
- Bundle folder: TheseusNavigator/bundled-addons/aegis/ (was bchwallet/).
- Addon id:      "aegis" (was "bchwallet"). Vault-derive still accepts
                 legacy "bchwallet/*" and "siawallet/*" paths via the
                 absorbs list, so no on-chain funds move.
- Version:       0.4.0 (bumped to trigger seedBundledAddons's reseed).
- Retired:       TheseusNavigator/bundled-addons/siawallet/. Sia is
                 folded into Aegis as a chain adapter (lib/sia/*.js
                 already in-tree) and Aegis's manifest lists siawallet
                 under absorbs so pre-Aegis SC keys derive identically.

main.js migrateAegisRename() runs before seedBundledAddons on every
launch. First run does the move; subsequent runs are no-ops:
- addons/bchwallet/  -> addons-backups/bchwallet-migrated-<stamp>/
- addons-data/bchwallet.json COPIED to addons-data/aegis.json (kept
  copied not moved so a downgrade to 0.3.x can still boot).
- addons/siawallet/  -> addons-backups/siawallet-migrated-<stamp>/
  (addons-data/siawallet.json left untouched — its walletdUrl is
  per-user config Aegis's Sia wallet takes fresh via Settings).

settings.html Aegis update card now matches either "aegis" (new id) or
"bchwallet" (pre-rename) so upgraders coming from 0.3.x see the same
one card while the OTA endpoint's next signed bundle catches up.

Internal purpose paths inside index.js/chain-*.js are unchanged —
LEGACY_BCH_PURPOSE stays "bchwallet/mainnet/0" and every purposePrefix
still starts with "bchwallet/*". The addon absorbs its own former id,
so those paths keep resolving to the same seed the shipping Aegis has
been using since 0.3.14.
This commit is contained in:
Local Dev 2026-09-08 18:17:44 +02:00
parent 2e54bf5e5a
commit 2c7b82ad60
3 changed files with 56 additions and 8 deletions

View file

@ -1,13 +1,13 @@
{
"id": "bchwallet",
"id": "aegis",
"name": "Aegis Wallet",
"version": "0.3.1",
"version": "0.4.0",
"description": "Multi-chain wallet (BCH, BTC, TRX, ETH, SOL, SC, DGB) derived from your Theseus vault. Dapps get window.bitcoincash on .x sites; window.tronWeb / window.tronLink / window.ethereum / window.solana on any https page.",
"author": "Silent Mode",
"icon": "🛡",
"main": "index.js",
"capabilities": ["sidebar-panel", "vault-derive", "page-inject", "approval-modal"],
"absorbs": ["siawallet"],
"absorbs": ["bchwallet", "siawallet"],
"page-inject": {
"preload": "wallet-inject.js",
"origins": ["https://*/*"]

45
main.js
View file

@ -1330,6 +1330,48 @@ function readAddonVersion(dir) {
try { return JSON.parse(fs.readFileSync(path.join(dir, "addon.json"), "utf8"))?.version ?? null; }
catch { return null; }
}
// One-time migration for the bchwallet → aegis rename + the siawallet
// retirement. Idempotent: after the first run the sources are gone and
// subsequent runs are no-ops.
//
// - addons/bchwallet/ → addons-backups/bchwallet-migrated-<stamp>/
// (bundle folder is now aegis/; leaving the old dir active would load
// the pre-rename copy as a second addon under the same id and clash).
// - addons-data/bchwallet.json → addons-data/aegis.json (COPY, so any
// downgrade to a 0.3.x build can still read its own storage).
// - addons/siawallet/ → addons-backups/siawallet-migrated-<stamp>/
// (folded into Aegis via absorbs: ["siawallet"]; keeping it running
// would show duplicate Sia UI). Its data file stays under
// addons-data/ untouched — Aegis derives its own SC walletdUrl
// per-sub-wallet, so users re-paste their URL in Aegis Settings.
function migrateAegisRename() {
const stamp = new Date().toISOString().replace(/[:.]/g, "-");
const backups = addonsBackupDir();
try { fs.mkdirSync(backups, { recursive: true }); } catch {}
const addonsRoot = addonsUserDir();
const dataRoot = addonsDataDir();
const bchDir = path.join(addonsRoot, "bchwallet");
const aegisDir = path.join(addonsRoot, "aegis");
const bchJson = path.join(dataRoot, "bchwallet.json");
const aegisJson = path.join(dataRoot, "aegis.json");
if (fs.existsSync(bchDir) && !fs.existsSync(aegisDir)) {
if (fs.existsSync(bchJson) && !fs.existsSync(aegisJson)) {
try { fs.copyFileSync(bchJson, aegisJson); console.log("[addons] migrated bchwallet.json -> aegis.json"); }
catch (err) { console.warn("[addons] migrate storage failed:", err?.message); }
}
const backup = path.join(backups, `bchwallet-migrated-${stamp}`);
try { fs.renameSync(bchDir, backup); console.log(`[addons] retired addons/bchwallet -> addons-backups/${path.basename(backup)} (folder renamed to aegis/)`); }
catch (err) { console.warn("[addons] retire bchwallet failed:", err?.message); }
}
const siaDir = path.join(addonsRoot, "siawallet");
if (fs.existsSync(siaDir)) {
const backup = path.join(backups, `siawallet-migrated-${stamp}`);
try { fs.renameSync(siaDir, backup); console.log(`[addons] retired addons/siawallet -> addons-backups/${path.basename(backup)} (absorbed by aegis)`); }
catch (err) { console.warn("[addons] retire siawallet failed:", err?.message); }
}
}
function seedBundledAddons() {
const dst = addonsUserDir();
try { fs.mkdirSync(dst, { recursive: true }); } catch {}
@ -1371,6 +1413,9 @@ function initAddons() {
stagedDir: addonsStagedDir(),
logger: (...a) => console.log("[addons]", ...a),
});
// Retire the pre-rename bundle layouts before reseeding so the fresh
// aegis/ + siawallet-less state is what AddonHost enumerates.
migrateAegisRename();
seedBundledAddons();
addonHost = new AddonHost({
addonsDir: addonsUserDir(),

View file

@ -998,14 +998,17 @@
arRefresh.onclick = refreshAriadne;
refreshAriadne();
// ---- Aegis (bchwallet) update card --------------------------------------
// ---- Aegis update card --------------------------------------------------
// Aegis is a bundled add-on but its updates are shipped OTA via the signed
// add-on update endpoint, so users can get new wallet versions without
// updating Theseus. The same addons-check-updates IPC the Extensions page
// uses is filtered for the bchwallet id so this card only speaks for Aegis.
// uses is filtered for the aegis id so this card only speaks for Aegis.
// Legacy id "bchwallet" is also matched for upgrades from pre-rename
// installs (0.3.x); post-migration the entry lives at id="aegis".
const aegisStatus = document.getElementById("aegisStatus");
const aegisCheck = document.getElementById("aegisCheck");
const aegisApply = document.getElementById("aegisApply");
const isAegis = (a) => a && (a.id === "aegis" || a.id === "bchwallet");
async function refreshAegis() {
aegisApply.hidden = true;
try {
@ -1013,8 +1016,8 @@
C.listAddons ? C.listAddons() : Promise.resolve([]),
C.listStagedAddonUpdates ? C.listStagedAddonUpdates() : Promise.resolve([]),
]);
const cur = (installed || []).find((a) => a.id === "bchwallet");
const upd = (staged || []).find((a) => a.id === "bchwallet");
const cur = (installed || []).find(isAegis);
const upd = (staged || []).find(isAegis);
if (!cur) { aegisStatus.textContent = "Aegis isn't installed. Reinstall Theseus to add it back, or open Settings > Extensions to load it manually."; return; }
const curVer = cur.version || "?";
if (upd && upd.version) {
@ -1031,7 +1034,7 @@
aegisStatus.textContent = "Checking…";
try {
const staged = await (C.checkAddonUpdates ? C.checkAddonUpdates() : Promise.resolve([]));
const upd = (staged || []).find((a) => a.id === "bchwallet");
const upd = (staged || []).find(isAegis);
if (!upd) { aegisStatus.textContent = "You're on the latest Aegis."; }
// refresh will populate everything else + toggle the Apply button
refreshAegis();