@@ -1079,7 +1079,7 @@
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) {
- aegisStatus.innerHTML = `v${upd.version} staged — restart Theseus to switch to it. You're on v${curVer}.`;
+ aegisStatus.innerHTML = `v${upd.version} ready — click Apply update now to switch without restarting Theseus. You're on v${curVer}.`;
aegisApply.hidden = false;
} else {
aegisStatus.textContent = `You're on v${curVer}. Updates arrive over-the-air; the next check runs at boot and every 6h.`;
@@ -1100,7 +1100,29 @@
} catch (e) { aegisStatus.textContent = "Check failed: " + (e?.message || e); }
finally { aegisCheck.disabled = false; aegisCheck.textContent = orig; }
};
- aegisApply.onclick = () => { if (C && C.restartApp) C.restartApp(); };
+ // Apply staged update without restarting Theseus. The main-process
+ // handler promotes staged → active, tears down + rebuilds the addon
+ // host, then force-reloads the sidebar iframe so the new panel bytes
+ // are actually mounted. Falls back to a full restart if the IPC isn't
+ // wired (older Theseus builds).
+ aegisApply.onclick = async () => {
+ const orig = aegisApply.textContent;
+ aegisApply.disabled = true; aegisApply.textContent = "Applying…";
+ try {
+ if (C && C.applyStagedAddons) {
+ const r = await C.applyStagedAddons();
+ if (r && r.ok === false) throw new Error(r.err || "apply failed");
+ aegisStatus.textContent = "Update applied. Reopen the Aegis panel to see the new version.";
+ refreshAegis();
+ } else if (C && C.restartApp) {
+ C.restartApp();
+ } else {
+ aegisStatus.textContent = "Update staged — restart Theseus to switch.";
+ }
+ } catch (e) {
+ aegisStatus.textContent = "Apply failed: " + (e?.message || e) + " — restart Theseus to fall back.";
+ } finally { aegisApply.disabled = false; aegisApply.textContent = orig; }
+ };
refreshAegis();
// ---- Manual "Check for updates" -----------------------------------------
@@ -1280,13 +1302,7 @@
return '
' + msg + '
';
}
function renderAddons(snap) {
- // Plug-in category add-ons (Aegis and future first-class Silent Mode
- // components) live in Settings › Plug-ins with their own product-facing
- // copy — showing them again here as raw extension rows was confusing
- // ("why can I toggle my wallet off from two places?"). Filter them
- // out of the Extensions listing entirely; the Plug-ins tab is the
- // single source of truth for those.
- const items = ((snap && snap.installed) || []).filter((a) => a.category !== "plugin");
+ const items = (snap && snap.installed) || [];
if (!items.length) {
addonsList.innerHTML = '
No extensions installed. Drop a folder into the extensions directory to install one.
';
return;
@@ -1340,8 +1356,13 @@
let r;
try { r = await C.communityCatalog(); } catch (e) { r = { ok: false, error: e?.message || String(e), extensions: [] }; }
if (!r.ok) { communityList.innerHTML = '
Catalog unavailable: ' + escapeHtml(r.error) + '
'; return; }
- if (!r.extensions.length) { communityList.innerHTML = '
Nothing published yet. Be the first — see theseus.x/extensions.
'; return; }
- communityList.innerHTML = r.extensions.map((e) => {
+ // Hide extensions already shown in the Installed list above — the
+ // Community list's job is to surface things you DON'T have. Updates to
+ // installed extensions come through the poll + "Check for updates" flow
+ // in the Installed list, not through a second card for the same id here.
+ const catalog = r.extensions.filter((e) => !e.installedVersion);
+ if (!catalog.length) { communityList.innerHTML = '
' + (r.extensions.length ? "All catalog extensions are already installed." : "Nothing published yet. Be the first — see theseus.x/extensions.") + '