fix: ensure authenticated graceful shutdown exits process and sort live activity feed by timestamp descending

This commit is contained in:
Riz Ashraf committed 2026-10-04 02:55:56 +01:00
1 parent 3efee96230
commit 91d5565141
5 files changed
+46 -22

No files matched your search

+6
View File
@@ -137,6 +137,12 @@ pub fn create_router(app_state: Arc<AppState>) -> Router {
if let Some(tx) = state.shutdown_tx.lock().unwrap().take() {
let _ = tx.send(());
}
tokio::spawn(async move {
tokio::time::sleep(std::time::Duration::from_millis(200)).await;
std::process::exit(0);
});
(axum::http::StatusCode::OK, "Shutting down...").into_response()
},
),
+10 -2
View File
@@ -1141,13 +1141,21 @@
const feed = document.getElementById('activity-feed');
if (!feed) return;
feed.innerHTML = '';
[...history].reverse().forEach(item => {
// Sort history by timestamp descending so newest entries are at top
const sorted = [...history].sort((a, b) => {
const tA = (typeof a === 'object' && a) ? (a.timestamp || a.time || 0) : 0;
const tB = (typeof b === 'object' && b) ? (b.timestamp || b.time || 0) : 0;
return tB - tA;
});
sorted.forEach(item => {
const div = document.createElement('div');
div.className = 'feed-entry';
div.innerHTML = parseActivityPayload(item);
feed.appendChild(div);
});
if (history.length > 0) {
if (sorted.length > 0) {
feed.scrollTop = 0;
}
} catch(e) {
+3 -1
View File
@@ -392,7 +392,9 @@ pub async fn run_server(state: Arc<MemoryState>) -> Result<(), Box<dyn std::erro
.join(".gemini/mcp_memory/daemon_error.log");
let _ = tokio::fs::write(&log_path, format!("Server crashed: {}\n", e)).await;
}
Ok(())
tracing::info!("axum::serve graceful shutdown complete. Terminating process cleanly.");
std::process::exit(0);
}
pub fn init_logging(app_name: &str) -> Option<tracing_appender::non_blocking::WorkerGuard> {
+23 -13
View File
@@ -822,19 +822,26 @@ impl MemoryHandler {
pub fn format_tool_activity_description(name: &str, args: &serde_json::Value) -> String {
let detail = match name {
"log_code_change" => {
if let Some(file) = args.get("file").or_else(|| args.get("path")).and_then(|v| v.as_str()) {
if let Some(summary) = args.get("summary").and_then(|v| v.as_str()) {
format!("{}: {}", file, summary)
} else {
file.to_string()
}
} else {
args.get("summary").and_then(|v| v.as_str()).unwrap_or("").to_string()
let file = args.get("file_path")
.or_else(|| args.get("file"))
.or_else(|| args.get("path"))
.or_else(|| args.get("target_file"))
.and_then(|v| v.as_str());
let summary = args.get("summary")
.or_else(|| args.get("description"))
.and_then(|v| v.as_str());
match (file, summary) {
(Some(f), Some(s)) => format!("{}: {}", f, s),
(Some(f), None) => f.to_string(),
(None, Some(s)) => s.to_string(),
(None, None) => "".to_string(),
}
}
"log_decision" => {
args.get("title")
.or_else(|| args.get("decision"))
.or_else(|| args.get("summary"))
.and_then(|v| v.as_str())
.unwrap_or("")
.to_string()
@@ -842,14 +849,15 @@ pub fn format_tool_activity_description(name: &str, args: &serde_json::Value) ->
"log_error_fix" => {
args.get("error")
.or_else(|| args.get("summary"))
.or_else(|| args.get("solution"))
.and_then(|v| v.as_str())
.unwrap_or("")
.to_string()
}
"log_tech_debt" => {
if let Some(summary) = args.get("summary").and_then(|v| v.as_str()) {
if let Some(summary) = args.get("summary").or_else(|| args.get("description")).and_then(|v| v.as_str()) {
summary.to_string()
} else if let Some(file) = args.get("file").and_then(|v| v.as_str()) {
} else if let Some(file) = args.get("file_path").or_else(|| args.get("file")).and_then(|v| v.as_str()) {
file.to_string()
} else {
"".to_string()
@@ -859,7 +867,7 @@ pub fn format_tool_activity_description(name: &str, args: &serde_json::Value) ->
if let Some(entities) = args.get("entities").and_then(|v| v.as_array()) {
let names: Vec<&str> = entities
.iter()
.filter_map(|e| e.get("name").and_then(|n| n.as_str()))
.filter_map(|e| e.get("name").or_else(|| e.get("entity_name")).and_then(|n| n.as_str()))
.take(3)
.collect();
if !names.is_empty() {
@@ -871,7 +879,7 @@ pub fn format_tool_activity_description(name: &str, args: &serde_json::Value) ->
} else {
format!("{} entity/entities", entities.len())
}
} else if let Some(name) = args.get("name").and_then(|v| v.as_str()) {
} else if let Some(name) = args.get("name").or_else(|| args.get("entity_name")).and_then(|v| v.as_str()) {
name.to_string()
} else {
"".to_string()
@@ -882,7 +890,7 @@ pub fn format_tool_activity_description(name: &str, args: &serde_json::Value) ->
if let Some(first) = relations.first() {
let from = first.get("from").and_then(|v| v.as_str()).unwrap_or("?");
let to = first.get("to").and_then(|v| v.as_str()).unwrap_or("?");
let pred = first.get("predicate").and_then(|v| v.as_str()).unwrap_or("->");
let pred = first.get("relation_type").or_else(|| first.get("predicate")).and_then(|v| v.as_str()).unwrap_or("->");
if relations.len() > 1 {
format!("{} {} {} (+{} more)", from, pred, to, relations.len() - 1)
} else {
@@ -943,8 +951,10 @@ pub fn format_tool_activity_description(name: &str, args: &serde_json::Value) ->
if let Some(title) = args
.get("title")
.or_else(|| args.get("summary"))
.or_else(|| args.get("description"))
.or_else(|| args.get("name"))
.or_else(|| args.get("query"))
.or_else(|| args.get("file_path"))
.or_else(|| args.get("file"))
.or_else(|| args.get("path"))
.and_then(|v| v.as_str())