From e97854e29063f310240d9fcf6b3fd66f9611beaa Mon Sep 17 00:00:00 2001
From: Silent Mode
Date: Mon, 21 Sep 2026 03:31:16 +0200
Subject: [PATCH] fix(sirius-press): pin line endings, found by cloning the
published repo
Cloning the forge repo on Windows and running the suite there turned up two
things a checkout inside the monorepo could never show, because this working
copy has core.autocrlf=false.
Git on Windows defaults to autocrlf=true, so a fresh clone gets CRLF. For
most files that is cosmetic. For shell scripts it is not: install.sh copied
from such a clone onto a server fails with `bash: \r: command not found`,
which tells the person almost nothing about what is wrong. And a
CRLF-rewritten .patch file is no longer the bytes `patch` was given.
.gitattributes now pins eol=lf for the scripts, the container inputs and the
source, and marks *.patch as binary so nothing rewrites it at all.
tools/refresh-patches.sh --check also compares with --strip-trailing-cr, so
a clone made before this landed reports honestly instead of claiming the
patch record has drifted when it has not. A check that cries wolf is a check
somebody switches off.
---
extensions/index.html | 63 +++++++++++++++++++++++++++++++++++++++----
1 file changed, 58 insertions(+), 5 deletions(-)
diff --git a/extensions/index.html b/extensions/index.html
index aaf11132..85d8cfc4 100644
--- a/extensions/index.html
+++ b/extensions/index.html
@@ -104,6 +104,16 @@
.ext .install.alt{background:rgba(214,255,61,.12);color:var(--acid)}
.ext .act .st{font-size:13px;color:var(--mut)}
.ext .act .st.ok{color:var(--acid)} .ext .act .st.err{color:#f6768a}
+ .ext .act .how{flex-basis:100%;font-size:13px;color:var(--mut);background:#0e131b;border:1px solid var(--line);border-radius:8px;padding:8px 12px}
+ .ext .how b{color:var(--ink)}
+ .search{max-width:560px;margin:1.4rem auto 0;position:relative}
+ .search input{width:100%;background:var(--panel);border:1px solid var(--line);border-radius:12px;color:var(--ink);
+ font:inherit;font-size:15px;padding:11px 14px 11px 40px;outline:none}
+ .search input:focus{border-color:rgba(214,255,61,.5)}
+ .search svg{position:absolute;left:13px;top:50%;transform:translateY(-50%);width:17px;height:17px;color:var(--dim)}
+ .search .n{position:absolute;right:13px;top:50%;transform:translateY(-50%);font-size:12px;color:var(--dim)}
+ .ext.hide, .nomatch{display:none}
+ .nomatch.show{display:block}
.note{background:var(--panel);border:1px solid var(--line);border-left:3px solid var(--acid);
border-radius:10px;padding:14px 18px;color:var(--mut);font-size:14px;margin:1.4rem 0}
.note b{color:var(--ink)}
@@ -151,6 +161,11 @@
publish. Every package is signed (by the Silent Mode operator, or by the publisher's own BCDN name)
and verified on your device before install. No cert authority, no app-store gatekeeper.
First-party plug-ins (Aegis, Ariadne's Thread) have their own page.
+
+
+
+
+
@@ -180,6 +195,13 @@
Settings › Extensions · no update channel yet — ships with each Theseus release.
+
+
🌐 Translate bundled 0.1.0
+
Select text on any page and right-click Translate — the sidebar panel shows the translation,
+ with LibreTranslate or Google as the backend (your choice in the panel). Nothing is sent until you ask.
+
Settings › Extensions · no update channel yet — ships with each Theseus release.
+
+
PDF Editor current 0.1.0
Open a PDF in a full tab — read, highlight, mark up, reorder or rotate or drop pages,
@@ -194,6 +216,8 @@
sha256—
+
+
No bundled extension matches that search.
@@ -203,6 +227,7 @@
package itself and re-checks every signature against the name's current owner in its own chain index — the relay
cannot substitute code under a trusted name.
Loading the catalog…
+
No community extension matches that search.
Trust, stated plainly. A community extension runs with the same access as any add-on —
treat one like an unsigned executable from that publisher. The signature proves who published it,
not that it is safe.
@@ -268,11 +293,10 @@
// fetches the package, confirms in a native dialog and verifies the signature.
const inTheseus = !!window.bcnr;
const canInstall = inTheseus && typeof window.bcnr.installExtension === "function";
- const installUi = (id) => canInstall
- ? ``
- : inTheseus
- ? `Update Theseus to install from hereuntil then: Settings › Extensions › Community › Install`
- : `Get Theseus to installone click from this page inside Theseus`;
+ const mode = canInstall ? "bridge" : inTheseus ? "old" : "none";
+ const installUi = (id) => mode === "none"
+ ? `Get Theseus to installone click from this page inside Theseus`
+ : ``;
try {
const r = await fetch("./community/catalog.json", { cache: "no-store" });
const cat = r.ok ? await r.json() : { extensions: [] };
@@ -299,6 +323,16 @@
`).join("");
box.querySelectorAll("button[data-install]").forEach((btn) => btn.addEventListener("click", async () => {
const id = btn.dataset.install, st = box.querySelector(`[data-st="${CSS.escape(id)}"]`);
+ if (btn.dataset.mode === "old") {
+ // This Theseus predates the page bridge: point at the path it does have.
+ const name = [...btn.closest(".ext").querySelector("h3").childNodes].find((x) => x.nodeType === 3 && x.textContent.trim())?.textContent.trim() || id;
+ let how = btn.parentElement.querySelector(".how");
+ if (!how) { how = document.createElement("div"); how.className = "how"; btn.parentElement.appendChild(how); }
+ how.innerHTML = `Your Theseus is older than this button. Open Settings › Extensions, scroll to Community and press
+ Install next to ${esc(name)} — same signed package, same checks. Newer builds install from here in one click:
+ update Theseus.`;
+ return;
+ }
btn.disabled = true; st.className = "st"; st.textContent = "Confirm in the Theseus dialog…";
let r; try { r = await window.bcnr.installExtension(id); } catch (err) { r = { ok: false, error: err?.message || String(err) }; }
if (r && r.ok) { st.className = "st ok"; st.textContent = `Installed v${r.version} — signed by ${r.publisher}`; btn.textContent = "Installed"; }
@@ -306,6 +340,25 @@
}));
} catch (e) { box.innerHTML = '
Catalog unavailable right now.
'; }
})();
+// Search: filters the bundled and community cards by name, description, publisher, capabilities.
+(() => {
+ const q = document.getElementById("extSearch"), n = document.getElementById("extSearchN");
+ const apply = () => {
+ const s = q.value.trim().toLowerCase();
+ let shown = 0;
+ for (const sec of ["bundled", "community"]) {
+ const cards = [...document.querySelectorAll(`#${sec} .ext`)].filter((c) => c.querySelector("h3"));
+ let hit = 0;
+ for (const c of cards) { const ok = !s || c.textContent.toLowerCase().includes(s); c.classList.toggle("hide", !ok); if (ok) hit++; }
+ document.getElementById(sec === "bundled" ? "nomatchBundled" : "nomatchCommunity").classList.toggle("show", !!s && cards.length > 0 && hit === 0);
+ shown += hit;
+ }
+ n.textContent = s ? `${shown} match${shown === 1 ? "" : "es"}` : "";
+ };
+ q.addEventListener("input", apply);
+ new MutationObserver(() => { if (q.value.trim()) apply(); }).observe(document.getElementById("communityList"), { childList: true });
+ if (location.hash === "#search") q.focus();
+})();