Skip to content

Latest commit

Β 

History

History
353 lines (307 loc) Β· 20.5 KB

File metadata and controls

353 lines (307 loc) Β· 20.5 KB

InfoMesh Console Dashboard (Console App UI)

Overview

A console app UI (Textual-based TUI) dashboard for monitoring InfoMesh node status. Runs directly in the terminal without a separate web server, making it usable via SSH, mobile terminal apps (Termux, Blink, etc.), and low-spec server environments.

Technology Choice: Textual

Item Choice Reason
Framework Textual (β‰₯1.0) Rich-based, responsive CSS layout, mouse/keyboard support
Alternatives curses/blessed/urwid Textual dominates in CSS layout, widget system, and testability

Tab Layout (5 tabs)

Tab 1: Overview

β”Œβ”€ InfoMesh Dashboard ─────────────────────────── v0.1.0 ─┐
β”‚                                                          β”‚
β”‚  β”Œβ”€ Node ──────────────┐  β”Œβ”€ Resources ──────────────┐  β”‚
β”‚  β”‚ Peer ID: Qm...3kF   β”‚  β”‚ CPU:  β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘  38%    β”‚  β”‚
β”‚  β”‚ State:  🟒 Running   β”‚  β”‚ RAM:  β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘  62%    β”‚  β”‚
β”‚  β”‚ Uptime: 3d 14h 22m  β”‚  β”‚ Disk: β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘  81%    β”‚  β”‚
β”‚  β”‚ Version: 0.1.0      β”‚  β”‚ Net↑: 2.1/5.0 Mbps       β”‚  β”‚
β”‚  β”‚ GitHub:  user@e...   β”‚  β”‚ Net↓: 4.3/10.0 Mbps      β”‚  β”‚
β”‚  β”‚ Data dir: ~/.info... β”‚  β”‚                           β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                                                          β”‚
β”‚  β”Œβ”€ Activity (last 1h) ──────────────────────────────┐  β”‚
β”‚  β”‚ Crawled:    142 pages    β–β–ƒβ–…β–‡β–…β–ƒβ–β–ƒβ–…β–‡β–ˆβ–ˆβ–ˆβ–…β–ƒβ–        β”‚  β”‚
β”‚  β”‚ Indexed:    138 docs     β–β–ƒβ–…β–‡β–…β–ƒβ–β–ƒβ–…β–‡β–ˆβ–ˆβ–ˆβ–…β–ƒβ–        β”‚  β”‚
β”‚  β”‚ Searches:    23 queries  ▁▁▃▁▁▅▃▁▁▃▁▇▅▁▁        β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                                                          β”‚
β”‚  β”Œβ”€ Recent Events ───────────────────────────────────┐  β”‚
β”‚  β”‚ 14:23:01  Crawled example.com/page1       +1.0 cr β”‚  β”‚
β”‚  β”‚ 14:22:58  πŸ” "python async" (12 results, 8ms)     β”‚  β”‚
β”‚  β”‚ 14:22:45  Peer Qm...xY2 connected                β”‚  β”‚
β”‚  β”‚ 14:22:30  Index snapshot exported (2.3 MB)        β”‚  β”‚
β”‚  β”‚ 14:22:15  Crawled docs.python.org/3/      +1.0 cr β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Implementation Notes: NodeInfoPanel shows Data dir instead of Peers. GitHub email is auto-detected from git config user.email and shown if available; displayed as not connected otherwise. The value is resolved once and cached. ResourcePanel displays CPU/RAM when psutil is installed, N/A otherwise. Resource bar colors auto-switch based on usage (β‰₯90% red, β‰₯70% yellow).

Tab 2: Crawl

β”Œβ”€ Crawl ─────────────────────────────────────────────────┐
β”‚                                                          β”‚
β”‚  Workers: 3/5 active    Rate: 42 pages/hr                β”‚
β”‚  Queue:   156 pending   Errors: 2 (1.4%)                 β”‚
β”‚                                                          β”‚
β”‚  β”Œβ”€ Top Domains ─────────────────────────────────────┐  β”‚
β”‚  β”‚ docs.python.org      β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ  234 pages      β”‚  β”‚
β”‚  β”‚ en.wikipedia.org     β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ     178 pages      β”‚  β”‚
β”‚  β”‚ developer.mozilla.org β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ      145 pages      β”‚  β”‚
β”‚  β”‚ stackoverflow.com    β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ         98 pages       β”‚  β”‚
β”‚  β”‚ arxiv.org            β–ˆβ–ˆβ–ˆ           67 pages       β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                                                          β”‚
β”‚  β”Œβ”€ Live Feed ───────────────────────────────────────┐  β”‚
β”‚  β”‚ βœ“  docs.python.org/3/tutorial/       1.2s  4.2KB β”‚  β”‚
β”‚  β”‚ βœ“  en.wikipedia.org/wiki/P2P         0.8s  8.1KB β”‚  β”‚
β”‚  β”‚ βœ—  example.com/blocked  robots.txt   β€”     β€”     β”‚  β”‚
β”‚  β”‚ βœ“  arxiv.org/abs/2401.01234          2.1s  3.7KB β”‚  β”‚
β”‚  β”‚ ⟳  developer.mozilla.org/en-US/...  crawling...  β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Tab 3: Search

β”Œβ”€ Search ────────────────────────────────────────────────┐
β”‚                                                          β”‚
β”‚  πŸ” Query: [python async tutorial________________]       β”‚
β”‚                                                          β”‚
β”‚  Found 12 results (8ms, local):                          β”‚
β”‚                                                          β”‚
β”‚  β”Œβ”€ Results ─────────────────────────────────────────┐  β”‚
β”‚  β”‚ 1. Python Asyncio Tutorial                        β”‚  β”‚
β”‚  β”‚    https://docs.python.org/3/library/asyncio.html β”‚  β”‚
β”‚  β”‚    BM25=2.341  Fresh=0.95  Trust=0.88  Auth=0.72  β”‚  β”‚
β”‚  β”‚    Score: 1.8234                                   β”‚  β”‚
β”‚  β”‚    This module provides infrastructure for writing β”‚  β”‚
β”‚  β”‚    single-threaded concurrent code using...        β”‚  β”‚
β”‚  β”‚                                                    β”‚  β”‚
β”‚  β”‚ 2. Async IO in Python                             β”‚  β”‚
β”‚  β”‚    https://realpython.com/async-io-python/        β”‚  β”‚
β”‚  β”‚    BM25=2.102  Fresh=0.82  Trust=0.91  Auth=0.68  β”‚  β”‚
β”‚  β”‚    Score: 1.6891                                   β”‚  β”‚
β”‚  β”‚    Async IO is a concurrent programming design... β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Tab 4: Network

β”Œβ”€ Network ───────────────────────────────────────────────┐
β”‚                                                          β”‚
β”‚  β”Œβ”€ P2P Status ──────────┐  β”Œβ”€ DHT ─────────────────┐  β”‚
β”‚  β”‚ State: πŸ”΄ Offline      β”‚  β”‚ Keys stored:   1,234  β”‚  β”‚
β”‚  β”‚ Peers: 0 connected    β”‚  β”‚ Lookups/hr:      456   β”‚  β”‚
β”‚  β”‚ Bootstrap: 3 nodes    β”‚  β”‚ Publications:    89    β”‚  β”‚
β”‚  β”‚ Port:  4001 TCP       β”‚  β”‚                        β”‚  β”‚
β”‚  β”‚ Replication: 3x       β”‚  β”‚                        β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                                                          β”‚
β”‚  β”Œβ”€ Connected Peers ─────────────────────────────────┐  β”‚
β”‚  β”‚ Peer ID          Latency   Trust    State         β”‚  β”‚
β”‚  β”‚ Qm...aB2         23ms     0.92     active        β”‚  β”‚
β”‚  β”‚ Qm...cD4         45ms     0.85     active        β”‚  β”‚
β”‚  β”‚ Qm...eF6        102ms     0.78     idle          β”‚  β”‚
β”‚  β”‚ Qm...gH8         67ms     0.71     active        β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                                                          β”‚
β”‚  β”Œβ”€ Bandwidth ───────────────────────────────────────┐  β”‚
β”‚  β”‚ Upload:   ▁▃▅▇▅▃▁▃▅▇  2.1/5.0 Mbps              β”‚  β”‚
β”‚  β”‚ Download: β–ƒβ–…β–‡β–ˆβ–‡β–…β–ƒβ–…β–‡β–ˆ  4.3/10.0 Mbps             β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Implementation Notes: P2P Status shows Bootstrap node count and Replication factor. Peer table columns: Peer ID, Latency, Trust, State (4 columns). Bandwidth sparkline shows current/limit format.

Tab 5: Credits

β”Œβ”€ Credits ───────────────────────────────────────────────┐
β”‚                                                          β”‚
β”‚  β”Œβ”€ Balance ─────────────────────────────────────────┐  β”‚
β”‚  β”‚                                                    β”‚  β”‚
β”‚  β”‚  Balance:  1,234.50 credits    Tier: ⭐⭐⭐ (3)     β”‚  β”‚
β”‚  β”‚  Earned:   1,456.75            Search cost: 0.033  β”‚  β”‚
β”‚  β”‚  Spent:      222.25            Score: 1,456.75     β”‚  β”‚
β”‚  β”‚                                                    β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                                                          β”‚
β”‚  β”Œβ”€ Earnings Breakdown ──────────────────────────────┐  β”‚
β”‚  β”‚ Crawling       β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ  702.0  (48.2%)     β”‚  β”‚
β”‚  β”‚ Uptime         β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ        396.0  (27.2%)     β”‚  β”‚
β”‚  β”‚ Query Process  β–ˆβ–ˆβ–ˆβ–ˆ            178.5  (12.2%)     β”‚  β”‚
β”‚  β”‚ LLM (own)      β–ˆβ–ˆβ–ˆ             135.0   (9.3%)     β”‚  β”‚
β”‚  β”‚ Doc Hosting    β–ˆβ–ˆ               45.25  (3.1%)     β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                                                          β”‚
β”‚  β”Œβ”€ Recent Transactions ─────────────────────────────┐  β”‚
β”‚  β”‚ 14:23:01  +1.000  crawl    example.com/page1      β”‚  β”‚
β”‚  β”‚ 14:22:58  -0.033  search   "python async"         β”‚  β”‚
β”‚  β”‚ 14:22:30  +0.500  uptime   1 hour                 β”‚  β”‚
β”‚  β”‚ 14:22:15  +1.000  crawl    docs.python.org/3/     β”‚  β”‚
β”‚  β”‚ 14:21:00  +1.500  llm_own  summarize page #456    β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Mobile Support (40-Column Mode)

Using Textual's responsive CSS, the layout automatically switches to a single-column layout on narrow screens (under 40 columns).

β”Œβ”€ InfoMesh ──── v0.1.0 ─┐
β”‚                          β”‚
β”‚ Peer: Qm...3kF           β”‚
β”‚ State: 🟒 Running        β”‚
β”‚ Uptime: 3d 14h           β”‚
β”‚ Peers: 12                β”‚
β”‚                          β”‚
β”‚ CPU:  β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘  38%      β”‚
β”‚ RAM:  β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘  62%      β”‚
β”‚ Disk: β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ  81%      β”‚
β”‚                          β”‚
β”‚ Crawled : 142 pages/hr   β”‚
β”‚ Indexed : 138 docs/hr    β”‚
β”‚ Searches:  23 queries/hr β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Module Structure

infomesh/dashboard/            # 16 modules, 2,340 lines
β”œβ”€β”€ __init__.py
β”œβ”€β”€ app.py              # DashboardApp (main Textual Application, 276 lines)
β”œβ”€β”€ bgm.py              # BGMPlayer (background music via mpv/ffplay/aplay, 228 lines)
β”œβ”€β”€ text_report.py      # Rich-based text report (non-interactive fallback, 333 lines)
β”œβ”€β”€ screens/
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”œβ”€β”€ overview.py     # OverviewPane β€” NodeInfoPanel, ResourcePanel, ActivityPanel, LiveLog (284 lines)
β”‚   β”œβ”€β”€ crawl.py        # CrawlPane β€” CrawlStatsPanel, TopDomainsPanel, LiveLog (182 lines)
β”‚   β”œβ”€β”€ search.py       # SearchPane β€” Input, SearchResultsPanel (151 lines)
β”‚   β”œβ”€β”€ network.py      # NetworkPane β€” P2PStatusPanel, DHTPanel, PeerTable, BandwidthPanel (246 lines)
β”‚   └── credits.py      # CreditsPane β€” BalancePanel, EarningsBreakdownPanel, TransactionTable (289 lines)
β”œβ”€β”€ widgets/
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”œβ”€β”€ sparkline.py    # SparklineChart (Unicode block character mini chart, 75 lines)
β”‚   β”œβ”€β”€ bar_chart.py    # BarChart + BarItem (horizontal bar graph, 90 lines)
β”‚   β”œβ”€β”€ resource_bar.py # ResourceBar (CPU/RAM/Disk/Net resource bar, 80 lines)
β”‚   └── live_log.py     # LiveLog (real-time event log, RichLog-based, 96 lines)
└── dashboard.tcss      # Textual CSS stylesheet (responsive layout)

CLI Commands

# Launch dashboard
infomesh dashboard

# Start on a specific tab
infomesh dashboard --tab credits

# Available tabs: overview, crawl, search, network, credits (default: overview)
infomesh dashboard -t network

App Architecture

DashboardApp (App[None])
β”œβ”€β”€ Header β€” Title "InfoMesh Dashboard" + version display
β”œβ”€β”€ TabbedContent (initial=selected tab)
β”‚   β”œβ”€β”€ TabPane "Overview" β†’ OverviewPane
β”‚   β”‚   β”œβ”€β”€ Horizontal
β”‚   β”‚   β”‚   β”œβ”€β”€ NodeInfoPanel (Peer ID, State, Uptime, Version, Data dir)
β”‚   β”‚   β”‚   └── ResourcePanel (CPU, RAM, Disk, Net↑, Net↓)
β”‚   β”‚   β”œβ”€β”€ ActivityPanel (Crawled/Indexed/Searches + SparklineChart Γ—3)
β”‚   β”‚   └── LiveLog (event feed)
β”‚   β”œβ”€β”€ TabPane "Crawl" β†’ CrawlPane
β”‚   β”‚   β”œβ”€β”€ CrawlStatsPanel (Workers, Queue, Rate, Errors)
β”‚   β”‚   β”œβ”€β”€ TopDomainsPanel (SQL GROUP BY domain β†’ BarChart)
β”‚   β”‚   └── LiveLog (crawl feed)
β”‚   β”œβ”€β”€ TabPane "Search" β†’ SearchPane
β”‚   β”‚   β”œβ”€β”€ Input (search query)
β”‚   β”‚   └── SearchResultsPanel (BM25 scores + snippets)
β”‚   β”œβ”€β”€ TabPane "Network" β†’ NetworkPane
β”‚   β”‚   β”œβ”€β”€ Horizontal
β”‚   β”‚   β”‚   β”œβ”€β”€ P2PStatusPanel (State, Peers, Bootstrap, Port, Replication)
β”‚   β”‚   β”‚   └── DHTPanel (Keys, Lookups/hr, Publications)
β”‚   β”‚   β”œβ”€β”€ PeerTable (DataTable: Peer ID, Latency, Trust, State)
β”‚   β”‚   └── BandwidthPanel (Upload/Download SparklineChart + current/limit)
β”‚   └── TabPane "Credits" β†’ CreditsPane
β”‚       β”œβ”€β”€ BalancePanel (Balance, Earned, Spent, Tier, Search cost)
β”‚       β”œβ”€β”€ EarningsBreakdownPanel (per-action BarChart)
β”‚       └── TransactionTable (DataTable: Time, Amount, Type, Note)
└── Footer β€” keyboard shortcut display

Keyboard Shortcuts

Key Action Scope
1-5 Switch tabs (Overview β†’ Credits) Global
Tab Focus next widget Global (Textual default)
Shift+Tab Focus previous widget Global (Textual default)
/ Focus search input Search tab only
q Quit Global
r Refresh (Overview, Crawl, Network, Credits) Global
m Toggle BGM on/off Global
? Show help notification (5s timeout) Global

BGM (Background Music)

The dashboard can play background music during operation via an external player subprocess.

Supported Players

Players are auto-detected in this order: mpv, ffplay (part of ffmpeg). If neither is found, BGM is silently disabled.

# Install on Debian/Ubuntu:
sudo apt install mpv     # or: sudo apt install ffmpeg

# Install on macOS:
brew install mpv         # or: brew install ffmpeg

Configuration

BGM is off by default. Enable it with the m keyboard shortcut or via config:

[dashboard]
bgm_auto_start = true    # false by default β€” enable to auto-play on start
bgm_volume = 50           # 0–100
bgm_idle_stop = true      # auto-stop BGM when crawling is idle (set false to keep playing)

Auto-Restart

If the audio player process crashes unexpectedly, BGM will automatically restart (up to 5 attempts). This is handled transparently β€” a notification appears when auto-restart occurs.

Performance Note

On resource-constrained systems (especially WSL2), the audio player subprocess may compete with crawling and indexing for CPU time, causing stuttering. If this occurs:

  1. Press m to disable BGM
  2. Use mpv instead of ffplay (lighter CPU usage)
  3. Increase refresh_interval to reduce dashboard overhead
  4. Use the minimal resource profile

Implementation Specs

  • Dependencies: textual>=1.0 (in main deps, currently textual==8.0.0)
  • Data refresh intervals (per-tab):
    • Overview: set_interval(2.0) β€” refresh resource/node status every 2s
    • Crawl: set_interval(3.0) β€” refresh domain stats every 3s
    • Network: set_interval(2.0) β€” refresh P2P status every 2s
    • Credits: set_interval(5.0) β€” refresh credit data every 5s
    • Search: no auto-refresh (runs only on user query input)
  • Data sources:
    • LocalStore β€” document count, domain stats, search (SQLite FTS5)
    • CreditLedger β€” balance, earnings breakdown, transaction records
    • psutil (optional) β€” CPU/RAM usage (shows N/A if not installed)
    • shutil.disk_usage() β€” disk usage
    • PID file (infomesh.pid) β€” node running status check
    • KeyPair.load() β€” Peer ID loading
  • Error handling: Shows "N/A" or guidance message when data source is unavailable; all refresh_data() wrapped with contextlib.suppress(Exception)
  • Tests: 53 pytest unit/integration tests (tests/test_dashboard.py)
    • Widget tests: SparklineChart (6), BarChart (4), ResourceBar (4), LiveLog (1)
    • Helper tests: _format_uptime(), _is_node_running(), _get_peer_id() (7)
    • Screen tests: SearchResultsPanel (3), CreditsHelpers (2), NetworkPanels (1), CrawlStatsPanel (2)
    • App/CLI tests: DashboardApp (3), CLI command (1), BarItem (3), Sparkline edge cases (4)
    • BGM/text report tests: BGMPlayer, text_report, etc. (12)

Widget Implementation Details

SparklineChart

  • Uses Unicode block characters: " β–β–‚β–ƒβ–„β–…β–†β–‡β–ˆ" (9 levels)
  • reactive properties for automatic re-render on data change
  • push_value(max_points=30) β€” maintains up to 30 data points
  • Automatic value normalization (min-max scaling)

BarChart

  • BarItem dataclass: label, value, color, suffix
  • β–ˆ/β–‘ characters for horizontal bar rendering (default width 20 chars)
  • Displays both ratio to max value and percentage of total simultaneously

Related docs: Overview Β· Architecture Β· Credit System Β· Tech Stack Β· Legal Β· Trust & Integrity Β· Security Audit Β· MCP Integration Β· Publishing Β· FAQ