refactor(v2): unify sidecar to single agent-runner.mjs bundle

Consolidated from two separate runners (agent-runner-deno.ts +
agent-runner.ts) to a single pre-built agent-runner.mjs that runs
under both Deno and Node.js. resolve_sidecar_command() now checks
runtime availability upfront before path search, with improved
error messages. Removed agent-runner-deno.ts from tauri.conf.json
bundled resources.
This commit is contained in:
Hibryda 2026-03-07 01:07:06 +01:00
parent 658dc4715e
commit 2409642925
2 changed files with 37 additions and 31 deletions

View file

@ -1,5 +1,5 @@
// Sidecar lifecycle management (Deno-first, Node.js fallback) // Sidecar lifecycle management (Deno-first, Node.js fallback)
// Spawns agent-runner-deno.ts (or agent-runner.mjs), communicates via stdio NDJSON // Spawns bundled agent-runner.mjs via deno or node, communicates via stdio NDJSON
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::io::{BufRead, BufReader, Write}; use std::io::{BufRead, BufReader, Write};
@ -207,14 +207,27 @@ impl SidecarManager {
} }
fn resolve_sidecar_command(&self) -> Result<SidecarCommand, String> { fn resolve_sidecar_command(&self) -> Result<SidecarCommand, String> {
let mut checked_deno = Vec::new(); // Single bundled .mjs works with both Deno and Node.js.
let mut checked_node = Vec::new(); // Try Deno first (faster startup, better perf), fall back to Node.js.
let has_deno = Command::new("deno")
.arg("--version")
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.is_ok();
let has_node = Command::new("node")
.arg("--version")
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.is_ok();
let mut checked = Vec::new();
// Try Deno first in each search path
for base in &self.config.search_paths { for base in &self.config.search_paths {
let deno_path = base.join("agent-runner-deno.ts"); let mjs_path = base.join("dist").join("agent-runner.mjs");
if deno_path.exists() { if mjs_path.exists() {
if Command::new("deno").arg("--version").output().is_ok() { if has_deno {
return Ok(SidecarCommand { return Ok(SidecarCommand {
program: "deno".to_string(), program: "deno".to_string(),
args: vec![ args: vec![
@ -224,36 +237,30 @@ impl SidecarManager {
"--allow-read".to_string(), "--allow-read".to_string(),
"--allow-write".to_string(), "--allow-write".to_string(),
"--allow-net".to_string(), "--allow-net".to_string(),
deno_path.to_string_lossy().to_string(), mjs_path.to_string_lossy().to_string(),
], ],
}); });
} }
log::warn!( if has_node {
"Deno sidecar found at {} but deno not in PATH, falling back to Node.js", return Ok(SidecarCommand {
deno_path.display() program: "node".to_string(),
); args: vec![mjs_path.to_string_lossy().to_string()],
});
}
} }
checked_deno.push(deno_path); checked.push(mjs_path);
} }
// Fallback to Node.js let paths: Vec<_> = checked.iter().map(|p| p.display().to_string()).collect();
for base in &self.config.search_paths { let runtime_note = if !has_deno && !has_node {
let node_path = base.join("dist").join("agent-runner.mjs"); ". Neither deno nor node found in PATH"
if node_path.exists() { } else {
return Ok(SidecarCommand { ""
program: "node".to_string(), };
args: vec![node_path.to_string_lossy().to_string()],
});
}
checked_node.push(node_path);
}
let deno_list: Vec<_> = checked_deno.iter().map(|p| p.display().to_string()).collect();
let node_list: Vec<_> = checked_node.iter().map(|p| p.display().to_string()).collect();
Err(format!( Err(format!(
"Sidecar not found. Checked Deno ({}) and Node.js ({})", "Sidecar not found. Checked: {}{}",
deno_list.join(", "), paths.join(", "),
node_list.join(", "), runtime_note,
)) ))
} }
} }

View file

@ -44,7 +44,6 @@
"icons/icon.ico" "icons/icon.ico"
], ],
"resources": [ "resources": [
"../sidecar/agent-runner-deno.ts",
"../sidecar/dist/agent-runner.mjs" "../sidecar/dist/agent-runner.mjs"
], ],
"category": "DeveloperTool", "category": "DeveloperTool",