/* Brain of Reese — Git sources admin page (phase 35, task 04; * local directories, phase 38 task 04). * * The page module for /git-sources.html: the admin-only manager for the * stored source list (git-sources table, phase 35 tasks 01/02) — git * repo URLs (kind "git") and existing local directories (kind * "local", phase 38). * This module is the single owner of the page's behaviour: * * • boot — initSharedHeader() (one cached whoami, shared with the * header toggling): anonymous → the sign-in gate shows and the * manager stays hidden (the exact Sources page gate pattern, and * NO /api/git-sources call is made); admin → gate hidden, * #git-sources-content revealed, loadSources(). * • loadSources() — GET /api/git-sources → the table rows * (#git-sources-tbody), the env-fallback note's visibility * (from_env), and the empty state. Each row leads with its kind * badge (Git/Local — text + color, never color alone) plus the * location in a mono : the git URL, or the full local path * for kind "local" rows (phase 38). Values are ALWAYS rendered * with textContent — never innerHTML (URLs may embed user:pass@ * credentials; phase 32's masking discipline). Non-2xx or a * network failure renders the role="alert" load error with a * retry button — never a stuck page. * • add — #git-source-form submit → POST /api/git-sources {url}; * #local-source-form submit → POST /api/git-sources * {kind: "local", path} (phase 38). ONE §7.4 never-stale * lifecycle for both (wireAddForm): the button disables + * relabels "Adding…" while the request is out, re-enables on * success AND failure. 201 clears the input, reloads the list, * and focuses the new row's Remove button (a11y); a failure (409 * duplicate, 422 validation) shows the server detail inline under * the form (role="alert", 422 shape-aware like the tuning forms) * and keeps the input — the instruction survives. Local 422/409 * details name the path (paths are not secrets, unlike URLs). * • remove — a row's Remove button asks window.confirm first * (removal prunes the documents only on the NEXT sync — the * confirm says so). Cancel → nothing; ok → the row button * disables, DELETE /api/git-sources/{id}, loadSources(). A * failure shows a per-row role="alert" error and re-enables the * button. Env-fallback rows (id null — the list comes from * BOR_GIT_SOURCES, not the table) carry no Remove: nothing is * stored to remove — they show a "from .env" tag instead. * • announce(msg) — #git-sources-announcer (role=status, * aria-live=polite): the screen-reader confirmation for loads, * adds, and removals. * * Scope boundary (phase locked decisions): adding or removing a repo * does NOT clone, import, or prune — the header's Sync sources button * (module-owned in assets/header.js) performs that; the page's hint * box says so. * * The shared header module loads through this script's own relative * import ("./header.js") — a hoisted import evaluated before this body * runs (single-evaluation design: no direct