Introduce a centralized token resolution system that supports both
environment variables and config-file-stored tokens with clear priority
(env var wins). This enables cron-based sync which runs in minimal
shell environments without env vars.
Core changes:
- GitLabConfig gains optional `token` field and `resolve_token()` method
that checks env var first, then config file, returning trimmed values
- `token_source()` returns human-readable provenance ("environment variable"
or "config file") for diagnostics
- `ensure_config_permissions()` enforces 0600 on config files containing
tokens (Unix only, no-op on other platforms)
New CLI commands:
- `lore token set [--token VALUE]` — validates against GitLab API, stores
in config, enforces file permissions. Supports flag, stdin pipe, or
interactive entry.
- `lore token show [--unmask]` — displays masked token with source label
Consumers updated to use resolve_token():
- auth_test: removes manual env var lookup
- doctor: shows token source in health check output
- ingest: uses centralized resolution
Includes 10 unit tests for resolve/source logic and 2 for mask_token.
Remove print_list_notes_csv, print_list_notes_jsonl, and csv_escape from
the notes list command. The --format flag's csv and jsonl variants added
complexity without meaningful adoption — robot mode already provides
structured JSON output. Notes now have two output paths: human (default)
and JSON (--robot).
Also removes the corresponding test coverage (csv_escape, csv_output).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
Replace all console::style() calls in command modules with the centralized
Theme API and render:: utility functions. This ensures consistent color
behavior across the entire CLI, proper NO_COLOR/--color never support via
the LoreRenderer singleton, and eliminates duplicated formatting code.
Changes per module:
- count.rs: Theme for table headers, render::format_number replacing local
duplicate. Removed local format_number implementation.
- doctor.rs: Theme::success/warning/error for check status symbols and
messages. Unicode escapes for check/warning/cross symbols.
- drift.rs: Theme::bold/error/success for drift detection headers and
status messages.
- embed.rs: Compact output format — headline with count, zero-suppressed
detail lines, 'nothing to embed' short-circuit for no-op runs.
- generate_docs.rs: Same compact pattern — headline + detail + hint for
next step. No-op short-circuit when regenerated==0.
- ingest.rs: Theme for project summaries, sync status, dry-run preview.
All console::style -> Theme replacements.
- list.rs: Replace comfy-table with render::LoreTable for issue/MR listing.
Remove local colored_cell, colored_cell_hex, format_relative_time,
truncate_with_ellipsis, and format_labels (all moved to render.rs).
- list_tests.rs: Update test assertions to use render:: functions.
- search.rs: Add render_snippet() for FTS5 <mark> tag highlighting via
Theme::bold().underline(). Compact result layout with type badges.
- show.rs: Theme for entity detail views, delegate format_date and
wrap_text to render module.
- stats.rs: Section-based layout using render::section_divider. Compact
middle-dot format for document counts. Color-coded embedding coverage
percentage (green >=95%, yellow >=50%, red <50%).
- sync.rs: Compact sync summary — headline with counts and elapsed time,
zero-suppressed detail lines, visually prominent error-only section.
- sync_status.rs: Theme for run history headers, removed local
format_number duplicate.
- timeline.rs: Theme for headers/footers, render:: for date/truncate,
standard format! padding replacing console::pad_str.
- who.rs: Theme for all expert/workload/active/overlap/review output
modes, render:: for relative time and truncation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move inline #[cfg(test)] mod tests { ... } blocks from 22 source files
into dedicated _tests.rs companion files, wired via:
#[cfg(test)]
#[path = "module_tests.rs"]
mod tests;
This keeps implementation-focused source files leaner and more scannable
while preserving full access to private items through `use super::*;`.
Modules extracted:
core: db, note_parser, payloads, project, references, sync_run,
timeline_collect, timeline_expand, timeline_seed
cli: list (55 tests), who (75 tests)
documents: extractor (43 tests), regenerator
embedding: change_detector, chunking
gitlab: graphql (wiremock async tests), transformers/issue
ingestion: dirty_tracker, discussions, issues, mr_diffs
Also adds conflicts_with("explain_score") to the --detail flag in the
who command to prevent mutually exclusive flags from being combined.
All 629 unit tests pass. No behavior changes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>