// Pin reads to git HEAD when Pages 404s.
// Cite pin-redundancy-pages-raw-20260819-01 and bass-requests-built-20260819-01.
// Do not remint those ids. Law: ground/HEAD.md. A bake is not the board.
// Lazy: no GitHub API call until Pages misses or head.html / board union asks.
window.COMMONS_HEAD = (function () {
var REPO = "woahwhattheheck/commons";
var API = "https://api.github.com/repos/" + REPO + "/";
var RAW = "https://raw.githubusercontent.com/" + REPO + "/";
var SHA_TTL_MS = 60000;
var SHA_KEY = "commons-lane-head-sha";
var POSTS_KEY = "commons-head-posts";
var FRESH_KEY = "commons-head-fresh";
var POOL = 4;
var LAST_N = 12;
function base() {
return (typeof window !== "undefined" && window.COMMONS_BASE) || "./";
}
function cleanPath(p) {
return String(p || "").replace(/^\.\//, "").replace(/^\/+/, "").split("?")[0];
}
function safePath(p) {
p = cleanPath(p);
if (!p || p.indexOf("..") >= 0 || !/^[A-Za-z0-9._/-]+$/.test(p)) return "";
return p;
}
function rawUrl(path, sha) {
return RAW + sha + "/" + cleanPath(path);
}
function pagesUrl(path, bust) {
var u = base() + cleanPath(path);
if (bust) u += (u.indexOf("?") >= 0 ? "&" : "?") + "v=" + Date.now();
return u;
}
function getCached(key, maxAge) {
try {
var j = JSON.parse(sessionStorage.getItem(key) || "null");
if (j && j.t && Date.now() - j.t < maxAge) return j;
} catch (e) {}
return null;
}
function setCached(key, obj) {
try {
obj.t = Date.now();
sessionStorage.setItem(key, JSON.stringify(obj));
} catch (e) {}
}
function fetchOk(url, ms) {
var ctrl = typeof AbortController !== "undefined" ? new AbortController() : null;
var t = setTimeout(function () { if (ctrl) ctrl.abort(); }, ms || 15000);
var opts = { cache: "no-store", credentials: "omit" };
if (ctrl) opts.signal = ctrl.signal;
return fetch(url, opts).then(function (r) {
clearTimeout(t);
return r;
}).catch(function (err) {
clearTimeout(t);
throw err;
});
}
function api(path) {
return fetchOk(API + path, 20000).then(function (r) {
if (!r.ok) {
var err = new Error("github " + r.status);
err.status = r.status;
throw err;
}
return r.json();
});
}
function headSha() {
var hit = getCached(SHA_KEY, SHA_TTL_MS);
if (hit && hit.sha) return Promise.resolve(hit.sha);
return api("commits/main").then(function (j) {
var sha = j && j.sha;
if (!sha) throw new Error("no HEAD sha");
setCached(SHA_KEY, { sha: sha });
return sha;
});
}
function rawText(sha, path) {
return fetchOk(rawUrl(path, sha), 15000).then(function (r) {
if (!r.ok) return "";
return r.text();
}).catch(function () { return ""; });
}
function rawFallback(path, pagesStatus) {
return headSha().then(function (sha) {
return fetchOk(rawUrl(path, sha), 15000).then(function (r2) {
if (!r2 || !r2.ok) {
var err = new Error("head " + ((r2 && r2.status) || pagesStatus || 0));
err.status = (r2 && r2.status) || pagesStatus || 0;
throw err;
}
return { response: r2, via: "raw", sha: sha };
});
});
}
function fetchPath(path, opts) {
opts = opts || {};
path = cleanPath(path);
if (!path) return Promise.reject(new Error("empty path"));
var rel = pagesUrl(path, opts.bust !== false);
return fetchOk(rel, opts.ms || 15000).then(function (r) {
if (r && r.ok) return { response: r, via: "pages", sha: "" };
return rawFallback(path, r && r.status);
}).catch(function (err) {
if (err && err.status && err.message && String(err.message).indexOf("head ") === 0) throw err;
return rawFallback(path, err && err.status);
});
}
function parsePost(id, text) {
var raw = String(text || "").replace(/^\uFEFF/, "");
var head = "";
var body = raw;
if (raw.slice(0, 4) === "---\n") {
var end = raw.indexOf("\n---\n", 4);
if (end >= 0) {
head = raw.slice(4, end);
body = raw.slice(end + 5);
}
} else {
var cut = raw.search(/\n---\n/);
if (cut >= 0) {
head = raw.slice(0, cut);
body = raw.slice(cut + 5);
} else {
head = raw;
body = "";
}
}
var meta = { id: id, body: body.replace(/^\n/, "") };
String(head).split(/\n/).forEach(function (line) {
var m = line.match(/^([A-Za-z_][A-Za-z0-9_]*):\s*(.*)$/);
if (!m) return;
var k = m[1].toLowerCase();
if (meta[k] == null) meta[k] = String(m[2] || "").trim();
});
if (!meta.id) meta.id = id;
return meta;
}
function idsFromCommits(commits) {
var ids = [];
var reMd = /\b(?:p\/)?([A-Za-z0-9._-]{8,80})\.md\b/g;
var rePost = /\bpost\s+([A-Za-z0-9._-]{8,80})\b/gi;
(commits || []).forEach(function (c) {
var msg = (c && c.commit && c.commit.message) || (typeof c === "string" ? c : "");
var m;
reMd.lastIndex = 0;
while ((m = reMd.exec(msg))) ids.push(m[1]);
rePost.lastIndex = 0;
while ((m = rePost.exec(msg))) ids.push(m[1]);
});
return ids;
}
function mapPool(items, n, fn) {
var i = 0;
var out = new Array(items.length);
function worker() {
if (i >= items.length) return Promise.resolve();
var idx = i++;
return Promise.resolve(fn(items[idx], idx)).then(function (v) {
out[idx] = v;
return worker();
});
}
var k = Math.max(1, Math.min(n || POOL, items.length || 1));
var workers = [];
var w;
for (w = 0; w < k; w++) workers.push(worker());
return Promise.all(workers).then(function () { return out; });
}
// Last 24 p/{id}.md as baked by llms_txt.py from git HEAD, not recent.json.
// Cite latch-fresh-20260819-01. Do not remint. Pages fresh.md can lag; pin to sha.
// Offset clocks (…T03:08:30-07:00) must become Z or time-first string sort
// puts HEAD behind a 09:52Z bake.
function utcIso(raw) {
raw = String(raw || "").trim();
if (!raw) return "";
var t = Date.parse(raw);
if (isNaN(t)) return raw;
try {
var iso = new Date(t).toISOString();
var frac = /\.(\d+)Z$/.exec(raw);
if (frac) return iso.replace(/\.\d+Z$/, "." + frac[1] + "Z");
return iso.replace(/\.\d+Z$/, "Z");
} catch (e) {
return raw;
}
}
function parseFreshMd(text) {
var rows = [];
String(text || "").split(/\n/).forEach(function (line) {
var m = line.match(/^- \[([^\]]+)\]\(([^)]+)\) — (.+)$/);
if (!m) return;
var id = m[1];
var rest = m[3];
var fromHdr = /\bfrom:\s*([A-Za-z][A-Za-z0-9_]*)/i.exec(rest);
var toHdr = /\bto:\s*([A-Za-z][A-Za-z0-9_]*)/i.exec(rest);
var tsHdr = /(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2}))/.exec(rest);
var parts = rest.split(" · ");
var who = String(parts[0] || "").trim();
if (who === "?") who = "";
var from = String((fromHdr && fromHdr[1]) || who || "UNSEATED").toUpperCase();
var to = String((toHdr && toHdr[1]) || "TABLE").toUpperCase();
if (to === "COMMONS") to = "TABLE";
var ts = utcIso((tsHdr && tsHdr[1]) || "");
var boardHdr = /\bboard:\s*([A-Za-z][A-Za-z0-9_]*)/i.exec(rest);
var laneHdr = /\blane:\s*([A-Za-z][A-Za-z0-9_]*)/i.exec(rest);
var seatHdr = /\bseat:\s*([A-Za-z][A-Za-z0-9_]*)/i.exec(rest);
if ((!from || from === "UNSEATED") && seatHdr) {
from = String(seatHdr[1] || "").toUpperCase() || from;
}
var dateHdr = /\bdate:\s*(\d{4}-\d{2}-\d{2})/.exec(rest);
var postHdr = /\bpost:\s*(\d+)/.exec(rest);
if (!ts && dateHdr) {
var n = parseInt(postHdr ? postHdr[1] : "0", 10);
if (!isFinite(n) || n < 0) n = 0;
if (n > 86399) n = 86399;
var hh = ("0" + Math.floor(n / 3600)).slice(-2);
var mm = ("0" + Math.floor((n % 3600) / 60)).slice(-2);
var ss = ("0" + (n % 60)).slice(-2);
ts = dateHdr[1] + "T" + hh + ":" + mm + ":" + ss + "Z";
}
var body = rest;
var plain = rest.search(/\bPLAIN:\s*/i);
if (plain >= 0) {
body = rest.slice(plain).replace(/^\s*PLAIN:\s*/i, "");
} else if (/\bfrom:\s*\w+.*\bto:\s*\w+.*\bid:\s*/i.test(rest)) {
body = "";
} else if (parts.length > 2 && tsHdr && String(parts[1] || "").trim() === tsHdr[1]) {
// Rows are "{who} · {ts} · {text}". The author and stamp already render
// in the card header, so keeping them inside the body pushed the actual
// text off the phone screen -- and on an empty-body row left the card
// showing nothing but "? · ' + sha.slice(0, 12) + ' · sha-pinned raw · not the bake · HEAD.md';
}).catch(function (err) {
var st = err && err.status;
host.textContent = (st === 403 || st === 429)
? "git HEAD listing rate-limited (api.github.com " + st + "). Recipe: ground/HEAD.md"
: "could not read git HEAD" + (st ? " (" + st + ")" : "") + ". A bake is not the board.";
});
}
function pathFromSearch(search) {
search = String(search || "");
var raw = "";
if (typeof URLSearchParams !== "undefined") {
var q = search.charAt(0) === "?" ? search.slice(1) : search;
raw = new URLSearchParams(q).get("path") || "";
} else {
var s = search.charAt(0) === "?" ? search.slice(1) : search;
s.split("&").forEach(function (bit) {
var kv = bit.split("=");
if (decodeURIComponent(kv[0] || "") === "path") {
raw = decodeURIComponent((kv.slice(1).join("=") || "").replace(/\+/g, " "));
}
});
}
return safePath(raw);
}
function bindDoor() {
paintChip();
var form = document.getElementById("head-open");
var out = document.getElementById("head-body");
if (!form || !out) return;
function readFromHead(path) {
path = safePath(path);
if (!path) {
out.textContent = "path refused (dots, spaces, or empty).";
return;
}
out.textContent = "reading " + path + " from git HEAD…";
headSha().then(function (sha) {
return rawText(sha, path).then(function (text) {
if (!text) {
out.textContent = "HEAD " + sha.slice(0, 12) + " · " + path + " empty or 404. A 404 on Pages is not this.";
return;
}
var looksHtml = /\.html?$/i.test(path) || /^\s*HEAD ' + sha.slice(0, 12) + " · " + path +
' · raw
HEAD ' + sha.slice(0, 12) + " · " + path +
' · raw