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.
This commit is contained in:
parent
1637e2dd16
commit
e97854e290
1 changed files with 58 additions and 5 deletions
|
|
@ -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 <a href="../plug-ins/">own page</a>.</p>
|
||||
<div class="search">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg>
|
||||
<input id="extSearch" type="search" placeholder="Search extensions — name, what it does, publisher" autocomplete="off" aria-label="Search extensions">
|
||||
<span class="n" id="extSearchN"></span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="wrap">
|
||||
|
|
@ -180,6 +195,13 @@
|
|||
<div class="meta">Settings › Extensions · no update channel yet — ships with each Theseus release.</div>
|
||||
</div>
|
||||
|
||||
<div class="ext" id="translate">
|
||||
<h3><span class="icon">🌐</span> Translate <span class="cur" style="margin-left:auto">bundled 0.1.0</span></h3>
|
||||
<div class="desc">Select text on any page and right-click <i>Translate</i> — the sidebar panel shows the translation,
|
||||
with LibreTranslate or Google as the backend (your choice in the panel). Nothing is sent until you ask.</div>
|
||||
<div class="meta">Settings › Extensions · no update channel yet — ships with each Theseus release.</div>
|
||||
</div>
|
||||
|
||||
<div class="ext" id="pdf-editor" data-ext="pdf-editor">
|
||||
<h3><span class="icon" aria-hidden="true"><svg width="20" height="20" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" style="vertical-align:middle"><path d="M6 2h8l6 6v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2z" fill="#dc2626"/><path d="M14 2v6h6z" fill="#991b1b"/><text x="12" y="17" text-anchor="middle" font-family="system-ui,-apple-system,sans-serif" font-size="5.5" font-weight="800" fill="#fff">PDF</text></svg></span> PDF Editor <span class="cur" style="margin-left:auto">current <span data-live="version">0.1.0</span></span></h3>
|
||||
<div class="desc">Open a PDF in a full tab — read, highlight, mark up, reorder or rotate or drop pages,
|
||||
|
|
@ -194,6 +216,8 @@
|
|||
<div class="h"><b>sha256</b><code data-live="sha256">—</code></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="nomatch note" id="nomatchBundled">No bundled extension matches that search.</div>
|
||||
</section>
|
||||
|
||||
<section id="community">
|
||||
|
|
@ -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.</p>
|
||||
<div id="communityList"><div class="ext" style="color:var(--dim)">Loading the catalog…</div></div>
|
||||
<div class="nomatch note" id="nomatchCommunity">No community extension matches that search.</div>
|
||||
<div class="note"><b>Trust, stated plainly.</b> A community extension runs with the same access as any add-on —
|
||||
treat one like an unsigned executable from that publisher. The signature proves <i>who</i> published it,
|
||||
not that it is safe.</div>
|
||||
|
|
@ -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
|
||||
? `<button class="install" type="button" data-install="${esc(id)}">Install in Theseus</button><span class="st" data-st="${esc(id)}"></span>`
|
||||
: inTheseus
|
||||
? `<a class="install alt" href="../#download">Update Theseus to install from here</a><span class="st">until then: Settings › Extensions › Community › Install</span>`
|
||||
: `<a class="install alt" href="../#download">Get Theseus to install</a><span class="st">one click from this page inside Theseus</span>`;
|
||||
const mode = canInstall ? "bridge" : inTheseus ? "old" : "none";
|
||||
const installUi = (id) => mode === "none"
|
||||
? `<a class="install" href="../#download">Get Theseus to install</a><span class="st">one click from this page inside Theseus</span>`
|
||||
: `<button class="install" type="button" data-install="${esc(id)}" data-mode="${mode}">Install in Theseus</button><span class="st" data-st="${esc(id)}"></span>`;
|
||||
try {
|
||||
const r = await fetch("./community/catalog.json", { cache: "no-store" });
|
||||
const cat = r.ok ? await r.json() : { extensions: [] };
|
||||
|
|
@ -299,6 +323,16 @@
|
|||
</div>`).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 <b>Settings › Extensions</b>, scroll to <b>Community</b> and press
|
||||
<b>Install</b> next to <b>${esc(name)}</b> — same signed package, same checks. Newer builds install from here in one click:
|
||||
<a href="../#download">update Theseus</a>.`;
|
||||
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 = '<div class="ext" style="color:var(--dim)">Catalog unavailable right now.</div>'; }
|
||||
})();
|
||||
// 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();
|
||||
})();
|
||||
</script>
|
||||
|
||||
<section id="updates">
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue