diff --git a/justfile b/justfile index 7ac4b33..d2582d2 100644 --- a/justfile +++ b/justfile @@ -35,7 +35,7 @@ deploy-win: deploy-server deploy-stub-win deploy-nvim-win deploy-rules-win # Stop the background server stop port="3000": @Write-Host "Shutting down MCP server gracefully on port {{port}}..." -ForegroundColor Cyan - -& { $token = Get-Content "$env:USERPROFILE\.gemini\mcp_memory\admin.token" -ErrorAction SilentlyContinue; if ($token) { $hdr = @{ Authorization = "Bearer $($token.Trim())" }; Invoke-RestMethod -Uri "http://127.0.0.1:{{port}}/shutdown" -Method Post -Headers $hdr -ErrorAction SilentlyContinue } else { Invoke-RestMethod -Uri "http://127.0.0.1:{{port}}/shutdown" -Method Post -ErrorAction SilentlyContinue }; $stopped = $false; for ($i = 1; $i -le 10; $i++) { $conn = Get-NetTCPConnection -LocalPort {{port}} -State Listen -ErrorAction SilentlyContinue; $proc = Get-Process mcp-memory-server -ErrorAction SilentlyContinue; if (-not $conn -and -not $proc) { $stopped = $true; Write-Host '✅ Server process and port {{port}} fully terminated.' -ForegroundColor Green; break }; Start-Sleep -Seconds 1 }; if (-not $stopped) { Write-Host '⚠️ Server process did not exit within 10s. Force killing process...' -ForegroundColor Yellow; Get-Process mcp-memory-server -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue; Get-NetTCPConnection -LocalPort {{port}} -State Listen -ErrorAction SilentlyContinue | Select-Object -ExpandProperty OwningProcess | ForEach-Object { Stop-Process -Id $_ -Force -ErrorAction SilentlyContinue }; Start-Sleep -Seconds 2 } } + -& { $token = Get-Content "$env:USERPROFILE\.gemini\mcp_memory\admin.token" -ErrorAction SilentlyContinue; if ($token) { $hdr = @{ Authorization = "Bearer $($token.Trim())" }; $res = Invoke-RestMethod -Uri "http://127.0.0.1:{{port}}/shutdown" -Method Post -Headers $hdr -ErrorAction SilentlyContinue } else { $res = Invoke-RestMethod -Uri "http://127.0.0.1:{{port}}/shutdown" -Method Post -ErrorAction SilentlyContinue }; if ($res) { Write-Host "✅ Shutdown acknowledged with version details:" -ForegroundColor Green; $res | ConvertTo-Json -Depth 5 }; $stopped = $false; for ($i = 1; $i -le 10; $i++) { $conn = Get-NetTCPConnection -LocalPort {{port}} -State Listen -ErrorAction SilentlyContinue; $proc = Get-Process mcp-memory-server -ErrorAction SilentlyContinue; if (-not $conn -and -not $proc) { $stopped = $true; Write-Host '✅ Server process and port {{port}} fully terminated.' -ForegroundColor Green; break }; Start-Sleep -Seconds 1 }; if (-not $stopped) { Write-Host '⚠️ Server process did not exit within 10s. Force killing process...' -ForegroundColor Yellow; Get-Process mcp-memory-server -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue; Get-NetTCPConnection -LocalPort {{port}} -State Listen -ErrorAction SilentlyContinue | Select-Object -ExpandProperty OwningProcess | ForEach-Object { Stop-Process -Id $_ -Force -ErrorAction SilentlyContinue }; Start-Sleep -Seconds 2 } } @Write-Host "✅ Shutdown complete. Port {{port}} and process are free." -ForegroundColor Green # Start the server in the background (nohup equivalent) diff --git a/server/src/api/rest.rs b/server/src/api/rest.rs index add5414..15c0615 100644 --- a/server/src/api/rest.rs +++ b/server/src/api/rest.rs @@ -104,8 +104,16 @@ pub async fn gate_set_handler( Ok((axum::http::StatusCode::OK, "Gate state updated.")) } -pub async fn health_handler() -> &'static str { - "OK" +pub async fn health_handler() -> impl IntoResponse { + axum::Json(serde_json::json!({ + "status": "ok", + "version": { + "app_version": env!("APP_VERSION"), + "cargo_pkg_version": env!("CARGO_PKG_VERSION"), + "target_os": std::env::consts::OS, + "target_arch": std::env::consts::ARCH, + } + })) } #[cfg(test)] diff --git a/server/src/api/setup.rs b/server/src/api/setup.rs index d1ddf7a..3c81f7f 100644 --- a/server/src/api/setup.rs +++ b/server/src/api/setup.rs @@ -143,7 +143,17 @@ pub fn create_router(app_state: Arc) -> Router { std::process::exit(0); }); - (axum::http::StatusCode::OK, "Shutting down...").into_response() + axum::Json(serde_json::json!({ + "status": "shutting_down", + "message": "MCP Memory Server gracefully shutting down.", + "version_details": { + "app_version": env!("APP_VERSION"), + "cargo_pkg_version": env!("CARGO_PKG_VERSION"), + "target_os": std::env::consts::OS, + "target_arch": std::env::consts::ARCH, + "shutdown_checkpoint": format!("chk_shutdown_{}", now) + } + })).into_response() }, ), ) diff --git a/server/src/dashboard.html b/server/src/dashboard.html index f92a524..18f3f7c 100644 --- a/server/src/dashboard.html +++ b/server/src/dashboard.html @@ -1142,12 +1142,18 @@ if (!feed) return; feed.innerHTML = ''; - // 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; - }); + // Helper to normalize timestamp to epoch milliseconds + const getMillis = (item) => { + if (!item || typeof item !== 'object') return 0; + let val = item.timestamp || item.time || item.updated_at || 0; + if (typeof val === 'number' && val < 10000000000) { + val = val * 1000; + } + return val; + }; + + // Sort history by normalized timestamp descending so newest entries are always at top + const sorted = [...history].sort((a, b) => getMillis(b) - getMillis(a)); sorted.forEach(item => { const div = document.createElement('div'); @@ -1396,7 +1402,7 @@ const data = await res.json(); const verEl = document.getElementById('app-version'); if (verEl) { - verEl.textContent = `v${data.version}`; + verEl.innerHTML = `v${data.version}`; } } catch (err) { console.error("Failed to load version", err);