feat(me): improve dashboard rendering with dynamic layout and table-based activity

Overhaul the `lore me` human-mode renderer for better terminal adaptation
and visual clarity:

Layout:
- Add terminal_width() detection (COLUMNS env -> stderr ioctl -> 80 fallback)
- Replace hardcoded column widths with dynamic title_width() that adapts to
  terminal size, clamped to [20, 80]
- Section dividers now span the full terminal width

Activity feed:
- Replace manual println! formatting with Table-based rendering for proper
  column alignment across variable-width content
- Split event_badge() into activity_badge_label() + activity_badge_style()
  for table cell compatibility
- Add system_event_style() (#555555 dark gray) to visually suppress
  non-note events (label, assign, status, milestone, review changes)
- Own actions use dim styling; others' notes render at full color

MR display:
- Add humanize_merge_status() to convert GitLab API values like
  "not_approved" -> "needs approval", "ci_must_pass" -> "CI pending"

Table infrastructure (render.rs):
- Add Table::columns() for headerless tables
- Add Table::indent() for row-level indentation
- Add truncate_pad() for fixed-width cell formatting
- Table::render() now supports headerless mode (no separator line)

Other:
- Default activity lookback changed from 30d to 1d (more useful default)
- Robot-docs schema added for `me` command
- AGENTS.md and CLAUDE.md updated with `lore me` examples

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
teernisse
2026-02-21 09:20:25 -05:00
parent 7e9a23cc0f
commit 6e487532aa
7 changed files with 344 additions and 99 deletions

View File

@@ -18,8 +18,8 @@ use crate::core::time::parse_since;
use self::queries::{query_activity, query_authored_mrs, query_open_issues, query_reviewing_mrs};
use self::types::{AttentionState, MeDashboard, MeSummary};
/// Default activity lookback: 30 days in milliseconds (AC-2.3).
const DEFAULT_ACTIVITY_SINCE_DAYS: i64 = 30;
/// Default activity lookback: 1 day in milliseconds.
const DEFAULT_ACTIVITY_SINCE_DAYS: i64 = 1;
const MS_PER_DAY: i64 = 24 * 60 * 60 * 1000;
/// Resolve the effective username from CLI flag or config.
@@ -96,7 +96,7 @@ pub fn run_me(config: &Config, args: &MeArgs, robot_mode: bool) -> Result<()> {
let project_ids = resolve_project_scope(&conn, args, config)?;
let single_project = project_ids.len() == 1;
// 5. Parse --since (default 30d for activity feed, AC-2.3)
// 5. Parse --since (default 1d for activity feed)
let since_ms = match args.since.as_deref() {
Some(raw) => parse_since(raw).ok_or_else(|| {
LoreError::Other(format!(