feat(cli): status display/filtering, expanded --fields, and robot-docs --brief
Work item status integration across all CLI output:
Issue listing (lore list issues):
- New Status column appears when any issue has status data, with
hex-color rendering using ANSI 256-color approximation
- New --status flag for case-insensitive filtering (OR logic for
multiple values): lore issues --status "In progress" --status "To do"
- Status fields (name, category, color, icon_name, synced_at) in issue
list query and JSON output with conditional serialization
Issue detail (lore show issue):
- Displays "Status: In progress (in_progress)" with color-coded output
using ANSI 256-color approximation from hex color values
- Status fields included in robot mode JSON with ISO timestamps
- IssueRow, IssueDetail, IssueDetailJson all carry status columns
Robot mode field selection expanded to new commands:
- search: --fields with "minimal" preset (document_id, title, source_type, score)
- timeline: --fields with "minimal" preset (timestamp, type, entity_iid, detail)
- who: --fields with per-mode presets (expert_minimal, workload_minimal, etc.)
- robot-docs: new --brief flag strips response_schema from output (~60% smaller)
- strip_schemas() utility in robot.rs for --brief mode
- expand_fields_preset() extended for search, timeline, and all who modes
Robot-docs manifest updated with --status flag documentation, --fields
flags for search/timeline/who, fields_presets sections, and corrected
search response schema field names.
Note: replaces empty commit dcfd449 which lost staging during hook execution.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
44
src/main.rs
44
src/main.rs
@@ -24,7 +24,7 @@ use lore::cli::commands::{
|
||||
run_init, run_list_issues, run_list_mrs, run_search, run_show_issue, run_show_mr, run_stats,
|
||||
run_sync, run_sync_status, run_timeline, run_who,
|
||||
};
|
||||
use lore::cli::robot::RobotMeta;
|
||||
use lore::cli::robot::{RobotMeta, strip_schemas};
|
||||
use lore::cli::{
|
||||
Cli, Commands, CountArgs, EmbedArgs, GenerateDocsArgs, IngestArgs, IssuesArgs, MrsArgs,
|
||||
SearchArgs, StatsArgs, SyncArgs, TimelineArgs, WhoArgs,
|
||||
@@ -162,7 +162,7 @@ async fn main() {
|
||||
// Phase 2: Handle no-args case - in robot mode, output robot-docs; otherwise show help
|
||||
None => {
|
||||
if robot_mode {
|
||||
handle_robot_docs(robot_mode)
|
||||
handle_robot_docs(robot_mode, false)
|
||||
} else {
|
||||
use clap::CommandFactory;
|
||||
let mut cmd = Cli::command();
|
||||
@@ -224,7 +224,7 @@ async fn main() {
|
||||
Some(Commands::Reset { yes: _ }) => handle_reset(robot_mode),
|
||||
Some(Commands::Migrate) => handle_migrate(cli.config.as_deref(), robot_mode).await,
|
||||
Some(Commands::Health) => handle_health(cli.config.as_deref(), robot_mode).await,
|
||||
Some(Commands::RobotDocs) => handle_robot_docs(robot_mode),
|
||||
Some(Commands::RobotDocs { brief }) => handle_robot_docs(robot_mode, brief),
|
||||
|
||||
Some(Commands::List {
|
||||
entity,
|
||||
@@ -703,6 +703,7 @@ fn handle_issues(
|
||||
since: args.since.as_deref(),
|
||||
due_before: args.due_before.as_deref(),
|
||||
has_due_date: has_due,
|
||||
statuses: &args.status,
|
||||
sort: &args.sort,
|
||||
order,
|
||||
};
|
||||
@@ -1697,6 +1698,7 @@ fn handle_timeline(
|
||||
result.total_events_before_limit,
|
||||
params.depth,
|
||||
params.expand_mentions,
|
||||
args.fields.as_deref(),
|
||||
);
|
||||
} else {
|
||||
print_timeline(&result);
|
||||
@@ -1740,7 +1742,7 @@ async fn handle_search(
|
||||
let elapsed_ms = start.elapsed().as_millis() as u64;
|
||||
|
||||
if robot_mode {
|
||||
print_search_results_json(&response, elapsed_ms);
|
||||
print_search_results_json(&response, elapsed_ms, args.fields.as_deref());
|
||||
} else {
|
||||
print_search_results(&response);
|
||||
}
|
||||
@@ -2038,7 +2040,7 @@ struct RobotDocsActivation {
|
||||
auto: String,
|
||||
}
|
||||
|
||||
fn handle_robot_docs(robot_mode: bool) -> Result<(), Box<dyn std::error::Error>> {
|
||||
fn handle_robot_docs(robot_mode: bool, brief: bool) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let version = env!("CARGO_PKG_VERSION").to_string();
|
||||
|
||||
let commands = serde_json::json!({
|
||||
@@ -2105,7 +2107,7 @@ fn handle_robot_docs(robot_mode: bool) -> Result<(), Box<dyn std::error::Error>>
|
||||
},
|
||||
"issues": {
|
||||
"description": "List or show issues",
|
||||
"flags": ["<IID>", "-n/--limit", "--fields <list>", "-s/--state", "-p/--project", "-a/--author", "-A/--assignee", "-l/--label", "-m/--milestone", "--since", "--due-before", "--has-due", "--no-has-due", "--sort", "--asc", "--no-asc", "-o/--open", "--no-open"],
|
||||
"flags": ["<IID>", "-n/--limit", "--fields <list>", "-s/--state", "--status <name>", "-p/--project", "-a/--author", "-A/--assignee", "-l/--label", "-m/--milestone", "--since", "--due-before", "--has-due", "--no-has-due", "--sort", "--asc", "--no-asc", "-o/--open", "--no-open"],
|
||||
"example": "lore --robot issues --state opened --limit 10",
|
||||
"response_schema": {
|
||||
"list": {
|
||||
@@ -2141,13 +2143,14 @@ fn handle_robot_docs(robot_mode: bool) -> Result<(), Box<dyn std::error::Error>>
|
||||
},
|
||||
"search": {
|
||||
"description": "Search indexed documents (lexical, hybrid, semantic)",
|
||||
"flags": ["<QUERY>", "--mode", "--type", "--author", "-p/--project", "--label", "--path", "--since", "--updated-since", "-n/--limit", "--explain", "--no-explain", "--fts-mode"],
|
||||
"flags": ["<QUERY>", "--mode", "--type", "--author", "-p/--project", "--label", "--path", "--since", "--updated-since", "-n/--limit", "--fields <list>", "--explain", "--no-explain", "--fts-mode"],
|
||||
"example": "lore --robot search 'authentication bug' --mode hybrid --limit 10",
|
||||
"response_schema": {
|
||||
"ok": "bool",
|
||||
"data": {"results": "[{doc_id:int, source_type:string, title:string, snippet:string, score:float, project_path:string, web_url:string?}]", "total_count": "int", "query": "string", "mode": "string"},
|
||||
"data": {"results": "[{document_id:int, source_type:string, title:string, snippet:string, score:float, url:string?, author:string?, created_at:string?, updated_at:string?, project_path:string, labels:[string], paths:[string]}]", "total_results": "int", "query": "string", "mode": "string", "warnings": "[string]"},
|
||||
"meta": {"elapsed_ms": "int"}
|
||||
}
|
||||
},
|
||||
"fields_presets": {"minimal": ["document_id", "title", "source_type", "score"]}
|
||||
},
|
||||
"count": {
|
||||
"description": "Count entities in local database",
|
||||
@@ -2226,17 +2229,18 @@ fn handle_robot_docs(robot_mode: bool) -> Result<(), Box<dyn std::error::Error>>
|
||||
},
|
||||
"timeline": {
|
||||
"description": "Chronological timeline of events matching a keyword query",
|
||||
"flags": ["<QUERY>", "-p/--project", "--since <duration>", "--depth <n>", "--expand-mentions", "-n/--limit", "--max-seeds", "--max-entities", "--max-evidence"],
|
||||
"flags": ["<QUERY>", "-p/--project", "--since <duration>", "--depth <n>", "--expand-mentions", "-n/--limit", "--fields <list>", "--max-seeds", "--max-entities", "--max-evidence"],
|
||||
"example": "lore --robot timeline '<keyword>' --since 30d",
|
||||
"response_schema": {
|
||||
"ok": "bool",
|
||||
"data": {"entities": "[{type:string, iid:int, title:string, project_path:string}]", "events": "[{timestamp:string, type:string, entity_type:string, entity_iid:int, detail:string}]", "total_events": "int"},
|
||||
"meta": {"elapsed_ms": "int"}
|
||||
}
|
||||
},
|
||||
"fields_presets": {"minimal": ["timestamp", "type", "entity_iid", "detail"]}
|
||||
},
|
||||
"who": {
|
||||
"description": "People intelligence: experts, workload, active discussions, overlap, review patterns",
|
||||
"flags": ["<target>", "--path <path>", "--active", "--overlap <path>", "--reviews", "--since <duration>", "-p/--project", "-n/--limit"],
|
||||
"flags": ["<target>", "--path <path>", "--active", "--overlap <path>", "--reviews", "--since <duration>", "-p/--project", "-n/--limit", "--fields <list>"],
|
||||
"modes": {
|
||||
"expert": "lore who <file-path> -- Who knows about this area? (also: --path for root files)",
|
||||
"workload": "lore who <username> -- What is someone working on?",
|
||||
@@ -2254,15 +2258,26 @@ fn handle_robot_docs(robot_mode: bool) -> Result<(), Box<dyn std::error::Error>>
|
||||
"...": "mode-specific fields"
|
||||
},
|
||||
"meta": {"elapsed_ms": "int"}
|
||||
},
|
||||
"fields_presets": {
|
||||
"expert_minimal": ["username", "score"],
|
||||
"workload_minimal": ["entity_type", "iid", "title", "state"],
|
||||
"active_minimal": ["entity_type", "iid", "title", "participants"]
|
||||
}
|
||||
},
|
||||
"robot-docs": {
|
||||
"description": "This command (agent self-discovery manifest)",
|
||||
"flags": [],
|
||||
"example": "lore robot-docs"
|
||||
"flags": ["--brief"],
|
||||
"example": "lore robot-docs --brief"
|
||||
}
|
||||
});
|
||||
|
||||
// --brief: strip response_schema from every command (~60% smaller)
|
||||
let mut commands = commands;
|
||||
if brief {
|
||||
strip_schemas(&mut commands);
|
||||
}
|
||||
|
||||
let exit_codes = serde_json::json!({
|
||||
"0": "Success",
|
||||
"1": "Internal error",
|
||||
@@ -2429,6 +2444,7 @@ async fn handle_list_compat(
|
||||
since: since_filter,
|
||||
due_before: due_before_filter,
|
||||
has_due_date,
|
||||
statuses: &[],
|
||||
sort,
|
||||
order,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user