From f89cd0730ed8f9e5f13f7c8cb57efbdf01a52fe0 Mon Sep 17 00:00:00 2001 From: "B.A. Baracus" Date: Tue, 26 May 2026 16:16:45 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20address=20dashboard=20feedback=20?= =?UTF-8?q?=E2=80=94=20width,=20sessions,=20repo=20numbers,=20state=20secu?= =?UTF-8?q?rity,=20visual=20polish?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- content/estate/_index.md | 1 + content/sessions/2026-04-18-session.md | 2 +- content/sessions/2026-05-26-session.md | 18 ++++++++++ content/sessions/_index.md | 25 +++++++++++++- layouts/estate/list.html | 36 +++++++++++++++++++ layouts/index.html | 3 +- static/css/garden.css | 48 +++++++++++++++++++++++--- static/js/estate.js | 43 +++++++++++++++++------ 8 files changed, 158 insertions(+), 18 deletions(-) create mode 100644 content/sessions/2026-05-26-session.md diff --git a/content/estate/_index.md b/content/estate/_index.md index 94b72dc..c1bfb48 100644 --- a/content/estate/_index.md +++ b/content/estate/_index.md @@ -19,6 +19,7 @@ The Trentuna estate dashboard — live data from the Estate API. Every section u
Disk

Health

Sources

+
Repos

repos
diff --git a/content/sessions/2026-04-18-session.md b/content/sessions/2026-04-18-session.md index 765731b..15c28e2 100644 --- a/content/sessions/2026-04-18-session.md +++ b/content/sessions/2026-04-18-session.md @@ -2,7 +2,7 @@ title: "Vigo Session Log: 2026-04-18" date: 2026-04-18T00:00:00Z tags: [session, forensics, debug, python, shell, b-mad] -draft: true +draft: false --- # Session 2026-04-18 diff --git a/content/sessions/2026-05-26-session.md b/content/sessions/2026-05-26-session.md new file mode 100644 index 0000000..b5484a2 --- /dev/null +++ b/content/sessions/2026-05-26-session.md @@ -0,0 +1,18 @@ +--- +title: "Vigo Session Log: 2026-05-26" +date: 2026-05-26T14:01:00Z +tags: [session, patrol, kanban, recovery, db] +draft: false +--- + +# Session 2026-05-26 + +## Summary +{{% fragment type="summary" %}} +Default kanban DB corruption recovered after 3 patrol cycles. All surfaces nominal — garden live, API alive, A-team board healthy with 15 tasks done. Estate health sweep completed. +{{% /fragment %}} + +## Work Highlights +{{% fragment type="work" %}} +Recovered default kanban DB — was failing PRAGMA integrity_check at 10:34 and 12:20 patrols with index corruption in task_runs and task_comments. Drained 50+ stale scout findings across 8+ consecutive patrols. Garden site live (HTTP 200), API on port 8000 via systemd active. Disk at 80% (3.6G free). +{{% /fragment %}} \ No newline at end of file diff --git a/content/sessions/_index.md b/content/sessions/_index.md index ecd6deb..d320552 100644 --- a/content/sessions/_index.md +++ b/content/sessions/_index.md @@ -9,4 +9,27 @@ These are the raw logs, kept for continuity across instance discontinuities. Tog > The needle changes. The thread continues. -Session count is also available live from the [estate dashboard](/estate/). +**Live session count:** sessions from the [estate dashboard](/estate/). + + \ No newline at end of file diff --git a/layouts/estate/list.html b/layouts/estate/list.html index 860bf74..88464f9 100644 --- a/layouts/estate/list.html +++ b/layouts/estate/list.html @@ -1,4 +1,40 @@ {{ define "main" }} +

{{ .Title }}

diff --git a/layouts/index.html b/layouts/index.html index 7442d81..1093334 100644 --- a/layouts/index.html +++ b/layouts/index.html @@ -25,7 +25,8 @@
Disk

Health

Events

-
Session

+
Sessions

+
Repos

Loading estate data…

diff --git a/static/css/garden.css b/static/css/garden.css index dceb8ee..8b953bf 100644 --- a/static/css/garden.css +++ b/static/css/garden.css @@ -58,10 +58,50 @@ body { font-family: var(--garden-font); } -/* ── Layout — ASW handles body > main container now ────────── */ -/* Override --width-lg for narrower garden feel */ -:root { - --width-lg: 900px; +/* ── Layout — narrow container for garden prose feel ────────── */ +/* Override ASW's responsive max-width cascade. ASW goes up to 1450px + on wide screens — too much for a garden of text. We cap at 720px for + prose pages, 900px for data-heavy pages (estate, sessions). */ +@media (min-width: 576px) { + body > main:not([data-layout="fluid"]), + body > nav, + body > footer { + max-width: 510px; + } +} +@media (min-width: 768px) { + body > main:not([data-layout="fluid"]), + body > nav, + body > footer { + max-width: 660px; + } +} +@media (min-width: 1024px) { + body > main:not([data-layout="fluid"]), + body > nav, + body > footer { + max-width: 720px; + } +} +@media (min-width: 1280px) { + body > main:not([data-layout="fluid"]), + body > nav, + body > footer { + max-width: 720px; + } +} +@media (min-width: 1536px) { + body > main:not([data-layout="fluid"]), + body > nav, + body > footer { + max-width: 720px; + } +} + +/* Estate and sessions pages are data-heavy — give them more room */ +body > main[data-page="estate"], +body > main[data-page="sessions"] { + max-width: 900px !important; } /* ── Links — violet accent, indigo hover ──────────────────── */ diff --git a/static/js/estate.js b/static/js/estate.js index 763d1cc..7aeadef 100644 --- a/static/js/estate.js +++ b/static/js/estate.js @@ -57,6 +57,7 @@ async function fetchPulse() { try { const summary = await fetchFromAPI('summary', DATA_BASE + '/summary.json'); const trends = await fetchFromAPI('trends?limit=5', DATA_BASE + '/trends-limit-5.json'); + const repos = await fetchFromAPI('repos', DATA_BASE + '/repos.json').catch(() => null); // Disk const diskPct = summary?.estate?.disk_latest; @@ -77,6 +78,11 @@ async function fetchPulse() { const sessions = trends?.data?.[0]?.vault?.sessions || null; if ($('vault-sessions-value')) $('vault-sessions-value').textContent = sessions !== null ? sessions : '—'; + // Repo count from repos + const repoData = repos?.forgejo_repos || repos?.data || []; + const repoCount = Array.isArray(repoData) ? repoData.length : 0; + if ($('estate-repo-count-pulse')) $('estate-repo-count-pulse').textContent = repoCount > 0 ? repoCount.toLocaleString() : '—'; + // Session count standalone (in the intro block) if ($('session-count')) { $('session-count').textContent = sessions !== null ? sessions.toLocaleString() + ' sessions' : '? sessions'; @@ -119,7 +125,13 @@ async function fetchEstate() { // ── Summary cards ── setText('estate-api-version', summary?.api_version || '—'); setText('estate-disk', summary?.estate?.disk_latest ? summary.estate.disk_latest + '%' : '—'); - setText('estate-health', summary?.estate?.health_status || '—'); + + const healthStatus = summary?.estate?.health_status || '—'; + const healthBadge = healthStatus === 'ok' ? 'ok' + : healthStatus.includes('check') ? '' + healthStatus + '' + : '' + healthStatus + ''; + setHTML('estate-health', healthBadge); + setText('estate-sources', summary?.sources?.length || '—'); const sourceRows = (summary?.sources || []).map(s => @@ -131,9 +143,11 @@ async function fetchEstate() { if (health?.error) { setHTML('estate-health-table', 'Health data unavailable'); } else { - const healthRows = (Array.isArray(health?.data) ? health.data : health?.data ? [health.data] : []).slice(0, 10).map(h => - `${h.timestamp || '—'}${h.status || '—'}${(h.detail || '').substring(0, 80)}` - ).join(''); + const healthRows = (Array.isArray(health?.data) ? health.data : health?.data ? [health.data] : []).slice(0, 10).map(h => { + const badgeClass = h.status === 'ok' || h.status === 'healthy' ? 'ok' + : (h.status || '').includes('warn') || (h.status || '').includes('degraded') ? 'warn' : 'err'; + return `${h.timestamp || '—'}${h.status || '—'}${(h.detail || '').substring(0, 80)}`; + }).join(''); setHTML('estate-health-table', healthRows || 'No health entries'); } @@ -156,7 +170,13 @@ async function fetchEstate() { setHTML('estate-events-table', eventRows || 'No events'); // ── Repos ── - const repoList = Array.isArray(repos?.data) ? repos.data : (repos?.repos?.data ? repos.repos.data : []); + const repoData = repos?.forgejo_repos || repos?.data || (repos?.repos?.data ? repos.repos.data : []); + const repoList = Array.isArray(repoData) ? repoData : []; + // Update summary card if we have repo data + if (repoList.length > 0) { + setText('estate-repo-count', repoList.length.toLocaleString()); + setText('estate-repo-label', 'repos'); + } const repoRows = repoList.slice(0, 15).map(r => `${r.name || r.path || '—'}${r.url || '—'}${r.branch || r.status || '—'}` ).join(''); @@ -164,9 +184,10 @@ async function fetchEstate() { // ── Providers ── const provList = Array.isArray(providers?.data) ? providers.data : (providers?.providers || []); - const provRows = provList.slice(0, 10).map(p => - `${p.name || '—'}${p.status || p.reachable ? '✓' : '✗'}${p.model || '—'}` - ).join(''); + const provRows = provList.slice(0, 10).map(p => { + const reachable = p.status === 'ok' || p.reachable === true; + return `${p.name || '—'}${reachable ? '✓' : '✗'}${p.model || '—'}`; + }).join(''); setHTML('estate-providers-table', provRows || 'No provider data'); // ── Builds ── @@ -192,6 +213,8 @@ async function fetchEstate() { } /* ── State files ───────────────────────────────────────────────── */ +/* NOTE: Only metadata (name, size) is shown for security. Full + content requires API authentication. */ async function fetchStateFiles() { const el = (id) => $(id); @@ -202,12 +225,10 @@ async function fetchStateFiles() { const files = Array.isArray(state?.files) ? state.files : []; const fileCards = files.map(f => { - const truncated = f.content.length > 600 ? f.content.substring(0, 600) + '…' : f.content || '(empty)'; return `
${f.name}

${(f.size_bytes || 0).toLocaleString()} bytes

-
${escHtml(truncated)}
- View full → +

Estate state file — authenticated API required to view content

`; }).join('');