refactor(commands): Add IngestDisplay, resolve_project, and color-aware tables

Ingest:
- Introduce IngestDisplay struct with show_progress/show_text booleans
  to decouple progress bars from text output. Replaces the robot_mode
  bool parameter with explicit display control, enabling sync to show
  progress without duplicating summary text (progress_only mode).
- Use resolve_project() for --project filtering instead of LIKE queries,
  providing proper error messages for ambiguous or missing projects.

List:
- Add colored_cell() helper that checks console::colors_enabled() before
  applying comfy-table foreground colors, bridging the gap between the
  console and comfy-table crates for --color flag support.
- Use resolve_project() for project filtering (exact ID match).
- Improve since filter to return explicit errors instead of silently
  ignoring invalid values.
- Improve format_relative_time for proper singular/plural forms.

Search:
- Validate --after/--updated-after with explicit error messages.
- Handle optional title field (Option<String>) in HydratedRow.

Show:
- Use resolve_project() for project disambiguation.

Sync:
- Thread robot_mode via SyncOptions for IngestDisplay selection.
- Use IngestDisplay::progress_only() in interactive sync mode.

GenerateDocs:
- Use resolve_project() for --project filtering.

Co-Authored-By: Claude (us.anthropic.claude-opus-4-5-20251101-v1:0) <noreply@anthropic.com>
This commit is contained in:
Taylor Eernisse
2026-01-30 16:54:36 -05:00
parent 585b746461
commit 667f70e177
7 changed files with 207 additions and 104 deletions

View File

@@ -104,8 +104,30 @@ pub fn run_search(
.map(|p| resolve_project(&conn, p))
.transpose()?;
let after = cli_filters.after.as_deref().and_then(parse_since);
let updated_after = cli_filters.updated_after.as_deref().and_then(parse_since);
let after = cli_filters
.after
.as_deref()
.map(|s| {
parse_since(s).ok_or_else(|| {
LoreError::Other(format!(
"Invalid --after value '{}'. Use relative (7d, 2w, 1m) or absolute (YYYY-MM-DD) format.",
s
))
})
})
.transpose()?;
let updated_after = cli_filters
.updated_after
.as_deref()
.map(|s| {
parse_since(s).ok_or_else(|| {
LoreError::Other(format!(
"Invalid --updated-after value '{}'. Use relative (7d, 2w, 1m) or absolute (YYYY-MM-DD) format.",
s
))
})
})
.transpose()?;
let path = cli_filters.path.as_deref().map(|p| {
if p.ends_with('/') {
@@ -192,7 +214,7 @@ pub fn run_search(
results.push(SearchResultDisplay {
document_id: row.document_id,
source_type: row.source_type.clone(),
title: row.title.clone(),
title: row.title.clone().unwrap_or_default(),
url: row.url.clone(),
author: row.author.clone(),
created_at: row.created_at.map(ms_to_iso),
@@ -219,7 +241,7 @@ pub fn run_search(
struct HydratedRow {
document_id: i64,
source_type: String,
title: String,
title: Option<String>,
url: Option<String>,
author: Option<String>,
created_at: Option<i64>,