Compare commits
3 Commits
5c44ee91fb
...
v0.9.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
60075cd400 | ||
|
|
ddab186315 | ||
|
|
d6d1686f8e |
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -1324,7 +1324,7 @@ checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
||||
|
||||
[[package]]
|
||||
name = "lore"
|
||||
version = "0.9.3"
|
||||
version = "0.9.4"
|
||||
dependencies = [
|
||||
"asupersync",
|
||||
"async-stream",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "lore"
|
||||
version = "0.9.3"
|
||||
version = "0.9.4"
|
||||
edition = "2024"
|
||||
description = "Gitlore - Local GitLab data management with semantic search"
|
||||
authors = ["Taylor Eernisse"]
|
||||
|
||||
@@ -361,7 +361,7 @@ fn print_combined_ingest_json(
|
||||
notes_upserted: mrs.notes_upserted,
|
||||
},
|
||||
},
|
||||
meta: RobotMeta { elapsed_ms },
|
||||
meta: RobotMeta::new(elapsed_ms),
|
||||
};
|
||||
|
||||
println!(
|
||||
@@ -975,9 +975,7 @@ async fn handle_auth_test(
|
||||
name: result.name.clone(),
|
||||
gitlab_url: result.base_url.clone(),
|
||||
},
|
||||
meta: RobotMeta {
|
||||
elapsed_ms: start.elapsed().as_millis() as u64,
|
||||
},
|
||||
meta: RobotMeta::new(start.elapsed().as_millis() as u64),
|
||||
};
|
||||
println!("{}", serde_json::to_string(&output)?);
|
||||
} else {
|
||||
@@ -1038,9 +1036,7 @@ async fn handle_doctor(
|
||||
success: result.success,
|
||||
checks: result.checks,
|
||||
},
|
||||
meta: RobotMeta {
|
||||
elapsed_ms: start.elapsed().as_millis() as u64,
|
||||
},
|
||||
meta: RobotMeta::new(start.elapsed().as_millis() as u64),
|
||||
};
|
||||
println!("{}", serde_json::to_string(&output)?);
|
||||
} else {
|
||||
@@ -1085,9 +1081,7 @@ fn handle_version(robot_mode: bool) -> Result<(), Box<dyn std::error::Error>> {
|
||||
Some(git_hash)
|
||||
},
|
||||
},
|
||||
meta: RobotMeta {
|
||||
elapsed_ms: start.elapsed().as_millis() as u64,
|
||||
},
|
||||
meta: RobotMeta::new(start.elapsed().as_millis() as u64),
|
||||
};
|
||||
println!("{}", serde_json::to_string(&output)?);
|
||||
} else if git_hash.is_empty() {
|
||||
@@ -1245,9 +1239,7 @@ async fn handle_migrate(
|
||||
after_version,
|
||||
migrated: after_version > before_version,
|
||||
},
|
||||
meta: RobotMeta {
|
||||
elapsed_ms: start.elapsed().as_millis() as u64,
|
||||
},
|
||||
meta: RobotMeta::new(start.elapsed().as_millis() as u64),
|
||||
};
|
||||
println!("{}", serde_json::to_string(&output)?);
|
||||
} else if after_version > before_version {
|
||||
@@ -1962,9 +1954,7 @@ async fn handle_health(
|
||||
schema_version,
|
||||
actions,
|
||||
},
|
||||
meta: RobotMeta {
|
||||
elapsed_ms: start.elapsed().as_millis() as u64,
|
||||
},
|
||||
meta: RobotMeta::new(start.elapsed().as_millis() as u64),
|
||||
};
|
||||
println!("{}", serde_json::to_string(&output)?);
|
||||
} else {
|
||||
|
||||
@@ -382,7 +382,7 @@ fn handle_robot_docs(robot_mode: bool, brief: bool) -> Result<(), Box<dyn std::e
|
||||
"mentioned_in": "[{entity_type:string, project:string, iid:int, title:string, state:string, attention_state:string, attention_reason:string, updated_at_iso:string, web_url:string?}]",
|
||||
"activity": "[{timestamp_iso:string, event_type:string, entity_type:string, entity_iid:int, project:string, actor:string?, is_own:bool, summary:string, body_preview:string?}]"
|
||||
},
|
||||
"meta": {"elapsed_ms": "int"}
|
||||
"meta": {"elapsed_ms": "int", "gitlab_base_url": "string (GitLab instance URL for constructing entity links: {base_url}/{project}/-/issues/{iid})"}
|
||||
},
|
||||
"fields_presets": {
|
||||
"me_items_minimal": ["iid", "title", "attention_state", "attention_reason", "updated_at_iso"],
|
||||
@@ -396,7 +396,8 @@ fn handle_robot_docs(robot_mode: bool, brief: bool) -> Result<(), Box<dyn std::e
|
||||
"since_default": "1d for activity feed",
|
||||
"issue_filter": "Only In Progress / In Review status issues shown",
|
||||
"since_last_check": "Cursor-based inbox showing events since last run. Null on first run (no cursor yet). Groups events by entity (issue/MR). Sources: others' comments on your items, @mentions, assignment/review-request notes. Cursor auto-advances after each run. Use --reset-cursor to clear.",
|
||||
"cursor_persistence": "Stored per user in ~/.local/share/lore/me_cursor_<username>.json. --project filters display only for since-last-check; cursor still advances for all projects for that user."
|
||||
"cursor_persistence": "Stored per user in ~/.local/share/lore/me_cursor_<username>.json. --project filters display only for since-last-check; cursor still advances for all projects for that user.",
|
||||
"url_construction": "Use meta.gitlab_base_url + project + entity_type + iid to build links: {gitlab_base_url}/{project}/-/{issues|merge_requests}/{iid}"
|
||||
}
|
||||
},
|
||||
"robot-docs": {
|
||||
|
||||
@@ -254,7 +254,7 @@ pub fn print_event_count_json(counts: &EventCounts, elapsed_ms: u64) {
|
||||
},
|
||||
total: counts.total(),
|
||||
},
|
||||
meta: RobotMeta { elapsed_ms },
|
||||
meta: RobotMeta::new(elapsed_ms),
|
||||
};
|
||||
|
||||
match serde_json::to_string(&output) {
|
||||
@@ -325,7 +325,7 @@ pub fn print_count_json(result: &CountResult, elapsed_ms: u64) {
|
||||
system_excluded: result.system_count,
|
||||
breakdown,
|
||||
},
|
||||
meta: RobotMeta { elapsed_ms },
|
||||
meta: RobotMeta::new(elapsed_ms),
|
||||
};
|
||||
|
||||
match serde_json::to_string(&output) {
|
||||
|
||||
@@ -80,7 +80,7 @@ pub fn print_cron_install_json(result: &CronInstallResult, elapsed_ms: u64) {
|
||||
log_path: result.log_path.display().to_string(),
|
||||
replaced: result.replaced,
|
||||
},
|
||||
meta: RobotMeta { elapsed_ms },
|
||||
meta: RobotMeta::new(elapsed_ms),
|
||||
};
|
||||
if let Ok(json) = serde_json::to_string(&output) {
|
||||
println!("{json}");
|
||||
@@ -128,7 +128,7 @@ pub fn print_cron_uninstall_json(result: &CronUninstallResult, elapsed_ms: u64)
|
||||
action: "uninstall",
|
||||
was_installed: result.was_installed,
|
||||
},
|
||||
meta: RobotMeta { elapsed_ms },
|
||||
meta: RobotMeta::new(elapsed_ms),
|
||||
};
|
||||
if let Ok(json) = serde_json::to_string(&output) {
|
||||
println!("{json}");
|
||||
@@ -284,7 +284,7 @@ pub fn print_cron_status_json(info: &CronStatusInfo, elapsed_ms: u64) {
|
||||
last_sync_at: info.last_sync.as_ref().map(|s| s.started_at_iso.clone()),
|
||||
last_sync_status: info.last_sync.as_ref().map(|s| s.status.clone()),
|
||||
},
|
||||
meta: RobotMeta { elapsed_ms },
|
||||
meta: RobotMeta::new(elapsed_ms),
|
||||
};
|
||||
if let Ok(json) = serde_json::to_string(&output) {
|
||||
println!("{json}");
|
||||
|
||||
@@ -468,7 +468,7 @@ pub fn print_drift_human(response: &DriftResponse) {
|
||||
}
|
||||
|
||||
pub fn print_drift_json(response: &DriftResponse, elapsed_ms: u64) {
|
||||
let meta = RobotMeta { elapsed_ms };
|
||||
let meta = RobotMeta::new(elapsed_ms);
|
||||
let output = serde_json::json!({
|
||||
"ok": true,
|
||||
"data": response,
|
||||
|
||||
@@ -135,7 +135,7 @@ pub fn print_embed_json(result: &EmbedCommandResult, elapsed_ms: u64) {
|
||||
let output = EmbedJsonOutput {
|
||||
ok: true,
|
||||
data: result,
|
||||
meta: RobotMeta { elapsed_ms },
|
||||
meta: RobotMeta::new(elapsed_ms),
|
||||
};
|
||||
match serde_json::to_string(&output) {
|
||||
Ok(json) => println!("{json}"),
|
||||
|
||||
@@ -257,7 +257,7 @@ pub fn print_generate_docs_json(result: &GenerateDocsResult, elapsed_ms: u64) {
|
||||
unchanged: result.unchanged,
|
||||
errored: result.errored,
|
||||
},
|
||||
meta: RobotMeta { elapsed_ms },
|
||||
meta: RobotMeta::new(elapsed_ms),
|
||||
};
|
||||
match serde_json::to_string(&output) {
|
||||
Ok(json) => println!("{json}"),
|
||||
|
||||
@@ -191,7 +191,7 @@ pub fn print_ingest_summary_json(result: &IngestResult, elapsed_ms: u64) {
|
||||
status_enrichment,
|
||||
status_enrichment_errors: result.status_enrichment_errors,
|
||||
},
|
||||
meta: RobotMeta { elapsed_ms },
|
||||
meta: RobotMeta::new(elapsed_ms),
|
||||
};
|
||||
|
||||
match serde_json::to_string(&output) {
|
||||
|
||||
@@ -370,7 +370,7 @@ pub fn print_list_mrs(result: &MrListResult) {
|
||||
|
||||
pub fn print_list_mrs_json(result: &MrListResult, elapsed_ms: u64, fields: Option<&[String]>) {
|
||||
let json_result = MrListResultJson::from(result);
|
||||
let meta = RobotMeta { elapsed_ms };
|
||||
let meta = RobotMeta::new(elapsed_ms);
|
||||
let output = serde_json::json!({
|
||||
"ok": true,
|
||||
"data": json_result,
|
||||
|
||||
@@ -193,7 +193,7 @@ pub fn print_list_notes(result: &NoteListResult) {
|
||||
|
||||
pub fn print_list_notes_json(result: &NoteListResult, elapsed_ms: u64, fields: Option<&[String]>) {
|
||||
let json_result = NoteListResultJson::from(result);
|
||||
let meta = RobotMeta { elapsed_ms };
|
||||
let meta = RobotMeta::new(elapsed_ms);
|
||||
let output = serde_json::json!({
|
||||
"ok": true,
|
||||
"data": json_result,
|
||||
|
||||
@@ -247,7 +247,7 @@ pub fn run_me(config: &Config, args: &MeArgs, robot_mode: bool) -> Result<()> {
|
||||
|
||||
if robot_mode {
|
||||
let fields = args.fields.as_deref();
|
||||
render_robot::print_me_json(&dashboard, elapsed_ms, fields)?;
|
||||
render_robot::print_me_json(&dashboard, elapsed_ms, fields, &config.gitlab.base_url)?;
|
||||
} else if show_all {
|
||||
render_human::print_me_dashboard(&dashboard, single_project);
|
||||
} else {
|
||||
|
||||
@@ -15,11 +15,12 @@ pub fn print_me_json(
|
||||
dashboard: &MeDashboard,
|
||||
elapsed_ms: u64,
|
||||
fields: Option<&[String]>,
|
||||
gitlab_base_url: &str,
|
||||
) -> crate::core::error::Result<()> {
|
||||
let envelope = MeJsonEnvelope {
|
||||
ok: true,
|
||||
data: MeDataJson::from_dashboard(dashboard),
|
||||
meta: RobotMeta { elapsed_ms },
|
||||
meta: RobotMeta::with_base_url(elapsed_ms, gitlab_base_url),
|
||||
};
|
||||
|
||||
let mut value = serde_json::to_value(&envelope)
|
||||
|
||||
@@ -558,7 +558,7 @@ pub fn print_related_human(response: &RelatedResponse) {
|
||||
}
|
||||
|
||||
pub fn print_related_json(response: &RelatedResponse, elapsed_ms: u64) {
|
||||
let meta = RobotMeta { elapsed_ms };
|
||||
let meta = RobotMeta::new(elapsed_ms);
|
||||
let output = serde_json::json!({
|
||||
"ok": true,
|
||||
"data": response,
|
||||
|
||||
@@ -557,7 +557,7 @@ impl From<&MrNoteDetail> for MrNoteDetailJson {
|
||||
|
||||
pub fn print_show_issue_json(issue: &IssueDetail, elapsed_ms: u64) {
|
||||
let json_result = IssueDetailJson::from(issue);
|
||||
let meta = RobotMeta { elapsed_ms };
|
||||
let meta = RobotMeta::new(elapsed_ms);
|
||||
let output = serde_json::json!({
|
||||
"ok": true,
|
||||
"data": json_result,
|
||||
@@ -571,7 +571,7 @@ pub fn print_show_issue_json(issue: &IssueDetail, elapsed_ms: u64) {
|
||||
|
||||
pub fn print_show_mr_json(mr: &MrDetail, elapsed_ms: u64) {
|
||||
let json_result = MrDetailJson::from(mr);
|
||||
let meta = RobotMeta { elapsed_ms };
|
||||
let meta = RobotMeta::new(elapsed_ms);
|
||||
let output = serde_json::json!({
|
||||
"ok": true,
|
||||
"data": json_result,
|
||||
|
||||
@@ -583,7 +583,7 @@ pub fn print_stats_json(result: &StatsResult, elapsed_ms: u64) {
|
||||
}),
|
||||
}),
|
||||
},
|
||||
meta: RobotMeta { elapsed_ms },
|
||||
meta: RobotMeta::new(elapsed_ms),
|
||||
};
|
||||
match serde_json::to_string(&output) {
|
||||
Ok(json) => println!("{json}"),
|
||||
|
||||
@@ -313,7 +313,7 @@ pub fn print_sync_status_json(result: &SyncStatusResult, elapsed_ms: u64) {
|
||||
system_notes: result.summary.system_note_count,
|
||||
},
|
||||
},
|
||||
meta: RobotMeta { elapsed_ms },
|
||||
meta: RobotMeta::new(elapsed_ms),
|
||||
};
|
||||
|
||||
match serde_json::to_string(&output) {
|
||||
|
||||
@@ -376,7 +376,7 @@ pub fn print_who_json(run: &WhoRun, args: &WhoArgs, elapsed_ms: u64) {
|
||||
resolved_input,
|
||||
result: data,
|
||||
},
|
||||
meta: RobotMeta { elapsed_ms },
|
||||
meta: RobotMeta::new(elapsed_ms),
|
||||
};
|
||||
|
||||
let mut value = serde_json::to_value(&output).unwrap_or_else(|e| {
|
||||
|
||||
@@ -3,6 +3,26 @@ use serde::Serialize;
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct RobotMeta {
|
||||
pub elapsed_ms: u64,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub gitlab_base_url: Option<String>,
|
||||
}
|
||||
|
||||
impl RobotMeta {
|
||||
/// Standard meta with timing only.
|
||||
pub fn new(elapsed_ms: u64) -> Self {
|
||||
Self {
|
||||
elapsed_ms,
|
||||
gitlab_base_url: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Meta with GitLab base URL for URL construction by consumers.
|
||||
pub fn with_base_url(elapsed_ms: u64, base_url: &str) -> Self {
|
||||
Self {
|
||||
elapsed_ms,
|
||||
gitlab_base_url: Some(base_url.trim_end_matches('/').to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Filter JSON object fields in-place for `--fields` support.
|
||||
@@ -133,4 +153,27 @@ mod tests {
|
||||
let expanded = expand_fields_preset(&fields, "notes");
|
||||
assert_eq!(expanded, ["id", "body"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn meta_new_omits_base_url() {
|
||||
let meta = RobotMeta::new(42);
|
||||
let json = serde_json::to_value(&meta).unwrap();
|
||||
assert_eq!(json["elapsed_ms"], 42);
|
||||
assert!(json.get("gitlab_base_url").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn meta_with_base_url_includes_it() {
|
||||
let meta = RobotMeta::with_base_url(99, "https://gitlab.example.com");
|
||||
let json = serde_json::to_value(&meta).unwrap();
|
||||
assert_eq!(json["elapsed_ms"], 99);
|
||||
assert_eq!(json["gitlab_base_url"], "https://gitlab.example.com");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn meta_with_base_url_strips_trailing_slash() {
|
||||
let meta = RobotMeta::with_base_url(0, "https://gitlab.example.com/");
|
||||
let json = serde_json::to_value(&meta).unwrap();
|
||||
assert_eq!(json["gitlab_base_url"], "https://gitlab.example.com");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user