feat(setup): auto-detect npx path during installation
The setup wizard now auto-detects the npx/npx.cmd path via `which npx` (Unix) or `where npx.cmd` (Windows) and writes it to [browser].node_path in config.toml. Changes: - detect_npx_path(): cross-platform detection using which/where - SerializedConfig now includes optional [browser] section - Flat config parser (main.rs) handles [browser] section - browser: BrowserSection threaded through AgentConfig everywhere - init_browser() accepts node_path parameter with proper fallback
This commit is contained in:
@@ -424,6 +424,8 @@ fn write_config_file(config: &ProviderConfig) -> anyhow::Result<PathBuf> {
|
||||
struct SerializedConfig {
|
||||
provider: SerializedProvider,
|
||||
agent: SerializedAgent,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
browser: Option<SerializedBrowser>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
@@ -445,10 +447,46 @@ struct SerializedAgent {
|
||||
name: String,
|
||||
}
|
||||
|
||||
/// Serializable [browser] section for TOML output.
|
||||
#[derive(Serialize)]
|
||||
struct SerializedBrowser {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
node_path: Option<String>,
|
||||
}
|
||||
|
||||
fn is_false(v: &bool) -> bool {
|
||||
!v
|
||||
}
|
||||
|
||||
/// Auto-detect the path to npx/npx.cmd.
|
||||
///
|
||||
/// Tries `which npx` on Unix, `where npx.cmd` on Windows.
|
||||
/// Returns `None` if not found on PATH.
|
||||
fn detect_npx_path() -> Option<String> {
|
||||
let (prog, arg) = if cfg!(target_os = "windows") {
|
||||
("where", "npx.cmd")
|
||||
} else {
|
||||
("which", "npx")
|
||||
};
|
||||
|
||||
std::process::Command::new(prog)
|
||||
.arg(arg)
|
||||
.output()
|
||||
.ok()
|
||||
.and_then(|out| {
|
||||
if out.status.success() {
|
||||
let path = String::from_utf8_lossy(&out.stdout)
|
||||
.lines()
|
||||
.next()?
|
||||
.trim()
|
||||
.to_string();
|
||||
if !path.is_empty() { Some(path) } else { None }
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
impl From<&ProviderConfig> for SerializedConfig {
|
||||
fn from(c: &ProviderConfig) -> Self {
|
||||
let kind_str = match c.kind {
|
||||
@@ -475,6 +513,9 @@ impl From<&ProviderConfig> for SerializedConfig {
|
||||
agent: SerializedAgent {
|
||||
name: "gyandoot".to_string(),
|
||||
},
|
||||
browser: detect_npx_path().map(|np| SerializedBrowser {
|
||||
node_path: Some(np),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
13
src/main.rs
13
src/main.rs
@@ -293,6 +293,8 @@ fn load_and_convert_config(path: &std::path::Path) -> Result<gyandoot_core::conf
|
||||
struct FlatConfig {
|
||||
provider: FlatProvider,
|
||||
agent: Option<FlatAgent>,
|
||||
#[serde(default)]
|
||||
browser: Option<FlatBrowser>,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
@@ -316,6 +318,12 @@ fn load_and_convert_config(path: &std::path::Path) -> Result<gyandoot_core::conf
|
||||
name: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
struct FlatBrowser {
|
||||
#[serde(default)]
|
||||
node_path: Option<String>,
|
||||
}
|
||||
|
||||
let flat: FlatConfig = toml::from_str(&content)?;
|
||||
tracing::info!("Loaded config from {} (converted from flat [provider] format)", path.display());
|
||||
|
||||
@@ -346,7 +354,10 @@ fn load_and_convert_config(path: &std::path::Path) -> Result<gyandoot_core::conf
|
||||
platform: gyandoot_core::config::PlatformSection::default(),
|
||||
memory: gyandoot_core::config::MemorySection::default(),
|
||||
gateway: gyandoot_core::config::GatewaySection::default(),
|
||||
browser: gyandoot_core::config::BrowserSection::default(),
|
||||
browser: gyandoot_core::config::BrowserSection {
|
||||
node_path: flat.browser.and_then(|b| b.node_path),
|
||||
..gyandoot_core::config::BrowserSection::default()
|
||||
},
|
||||
};
|
||||
|
||||
Ok(gyandoot_core::config::AgentConfig::from(gyandoot_cfg))
|
||||
|
||||
Reference in New Issue
Block a user