feat(embedding,vision): candle embeddings with offline fallback, on-demand clipboard vision capture, and concurrency audit
This commit is contained in:
1 parent
5bd8b1587a
commit
e4a0fe72df
47 files changed
+6292
-3503
No files matched your search
+58
-12
@@ -1,11 +1,12 @@
|
||||
use std::sync::Arc;
|
||||
use std::sync::LazyLock;
|
||||
use tokio::io::AsyncBufReadExt;
|
||||
|
||||
pub static ACTIVE_SOCKET: LazyLock<Arc<std::sync::Mutex<Option<String>>>> =
|
||||
LazyLock::new(|| Arc::new(std::sync::Mutex::new(None)));
|
||||
pub static ACTIVE_SOCKET: LazyLock<Arc<tokio::sync::Mutex<Option<String>>>> =
|
||||
LazyLock::new(|| Arc::new(tokio::sync::Mutex::new(None)));
|
||||
|
||||
pub static HEADLESS_PROC: LazyLock<Arc<std::sync::Mutex<Option<tokio::process::Child>>>> =
|
||||
LazyLock::new(|| Arc::new(std::sync::Mutex::new(None)));
|
||||
pub static HEADLESS_PROC: LazyLock<Arc<tokio::sync::Mutex<Option<tokio::process::Child>>>> =
|
||||
LazyLock::new(|| Arc::new(tokio::sync::Mutex::new(None)));
|
||||
|
||||
pub async fn spawn_headless_nvim() -> Result<String, String> {
|
||||
if std::process::Command::new("nvim")
|
||||
@@ -17,25 +18,71 @@ pub async fn spawn_headless_nvim() -> Result<String, String> {
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
let socket_name = format!(r"\\.\pipe\agy-headless-nvim-{}", std::process::id());
|
||||
let socket_name = format!(
|
||||
r"\\.\pipe\agy-headless-nvim-{}-{}",
|
||||
std::process::id(),
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.map(|d| d.as_nanos())
|
||||
.unwrap_or(0)
|
||||
);
|
||||
#[cfg(unix)]
|
||||
let socket_name = format!("/tmp/agy-headless-nvim-{}.sock", std::process::id());
|
||||
let socket_name = format!(
|
||||
"/tmp/agy-headless-nvim-{}-{}.sock",
|
||||
std::process::id(),
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.map(|d| d.as_nanos())
|
||||
.unwrap_or(0)
|
||||
);
|
||||
|
||||
let child = tokio::process::Command::new("nvim")
|
||||
let mut child = tokio::process::Command::new("nvim")
|
||||
.arg("--headless")
|
||||
.arg("--listen")
|
||||
.arg(&socket_name)
|
||||
.arg("--cmd")
|
||||
.arg("lua vim.schedule(function() io.stdout:write('READY\\n') io.stdout:flush() end)")
|
||||
.stdin(std::process::Stdio::piped())
|
||||
.stdout(std::process::Stdio::null())
|
||||
.stdout(std::process::Stdio::piped())
|
||||
.stderr(std::process::Stdio::null())
|
||||
.kill_on_drop(true)
|
||||
.spawn()
|
||||
.map_err(|e| format!("Failed to spawn headless Neovim: {}", e))?;
|
||||
|
||||
tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await;
|
||||
if let Some(stdout) = child.stdout.take() {
|
||||
let mut reader = tokio::io::BufReader::new(stdout);
|
||||
let mut ready_line = String::new();
|
||||
match tokio::time::timeout(
|
||||
tokio::time::Duration::from_millis(2000),
|
||||
reader.read_line(&mut ready_line),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(Ok(_)) => {
|
||||
if ready_line.trim() != "READY" {
|
||||
let _ = child.kill().await;
|
||||
return Err(format!(
|
||||
"Headless Neovim child output unexpected banner: {:?}",
|
||||
ready_line
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(Err(e)) => {
|
||||
let _ = child.kill().await;
|
||||
return Err(format!(
|
||||
"Failed to read readiness from headless Neovim: {}",
|
||||
e
|
||||
));
|
||||
}
|
||||
Err(_) => {
|
||||
let _ = child.kill().await;
|
||||
return Err("Timeout waiting for headless Neovim to become ready".to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let old_child = {
|
||||
let mut lock = HEADLESS_PROC.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let mut lock = HEADLESS_PROC.lock().await;
|
||||
let old = lock.take();
|
||||
*lock = Some(child);
|
||||
old
|
||||
@@ -50,7 +97,7 @@ pub async fn spawn_headless_nvim() -> Result<String, String> {
|
||||
|
||||
pub async fn kill_headless_nvim() {
|
||||
let child_to_kill = {
|
||||
let mut proc_lock = HEADLESS_PROC.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let mut proc_lock = HEADLESS_PROC.lock().await;
|
||||
proc_lock.take()
|
||||
};
|
||||
if let Some(mut child) = child_to_kill {
|
||||
@@ -71,4 +118,3 @@ mod tests {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user