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 {
|
struct SerializedConfig {
|
||||||
provider: SerializedProvider,
|
provider: SerializedProvider,
|
||||||
agent: SerializedAgent,
|
agent: SerializedAgent,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
browser: Option<SerializedBrowser>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
@@ -445,10 +447,46 @@ struct SerializedAgent {
|
|||||||
name: String,
|
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 {
|
fn is_false(v: &bool) -> bool {
|
||||||
!v
|
!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 {
|
impl From<&ProviderConfig> for SerializedConfig {
|
||||||
fn from(c: &ProviderConfig) -> Self {
|
fn from(c: &ProviderConfig) -> Self {
|
||||||
let kind_str = match c.kind {
|
let kind_str = match c.kind {
|
||||||
@@ -475,6 +513,9 @@ impl From<&ProviderConfig> for SerializedConfig {
|
|||||||
agent: SerializedAgent {
|
agent: SerializedAgent {
|
||||||
name: "gyandoot".to_string(),
|
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 {
|
struct FlatConfig {
|
||||||
provider: FlatProvider,
|
provider: FlatProvider,
|
||||||
agent: Option<FlatAgent>,
|
agent: Option<FlatAgent>,
|
||||||
|
#[serde(default)]
|
||||||
|
browser: Option<FlatBrowser>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
@@ -316,6 +318,12 @@ fn load_and_convert_config(path: &std::path::Path) -> Result<gyandoot_core::conf
|
|||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Deserialize)]
|
||||||
|
struct FlatBrowser {
|
||||||
|
#[serde(default)]
|
||||||
|
node_path: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
let flat: FlatConfig = toml::from_str(&content)?;
|
let flat: FlatConfig = toml::from_str(&content)?;
|
||||||
tracing::info!("Loaded config from {} (converted from flat [provider] format)", path.display());
|
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(),
|
platform: gyandoot_core::config::PlatformSection::default(),
|
||||||
memory: gyandoot_core::config::MemorySection::default(),
|
memory: gyandoot_core::config::MemorySection::default(),
|
||||||
gateway: gyandoot_core::config::GatewaySection::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))
|
Ok(gyandoot_core::config::AgentConfig::from(gyandoot_cfg))
|
||||||
|
|||||||
Reference in New Issue
Block a user