fix: ensure authenticated graceful shutdown exits process and sort live activity feed by timestamp descending
This commit is contained in:
1 parent
3efee96230
commit
91d5565141
5 files changed
+46
-22
No files matched your search
@@ -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()
|
||||
},
|
||||
),
|
||||
|
||||
@@ -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
@@ -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
@@ -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())
|
||||
|
||||
Reference in new issue
Block a user