diff --git a/Cargo.lock b/Cargo.lock index fd6afc0..dc36836 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -520,6 +520,15 @@ dependencies = [ "dirs-sys", ] +[[package]] +name = "dirs" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d57d423b3c82e89b9a24ca3091fee61f456a26edbd28d26c65906f4bc1dcd8f" +dependencies = [ + "dirs-sys", +] + [[package]] name = "dirs-sys" version = "0.5.0" @@ -1258,12 +1267,16 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" name = "mcp-memory-linux-nvim" version = "0.1.0" dependencies = [ + "dirs 7.0.0", "rmp-serde", "rmpv", "schemars 0.8.22", "serde", "serde_json", "tokio", + "tracing", + "tracing-appender", + "tracing-subscriber", ] [[package]] @@ -1276,7 +1289,7 @@ dependencies = [ "chrono", "clap", "dashmap", - "dirs", + "dirs 6.0.0", "futures-util", "git2", "glob", @@ -1292,6 +1305,7 @@ dependencies = [ "tokio-tungstenite 0.21.0", "tokio-util", "tracing", + "tracing-appender", "tracing-subscriber", "uuid", ] @@ -1301,23 +1315,31 @@ name = "mcp-memory-stub" version = "0.1.0" dependencies = [ "clap", + "dirs 7.0.0", "futures-util", "reqwest", "tokio", "tokio-tungstenite 0.21.0", "tokio-util", + "tracing", + "tracing-appender", + "tracing-subscriber", ] [[package]] name = "mcp-memory-win-nvim" version = "0.1.0" dependencies = [ + "dirs 7.0.0", "rmp-serde", "rmpv", "schemars 0.8.22", "serde", "serde_json", "tokio", + "tracing", + "tracing-appender", + "tracing-subscriber", ] [[package]] @@ -2220,6 +2242,12 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "symlink" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" + [[package]] name = "syn" version = "2.0.119" @@ -2671,6 +2699,19 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-appender" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "050686193eb999b4bb3bc2acfa891a13da00f79734704c4b8b4ef1a10b368a3c" +dependencies = [ + "crossbeam-channel", + "symlink", + "thiserror 2.0.20", + "time", + "tracing-subscriber", +] + [[package]] name = "tracing-attributes" version = "0.1.31" diff --git a/design.md b/design.md index 7d1d43f..8019e32 100644 --- a/design.md +++ b/design.md @@ -115,3 +115,29 @@ eqwest and okio). * **Role:** A dedicated, OS-agnostic proxy binary used strictly for routing stdio JSON-RPC traffic over HTTP to a remote Leader. Windows gy clients point directly to this binary to bypass loading the heavy Server daemon into memory. * **WSL Behavior:** Compiled as a Linux native binary (x86_64-unknown-linux-musl). When executed by WSL agy, it acts as a transparent proxy to http://127.0.0.1:3000. It can also execute wake_cmd (e.g., WSL interop) to silently wake the Windows host if the Leader is offline. + + +## 14. Neovim Integration Architecture & "God Mode" +To enable seamless pair-programming inside Neovim, the daemon integrates with Neovim using two complementary systems: a Webhook Telemetry pipeline and dedicated MCP binaries. + +### Telemetry Pipeline (Last Focused Wins) +A lightweight Lua script (gemini-integration.lua) is loaded into Neovim, which fires an asynchronous curl POST to http://127.0.0.1:3000/nvim/telemetry whenever the user focuses a buffer or moves the cursor. The server then writes this data (including session_id, ile, line, and col) to both the Windows and WSL ctive_nvim.txt files and broadcasts it over WebSockets. + +### Native MCP Binaries (win-nvim & linux-nvim) +The project compiles two standalone, highly-performant binaries that implement the MCP JSON-RPC protocol over Stdio and bridge it directly to Neovim's Msgpack-RPC Named Pipes/Sockets. These binaries avoid hardcoding infinite tools by utilizing a "God Mode" escape hatch. + +Exposed Neovim Tools: +* ** +vim_get_active_buffer & +vim_get_cursor**: Read file state. +* ** +vim_goto_line & +vim_set_diagnostics**: Manipulate IDE state. +* ** +vim_get_visual_selection**: Read exact highlight coordinates (handles mode dynamically). +* ** +vim_list_buffers**: Discover unsaved work and context. +* ** +vim_get_diagnostics**: Read live LSP errors dynamically instead of requiring a compiler. +* ** +vim_execute_lua ("God Mode")**: The ultimate fallback tool. Evaluates raw Lua scripts inside the active Neovim instance and returns JSON. This prevents the need to continuously recompile the Rust server whenever a new Neovim capability is required. diff --git a/gemini-integration.lua b/gemini-integration.lua index 5a60248..1f109bf 100644 --- a/gemini-integration.lua +++ b/gemini-integration.lua @@ -36,3 +36,8 @@ vim.api.nvim_create_autocmd({"VimEnter", "FocusGained", "BufEnter"}, { end, desc = "Register active Neovim instance for Gemini CLI", }) + +-- Load UI & Keymaps +local ui = dofile("C:/Users/reazul.ashraf/workspace/rust/mcp-memory/gemini-ui.lua") +ui.setup() +_G.gemini = ui -- Expose globally so Agent can call it via execute_lua diff --git a/gemini-ui.lua b/gemini-ui.lua new file mode 100644 index 0000000..7b08d06 --- /dev/null +++ b/gemini-ui.lua @@ -0,0 +1,97 @@ +local M = {} + +local progress_win = nil +local progress_buf = nil +local job_id = nil + +function M.show_progress(msg) + if progress_win and vim.api.nvim_win_is_valid(progress_win) then + local lines = vim.split(msg, "\n") + vim.api.nvim_buf_set_lines(progress_buf, -1, -1, false, lines) + local line_count = vim.api.nvim_buf_line_count(progress_buf) + vim.api.nvim_win_set_cursor(progress_win, {line_count, 0}) + return + end + + progress_buf = vim.api.nvim_create_buf(false, true) + local lines = vim.split(msg, "\n") + vim.api.nvim_buf_set_lines(progress_buf, 0, -1, false, lines) + + local width = math.min(math.floor(vim.o.columns * 0.4), 80) + local height = math.min(math.floor(vim.o.lines * 0.4), 20) + local row = 1 + local col = vim.o.columns - width - 2 + + progress_win = vim.api.nvim_open_win(progress_buf, true, { + relative = 'editor', + width = width, + height = height, + row = row, + col = col, + style = 'minimal', + border = 'rounded', + title = ' Antigravity AI ', + title_pos = 'center' + }) + + local function close_win() + if job_id then + vim.fn.jobstop(job_id) + job_id = nil + end + if progress_win and vim.api.nvim_win_is_valid(progress_win) then + vim.api.nvim_win_close(progress_win, true) + progress_win = nil + end + end + vim.keymap.set('n', 'q', close_win, { buffer = progress_buf, noremap = true, silent = true }) + vim.keymap.set('n', '', close_win, { buffer = progress_buf, noremap = true, silent = true }) +end + +function M.close_progress() + if progress_win and vim.api.nvim_win_is_valid(progress_win) then + vim.api.nvim_win_close(progress_win, true) + progress_win = nil + end +end + +local function execute_agent(prompt) + local cmd = { "agy", "--new-project", "-i", prompt } + + M.show_progress("Starting Antigravity...") + + -- termopen will attach to the current buffer (which show_progress just focused) + job_id = vim.fn.termopen(cmd, { + on_exit = function(_, code) + job_id = nil + end + }) + vim.cmd('startinsert') +end + +function M.ask_agent() + vim.ui.input({ prompt = 'Ask Agent: ' }, function(input) + if not input or input == '' then return end + execute_agent(input) + end) +end + +function M.setup() + vim.keymap.set('n', 'ai', M.ask_agent, { desc = "Ask Antigravity Agent", noremap = true, silent = true }) + vim.keymap.set('v', 'ai', function() + local _, csrow, cscol, _ = unpack(vim.fn.getpos("'<")) + local _, cerow, cecol, _ = unpack(vim.fn.getpos("'>")) + + vim.ui.input({ prompt = 'Ask Agent (about selection): ' }, function(input) + if not input or input == '' then return end + + local file = vim.api.nvim_buf_get_name(0) + local context = string.format(" [Context: %s lines %d-%d]", file, csrow, cerow) + local final_input = input .. context + + execute_agent(final_input) + end) + end, { desc = "Ask Antigravity Agent about selection", noremap = true, silent = true }) +end + +return M diff --git a/instructions.md b/instructions.md index c0e16f1..1a8feaf 100644 --- a/instructions.md +++ b/instructions.md @@ -118,3 +118,14 @@ When instructed to restart, update, or stop the mcp-memory-server binary, never - **WebSockets (/ws):** Used strictly by external UI clients (e.g., dashboard.html) or the mcp-memory-stub proxy. - **Behavior:** Both transport layers route into the exact same central handle_request pipeline. Do not build feature logic that only works on one transport protocol. + + +## 15. Neovim Integration & God Mode +The project contains two MCP binaries (win-nvim and linux-nvim) that bridge JSON-RPC over stdio directly to the active Neovim instance (using ctive_nvim.txt for Last Focused Wins telemetry). +- These binaries expose basic tools ( +vim_get_cursor, +vim_get_active_buffer, +vim_list_buffers, etc.). +- **God Mode**: They also expose +vim_execute_lua. This is the ultimate fallback tool. If you need to access *any* Neovim API that does not have a dedicated Rust tool (e.g., getting LSP diagnostics, evaluating a visual selection block based on modes, setting registers), you MUST write a short Lua script and pass it to +vim_execute_lua. Do not attempt to recompile the Rust server to add new basic tools; use the Lua escape hatch dynamically. diff --git a/linux-nvim/Cargo.toml b/linux-nvim/Cargo.toml index b2177fd..769820d 100644 --- a/linux-nvim/Cargo.toml +++ b/linux-nvim/Cargo.toml @@ -10,3 +10,7 @@ rmp-serde = "1.1" rmpv = "1.0" tokio = { version = "1.37", features = ["full"] } schemars = "0.8" +tracing-appender = "0.2.5" +tracing = "0.1.44" +tracing-subscriber = "0.3.23" +dirs = "7.0.0" diff --git a/linux-nvim/src/main.rs b/linux-nvim/src/main.rs index 0970e40..c473b93 100644 --- a/linux-nvim/src/main.rs +++ b/linux-nvim/src/main.rs @@ -5,10 +5,36 @@ use serde_json::json; use tokio::net::UnixStream; use tokio::io::{AsyncReadExt, AsyncWriteExt}; +fn init_logging(app_name: &str) -> Option { + let base_dir = std::env::var("MCP_MEMORY_STORE_DIR").unwrap_or_else(|_| { + dirs::home_dir() + .map(|mut h| { + h.push(".gemini/mcp_memory"); + h.to_string_lossy().to_string() + }) + .unwrap_or_else(|| ".gemini/mcp_memory".into()) + }); + let log_dir = std::path::PathBuf::from(base_dir).join("logs"); + std::fs::create_dir_all(&log_dir).unwrap_or_default(); + + let file_appender = tracing_appender::rolling::daily(log_dir, format!("{}.log", app_name)); + let (non_blocking, guard) = tracing_appender::non_blocking(file_appender); + + let _ = tracing_subscriber::fmt() + .with_writer(non_blocking) + .with_ansi(false) + .with_max_level(tracing::Level::INFO) + .try_init(); + + Some(guard) +} + #[tokio::main] async fn main() { + let _guard = init_logging("linux-nvim"); + let mut stdin = tokio::io::BufReader::new(tokio::io::stdin()); loop { - let msg = match read_message().await { + let msg = match read_message(&mut stdin).await { Some(m) => m, None => break, }; @@ -84,6 +110,33 @@ async fn main() { }, "required": ["line", "message"] } + }, + { + "name": "nvim_execute_lua", + "description": "Execute arbitrary Lua code in Neovim and return the result (JSON serialized).", + "inputSchema": { + "type": "object", + "properties": { + "code": { "type": "string" } + }, + "required": ["code"] + } + }, + { + "name": "nvim_list_buffers", + "description": "Get a list of all loaded Neovim buffers and their IDs.", + "inputSchema": { + "type": "object", + "properties": {} + } + }, + { + "name": "nvim_get_diagnostics", + "description": "Get all LSP diagnostics (errors, warnings) for the active buffer.", + "inputSchema": { + "type": "object", + "properties": {} + } } ] })), @@ -198,6 +251,62 @@ async fn main() { } } } + + "nvim_execute_lua" => { + let code = args.get("code").and_then(|v| v.as_str()).unwrap_or(""); + match execute_nvim_lua(code).await { + Ok(content) => { + send_response(JsonRpcResponse { + jsonrpc: "2.0".to_string(), id, result: Some(json!({ "content": [{ "type": "text", "text": content }] })), error: None, + }).await; + } + Err(e) => { send_error(id, -32603, &format!("Failed to execute lua: {}", e)).await; } + } + } + "nvim_list_buffers" => { + let code = r#" + local bufs = vim.api.nvim_list_bufs() + local loaded = {} + for _, b in ipairs(bufs) do + if vim.api.nvim_buf_is_loaded(b) then + local name = vim.api.nvim_buf_get_name(b) + table.insert(loaded, {id = b, name = name == "" and "[No Name]" or name}) + end + end + return loaded + "#; + match execute_nvim_lua(code).await { + Ok(content) => { + send_response(JsonRpcResponse { + jsonrpc: "2.0".to_string(), id, result: Some(json!({ "content": [{ "type": "text", "text": content }] })), error: None, + }).await; + } + Err(e) => { send_error(id, -32603, &format!("Failed to list buffers: {}", e)).await; } + } + } + "nvim_get_diagnostics" => { + let code = r#" + local diags = vim.diagnostic.get(0) + local res = {} + for _, d in ipairs(diags) do + table.insert(res, { + line = d.lnum + 1, + col = d.col, + message = d.message, + severity = d.severity + }) + end + return res + "#; + match execute_nvim_lua(code).await { + Ok(content) => { + send_response(JsonRpcResponse { + jsonrpc: "2.0".to_string(), id, result: Some(json!({ "content": [{ "type": "text", "text": content }] })), error: None, + }).await; + } + Err(e) => { send_error(id, -32603, &format!("Failed to get diagnostics: {}", e)).await; } + } + } _ => { send_error(id, -32601, "Tool not found").await; } @@ -269,11 +378,15 @@ async fn call_nvim(req: rmpv::Value) -> Result { continue; }, Err(_) => { - let n = stream.read(&mut chunk).await.map_err(|e| e.to_string())?; - if n == 0 { - return Err("Unexpected EOF from Neovim".to_string()); + let read_future = stream.read(&mut chunk); + match tokio::time::timeout(tokio::time::Duration::from_secs(5), read_future).await { + Ok(Ok(n)) => { + if n == 0 { return Err("Connection closed".into()); } + resp_buf.extend_from_slice(&chunk[..n]); + } + Ok(Err(e)) => return Err(e.to_string()), + Err(_) => return Err("Timeout waiting for Neovim response".into()), } - resp_buf.extend_from_slice(&chunk[..n]); } } } @@ -430,3 +543,70 @@ async fn set_nvim_diagnostics(line: i64, message: &str) -> Result<(), String> { } Err("Invalid response".to_string()) } + +fn rmpv_to_json(val: &rmpv::Value) -> serde_json::Value { + match val { + rmpv::Value::Nil => serde_json::Value::Null, + rmpv::Value::Boolean(b) => serde_json::json!(b), + rmpv::Value::Integer(i) => { + if let Some(n) = i.as_i64() { + serde_json::json!(n) + } else if let Some(n) = i.as_u64() { + serde_json::json!(n) + } else { + serde_json::Value::Null + } + }, + rmpv::Value::F32(f) => serde_json::json!(f), + rmpv::Value::F64(f) => serde_json::json!(f), + rmpv::Value::String(s) => { + if let Some(str_val) = s.as_str() { + serde_json::json!(str_val) + } else { + serde_json::Value::Null + } + }, + rmpv::Value::Array(arr) => { + let vec: Vec = arr.iter().map(rmpv_to_json).collect(); + serde_json::Value::Array(vec) + }, + rmpv::Value::Map(map) => { + let mut obj = serde_json::Map::new(); + for (k, v) in map { + let key_str = if let rmpv::Value::String(s) = k { + s.as_str().unwrap_or("").to_string() + } else { + format!("{:?}", k) + }; + obj.insert(key_str, rmpv_to_json(v)); + } + serde_json::Value::Object(obj) + }, + _ => serde_json::json!(format!("{:?}", val)), + } +} + +async fn execute_nvim_lua(code: &str) -> Result { + use rmpv::Value as RmpValue; + let req = RmpValue::Array(vec![ + RmpValue::Integer(0.into()), + RmpValue::Integer(6.into()), // msgid + RmpValue::String("nvim_exec_lua".into()), + RmpValue::Array(vec![ + RmpValue::String(code.into()), + RmpValue::Array(vec![]), + ]), + ]); + + let resp = call_nvim(req).await?; + if let RmpValue::Array(arr) = resp { + if !arr[2].is_nil() { + return Err(format!("Neovim error: {:?}", arr[2])); + } + if arr.len() > 3 { + return Ok(serde_json::to_string_pretty(&rmpv_to_json(&arr[3])).unwrap_or_default()); + } + return Ok("".to_string()); + } + Err("Invalid response".to_string()) +} diff --git a/linux-nvim/src/mcp.rs b/linux-nvim/src/mcp.rs index 51c7421..4c33a65 100644 --- a/linux-nvim/src/mcp.rs +++ b/linux-nvim/src/mcp.rs @@ -20,8 +20,7 @@ pub struct JsonRpcResponse { pub error: Option, } -pub async fn read_message() -> Option { - let mut stdin = BufReader::new(tokio::io::stdin()); +pub async fn read_message(stdin: &mut BufReader) -> Option { let mut length = 0; loop { let mut line = String::new(); diff --git a/server/Cargo.toml b/server/Cargo.toml index e584a65..eadb2bf 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -27,6 +27,7 @@ tracing = "0.1.44" tracing-subscriber = "0.3.23" uuid = { version = "1.26.0", features = ["v4"] } tokio-tungstenite = "0.21.0" +tracing-appender = "0.2.5" [build-dependencies] chrono = "0.4.45" diff --git a/server/src/main.rs b/server/src/main.rs index b8fb587..d4ca0c2 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -151,13 +151,13 @@ async fn git_sync_worker(state: Arc) { file_path: "".to_string(), }); }); - eprintln!("Git Sync: Logged new commit {}", current_id); + tracing::info!("Git Sync: Logged new commit {}", current_id); state.tasks.modify(|tasks| { for task in tasks.iter_mut() { if task.status != "completed" && msg.to_lowercase().contains(&task.title.to_lowercase()) { task.status = "completed".to_string(); - eprintln!("Git Sync: Auto-completed task '{}'", task.title); + tracing::info!("Git Sync: Auto-completed task '{}'", task.title); } } }); @@ -505,8 +505,8 @@ fn run_server(state: Arc) -> Result<(), Box> tokio::spawn(garbage_collector_worker(Arc::clone(&state))); tokio::spawn(git_sync_worker(Arc::clone(&state))); -eprintln!("MCP Memory Server running on http://127.0.0.1:3000/sse"); - if let Err(e) = axum::serve(listener, app).await { + tracing::info!("MCP Memory Server running on http://127.0.0.1:3000/sse"); + if let Err(e) = axum::serve(listener, app).await { let log_path = dirs::home_dir() .unwrap_or_default() .join(".gemini/mcp_memory/daemon_error.log"); @@ -676,8 +676,32 @@ async fn health_handler() -> &'static str { "OK" } +fn init_logging(app_name: &str) -> Option { + let base_dir = std::env::var("MCP_MEMORY_STORE_DIR").unwrap_or_else(|_| { + dirs::home_dir() + .map(|mut h| { + h.push(".gemini/mcp_memory"); + h.to_string_lossy().to_string() + }) + .unwrap_or_else(|| ".gemini/mcp_memory".into()) + }); + let log_dir = std::path::PathBuf::from(base_dir).join("logs"); + std::fs::create_dir_all(&log_dir).unwrap_or_default(); + + let file_appender = tracing_appender::rolling::daily(log_dir, format!("{}.log", app_name)); + let (non_blocking, guard) = tracing_appender::non_blocking(file_appender); + + let _ = tracing_subscriber::fmt() + .with_writer(non_blocking) + .with_ansi(false) + .with_max_level(tracing::Level::INFO) + .try_init(); + + Some(guard) +} fn main() -> Result<(), Box> { + let _guard = init_logging("server"); let cli = Cli::parse(); if cli.exit { diff --git a/server/src/state.rs b/server/src/state.rs index b03e551..1bc1d40 100644 --- a/server/src/state.rs +++ b/server/src/state.rs @@ -192,12 +192,12 @@ impl MemoryState { pub fn rebuild_index(&self) { if let Ok(new_idx) = MemoryIndex::new(&self.base_dir) { - let session = self.session_graph.read().unwrap(); - let cache = self.master_cache.read().unwrap(); + let session_clone = { self.session_graph.read().unwrap().clone() }; + let cache_clone = { self.master_cache.read().unwrap().0.clone() }; // Index entities that are only in master, or merge if they are in both - for (name, e) in &cache.0.entities { - if let Some(session_e) = session.entities.get(name) { + for (name, e) in &cache_clone.entities { + if let Some(session_e) = session_clone.entities.get(name) { let mut merged_e = e.clone(); for obs in &session_e.observations { if !merged_e.observations.contains(obs) { @@ -210,19 +210,22 @@ impl MemoryState { } } // Index entities that are only in session - for (name, session_e) in &session.entities { - if !cache.0.entities.contains_key(name) { + for (name, session_e) in &session_clone.entities { + if !cache_clone.entities.contains_key(name) { let _ = new_idx.index_entity(session_e); } } - for t in self.tasks.read() { + let tasks = self.tasks.read(); + for t in tasks { let _ = new_idx.index_task(&t); } - for s in self.snippets.read() { + let snippets = self.snippets.read(); + for s in snippets { let _ = new_idx.index_snippet(&s); } - for a in self.adrs.read() { + let adrs = self.adrs.read(); + for a in adrs { let _ = new_idx.index_adr(&a); } let _ = new_idx.commit(); diff --git a/stub/Cargo.toml b/stub/Cargo.toml index ac91716..f80cd56 100644 --- a/stub/Cargo.toml +++ b/stub/Cargo.toml @@ -10,3 +10,7 @@ tokio = { version = "1.53.1", features = ["full"] } tokio-util = { version = "0.7.19", features = ["io"] } futures-util = "0.3.34" tokio-tungstenite = "0.21.0" +tracing-appender = "0.2.5" +tracing = "0.1.44" +tracing-subscriber = "0.3.23" +dirs = "7.0.0" diff --git a/stub/src/main.rs b/stub/src/main.rs index 2100ade..25563eb 100644 --- a/stub/src/main.rs +++ b/stub/src/main.rs @@ -15,7 +15,58 @@ struct Cli { wake_cmd: Option, } +async fn read_mcp_message(stdin: &mut tokio::io::BufReader) -> Option { + use tokio::io::AsyncReadExt; + let mut length = 0; + loop { + let mut line = String::new(); + if stdin.read_line(&mut line).await.unwrap_or(0) == 0 { + return None; + } + let line = line.trim_end(); + if line.is_empty() { + break; + } + if let Some(len_str) = line.strip_prefix("Content-Length: ") { + length = len_str.parse().unwrap_or(0); + } + } + if length == 0 { + return None; + } + let mut buffer = vec![0; length]; + if stdin.read_exact(&mut buffer).await.is_err() { + return None; + } + String::from_utf8(buffer).ok() +} + +fn init_logging(app_name: &str) -> Option { + let base_dir = std::env::var("MCP_MEMORY_STORE_DIR").unwrap_or_else(|_| { + dirs::home_dir() + .map(|mut h| { + h.push(".gemini/mcp_memory"); + h.to_string_lossy().to_string() + }) + .unwrap_or_else(|| ".gemini/mcp_memory".into()) + }); + let log_dir = std::path::PathBuf::from(base_dir).join("logs"); + std::fs::create_dir_all(&log_dir).unwrap_or_default(); + + let file_appender = tracing_appender::rolling::daily(log_dir, format!("{}.log", app_name)); + let (non_blocking, guard) = tracing_appender::non_blocking(file_appender); + + let _ = tracing_subscriber::fmt() + .with_writer(non_blocking) + .with_ansi(false) + .with_max_level(tracing::Level::INFO) + .try_init(); + + Some(guard) +} + fn main() -> Result<(), Box> { + let _guard = init_logging("stub"); let cli = Cli::parse(); let rt = tokio::runtime::Runtime::new()?; rt.block_on(async { @@ -24,13 +75,8 @@ fn main() -> Result<(), Box> { tokio::spawn(async move { let mut stdin = tokio::io::BufReader::new(tokio::io::stdin()); - let mut buffer = String::new(); - while let Ok(bytes) = stdin.read_line(&mut buffer).await { - if bytes == 0 { - break; - } - let _ = msg_tx.send(buffer.clone()).await; - buffer.clear(); + while let Some(msg) = read_mcp_message(&mut stdin).await { + let _ = msg_tx.send(msg).await; } let _ = shutdown_tx.send(()).await; }); @@ -43,11 +89,14 @@ fn main() -> Result<(), Box> { loop { if shutdown_rx.try_recv().is_ok() { + tracing::info!("Stub shutdown requested"); break; } + tracing::info!("Attempting to connect to {}", ws_url); match tokio_tungstenite::connect_async(&ws_url).await { Ok((ws_stream, _)) => { + tracing::info!("Successfully connected to target server"); let (mut write, mut read) = ws_stream.split(); let msg_rx_clone = Arc::clone(&msg_rx); @@ -57,7 +106,9 @@ fn main() -> Result<(), Box> { match rx.recv().await { Some(msg) => { drop(rx); + tracing::info!("Forwarding message to target server"); if write.send(tokio_tungstenite::tungstenite::Message::Text(msg)).await.is_err() { + tracing::error!("Failed to write to websocket"); break; } }, @@ -69,26 +120,37 @@ fn main() -> Result<(), Box> { let mut recv_task = tokio::spawn(async move { while let Some(Ok(msg)) = read.next().await { if let tokio_tungstenite::tungstenite::Message::Text(text) = msg { - println!("{}", text); + tracing::info!("Received message from target server, proxying to stdout"); + let payload = format!("Content-Length: {}\r\n\r\n{}", text.len(), text); + use std::io::Write; + let mut stdout = std::io::stdout(); + let _ = stdout.write_all(payload.as_bytes()); + let _ = stdout.flush(); } } + tracing::error!("Websocket read loop exited"); }); tokio::select! { _ = shutdown_rx.recv() => { + tracing::info!("Shutdown received while connected"); return Ok(()); // Stdin closed, exit entirely } _ = &mut send_task => { + tracing::error!("Send task exited"); recv_task.abort(); } _ = &mut recv_task => { + tracing::error!("Recv task exited"); send_task.abort(); } } tokio::time::sleep(tokio::time::Duration::from_millis(50)).await; } - Err(_) => { + Err(e) => { + tracing::error!("Failed to connect to target server: {}", e); if let Some(ref cmd) = wake_cmd { + tracing::info!("Executing wake command: {}", cmd); let parts: Vec<&str> = cmd.split_whitespace().collect(); if !parts.is_empty() { let _ = std::process::Command::new(parts[0]) diff --git a/test_connection.log b/test_connection.log new file mode 100644 index 0000000..2027d5c --- /dev/null +++ b/test_connection.log @@ -0,0 +1,187 @@ +I0913 07:13:11.799197 45 server.go:1560] Starting language server process with pid 34896 +I0913 07:13:11.805667 45 server.go:1613] Language server version: 1.2.2 +I0913 07:13:11.805667 45 server.go:613] Language server will attempt to listen on host localhost +I0913 07:13:11.870861 45 server.go:628] Language server listening on random port at 58424 for HTTPS (gRPC) +I0913 07:13:11.872918 45 server.go:636] Language server listening on random port at 58425 for HTTP +W0913 07:13:12.228039 79 cache.go:135] Cache(loadCodeAssistResponse): Singleflight refresh failed: error getting token source: You are not logged into Antigravity. +E0913 07:13:12.228601 79 errorreport.go:224] error getting token source: You are not logged into Antigravity. +E0913 07:13:12.232567 79 errorreport.go:224] Failed to poll ListExperiments: error getting token source: You are not logged into Antigravity. +I0913 07:13:12.232567 79 model_configs.go:65] Auth mode is unspecified, skipping fetchAvailableModels and returning empty response +I0913 07:13:12.241299 117 store_client.go:680] summary store: starting background reconciliation (trigger=startup) +I0913 07:13:12.242528 117 store_client.go:730] summary store: reconciliation complete, synced 6 records +W0913 07:13:12.243100 117 cache.go:135] Cache(loadCodeAssistResponse): Singleflight refresh failed: error getting token source: You are not logged into Antigravity. +E0913 07:13:12.243100 117 errorreport.go:224] error getting token source: You are not logged into Antigravity. +W0913 07:13:12.243721 117 cache.go:135] Cache(userInfo): Singleflight refresh failed: failed to get load code assist response: error getting token source: You are not logged into Antigravity. +E0913 07:13:12.243721 117 errorreport.go:224] failed to get load code assist response: error getting token source: You are not logged into Antigravity. +W0913 07:13:12.243721 45 cache.go:135] Cache(loadCodeAssistResponse): Singleflight refresh failed: error getting token source: You are not logged into Antigravity. +E0913 07:13:12.243721 45 errorreport.go:224] error getting token source: You are not logged into Antigravity. +W0913 07:13:12.243721 45 cache.go:135] Cache(userInfo): Singleflight refresh failed: failed to get load code assist response: error getting token source: You are not logged into Antigravity. +E0913 07:13:12.243721 45 errorreport.go:224] failed to get load code assist response: error getting token source: You are not logged into Antigravity. +W0913 07:13:12.247405 45 cache.go:135] Cache(loadCodeAssistResponse): Singleflight refresh failed: error getting token source: You are not logged into Antigravity. +E0913 07:13:12.247405 45 errorreport.go:224] error getting token source: You are not logged into Antigravity. +W0913 07:13:12.247405 45 cache.go:135] Cache(userInfo): Singleflight refresh failed: failed to get load code assist response: error getting token source: You are not logged into Antigravity. +E0913 07:13:12.247405 45 errorreport.go:224] failed to get load code assist response: error getting token source: You are not logged into Antigravity. +W0913 07:13:12.248015 45 cache.go:135] Cache(loadCodeAssistResponse): Singleflight refresh failed: error getting token source: You are not logged into Antigravity. +E0913 07:13:12.248015 45 errorreport.go:224] error getting token source: You are not logged into Antigravity. +W0913 07:13:12.248015 45 cache.go:135] Cache(userInfo): Singleflight refresh failed: failed to get load code assist response: error getting token source: You are not logged into Antigravity. +E0913 07:13:12.248015 45 errorreport.go:224] failed to get load code assist response: error getting token source: You are not logged into Antigravity. +W0913 07:13:12.248015 147 cache.go:135] Cache(loadCodeAssistResponse): Singleflight refresh failed: error getting token source: You are not logged into Antigravity. +E0913 07:13:12.248567 147 errorreport.go:224] error getting token source: You are not logged into Antigravity. +W0913 07:13:12.249258 147 cache.go:135] Cache(userInfo): Singleflight refresh failed: failed to get load code assist response: error getting token source: You are not logged into Antigravity. +E0913 07:13:12.249258 147 errorreport.go:224] failed to get load code assist response: error getting token source: You are not logged into Antigravity. +W0913 07:13:12.254061 45 launchmanager.go:69] Entering local chrome mode! This is WRONG unless you are running tests or in eval mode on Linux. +W0913 07:13:12.260093 45 defaults.go:778] failed to get cs path: cs path /usr/bin/cs invalid +I0913 07:13:12.260093 45 manager.go:108] Creating trajectory store manager with proto store and SQLite store +W0913 07:13:12.263716 157 cache.go:135] Cache(loadCodeAssistResponse): Singleflight refresh failed: error getting token source: You are not logged into Antigravity. +E0913 07:13:12.263716 157 errorreport.go:224] error getting token source: You are not logged into Antigravity. +W0913 07:13:12.267188 45 cache.go:135] Cache(loadCodeAssistResponse): Singleflight refresh failed: error getting token source: You are not logged into Antigravity. +E0913 07:13:12.267892 45 errorreport.go:224] error getting token source: You are not logged into Antigravity. +W0913 07:13:12.268559 45 cache.go:135] Cache(userInfo): Singleflight refresh failed: failed to get load code assist response: error getting token source: You are not logged into Antigravity. +E0913 07:13:12.268559 45 errorreport.go:224] failed to get load code assist response: error getting token source: You are not logged into Antigravity. +I0913 07:13:12.275926 203 manager.go:88] Migration [MIGRATION_ID_SIDECAR_USER_CONFIG_BYPASS] is disabled, skipping entirely +I0913 07:13:12.275926 203 manager.go:91] Migration [MIGRATION_ID_SANITY_CHECK_PROJECT_URIS] is enabled +I0913 07:13:12.278668 203 manager.go:100] Migration [MIGRATION_ID_SANITY_CHECK_PROJECT_URIS] already has status MIGRATION_STATUS_COMPLETED, skipping +I0913 07:13:12.278668 203 manager.go:91] Migration [MIGRATION_ID_PLUGIN_ENABLEMENT] is enabled +I0913 07:13:12.280984 203 manager.go:100] Migration [MIGRATION_ID_PLUGIN_ENABLEMENT] already has status MIGRATION_STATUS_COMPLETED, skipping +I0913 07:13:12.280984 203 manager.go:91] Migration [MIGRATION_ID_BUILTIN_SIDECARS_TO_PLUGINS] is enabled +I0913 07:13:12.282861 203 manager.go:100] Migration [MIGRATION_ID_BUILTIN_SIDECARS_TO_PLUGINS] already has status MIGRATION_STATUS_COMPLETED, skipping +I0913 07:13:12.282861 203 manager.go:88] Migration [MIGRATION_ID_LIN_BUILTIN_TO_MARKETPLACE] is disabled, skipping entirely +I0913 07:13:12.286340 45 server.go:3003] Auth succeeded, refreshing features and managers +W0913 07:13:12.287121 45 cache.go:135] Cache(loadCodeAssistResponse): Singleflight refresh failed: error getting token source: You are not logged into Antigravity. +E0913 07:13:12.287121 45 errorreport.go:224] error getting token source: You are not logged into Antigravity. +E0913 07:13:12.287121 45 errorreport.go:224] Failed to poll ListExperiments: error getting token source: You are not logged into Antigravity. +I0913 07:13:12.287121 45 server.go:3009] State refresh took 0ms +I0913 07:13:12.287121 45 server.go:3019] [RemoteControl] Subscription callback triggered. +I0913 07:13:12.289628 45 server.go:3022] [RemoteControl] RemoteControlEnabled value: false +I0913 07:13:12.289628 45 server.go:3637] [RemoteControl] Session toggle is off, staying disconnected +I0913 07:13:12.289628 45 server.go:3348] [RemoteControl] Resolved proxyServerURL: "" +I0913 07:13:12.290222 45 profiler.go:231] Continuous pprof profiling is disabled. +I0913 07:13:12.290222 209 manager.go:88] Migration [MIGRATION_ID_SIDECAR_USER_CONFIG_BYPASS] is disabled, skipping entirely +I0913 07:13:12.290222 209 manager.go:91] Migration [MIGRATION_ID_SANITY_CHECK_PROJECT_URIS] is enabled +I0913 07:13:12.290222 45 server.go:2505] initialized server successfully in 487.2507ms +W0913 07:13:12.290887 212 cache.go:135] Cache(loadCodeAssistResponse): Singleflight refresh failed: error getting token source: You are not logged into Antigravity. +E0913 07:13:12.290887 212 errorreport.go:224] error getting token source: You are not logged into Antigravity. +W0913 07:13:12.290887 212 cache.go:135] Cache(userInfo): Singleflight refresh failed: failed to get load code assist response: error getting token source: You are not logged into Antigravity. +E0913 07:13:12.291441 212 errorreport.go:224] failed to get load code assist response: error getting token source: You are not logged into Antigravity. +I0913 07:13:12.292744 209 manager.go:100] Migration [MIGRATION_ID_SANITY_CHECK_PROJECT_URIS] already has status MIGRATION_STATUS_COMPLETED, skipping +I0913 07:13:12.292744 209 manager.go:91] Migration [MIGRATION_ID_PLUGIN_ENABLEMENT] is enabled +I0913 07:13:12.295037 209 manager.go:100] Migration [MIGRATION_ID_PLUGIN_ENABLEMENT] already has status MIGRATION_STATUS_COMPLETED, skipping +I0913 07:13:12.295037 209 manager.go:91] Migration [MIGRATION_ID_BUILTIN_SIDECARS_TO_PLUGINS] is enabled +I0913 07:13:12.295595 1 auto_updater.go:252] Last check was less than 15 minutes ago, skipping update (fast path) +I0913 07:13:12.295595 1 common.go:150] Launching CLI mode +E0913 07:13:12.295595 1 launchsteps.go:84] Failed to resolve GeminiDir ".gemini": .gemini must be an absolute path: path is not absolute, falling back to default +I0913 07:13:12.295595 1 common.go:172] CLI app data directory: C:\Users\reazul.ashraf\.gemini\antigravity-cli +I0913 07:13:12.295595 1 server.go:299] Creating CLI server backend: product=antigravity workspaceDirs=[C:\Users\reazul.ashraf\workspace\rust\mcp-memory] appDataDir=C:\Users\reazul.ashraf\.gemini\antigravity-cli cascadeManager=true codeAssist=true +I0913 07:13:12.296176 1 auth_provider.go:763] [AuthProvider] SetEnableBusinessLogin called with enable: true +I0913 07:13:12.297268 209 manager.go:100] Migration [MIGRATION_ID_BUILTIN_SIDECARS_TO_PLUGINS] already has status MIGRATION_STATUS_COMPLETED, skipping +I0913 07:13:12.297268 209 manager.go:88] Migration [MIGRATION_ID_LIN_BUILTIN_TO_MARKETPLACE] is disabled, skipping entirely +W0913 07:13:12.320261 182 cache.go:135] Cache(loadCodeAssistResponse): Singleflight refresh failed: error getting token source: You are not logged into Antigravity. +E0913 07:13:12.320887 182 errorreport.go:224] error getting token source: You are not logged into Antigravity. +W0913 07:13:12.320887 182 cache.go:135] Cache(userInfo): Singleflight refresh failed: failed to get load code assist response: error getting token source: You are not logged into Antigravity. +E0913 07:13:12.320887 182 errorreport.go:224] failed to get load code assist response: error getting token source: You are not logged into Antigravity. +I0913 07:13:12.329342 1 project.go:77] project: created project "mcp-memory" (id=f8f5bcad-a3d5-45cd-9413-a145efef016d) at C:\Users\reazul.ashraf\.gemini\config\projects\f8f5bcad-a3d5-45cd-9413-a145efef016d.json +I0913 07:13:12.329342 1 server.go:2091] Backend project ID updated dynamically to: f8f5bcad-a3d5-45cd-9413-a145efef016d +I0913 07:13:12.384573 1 analytics.go:179] CLI startup completed (took 588.6426ms) +I0913 07:13:12.384573 1 printmode.go:174] Print mode: starting (promptLength=19, model="", conversationID="") +I0913 07:13:12.384573 1 manager.go:426] Initializing CLI store manager for workspace C:\Users\reazul.ashraf\workspace\rust\mcp-memory +W0913 07:13:12.389494 182 cache.go:135] Cache(loadCodeAssistResponse): Singleflight refresh failed: error getting token source: You are not logged into Antigravity. +I0913 07:13:12.389494 1 cli_setting_manager.go:156] applyUserSettings: no shared config permissions from C:\Users\reazul.ashraf\.gemini\config\config.json +E0913 07:13:12.389494 182 errorreport.go:224] error getting token source: You are not logged into Antigravity. +I0913 07:13:12.389494 1 cli_setting_manager.go:92] CLI settings initialized: permissions=&{Allow:[command(wsl.exe) command(wsl.exe -d Ubuntu -e printenv | grep -i google)] Deny:[] Ask:[]}, toolPermission=always-proceed +W0913 07:13:12.390021 182 cache.go:135] Cache(userInfo): Singleflight refresh failed: failed to get load code assist response: error getting token source: You are not logged into Antigravity. +E0913 07:13:12.390021 182 errorreport.go:224] failed to get load code assist response: error getting token source: You are not logged into Antigravity. +W0913 07:13:12.390401 182 cache.go:135] Cache(loadCodeAssistResponse): Singleflight refresh failed: error getting token source: You are not logged into Antigravity. +E0913 07:13:12.390401 182 errorreport.go:224] error getting token source: You are not logged into Antigravity. +W0913 07:13:12.390912 182 cache.go:135] Cache(userInfo): Singleflight refresh failed: failed to get load code assist response: error getting token source: You are not logged into Antigravity. +E0913 07:13:12.390912 182 errorreport.go:224] failed to get load code assist response: error getting token source: You are not logged into Antigravity. +W0913 07:13:12.390912 182 cache.go:135] Cache(loadCodeAssistResponse): Singleflight refresh failed: error getting token source: You are not logged into Antigravity. +E0913 07:13:12.390912 182 errorreport.go:224] error getting token source: You are not logged into Antigravity. +W0913 07:13:12.390912 182 cache.go:135] Cache(userInfo): Singleflight refresh failed: failed to get load code assist response: error getting token source: You are not logged into Antigravity. +E0913 07:13:12.391628 182 errorreport.go:224] failed to get load code assist response: error getting token source: You are not logged into Antigravity. +I0913 07:13:12.395463 1 hooks_manager.go:53] loaded 0 named hooks from 0 hooks.json file(s) +I0913 07:13:12.395463 1 manager.go:600] CLI store manager initialized successfully +I0913 07:13:12.395463 1 printmode.go:365] Print mode: not authenticated, trying silent auth +I0913 07:13:12.396534 245 keyring.go:64] keyringAuth: loaded token, expiry=2026-09-13 07:17:47.0141665 +0100 BST expired=false +I0913 07:13:12.530611 245 browser.go:265] token refreshed, new expiry=2026-09-13 08:13:11.5306116 +0100 BST m=+3599.838249501 +I0913 07:13:12.548508 1 auth.go:148] ChainedAuth: authenticated via keyring (effective: gcp) +I0913 07:13:12.548508 1 server_oauth.go:192] applyAuthResult: email=reazul.ashraf@inseinc.com, authMethod=gcp, quotaProject=inse-r-and-d +I0913 07:13:12.548508 1 server_oauth.go:197] OAuth: authenticated successfully as reazul.ashraf@inseinc.com +I0913 07:13:12.548508 1 server_oauth.go:203] b.codeAssistClient.AuthProvider (0xfe2a5053590) is same as b.cliAuth (0xfe2a5053590) +W0913 07:13:12.557760 295 cache.go:163] Failed to refresh cache in background: admin controls not applicable +W0913 07:13:12.557760 256 cache.go:163] Failed to refresh cache in background: admin controls not applicable +I0913 07:13:12.721157 252 http_helpers.go:299] URL: https://cloudcode-pa.googleapis.com/v1internal:fetchAvailableModels Trace: 0x46b69e1d5153866c +I0913 07:13:12.727258 1 model_config_manager.go:327] Propagating selected model override to backend: label="Gemini 3.1 Pro (Low)" +I0913 07:13:12.727768 1 admin_controls_manager.go:42] Enabling admin controls refresh loop for business account +I0913 07:13:12.727768 1 printmode.go:367] Print mode: silent auth succeeded +I0913 07:13:12.727768 313 model_config_manager.go:327] Propagating selected model override to backend: label="Gemini 3.1 Pro (Low)" +I0913 07:13:12.727768 262 quota_manager.go:45] doRefreshQuota: starting reload (force=true) +I0913 07:13:12.727768 263 experiment_manager.go:56] Starting experiment refresh after login +I0913 07:13:12.763025 314 model_config_manager.go:327] Propagating selected model override to backend: label="Gemini 3.1 Pro (Low)" +I0913 07:13:12.763025 262 quota_manager.go:45] doRefreshQuota: starting reload (force=true) +I0913 07:13:12.910330 263 server.go:3637] [RemoteControl] Session toggle is off, staying disconnected +I0913 07:13:12.910330 263 server.go:3348] [RemoteControl] Resolved proxyServerURL: "" +I0913 07:13:12.910330 263 experiment_manager.go:60] Experiments refreshed after login +I0913 07:13:12.910330 263 experiment_manager.go:56] Starting experiment refresh after login +I0913 07:13:12.910881 324 manager.go:1281] Reloading system slash commands +I0913 07:13:12.910881 1 conversation_manager.go:451] Starting new conversation (agent=false) +I0913 07:13:12.910881 1 server.go:1142] Creating new cascade trajectory (agentScript=false) +I0913 07:13:12.910881 1 server.go:1145] Conversation using project ID: f8f5bcad-a3d5-45cd-9413-a145efef016d +I0913 07:13:12.974916 263 server.go:3637] [RemoteControl] Session toggle is off, staying disconnected +I0913 07:13:12.975499 263 server.go:3348] [RemoteControl] Resolved proxyServerURL: "" +I0913 07:13:12.975499 263 experiment_manager.go:60] Experiments refreshed after login +I0913 07:13:12.975499 327 manager.go:1281] Reloading system slash commands +I0913 07:13:12.994408 327 manager.go:1285] Slash commands unchanged, skipping update +I0913 07:13:13.015610 1 server.go:1177] Created conversation 2a0dd78e-ef6f-48a6-8958-9e847ba5ae44 +I0913 07:13:13.016754 1 server.go:3088] GetConversationDetail: found conversation 2a0dd78e-ef6f-48a6-8958-9e847ba5ae44 (active=true) +I0913 07:13:13.018963 1 server.go:3088] GetConversationDetail: found conversation 2a0dd78e-ef6f-48a6-8958-9e847ba5ae44 (active=true) +I0913 07:13:13.019519 1 conversation_manager.go:498] project: switching to conversation belonging to project ID: f8f5bcad-a3d5-45cd-9413-a145efef016d +I0913 07:13:13.020642 1 server.go:2091] Backend project ID updated dynamically to: f8f5bcad-a3d5-45cd-9413-a145efef016d +I0913 07:13:13.020642 1 cli_setting_manager.go:218] ApplyProjectPermissionGrants: no grants for project "mcp-memory", cleared project permissions +I0913 07:13:13.020642 387 manager.go:1304] Reloading system slash commands and skills +I0913 07:13:13.020642 387 manager.go:1281] Reloading system slash commands +I0913 07:13:13.028049 1 hooks_manager.go:53] loaded 0 named hooks from 0 hooks.json file(s) +I0913 07:13:13.028049 1 conversation_manager.go:544] project: synced active project to "mcp-memory" (id=f8f5bcad-a3d5-45cd-9413-a145efef016d) from conversation switch +I0913 07:13:13.028049 1 conversation_manager.go:821] Streaming conversation 2a0dd78e-ef6f-48a6-8958-9e847ba5ae44 +I0913 07:13:13.028635 402 manager.go:1304] Reloading system slash commands and skills +I0913 07:13:13.028635 402 manager.go:1281] Reloading system slash commands +I0913 07:13:13.028635 1 server.go:3088] GetConversationDetail: found conversation 2a0dd78e-ef6f-48a6-8958-9e847ba5ae44 (active=true) +I0913 07:13:13.033411 1 server.go:1186] Starting conversation update stream for 2a0dd78e-ef6f-48a6-8958-9e847ba5ae44 +I0913 07:13:13.033411 1 session.go:168] Print mode: conversation=2a0dd78e-ef6f-48a6-8958-9e847ba5ae44, sending message +I0913 07:13:13.033411 1 manager.go:1281] Reloading system slash commands +I0913 07:13:13.040855 387 manager.go:1285] Slash commands unchanged, skipping update +I0913 07:13:13.055590 1 manager.go:1285] Slash commands unchanged, skipping update +I0913 07:13:13.056337 1 conversation_manager.go:633] Forwarding user message to conversation 2a0dd78e-ef6f-48a6-8958-9e847ba5ae44 (items=1, media=0) +I0913 07:13:13.056337 1 server.go:1745] Sending user message to conversation 2a0dd78e-ef6f-48a6-8958-9e847ba5ae44 (items=1, media=0) +I0913 07:13:13.056900 402 manager.go:1285] Slash commands unchanged, skipping update +I0913 07:13:13.063256 1 latency_breakdown.go:142] SEND_USER_CASCADE_MESSAGE_LATENCY latency breakdown: map[active_user_state_latency_ms:0 blocking:false cascade_id:2a0dd78e-ef6f-48a6-8958-9e847ba5ae44 cascade_send_latency_ms:4 hydrate_slash_commands_latency_ms:0 load_trajectory_latency_ms:0 media_count:0 media_summaries_latency_ms:0 message_origin:AGENT_MESSAGE_ORIGIN_UNSPECIFIED refresh_browser_state_latency_ms:0 resolve_agent_config_latency_ms:1 save_media_latency_ms:0 saved_media_count:0 status:OK total_latency_ms:6 trajectory_id:1e6aeef3-6a26-47de-b767-5f796ce64de6] +I0913 07:13:13.669038 89 http_helpers.go:299] URL: https://aiplatform.googleapis.com/v1/projects/inse-r-and-d/locations/global/publishers/google/models/gemini-3.5-flash-lite:streamGenerateContent?alt=sse ResponseID: -T6maszCGYXZ1PIPkoa30Ac +I0913 07:13:42.265416 181 mcp_manager.go:873] MCP: 1 server(s) still connecting after 30s: win-nvim +I0913 07:14:12.265868 181 mcp_manager.go:873] MCP: 1 server(s) still connecting after 1m0s: win-nvim +I0913 07:14:42.265823 181 mcp_manager.go:873] MCP: 1 server(s) still connecting after 1m30s: win-nvim +I0913 07:15:12.265858 181 mcp_manager.go:873] MCP: 1 server(s) still connecting after 2m0s: win-nvim +I0913 07:15:42.266182 181 mcp_manager.go:873] MCP: 1 server(s) still connecting after 2m30s: win-nvim +I0913 07:16:12.266424 181 mcp_manager.go:873] MCP: 1 server(s) still connecting after 3m0s: win-nvim +I0913 07:16:42.266567 181 mcp_manager.go:873] MCP: 1 server(s) still connecting after 3m30s: win-nvim +I0913 07:17:12.267264 181 mcp_manager.go:873] MCP: 1 server(s) still connecting after 4m0s: win-nvim +I0913 07:17:42.267157 181 mcp_manager.go:873] MCP: 1 server(s) still connecting after 4m30s: win-nvim +I0913 07:18:12.266905 181 mcp_manager.go:873] MCP: 1 server(s) still connecting after 5m0s: win-nvim +W0913 07:18:13.081605 1 poll.go:204] Print mode: print timeout after 5m0s with turn in progress after 11786 polls (printed=0) +I0913 07:18:13.081605 1 manager.go:780] CLI store manager shutting down +I0913 07:18:13.089097 1 conversation_manager.go:778] Stopping conversation stream +I0913 07:18:13.089097 863 server.go:2862] Language server shutting down +I0913 07:18:13.089097 863 server.go:2867] Waiting for migrations to complete to prevent partial migration state... +I0913 07:18:13.089711 403 server.go:1233] Stream goroutine exited for 2a0dd78e-ef6f-48a6-8958-9e847ba5ae44, sending completion signal +I0913 07:18:13.089711 403 conversation_manager.go:922] Stream completed for 2a0dd78e-ef6f-48a6-8958-9e847ba5ae44, clearing ResponsePending +E0913 07:18:13.122238 411 sharedfragment.go:187] Failed to append MCP servers from specs: context canceled +E0913 07:18:13.141515 411 rules.go:393] Invalid rule trigger: CORTEX_MEMORY_TRIGGER_UNSPECIFIED +E0913 07:18:13.142864 411 rules.go:393] Invalid rule trigger: CORTEX_MEMORY_TRIGGER_UNSPECIFIED +E0913 07:18:13.144699 411 rules.go:393] Invalid rule trigger: CORTEX_MEMORY_TRIGGER_UNSPECIFIED +E0913 07:18:13.146554 411 rules.go:393] Invalid rule trigger: CORTEX_MEMORY_TRIGGER_UNSPECIFIED +E0913 07:18:13.147674 411 rules.go:393] Invalid rule trigger: CORTEX_MEMORY_TRIGGER_UNSPECIFIED +E0913 07:18:13.148896 411 rules.go:393] Invalid rule trigger: CORTEX_MEMORY_TRIGGER_UNSPECIFIED +E0913 07:18:13.149997 411 rules.go:393] Invalid rule trigger: CORTEX_MEMORY_TRIGGER_UNSPECIFIED +E0913 07:18:13.151139 411 rules.go:393] Invalid rule trigger: CORTEX_MEMORY_TRIGGER_UNSPECIFIED +W0913 07:18:13.157805 411 declarative_config_loader.go:253] skipping component during resolution: empty component: prompt section "subagent_reminder" +W0913 07:18:13.157805 411 declarative_config_loader.go:253] skipping component during resolution: empty component: prompt section "terminal_sandbox" +I0913 07:18:13.222695 904 http_helpers.go:299] URL: https://cloudcode-pa.googleapis.com/v1internal:fetchAvailableModels Trace: 0xf50151ad0d9158d9 +E0913 07:18:13.333887 160 file_watcher.go:194] skipping empty or temp file: diff --git a/test_hang.log b/test_hang.log new file mode 100644 index 0000000..c17a21d --- /dev/null +++ b/test_hang.log @@ -0,0 +1,154 @@ +I0913 07:26:28.955691 67 server.go:1560] Starting language server process with pid 36192 +I0913 07:26:28.966088 67 server.go:1613] Language server version: 1.2.2 +I0913 07:26:28.966088 67 server.go:613] Language server will attempt to listen on host localhost +I0913 07:26:29.009214 67 server.go:628] Language server listening on random port at 65520 for HTTPS (gRPC) +I0913 07:26:29.010778 67 server.go:636] Language server listening on random port at 65521 for HTTP +W0913 07:26:29.341265 27 cache.go:135] Cache(loadCodeAssistResponse): Singleflight refresh failed: error getting token source: You are not logged into Antigravity. +E0913 07:26:29.341812 27 errorreport.go:224] error getting token source: You are not logged into Antigravity. +E0913 07:26:29.343343 27 errorreport.go:224] Failed to poll ListExperiments: error getting token source: You are not logged into Antigravity. +I0913 07:26:29.343889 27 model_configs.go:65] Auth mode is unspecified, skipping fetchAvailableModels and returning empty response +I0913 07:26:29.375237 33 store_client.go:680] summary store: starting background reconciliation (trigger=startup) +W0913 07:26:29.380738 67 cache.go:135] Cache(loadCodeAssistResponse): Singleflight refresh failed: error getting token source: You are not logged into Antigravity. +E0913 07:26:29.381741 67 errorreport.go:224] error getting token source: You are not logged into Antigravity. +W0913 07:26:29.381741 67 cache.go:135] Cache(userInfo): Singleflight refresh failed: failed to get load code assist response: error getting token source: You are not logged into Antigravity. +E0913 07:26:29.381741 67 errorreport.go:224] failed to get load code assist response: error getting token source: You are not logged into Antigravity. +W0913 07:26:29.386594 116 cache.go:135] Cache(loadCodeAssistResponse): Singleflight refresh failed: error getting token source: You are not logged into Antigravity. +E0913 07:26:29.387227 116 errorreport.go:224] error getting token source: You are not logged into Antigravity. +I0913 07:26:29.387227 33 store_client.go:730] summary store: reconciliation complete, synced 6 records +W0913 07:26:29.387227 116 cache.go:135] Cache(userInfo): Singleflight refresh failed: failed to get load code assist response: error getting token source: You are not logged into Antigravity. +E0913 07:26:29.388039 116 errorreport.go:224] failed to get load code assist response: error getting token source: You are not logged into Antigravity. +W0913 07:26:29.389671 67 cache.go:135] Cache(loadCodeAssistResponse): Singleflight refresh failed: error getting token source: You are not logged into Antigravity. +E0913 07:26:29.389671 67 errorreport.go:224] error getting token source: You are not logged into Antigravity. +W0913 07:26:29.389671 67 cache.go:135] Cache(userInfo): Singleflight refresh failed: failed to get load code assist response: error getting token source: You are not logged into Antigravity. +E0913 07:26:29.389671 67 errorreport.go:224] failed to get load code assist response: error getting token source: You are not logged into Antigravity. +W0913 07:26:29.393413 67 launchmanager.go:69] Entering local chrome mode! This is WRONG unless you are running tests or in eval mode on Linux. +W0913 07:26:29.395116 67 defaults.go:778] failed to get cs path: cs path /usr/bin/cs invalid +I0913 07:26:29.396134 67 manager.go:108] Creating trajectory store manager with proto store and SQLite store +W0913 07:26:29.396642 130 cache.go:135] Cache(loadCodeAssistResponse): Singleflight refresh failed: error getting token source: You are not logged into Antigravity. +E0913 07:26:29.396642 130 errorreport.go:224] error getting token source: You are not logged into Antigravity. +W0913 07:26:29.400940 67 cache.go:135] Cache(loadCodeAssistResponse): Singleflight refresh failed: error getting token source: You are not logged into Antigravity. +E0913 07:26:29.401959 67 errorreport.go:224] error getting token source: You are not logged into Antigravity. +W0913 07:26:29.401959 67 cache.go:135] Cache(userInfo): Singleflight refresh failed: failed to get load code assist response: error getting token source: You are not logged into Antigravity. +E0913 07:26:29.402476 67 errorreport.go:224] failed to get load code assist response: error getting token source: You are not logged into Antigravity. +I0913 07:26:29.422534 93 manager.go:88] Migration [MIGRATION_ID_SIDECAR_USER_CONFIG_BYPASS] is disabled, skipping entirely +I0913 07:26:29.422534 93 manager.go:91] Migration [MIGRATION_ID_SANITY_CHECK_PROJECT_URIS] is enabled +I0913 07:26:29.427540 93 manager.go:100] Migration [MIGRATION_ID_SANITY_CHECK_PROJECT_URIS] already has status MIGRATION_STATUS_COMPLETED, skipping +I0913 07:26:29.427540 93 manager.go:91] Migration [MIGRATION_ID_PLUGIN_ENABLEMENT] is enabled +I0913 07:26:29.430393 93 manager.go:100] Migration [MIGRATION_ID_PLUGIN_ENABLEMENT] already has status MIGRATION_STATUS_COMPLETED, skipping +I0913 07:26:29.430393 93 manager.go:91] Migration [MIGRATION_ID_BUILTIN_SIDECARS_TO_PLUGINS] is enabled +I0913 07:26:29.432424 93 manager.go:100] Migration [MIGRATION_ID_BUILTIN_SIDECARS_TO_PLUGINS] already has status MIGRATION_STATUS_COMPLETED, skipping +I0913 07:26:29.432424 93 manager.go:88] Migration [MIGRATION_ID_LIN_BUILTIN_TO_MARKETPLACE] is disabled, skipping entirely +I0913 07:26:29.433310 67 server.go:3003] Auth succeeded, refreshing features and managers +W0913 07:26:29.433823 67 cache.go:135] Cache(loadCodeAssistResponse): Singleflight refresh failed: error getting token source: You are not logged into Antigravity. +E0913 07:26:29.433823 67 errorreport.go:224] error getting token source: You are not logged into Antigravity. +E0913 07:26:29.433823 67 errorreport.go:224] Failed to poll ListExperiments: error getting token source: You are not logged into Antigravity. +I0913 07:26:29.433823 67 server.go:3009] State refresh took 0ms +I0913 07:26:29.433823 67 server.go:3019] [RemoteControl] Subscription callback triggered. +I0913 07:26:29.436732 67 server.go:3022] [RemoteControl] RemoteControlEnabled value: false +I0913 07:26:29.436732 67 server.go:3637] [RemoteControl] Session toggle is off, staying disconnected +I0913 07:26:29.436732 67 server.go:3348] [RemoteControl] Resolved proxyServerURL: "" +I0913 07:26:29.437754 195 manager.go:88] Migration [MIGRATION_ID_SIDECAR_USER_CONFIG_BYPASS] is disabled, skipping entirely +I0913 07:26:29.437754 195 manager.go:91] Migration [MIGRATION_ID_SANITY_CHECK_PROJECT_URIS] is enabled +I0913 07:26:29.437754 67 profiler.go:231] Continuous pprof profiling is disabled. +I0913 07:26:29.438267 67 server.go:2505] initialized server successfully in 477.0362ms +W0913 07:26:29.438820 128 cache.go:135] Cache(loadCodeAssistResponse): Singleflight refresh failed: error getting token source: You are not logged into Antigravity. +E0913 07:26:29.438820 128 errorreport.go:224] error getting token source: You are not logged into Antigravity. +W0913 07:26:29.439414 128 cache.go:135] Cache(userInfo): Singleflight refresh failed: failed to get load code assist response: error getting token source: You are not logged into Antigravity. +E0913 07:26:29.439414 128 errorreport.go:224] failed to get load code assist response: error getting token source: You are not logged into Antigravity. +I0913 07:26:29.440442 195 manager.go:100] Migration [MIGRATION_ID_SANITY_CHECK_PROJECT_URIS] already has status MIGRATION_STATUS_COMPLETED, skipping +I0913 07:26:29.440442 195 manager.go:91] Migration [MIGRATION_ID_PLUGIN_ENABLEMENT] is enabled +I0913 07:26:29.441990 195 manager.go:100] Migration [MIGRATION_ID_PLUGIN_ENABLEMENT] already has status MIGRATION_STATUS_COMPLETED, skipping +I0913 07:26:29.441990 195 manager.go:91] Migration [MIGRATION_ID_BUILTIN_SIDECARS_TO_PLUGINS] is enabled +I0913 07:26:29.442649 1 auto_updater.go:252] Last check was less than 15 minutes ago, skipping update (fast path) +I0913 07:26:29.443288 1 common.go:150] Launching CLI mode +E0913 07:26:29.443288 1 launchsteps.go:84] Failed to resolve GeminiDir ".gemini": .gemini must be an absolute path: path is not absolute, falling back to default +I0913 07:26:29.443288 1 common.go:172] CLI app data directory: C:\Users\reazul.ashraf\.gemini\antigravity-cli +I0913 07:26:29.443288 1 server.go:299] Creating CLI server backend: product=antigravity workspaceDirs=[C:\Users\reazul.ashraf\workspace\rust\mcp-memory] appDataDir=C:\Users\reazul.ashraf\.gemini\antigravity-cli cascadeManager=true codeAssist=true +I0913 07:26:29.443835 1 auth_provider.go:763] [AuthProvider] SetEnableBusinessLogin called with enable: true +I0913 07:26:29.443835 195 manager.go:100] Migration [MIGRATION_ID_BUILTIN_SIDECARS_TO_PLUGINS] already has status MIGRATION_STATUS_COMPLETED, skipping +I0913 07:26:29.444414 195 manager.go:88] Migration [MIGRATION_ID_LIN_BUILTIN_TO_MARKETPLACE] is disabled, skipping entirely +W0913 07:26:29.463991 226 cache.go:135] Cache(loadCodeAssistResponse): Singleflight refresh failed: error getting token source: You are not logged into Antigravity. +E0913 07:26:29.463991 226 errorreport.go:224] error getting token source: You are not logged into Antigravity. +W0913 07:26:29.465009 226 cache.go:135] Cache(userInfo): Singleflight refresh failed: failed to get load code assist response: error getting token source: You are not logged into Antigravity. +E0913 07:26:29.465009 226 errorreport.go:224] failed to get load code assist response: error getting token source: You are not logged into Antigravity. +I0913 07:26:29.477397 1 project.go:77] project: created project "mcp-memory" (id=266dd20a-ce12-4f25-829b-17b0981db6a6) at C:\Users\reazul.ashraf\.gemini\config\projects\266dd20a-ce12-4f25-829b-17b0981db6a6.json +I0913 07:26:29.477397 1 server.go:2091] Backend project ID updated dynamically to: 266dd20a-ce12-4f25-829b-17b0981db6a6 +I0913 07:26:29.534151 1 analytics.go:179] CLI startup completed (took 581.6895ms) +I0913 07:26:29.534151 1 printmode.go:174] Print mode: starting (promptLength=4, model="", conversationID="") +I0913 07:26:29.534151 1 manager.go:426] Initializing CLI store manager for workspace C:\Users\reazul.ashraf\workspace\rust\mcp-memory +W0913 07:26:29.537427 226 cache.go:135] Cache(loadCodeAssistResponse): Singleflight refresh failed: error getting token source: You are not logged into Antigravity. +E0913 07:26:29.537427 226 errorreport.go:224] error getting token source: You are not logged into Antigravity. +W0913 07:26:29.537427 226 cache.go:135] Cache(userInfo): Singleflight refresh failed: failed to get load code assist response: error getting token source: You are not logged into Antigravity. +E0913 07:26:29.537992 226 errorreport.go:224] failed to get load code assist response: error getting token source: You are not logged into Antigravity. +W0913 07:26:29.537992 226 cache.go:135] Cache(loadCodeAssistResponse): Singleflight refresh failed: error getting token source: You are not logged into Antigravity. +E0913 07:26:29.537992 226 errorreport.go:224] error getting token source: You are not logged into Antigravity. +W0913 07:26:29.537992 226 cache.go:135] Cache(userInfo): Singleflight refresh failed: failed to get load code assist response: error getting token source: You are not logged into Antigravity. +E0913 07:26:29.537992 226 errorreport.go:224] failed to get load code assist response: error getting token source: You are not logged into Antigravity. +I0913 07:26:29.538447 1 cli_setting_manager.go:156] applyUserSettings: no shared config permissions from C:\Users\reazul.ashraf\.gemini\config\config.json +I0913 07:26:29.538447 1 cli_setting_manager.go:92] CLI settings initialized: permissions=&{Allow:[command(wsl.exe) command(wsl.exe -d Ubuntu -e printenv | grep -i google)] Deny:[] Ask:[]}, toolPermission=always-proceed +W0913 07:26:29.538969 226 cache.go:135] Cache(loadCodeAssistResponse): Singleflight refresh failed: error getting token source: You are not logged into Antigravity. +E0913 07:26:29.538969 226 errorreport.go:224] error getting token source: You are not logged into Antigravity. +W0913 07:26:29.538969 226 cache.go:135] Cache(userInfo): Singleflight refresh failed: failed to get load code assist response: error getting token source: You are not logged into Antigravity. +E0913 07:26:29.538969 226 errorreport.go:224] failed to get load code assist response: error getting token source: You are not logged into Antigravity. +I0913 07:26:29.542414 1 hooks_manager.go:53] loaded 0 named hooks from 0 hooks.json file(s) +I0913 07:26:29.542414 1 manager.go:600] CLI store manager initialized successfully +I0913 07:26:29.542414 1 printmode.go:365] Print mode: not authenticated, trying silent auth +I0913 07:26:29.545585 264 keyring.go:64] keyringAuth: loaded token, expiry=2026-09-13 08:17:36.8104589 +0100 BST expired=false +I0913 07:26:29.546294 1 auth.go:148] ChainedAuth: authenticated via keyring (effective: gcp) +I0913 07:26:29.546294 1 server_oauth.go:192] applyAuthResult: email=reazul.ashraf@inseinc.com, authMethod=gcp, quotaProject=inse-r-and-d +I0913 07:26:29.546294 1 server_oauth.go:197] OAuth: authenticated successfully as reazul.ashraf@inseinc.com +I0913 07:26:29.546294 1 server_oauth.go:203] b.codeAssistClient.AuthProvider (0x8c2590420f0) is same as b.cliAuth (0x8c2590420f0) +W0913 07:26:29.554924 271 cache.go:163] Failed to refresh cache in background: admin controls not applicable +W0913 07:26:29.555575 238 cache.go:163] Failed to refresh cache in background: admin controls not applicable +I0913 07:26:29.766407 267 http_helpers.go:299] URL: https://cloudcode-pa.googleapis.com/v1internal:fetchAvailableModels Trace: 0x929b277550fa25b7 +I0913 07:26:29.781984 1 model_config_manager.go:327] Propagating selected model override to backend: label="Gemini 3.1 Pro (Low)" +I0913 07:26:29.781984 1 admin_controls_manager.go:42] Enabling admin controls refresh loop for business account +I0913 07:26:29.781984 1 printmode.go:367] Print mode: silent auth succeeded +I0913 07:26:29.781984 249 quota_manager.go:45] doRefreshQuota: starting reload (force=true) +I0913 07:26:29.781984 250 experiment_manager.go:56] Starting experiment refresh after login +I0913 07:26:29.781984 282 model_config_manager.go:327] Propagating selected model override to backend: label="Gemini 3.1 Pro (Low)" +I0913 07:26:29.782560 249 quota_manager.go:45] doRefreshQuota: starting reload (force=true) +I0913 07:26:29.782560 189 model_config_manager.go:327] Propagating selected model override to backend: label="Gemini 3.1 Pro (Low)" +I0913 07:26:29.782560 249 quota_manager.go:45] doRefreshQuota: starting reload (force=true) +I0913 07:26:29.875679 250 server.go:3637] [RemoteControl] Session toggle is off, staying disconnected +I0913 07:26:29.875679 250 server.go:3348] [RemoteControl] Resolved proxyServerURL: "" +I0913 07:26:29.875679 250 experiment_manager.go:60] Experiments refreshed after login +I0913 07:26:29.875679 250 experiment_manager.go:56] Starting experiment refresh after login +I0913 07:26:29.875679 1 conversation_manager.go:451] Starting new conversation (agent=false) +I0913 07:26:29.875679 1 server.go:1142] Creating new cascade trajectory (agentScript=false) +I0913 07:26:29.875679 1 server.go:1145] Conversation using project ID: 266dd20a-ce12-4f25-829b-17b0981db6a6 +I0913 07:26:29.875679 310 manager.go:1281] Reloading system slash commands +I0913 07:26:29.916916 250 server.go:3637] [RemoteControl] Session toggle is off, staying disconnected +I0913 07:26:29.916916 250 server.go:3348] [RemoteControl] Resolved proxyServerURL: "" +I0913 07:26:29.916916 250 experiment_manager.go:60] Experiments refreshed after login +I0913 07:26:29.916916 140 manager.go:1281] Reloading system slash commands +I0913 07:26:29.926102 140 manager.go:1285] Slash commands unchanged, skipping update +I0913 07:26:29.953728 1 server.go:1177] Created conversation 6830bb37-81b9-4a73-98a9-6629670c6f8f +I0913 07:26:29.954794 1 server.go:3088] GetConversationDetail: found conversation 6830bb37-81b9-4a73-98a9-6629670c6f8f (active=true) +I0913 07:26:29.956348 1 server.go:3088] GetConversationDetail: found conversation 6830bb37-81b9-4a73-98a9-6629670c6f8f (active=true) +I0913 07:26:29.957361 1 conversation_manager.go:498] project: switching to conversation belonging to project ID: 266dd20a-ce12-4f25-829b-17b0981db6a6 +I0913 07:26:29.958879 1 server.go:2091] Backend project ID updated dynamically to: 266dd20a-ce12-4f25-829b-17b0981db6a6 +I0913 07:26:29.958879 1 cli_setting_manager.go:218] ApplyProjectPermissionGrants: no grants for project "mcp-memory", cleared project permissions +I0913 07:26:29.958879 168 manager.go:1304] Reloading system slash commands and skills +I0913 07:26:29.958879 168 manager.go:1281] Reloading system slash commands +I0913 07:26:29.966838 1 hooks_manager.go:53] loaded 0 named hooks from 0 hooks.json file(s) +I0913 07:26:29.967479 1 conversation_manager.go:544] project: synced active project to "mcp-memory" (id=266dd20a-ce12-4f25-829b-17b0981db6a6) from conversation switch +I0913 07:26:29.967479 1 conversation_manager.go:821] Streaming conversation 6830bb37-81b9-4a73-98a9-6629670c6f8f +I0913 07:26:29.967479 323 manager.go:1304] Reloading system slash commands and skills +I0913 07:26:29.967479 323 manager.go:1281] Reloading system slash commands +I0913 07:26:29.968014 1 server.go:3088] GetConversationDetail: found conversation 6830bb37-81b9-4a73-98a9-6629670c6f8f (active=true) +I0913 07:26:29.971692 1 server.go:1186] Starting conversation update stream for 6830bb37-81b9-4a73-98a9-6629670c6f8f +I0913 07:26:29.972274 1 session.go:168] Print mode: conversation=6830bb37-81b9-4a73-98a9-6629670c6f8f, sending message +I0913 07:26:29.972274 1 manager.go:1281] Reloading system slash commands +I0913 07:26:29.976922 168 manager.go:1285] Slash commands unchanged, skipping update +I0913 07:26:29.982877 323 manager.go:1285] Slash commands unchanged, skipping update +I0913 07:26:29.984585 1 manager.go:1285] Slash commands unchanged, skipping update +I0913 07:26:29.984585 1 conversation_manager.go:633] Forwarding user message to conversation 6830bb37-81b9-4a73-98a9-6629670c6f8f (items=1, media=0) +I0913 07:26:29.984585 1 server.go:1745] Sending user message to conversation 6830bb37-81b9-4a73-98a9-6629670c6f8f (items=1, media=0) +I0913 07:26:29.988180 1 latency_breakdown.go:142] SEND_USER_CASCADE_MESSAGE_LATENCY latency breakdown: map[active_user_state_latency_ms:0 blocking:false cascade_id:6830bb37-81b9-4a73-98a9-6629670c6f8f cascade_send_latency_ms:2 hydrate_slash_commands_latency_ms:0 load_trajectory_latency_ms:0 media_count:0 media_summaries_latency_ms:0 message_origin:AGENT_MESSAGE_ORIGIN_UNSPECIFIED refresh_browser_state_latency_ms:0 resolve_agent_config_latency_ms:1 save_media_latency_ms:0 saved_media_count:0 status:OK total_latency_ms:3 trajectory_id:41995427-45da-40eb-9a27-1362ca6cd08f] +I0913 07:26:30.663259 404 http_helpers.go:299] URL: https://aiplatform.googleapis.com/v1/projects/inse-r-and-d/locations/global/publishers/google/models/gemini-3.5-flash-lite:streamGenerateContent?alt=sse ResponseID: FkKmatyWFeXjz_IPhr7YyQ8 +I0913 07:26:59.398063 125 mcp_manager.go:873] MCP: 1 server(s) still connecting after 30s: win-nvim +I0913 07:27:29.398110 125 mcp_manager.go:873] MCP: 1 server(s) still connecting after 1m0s: win-nvim +I0913 07:27:59.398255 125 mcp_manager.go:873] MCP: 1 server(s) still connecting after 1m30s: win-nvim +I0913 07:28:29.398626 125 mcp_manager.go:873] MCP: 1 server(s) still connecting after 2m0s: win-nvim +I0913 07:28:59.399114 125 mcp_manager.go:873] MCP: 1 server(s) still connecting after 2m30s: win-nvim diff --git a/win-nvim/Cargo.toml b/win-nvim/Cargo.toml index ad845f5..6d60e5e 100644 --- a/win-nvim/Cargo.toml +++ b/win-nvim/Cargo.toml @@ -10,3 +10,7 @@ rmp-serde = "1.1" rmpv = "1.0" tokio = { version = "1.37", features = ["full"] } schemars = "0.8" +tracing-appender = "0.2.5" +tracing = "0.1.44" +tracing-subscriber = "0.3.23" +dirs = "7.0.0" diff --git a/win-nvim/src/main.rs b/win-nvim/src/main.rs index d2e6f3b..84ceb58 100644 --- a/win-nvim/src/main.rs +++ b/win-nvim/src/main.rs @@ -5,16 +5,50 @@ use serde_json::json; use tokio::net::windows::named_pipe::ClientOptions; use tokio::io::{AsyncReadExt, AsyncWriteExt}; +fn init_logging(app_name: &str) -> Option { + let base_dir = std::env::var("MCP_MEMORY_STORE_DIR").unwrap_or_else(|_| { + dirs::home_dir() + .map(|mut h| { + h.push(".gemini/mcp_memory"); + h.to_string_lossy().to_string() + }) + .unwrap_or_else(|| ".gemini/mcp_memory".into()) + }); + let log_dir = std::path::PathBuf::from(base_dir).join("logs"); + std::fs::create_dir_all(&log_dir).unwrap_or_default(); + + let file_appender = tracing_appender::rolling::daily(log_dir, format!("{}.log", app_name)); + let (non_blocking, guard) = tracing_appender::non_blocking(file_appender); + + let _ = tracing_subscriber::fmt() + .with_writer(non_blocking) + .with_ansi(false) + .with_max_level(tracing::Level::INFO) + .try_init(); + + Some(guard) +} + #[tokio::main] async fn main() { + let _guard = init_logging("win-nvim"); + tracing::info!("win-nvim MCP server started"); + let mut stdin = tokio::io::BufReader::new(tokio::io::stdin()); loop { - let msg = match read_message().await { - Some(m) => m, - None => break, + let msg = match read_message(&mut stdin).await { + Some(m) => { + tracing::info!("Received message method: {}", m.method); + m + }, + None => { + tracing::info!("Stdin closed, exiting loop"); + break; + } }; tokio::spawn(async move { let id = msg.id.clone().unwrap_or(json!(null)); + let start_time = std::time::Instant::now(); match msg.method.as_str() { "initialize" => { @@ -84,6 +118,33 @@ async fn main() { }, "required": ["line", "message"] } + }, + { + "name": "nvim_execute_lua", + "description": "Execute arbitrary Lua code in Neovim and return the result (JSON serialized).", + "inputSchema": { + "type": "object", + "properties": { + "code": { "type": "string" } + }, + "required": ["code"] + } + }, + { + "name": "nvim_list_buffers", + "description": "Get a list of all loaded Neovim buffers and their IDs.", + "inputSchema": { + "type": "object", + "properties": {} + } + }, + { + "name": "nvim_get_diagnostics", + "description": "Get all LSP diagnostics (errors, warnings) for the active buffer.", + "inputSchema": { + "type": "object", + "properties": {} + } } ] })), @@ -198,6 +259,62 @@ async fn main() { } } } + + "nvim_execute_lua" => { + let code = args.get("code").and_then(|v| v.as_str()).unwrap_or(""); + match execute_nvim_lua(code).await { + Ok(content) => { + send_response(JsonRpcResponse { + jsonrpc: "2.0".to_string(), id, result: Some(json!({ "content": [{ "type": "text", "text": content }] })), error: None, + }).await; + } + Err(e) => { send_error(id, -32603, &format!("Failed to execute lua: {}", e)).await; } + } + } + "nvim_list_buffers" => { + let code = r#" + local bufs = vim.api.nvim_list_bufs() + local loaded = {} + for _, b in ipairs(bufs) do + if vim.api.nvim_buf_is_loaded(b) then + local name = vim.api.nvim_buf_get_name(b) + table.insert(loaded, {id = b, name = name == "" and "[No Name]" or name}) + end + end + return loaded + "#; + match execute_nvim_lua(code).await { + Ok(content) => { + send_response(JsonRpcResponse { + jsonrpc: "2.0".to_string(), id, result: Some(json!({ "content": [{ "type": "text", "text": content }] })), error: None, + }).await; + } + Err(e) => { send_error(id, -32603, &format!("Failed to list buffers: {}", e)).await; } + } + } + "nvim_get_diagnostics" => { + let code = r#" + local diags = vim.diagnostic.get(0) + local res = {} + for _, d in ipairs(diags) do + table.insert(res, { + line = d.lnum + 1, + col = d.col, + message = d.message, + severity = d.severity + }) + end + return res + "#; + match execute_nvim_lua(code).await { + Ok(content) => { + send_response(JsonRpcResponse { + jsonrpc: "2.0".to_string(), id, result: Some(json!({ "content": [{ "type": "text", "text": content }] })), error: None, + }).await; + } + Err(e) => { send_error(id, -32603, &format!("Failed to get diagnostics: {}", e)).await; } + } + } _ => { send_error(id, -32601, "Tool not found").await; } @@ -242,11 +359,13 @@ async fn call_nvim(req: rmpv::Value) -> Result { if arr.len() > 1 { arr[1].clone() } else { rmpv::Value::Nil } } else { rmpv::Value::Nil }; + tracing::info!("Connecting to neovim pipe"); let socket_path = get_socket_path().await?; let mut client = ClientOptions::new().open(&socket_path).map_err(|e| e.to_string())?; let mut buf = Vec::new(); rmpv::encode::write_value(&mut buf, &req).map_err(|e| e.to_string())?; + tracing::info!("Sending RPC request to neovim (msgid: {})", msgid); client.write_all(&buf).await.map_err(|e| e.to_string())?; let mut resp_buf = Vec::new(); @@ -261,17 +380,25 @@ async fn call_nvim(req: rmpv::Value) -> Result { if let rmpv::Value::Array(ref arr) = val { if arr.len() >= 4 && arr[0] == rmpv::Value::Integer(1.into()) && arr[1] == msgid { + tracing::info!("Received RPC response from neovim (msgid: {})", msgid); return Ok(val); } } continue; }, Err(_) => { - let n = client.read(&mut chunk).await.map_err(|e| e.to_string())?; - if n == 0 { - return Err("Unexpected EOF from Neovim".to_string()); + let read_future = client.read(&mut chunk); + match tokio::time::timeout(tokio::time::Duration::from_secs(5), read_future).await { + Ok(Ok(n)) => { + if n == 0 { return Err("Connection closed".into()); } + resp_buf.extend_from_slice(&chunk[..n]); + } + Ok(Err(e)) => return Err(e.to_string()), + Err(_) => { + tracing::error!("Timeout waiting for Neovim response (msgid: {})", msgid); + return Err("Timeout waiting for Neovim response".into()); + } } - resp_buf.extend_from_slice(&chunk[..n]); } } } @@ -428,3 +555,70 @@ async fn set_nvim_diagnostics(line: i64, message: &str) -> Result<(), String> { } Err("Invalid response".to_string()) } + +fn rmpv_to_json(val: &rmpv::Value) -> serde_json::Value { + match val { + rmpv::Value::Nil => serde_json::Value::Null, + rmpv::Value::Boolean(b) => serde_json::json!(b), + rmpv::Value::Integer(i) => { + if let Some(n) = i.as_i64() { + serde_json::json!(n) + } else if let Some(n) = i.as_u64() { + serde_json::json!(n) + } else { + serde_json::Value::Null + } + }, + rmpv::Value::F32(f) => serde_json::json!(f), + rmpv::Value::F64(f) => serde_json::json!(f), + rmpv::Value::String(s) => { + if let Some(str_val) = s.as_str() { + serde_json::json!(str_val) + } else { + serde_json::Value::Null + } + }, + rmpv::Value::Array(arr) => { + let vec: Vec = arr.iter().map(rmpv_to_json).collect(); + serde_json::Value::Array(vec) + }, + rmpv::Value::Map(map) => { + let mut obj = serde_json::Map::new(); + for (k, v) in map { + let key_str = if let rmpv::Value::String(s) = k { + s.as_str().unwrap_or("").to_string() + } else { + format!("{:?}", k) + }; + obj.insert(key_str, rmpv_to_json(v)); + } + serde_json::Value::Object(obj) + }, + _ => serde_json::json!(format!("{:?}", val)), + } +} + +async fn execute_nvim_lua(code: &str) -> Result { + use rmpv::Value as RmpValue; + let req = RmpValue::Array(vec![ + RmpValue::Integer(0.into()), + RmpValue::Integer(6.into()), // msgid + RmpValue::String("nvim_exec_lua".into()), + RmpValue::Array(vec![ + RmpValue::String(code.into()), + RmpValue::Array(vec![]), + ]), + ]); + + let resp = call_nvim(req).await?; + if let RmpValue::Array(arr) = resp { + if !arr[2].is_nil() { + return Err(format!("Neovim error: {:?}", arr[2])); + } + if arr.len() > 3 { + return Ok(serde_json::to_string_pretty(&rmpv_to_json(&arr[3])).unwrap_or_default()); + } + return Ok("".to_string()); + } + Err("Invalid response".to_string()) +} diff --git a/win-nvim/src/mcp.rs b/win-nvim/src/mcp.rs index 51c7421..4c33a65 100644 --- a/win-nvim/src/mcp.rs +++ b/win-nvim/src/mcp.rs @@ -20,8 +20,7 @@ pub struct JsonRpcResponse { pub error: Option, } -pub async fn read_message() -> Option { - let mut stdin = BufReader::new(tokio::io::stdin()); +pub async fn read_message(stdin: &mut BufReader) -> Option { let mut length = 0; loop { let mut line = String::new();