Commit Graph

290 Commits

Author SHA1 Message Date
teernisse
e8ecb561cf feat: implement lore explain command (bd-9lbr)
Auto-generates structured narratives for issues and MRs from local DB:
- EntitySummary with title, state, author, labels, status
- Key decisions heuristic (correlates state/label changes with nearby notes)
- Activity summary with event counts and time span
- Open threads detection (unresolved discussions)
- Related entities (closing MRs, related issues)
- Timeline of all events in chronological order

7 unit tests, robot-docs entry, autocorrect registry, CLI dispatch wired.
2026-02-19 09:38:50 -05:00
teernisse
1e679a6d72 feat(sync): fetch and store GitLab issue links (bd-343o)
Add end-to-end support for GitLab issue link fetching:
- New GitLabIssueLink type + fetch_issue_links API client method
- Migration 029: add issue_links job type and watermark column
- issue_links.rs: bidirectional entity_reference storage with
  self-link skip, cross-project fallback, idempotent upsert
- Drain pipeline in orchestrator following mr_closes_issues pattern
- Display related issues in 'lore show issues' output
- --no-issue-links CLI flag with config, autocorrect, robot-docs
- 6 unit tests for storage logic
2026-02-19 09:26:47 -05:00
teernisse
9a1dbda522 docs: update AGENTS.md and CLAUDE.md with Phase B commands (bd-2fc)
Add temporal intelligence command examples: timeline, file-history,
trace, related, drift, who, count references, surgical sync.
Both AGENTS.md (project) and ~/.claude/CLAUDE.md (global) updated.
2026-02-19 09:05:19 -05:00
teernisse
a55f47161b docs(robot): update robot-docs manifest with Phase B commands (bd-1v8)
- Add 'related' command with entity/query modes and response schema
- Update 'count' to document 'references' entity type and its schema
- Expand temporal_intelligence workflow with file-history and trace steps
- Update lore_exclusive list with file-history, trace, related, drift
2026-02-19 09:03:24 -05:00
teernisse
2bbd1e3426 feat(cli): close bd-3jqx, add related to autocorrect registry, robot-docs updates
- Register related subcommand flags (--limit, --project) in COMMAND_FLAGS
- Robot-docs: add related command schema, count references schema
- Robot-docs: add file-history, trace, related, drift to capabilities
- Close bd-3jqx: all 4 integration tests passing (903 total, 0 failures)
- Beads sync
2026-02-19 09:03:16 -05:00
teernisse
574cd55eff feat(cli): add 'lore count references' command (bd-2ez)
Adds 'references' entity type to the count command with breakdowns
by reference_type (closes/mentioned/related), source_method
(api/note_parse/description_parse), and unresolved count.

Includes human and robot output formatters, 2 unit tests.
2026-02-19 09:01:05 -05:00
teernisse
c8dece8c60 feat(cli): add 'lore related' semantic similarity command (bd-8con)
Adds 'lore related' / 'lore similar' command for discovering semantically
related issues and MRs using vector embeddings.

Two modes:
- Entity mode: find entities similar to a specific issue/MR
- Query mode: embed free text and find matching entities

Includes distance-to-similarity conversion, label intersection,
human and robot output formatters, and 11 unit tests.
2026-02-19 08:56:16 -05:00
teernisse
3e96f19a11 feat(tui): add CLI/TUI parity tests (bd-wrw1)
10 parity tests verifying TUI and CLI query paths return consistent
results from the same SQLite database:
- Dashboard count parity (issues, MRs, discussions, notes)
- Issue list parity (IID ordering, state/author filters, ascending sort)
- MR list parity (IID ordering, state filter)
- Shared field parity (title, state, author, project_path)
- Empty database handling
- Terminal safety sanitization (dangerous sequences stripped)

Uses full-schema in-memory DB via create_connection + run_migrations.
Closes bd-wrw1, bd-2o49 (Phase 5.6 epic).
2026-02-19 08:01:55 -05:00
teernisse
8d24138655 chore: close Phase 5.5 epic (bd-1b6k) — 63 reliability tests 2026-02-19 07:49:59 -05:00
teernisse
01491b4180 feat(tui): add soak + pagination race tests (bd-14hv)
7 soak tests: 50k-event sustained load, watchdog timeout, render
interleaving, screen cycling, mode oscillation, depth bounds, multi-seed.
7 pagination race tests: concurrent read/write with snapshot fence,
multi-reader, within-fence writes, stress 1000 iterations.
2026-02-19 07:49:22 -05:00
teernisse
5143befe46 feat(tui): add 14 performance benchmark tests (bd-wnuo)
S/M/L tiered benchmarks measuring TUI update+render cycles with
synthetic data fixtures. SLO gates: S-tier <10ms update/<20ms render,
M-tier <50ms each. L-tier advisory only. All pass with generous margins.
2026-02-19 07:42:51 -05:00
teernisse
1e06cec3df feat(tui): add 10 navigation property tests (bd-3eis)
Deterministic seeded PRNG verifies NavigationStack invariants across
200k+ operations: depth >= 1, push/pop identity, forward cleared,
jump list only tracks detail screens, reset clears all, breadcrumbs
match depth, no panic under arbitrary sequences.
2026-02-19 01:13:20 -05:00
teernisse
9d6352a6af feat(tui): add 9 stress/fuzz tests for resize storm, rapid keys, event fuzz (bd-nu0d) 2026-02-19 01:09:02 -05:00
teernisse
656db00c04 feat(tui): add 16 race condition reliability tests (bd-3fjk)
- 4 stale response tests: issue list, dashboard, MR list, cross-screen isolation
- 4 SQLITE_BUSY error handling tests: toast display, nav preservation, idempotent toasts, error-then-success
- 7 cancel race tests: cancel/resubmit, rapid 5-submit sequence, key isolation, complete removes handle, stale completion no-op, stuck loading prevention, cancel_all
- 1 issue detail stale guard test
- Added active_cancel_token() method to TaskSupervisor for test observability
2026-02-19 01:03:25 -05:00
teernisse
9bcc512639 feat(tui): add 9 user flow integration tests (bd-2ygk)
Implements end-to-end flow tests covering all PRD Section 6 journeys:
- Morning triage (dashboard -> issue list -> detail -> back)
- Direct screen jumps (g-prefix chain: gt -> gw -> gi -> gh)
- Quick search (g/ -> results -> drill-in -> back with preserved state)
- Sync and browse (gs -> sync lifecycle -> complete -> browse)
- Expert navigation (gw -> Who -> verify expert mode default)
- Command palette (Ctrl+P -> verify open/filtered -> Esc close)
- Timeline navigation (gt -> events -> drill-in -> back)
- Bootstrap sync flow (Bootstrap -> gs -> SyncCompleted -> Dashboard)
- MR drill-in and back (gm -> detail -> Esc -> cursor preserved)

Key testing patterns:
- State generation alignment for dual-guard stale detection
- Key event injection via send_key/send_go helpers
- Data injection via supervisor.submit() + Msg handlers
- Cross-screen state preservation assertions
2026-02-19 00:52:58 -05:00
teernisse
403800be22 feat(tui): add snapshot test infrastructure + terminal compat matrix (bd-2nfs)
- 6 deterministic snapshot tests at 120x40 with FakeClock frozen at 2026-01-15T12:00:00Z
- Buffer-to-plaintext serializer resolving chars, graphemes, and wide-char continuations
- Golden file management with UPDATE_SNAPSHOTS=1 env var for regeneration
- Snapshot diff output on mismatch for easy debugging
- Tests: dashboard, issue list, issue detail, MR list, search results, empty state
- TERMINAL_COMPAT.md template for manual QA across iTerm2/tmux/Alacritty/kitty/WezTerm
2026-02-19 00:38:11 -05:00
teernisse
04ea1f7673 feat(tui): wire entity cache for near-instant detail view reopens (bd-3rjw)
- Add get_mut() and clear() methods to EntityCache<V>
- Add CachedIssuePayload / CachedMrPayload types to state
- Wire cache check in navigate_to for instant cache hits
- Populate cache on IssueDetailLoaded / MrDetailLoaded
- Update cache on DiscussionsLoaded
- Add 6 new entity_cache tests (get_mut, clear)
2026-02-19 00:25:28 -05:00
teernisse
026b3f0754 feat(tui): responsive breakpoints for detail views (bd-a6yb)
Apply breakpoint-aware layout to issue_detail and mr_detail views:
- Issue detail: hide labels on Xs, hide assignees on Xs/Sm, skip milestone row on Xs
- MR detail: hide branch names and merge status on Xs/Sm
- Issue detail allocate_sections gives description 60% on wide (Lg+) vs 40% narrow
- Add responsive tests for both detail views
- Close bd-a6yb: all TUI screens now adapt to terminal width

760 lib tests pass, clippy clean.
2026-02-19 00:10:43 -05:00
teernisse
ae1c3e3b05 chore: update beads tracking
Sync beads issue database to reflect current project state.
2026-02-18 23:59:40 -05:00
teernisse
bbfcfa2082 fix(tui): bounds-check scope picker selected index
Replace direct indexing (self.projects[self.selected_index - 1]) with
.get() to prevent panic if selected_index is somehow out of bounds.
Falls back to "All Projects" scope when the index is invalid instead
of panicking.
2026-02-18 23:59:11 -05:00
teernisse
45a989637c feat(tui): add per-screen responsive layout helpers
Introduce breakpoint-aware helper functions in layout.rs that
centralize per-screen responsive decisions. Each function maps a
Breakpoint to a screen-specific value, replacing scattered
hardcoded checks across view modules:

- detail_side_panel: show discussions side panel at Lg+
- info_screen_columns: 1 column on Xs/Sm, 2 on Md+
- search_show_project: hide project path column on narrow terminals
- timeline_time_width: compact time on Xs (5), full on Md+ (12)
- who_abbreviated_tabs: shorten tab labels on Xs/Sm
- sync_progress_bar_width: scale progress bar 15→50 with width

All functions are const fn with exhaustive match arms.
Includes 6 unit tests covering every breakpoint variant.
2026-02-18 23:59:04 -05:00
teernisse
1b66b80ac4 style(tui): apply rustfmt and clippy formatting across crate
Mechanical formatting pass to satisfy rustfmt line-width limits and
clippy pedantic/nursery lints. No behavioral changes.

Formatting (rustfmt line wrapping):
- action/sync.rs: multiline tuple destructure, function call args in tests
- state/sync.rs: if-let chain formatting, remove unnecessary Vec collect
- view/sync.rs: multiline array entries, format!(), vec! literals
- view/doctor.rs: multiline floor_char_boundary chain
- view/scope_picker.rs: multiline format!() with floor_char_boundary
- view/stats.rs: multiline render_stat_row call
- view/mod.rs: multiline assert!() in test
- app/update.rs: multiline enum variant destructure
- entity_cache.rs: multiline assert_eq!() with messages
- render_cache.rs: multiline retain() closure
- session.rs: multiline serde_json/File::create/parent() chains

Clippy:
- action/sync.rs: #[allow(clippy::too_many_arguments)] on test helper

Import/module ordering (alphabetical):
- state/mod.rs: move scope_picker mod + pub use to sorted position
- view/mod.rs: move scope_picker, stats, sync mod + use to sorted position
- view/scope_picker.rs: sort use imports (ScopeContext before ScopePickerState)
2026-02-18 23:58:29 -05:00
teernisse
09ffcfcf0f refactor(tui): deduplicate cursor_cell_offset into text_width module
Four view modules (search, command_palette, file_history, trace) each had
their own copy of cursor_cell_offset / text_cell_width for converting a
byte-offset cursor position to a display-column offset. Phase 5 introduced
a proper text_width module with these functions; this commit removes the
duplicates and rewires all call sites to use crate::text_width.

- search.rs: removed local text_cell_width + cursor_cell_offset definitions
- command_palette.rs: removed local cursor_cell_offset definition
- file_history.rs: replaced inline chars().count() cursor calc with import
- trace.rs: replaced inline chars().count() cursor calc with import
2026-02-18 23:58:13 -05:00
teernisse
146eb61623 feat(tui): Phase 4 completion + Phase 5 session/lock/text-width
Phase 4 (bd-1df9) — all 5 acceptance criteria met:
- Sync screen with delta ledger (bd-2x2h, bd-y095)
- Doctor screen with health checks (bd-2iqk)
- Stats screen with document counts (bd-2iqk)
- CLI integration: lore tui subcommand (bd-26lp)
- CLI integration: lore sync --tui flag (bd-3l56)

Phase 5 (bd-3h00) — session persistence + instance lock + text width:
- text_width.rs: Unicode-aware measurement, truncation, padding (16 tests)
- instance_lock.rs: Advisory PID lock with stale recovery (6 tests)
- session.rs: Atomic write + CRC32 checksum + quarantine (9 tests)

Closes: bd-26lp, bd-3h00, bd-3l56, bd-1df9, bd-y095
2026-02-18 23:51:54 -05:00
teernisse
418417b0f4 fix(tui): correct column names in file_history action queries + update beads
- file_history.rs: Fix SQL column references to match actual schema
  (position_new_path/position_old_path naming).

- beads: Update issue tracker state.
2026-02-18 22:58:14 -05:00
teernisse
fb40fdc677 feat(tui): Phase 3 power features — Who, Search, Timeline, Trace, File History screens
Complete TUI Phase 3 implementation with all 5 power feature screens:

- Who screen: 5 modes (expert/workload/reviews/active/overlap) with
  mode tabs, input bar, result rendering, and hint bar
- Search screen: full-text search with result list and scoring display
- Timeline screen: chronological event feed with time-relative display
- Trace screen: file provenance chains with expand/collapse, rename
  tracking, and linked issues/discussions
- File History screen: per-file MR timeline with rename chain display
  and discussion snippets

Also includes:
- Command palette overlay (fuzzy search)
- Bootstrap screen (initial sync flow)
- Action layer split from monolithic action.rs to per-screen modules
- Entity and render cache infrastructure
- Shared who_types module in core crate
- All screens wired into view/mod.rs dispatch
- 597 tests passing, clippy clean (pedantic + nursery), fmt clean
2026-02-18 22:56:38 -05:00
teernisse
f8d6180f06 fix: clippy lints — sort_by_key in drift, pub visibility for TUI, assert formatting
- drift.rs: Replace `sorted.sort_by(|a, b| b.1.cmp(&a.1))` with idiomatic
  `sort_by_key(|entry| std::cmp::Reverse(entry.1))` (clippy::use_sort_by_key).

- list.rs: Change `query_issues` and `query_mrs` from `fn` to `pub fn` so the
  TUI crate can call them directly instead of duplicating the query logic.

- vector.rs: Reformat multi-line assert! macro to satisfy rustfmt check
  (body moved onto separate lines with trailing message string).
2026-02-18 22:56:24 -05:00
teernisse
c1b1300675 refactor: extract who result types to core::who_types for TUI reuse
Move the 14 result structs and enums (WhoResult, ExpertResult, Expert,
ScoreComponents, ExpertMrDetail, WorkloadResult, WorkloadIssue, WorkloadMr,
WorkloadDiscussion, ReviewsResult, ReviewCategory, ActiveResult,
ActiveDiscussion, OverlapResult, OverlapUser) from cli::commands::who into
a new core::who_types module.

The TUI Who screen needs these types to render results, but importing from
the CLI layer would create a circular dependency (TUI -> CLI -> core). By
placing them in core, both the CLI and TUI can depend on them cleanly.

The CLI module re-exports all types via `pub use crate::core::who_types::*`
so existing consumers are unaffected.
2026-02-18 22:56:16 -05:00
teernisse
050e00345a feat(tui): Phase 2 detail screens — Issue Detail, MR Detail, discussion tree, cross-refs
Implements the remaining Phase 2 Core Screens:

- Discussion tree widget (view/common/discussion_tree.rs): DiscussionNode/NoteNode types,
  expand/collapse state, visual row flattening, format_relative_time with Clock trait
- Cross-reference widget (view/common/cross_ref.rs): CrossRefKind enum, navigable refs,
  badge rendering ([MR]/[REL]/[REF])
- Issue Detail (state + action + view): progressive hydration (metadata Phase 1,
  discussions Phase 2), section cycling, description scroll, sanitized GitLab content
- MR Detail (state + action + view): tab bar (Overview/Files/Discussions), file changes
  with change type indicators, branch info, draft/merge status, diff note support
- Message + update wiring: IssueDetailLoaded, MrDetailLoaded, DiscussionsLoaded handlers
  with TaskSupervisor stale-result guards

Closes bd-1d6z, bd-8ab7, bd-3t1b, bd-1cl9 (Phase 2 epic).
389 tests passing, clippy clean, fmt clean.
2026-02-18 15:37:23 -05:00
teernisse
90c8b43267 feat(tui): Phase 2 Issue List + MR List screens
Implement state, action, and view layers for both list screens:
- Issue List: keyset pagination, snapshot fence, filter DSL, label aggregation
- MR List: mirrors Issue pattern with draft/reviewer/target branch filters
- Migration 027: covering indexes for TUI list screen queries
- Updated Msg types to use typed Page structs instead of raw Vec<Row>
- 303 tests passing, clippy clean

Beads: bd-3ei1, bd-2kr0, bd-3pm2
2026-02-18 14:48:15 -05:00
teernisse
c5b7f4c864 (no description set) 2026-02-18 12:59:07 -05:00
teernisse
28ce63f818 refactor: split common/mod.rs into per-widget modules 2026-02-18 12:58:38 -05:00
teernisse
eb5b464d03 feat: TUI Phase 1 common widgets + scoring/path beads 2026-02-18 12:58:12 -05:00
teernisse
4664e0cfe3 feat: complete TUI Phase 0 — Toolchain Gate 2026-02-18 12:47:10 -05:00
teernisse
63bd58c9b4 feat(who): filter unresolved discussions to open entities only
Workload and active modes now exclude discussions on closed issues and
merged/closed MRs by default. Adds --include-closed flag to restore
the previous behavior when needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:34:28 -05:00
teernisse
714c8c2623 feat(path): rename-aware ambiguity resolution for suffix probe
When a bare filename like 'operators.ts' matches multiple full paths,
check if they are the same file connected by renames (via BFS on
mr_file_changes). If so, auto-resolve to the newest path instead of
erroring. Also wires path resolution into file-history and trace
commands so bare filenames work everywhere.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:34:28 -05:00
teernisse
171260a772 feat(cli): implement 'lore trace' command (bd-2n4, bd-9dd)
Gate 5 Code Trace - Tier 1 (API-only, no git blame).
Answers 'Why was this code introduced?' by building
file -> MR -> issue -> discussion chains.

New files:
- src/core/trace.rs: run_trace() query logic with rename-aware
  path resolution, entity_reference-based issue linking, and
  DiffNote discussion extraction
- src/core/trace_tests.rs: 7 unit tests for query logic
- src/cli/commands/trace.rs: CLI command with human output,
  robot JSON output, and :line suffix parsing (5 tests)

Human output shows full content (no truncation).
Robot JSON truncates discussion bodies to 500 chars for token efficiency.

Wiring:
- TraceArgs + Commands::Trace in cli/mod.rs
- handle_trace in main.rs
- VALID_COMMANDS + robot-docs manifest entry
- COMMAND_FLAGS autocorrect registry entry

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 14:57:21 -05:00
teernisse
a1bca10408 feat(cli): implement 'lore file-history' command (bd-z94)
Adds file-history command showing which MRs touched a file, with:
- Rename chain resolution via BFS (resolve_rename_chain from bd-1yx)
- DiffNote discussion snippets with --discussions flag
- --merged filter, --no-follow-renames, -n limit
- Human output with styled MR list and rename chain display
- Robot JSON output with {ok, data, meta} envelope
- Autocorrect registry and robot-docs manifest entry
- Fixes pre-existing --no-status missing from sync autocorrect registry
2026-02-17 12:57:56 -05:00
teernisse
491dc52864 release: v0.8.3 2026-02-16 10:29:52 -05:00
teernisse
b9063aa17a feat(cli): add --no-status flag to skip GraphQL status enrichment during sync 2026-02-16 10:29:11 -05:00
teernisse
fc0d9cb1d3 feat(sync): colored stage output, functional sub-rows, and error visibility
Overhaul the sync command's human output to use semantic colors and a
cleaner rendering architecture. The changes fall into four areas:

Stage lines: Replace direct finish_stage() calls with an
emit_stage_line/emit_stage_block pattern that clears the spinner first,
then prints static lines via MultiProgress::suspend. Stage icons are
now color-coded green (success) or yellow (warning) via color_icon().
A separate "Status" stage line now appears after Issues, summarizing
work-item status enrichment across all projects.

Sub-rows: Replace the imperative print_issue_sub_rows/print_mr_sub_rows
functions with functional issue_sub_rows(), mr_sub_rows(), and new
status_sub_rows() that return Vec<String>. Project paths use
Theme::muted(), error/failure counts use Theme::warning(), and
separators use the dim middle-dot style. Sub-rows are printed atomically
with their parent stage line to avoid interleaving with spinners.

Summary: In print_sync(), counts now use Theme::info().bold() for visual
pop, detail-line separators are individually styled (dim middle-dot),
and a new "Sync completed with issues" headline appears when any stage
had failures. Document errors and embedding failures are surfaced in
both the doc-parts line and the errors line.

Tests: Full coverage for append_failures, summarize_status_enrichment,
should_print_timings, issue_sub_rows, mr_sub_rows, and status_sub_rows.
2026-02-16 09:43:36 -05:00
teernisse
c8b47bf8f8 feat(cli): add --timings flag and enrich error tracking fields
Add -t/--timings flag to the sync subcommand, allowing users to opt
into a per-stage timing breakdown after the sync summary. Wire the flag
through main.rs into print_sync() which passes it to the new
should_print_timings() gate.

Enrich the data structures that flow through the sync pipeline so
downstream renderers have full error visibility:

- ProjectSummary gains status_errors (issue-side status enrichment
  failures per project)
- ProjectStatusEnrichment gains path (project path for sub-row display)
- SyncResult gains documents_errored and embedding_failed so the
  summary can surface doc-gen and embed failures separately
- Autocorrect table updated with --timings for fuzzy flag matching
2026-02-16 09:43:22 -05:00
teernisse
a570327a6b refactor(progress): extract format_stage_line with themed styling
Pull the line-formatting logic out of finish_stage() into a standalone
public format_stage_line() so that sync.rs can build stage lines without
needing a live ProgressBar (e.g. for static multi-line blocks printed
after the spinner is cleared).

The new function applies Theme::info().bold() to the label and
Theme::timing() to the elapsed column, giving every stage line
consistent color treatment. finish_stage() now delegates to it.

Includes a unit test asserting the formatted output contains the
expected icon, label, summary, and elapsed components.
2026-02-16 09:43:13 -05:00
teernisse
eef73decb5 fix(cli): timeline tag width, test env isolation, and logging verbosity
Miscellaneous fixes across CLI and core modules:

- Timeline: widen TAG_WIDTH from 10 to 11 to accommodate longer event
  type labels without truncation
- render.rs: save and restore LORE_ICONS env var in glyph_mode test to
  prevent interference from the test environment leaking into or from
  other tests that set LORE_ICONS
- logging.rs: adjust verbose=1 to info level (was debug), verbose=2 to
  debug — this reduces noise at -v while keeping -vv as the full debug
  experience
- issues.rs, merge_requests.rs: use infodebug! macro consistently for
  ingestion summary logging

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 11:25:42 -05:00
teernisse
bb6660178c feat(sync): per-project breakdown, status enrichment progress bars, and summary polish
Add per-project detail rows beneath stage completion lines during multi-project
syncs, showing itemized counts (issues/MRs, discussions, events, statuses, diffs)
for each project. Previously, only aggregate totals were visible, making it hard
to diagnose which project contributed what during a sync.

Status enrichment gets proper progress bars replacing the old spinner-only
display: StatusEnrichmentStarted now carries a total count so the CLI can
render a determinate bar with rate and ETA. The enrichment SQL is tightened
to use IS NOT comparisons for diff-only UPDATEs (skip rows where values
haven't changed), and a follow-up touch_stmt ensures status_synced_at is
updated even for unchanged rows so staleness detection works correctly.

Other improvements:
- New ProjectSummary struct aggregates per-project metrics during ingestion
- SyncResult gains statuses_enriched + per-project summary vectors
- "Already up to date" message when sync finds zero changes
- Remove Arc<AtomicBool> tick_started pattern from docs/embed stages
  (enable_steady_tick is idempotent, the guard was unnecessary)
- Progress bar styling: dim spinner, dark_gray track, per_sec + eta display
- Tick intervals tightened from 100ms to 60ms for smoother animation
- statuses_without_widget calculation uses fetch_result.statuses.len()
  instead of subtracting enriched (more accurate when some statuses lack
  work item widgets)
- Status enrichment completion log downgraded from info to debug

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 11:25:33 -05:00
teernisse
64e73b1cab fix(graphql): handle past HTTP dates in retry-after header gracefully
Extract parse_retry_after_value(header, now) as a pure function to enable
deterministic testing of Retry-After header parsing. The previous
implementation used let-chains with SystemTime::now() inline, which made
it untestable and would panic on negative durations when the server
clock was behind or the header contained a date in the past.

Changes:
- Extract parse_retry_after_value() taking an explicit `now` parameter
- Handle past HTTP dates by returning 1 second instead of panicking on
  negative Duration (date.duration_since(now) returns Err for past dates)
- Trim whitespace from header values before parsing
- Add test for past HTTP date returning 1 second minimum
- Add test for delta-seconds with surrounding whitespace

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 11:25:19 -05:00
teernisse
361757568f refactor(cli): remove deprecated stage_spinner, migrate remaining callers to v2
Phase 7 cleanup: migrate timeline.rs and main.rs search spinner
from stage_spinner() to stage_spinner_v2() with proper icon labels,
then remove the now-unused stage_spinner() function and its tests.

No external callers remain for the old numbered-stage API.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 10:13:06 -05:00
Taylor Eernisse
8572f6cc04 refactor(cli): polish secondary commands with icons, number formatting, and section dividers
Phase 6 of the UX overhaul. Applies consistent visual treatment across
the remaining command outputs: stats, doctor, timeline, who, count,
and drift.

Stats (stats.rs):
- Apply render::format_number() to all numeric values (documents,
  FTS indexed, embedding counts, chunks) for thousand-separator
  formatting in large databases

Doctor (doctor.rs):
- Replace Unicode check/warning/cross symbols with Icons::success(),
  Icons::warning(), Icons::error() for glyph-mode awareness
- Add summary line after checks showing "Ready/Not ready" with counts
  of passed, warnings, and failed checks separated by middle dots
- Remove "lore doctor" title header for cleaner output

Count (count.rs):
- Right-align numeric values with {:>10} format for columnar output
  in count and state breakdown displays

Timeline (timeline.rs):
- Add entity icons (issue/MR) before entity references in event rows
- Refactor format_event_tag to pad plain text before applying style,
  preventing ANSI codes from breaking column alignment
- Extract style_padded() helper for width-then-style pattern

Who (who.rs):
- Add Icons::user() before usernames in expert, workload, reviews,
  and overlap displays
- Replace manual bold section headers with render::section_divider()
  in workload view (Assigned Issues, Authored MRs, Reviewing MRs,
  Unresolved Discussions)

Drift (drift.rs):
- Add Icons::error()/success() before drift detection status line
- Replace '#' bar character with Unicode full block for similarity
  curve visualization

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 10:06:05 -05:00
Taylor Eernisse
d0744039ef refactor(show): polish issue and MR detail views with section dividers and icons
Phase 4 of the UX overhaul. Restructures the show issue and show MR
detail displays with consistent section layout, state icons, and
improved typography.

Issue detail changes:
- Replace bold header + box-drawing underline with indented title using
  Theme::bold() for the title text only
- Organize fields into named sections using render::section_divider():
  Details, Development, Description, Discussions
- Add state icons (Icons::issue_opened/closed) alongside text labels
- Add relative time in parentheses next to Created/Updated dates
- Switch labels from "Labels: (none)" to only showing when present,
  using format_labels_bare for clean comma-separated output
- Move URL and confidential indicator into Details section
- Closing MRs show state-colored icons (merged/opened/closed)
- Discussions use section_divider instead of bold text, remove colons
  from author lines, adjust wrap widths for consistent indentation

MR detail changes:
- Same section-divider layout: Details, Description, Discussions
- State icons for opened/merged/closed using Icons::mr_* helpers
- Draft indicator uses Icons::mr_draft() instead of [Draft] text prefix
- Relative times added to Created, Updated, Merged, Closed dates
- Reviewers and Assignees fields aligned with fixed-width labels
- Labels shown only when present, using format_labels_bare
- Discussion formatting matches issue detail style

Both views use 5-space left indent for field alignment and consistent
wrap widths (72 for descriptions, 68/66 for discussion notes/replies).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 10:06:05 -05:00
Taylor Eernisse
4b372dfb38 refactor(list): polish list commands with icons, compact timestamps, and styled discussions
Phase 3 of the UX overhaul. Enhances the issues, merge requests, and
notes list displays with visual indicators and improved formatting.

List display changes (src/cli/commands/list.rs):
- Add state icons to issues (opened/closed) and merge requests
  (opened/merged/closed) using Icons:: helpers alongside text labels
- Replace [DRAFT] prefix with Icons::mr_draft() glyph for draft MRs
- Switch from format_relative_time to format_relative_time_compact for
  tighter column widths in tabular output
- Switch from format_labels to format_labels_bare for unlabeled style
- Change format_discussions() return type from String to StyledCell so
  unresolved counts render with Theme::warning() color inline
- Bold the section headers ("Issues", "Merge Requests", "Notes")
  with count separated from the label for cleaner scanning
- Import Icons from render module

Test updates (src/cli/commands/list_tests.rs):
- Update format_discussions tests to assert on StyledCell.text field
  instead of raw String, since the function now returns styled output
- The unresolved-count test checks starts_with/contains to handle
  embedded ANSI escape codes from Theme::warning()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 10:06:05 -05:00