Fleet tools: add Rust version card (probe rustc + nightly latest + rustup update)
Adds Rust to the per-node dev-tool cards: daemon probes rustc → reports 'rust'; nightly checker fetches latest stable from GitHub rust-lang/rust; GET endpoint maps rust→Rust (after docker); one-click update runs 'rustup update stable'. Frontend is data-driven (no change). $HOME/.cargo/bin added to probe candidate dirs. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
96d1409a23
commit
1a531e91cd
@@ -216,14 +216,23 @@ fn probe_tools() -> Value {
|
|||||||
"/usr/bin".to_string(),
|
"/usr/bin".to_string(),
|
||||||
"/bin".to_string(),
|
"/bin".to_string(),
|
||||||
format!("{home}/.local/share/uv/tools/kimi-cli/bin"),
|
format!("{home}/.local/share/uv/tools/kimi-cli/bin"),
|
||||||
|
format!("{home}/.cargo/bin"),
|
||||||
];
|
];
|
||||||
let mut out = serde_json::Map::new();
|
let mut out = serde_json::Map::new();
|
||||||
for tool in ["docker", "claude", "kimi-cli", "ollama"] {
|
// (report key, binary name) — usually identical; Rust reports "rust" but its
|
||||||
|
// binary is `rustc`.
|
||||||
|
for (key, bin) in [
|
||||||
|
("docker", "docker"),
|
||||||
|
("claude", "claude"),
|
||||||
|
("kimi-cli", "kimi-cli"),
|
||||||
|
("ollama", "ollama"),
|
||||||
|
("rust", "rustc"),
|
||||||
|
] {
|
||||||
for d in &dirs {
|
for d in &dirs {
|
||||||
let p = std::path::Path::new(d).join(tool);
|
let p = std::path::Path::new(d).join(bin);
|
||||||
if p.exists() {
|
if p.exists() {
|
||||||
if let Some(v) = tool_version(&p) {
|
if let Some(v) = tool_version(&p) {
|
||||||
out.insert(tool.to_string(), Value::String(v));
|
out.insert(key.to_string(), Value::String(v));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -309,6 +318,14 @@ async fn update_tool(tool: &str) -> (bool, String) {
|
|||||||
c
|
c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
"rust" => match find("rustup") {
|
||||||
|
Some(p) => {
|
||||||
|
let mut c = tokio::process::Command::new(p);
|
||||||
|
c.args(["update", "stable"]);
|
||||||
|
c
|
||||||
|
}
|
||||||
|
None => return (false, "rustup not found".into()),
|
||||||
|
},
|
||||||
_ => return (false, "unsupported tool".into()),
|
_ => return (false, "unsupported tool".into()),
|
||||||
};
|
};
|
||||||
match tokio::time::timeout(Duration::from_secs(170), cmd.output()).await {
|
match tokio::time::timeout(Duration::from_secs(170), cmd.output()).await {
|
||||||
|
|||||||
@@ -199,6 +199,7 @@ pub async fn tools(
|
|||||||
// (probe key, display name, ui key) in display order; `glm` mirrors `claude`.
|
// (probe key, display name, ui key) in display order; `glm` mirrors `claude`.
|
||||||
let order = [
|
let order = [
|
||||||
("docker", "Docker", "docker"),
|
("docker", "Docker", "docker"),
|
||||||
|
("rust", "Rust", "rust"),
|
||||||
("claude", "Claude Code", "claude"),
|
("claude", "Claude Code", "claude"),
|
||||||
("kimi-cli", "Kimi", "kimi"),
|
("kimi-cli", "Kimi", "kimi"),
|
||||||
("glm", "GLM (Claude Code)", "glm"),
|
("glm", "GLM (Claude Code)", "glm"),
|
||||||
@@ -230,7 +231,7 @@ pub async fn tool_update(
|
|||||||
nodes::get(&state.pool, node_id, user.workspace_id)
|
nodes::get(&state.pool, node_id, user.workspace_id)
|
||||||
.await?
|
.await?
|
||||||
.ok_or(ApiError::NotFound)?;
|
.ok_or(ApiError::NotFound)?;
|
||||||
if !["claude", "glm", "kimi", "ollama"].contains(&tool.as_str()) {
|
if !["claude", "glm", "kimi", "ollama", "rust"].contains(&tool.as_str()) {
|
||||||
return Ok(Json(json!({ "ok": false, "output": "tool not updatable" })));
|
return Ok(Json(json!({ "ok": false, "output": "tool not updatable" })));
|
||||||
}
|
}
|
||||||
// ~180s: tool updates (npm/uv/brew/installer) legitimately run long.
|
// ~180s: tool updates (npm/uv/brew/installer) legitimately run long.
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ use serde_json::Value;
|
|||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
|
|
||||||
/// Fetch the latest version of each checkable tool and upsert `tool_latest`.
|
/// Fetch the latest version of each checkable tool and upsert `tool_latest`.
|
||||||
/// Stored under the same keys the daemon reports (`claude`, `kimi-cli`, `ollama`).
|
/// Stored under the same keys the daemon reports (`claude`, `kimi-cli`, `ollama`,
|
||||||
|
/// `rust`).
|
||||||
async fn check(pool: &PgPool, client: &reqwest::Client) {
|
async fn check(pool: &PgPool, client: &reqwest::Client) {
|
||||||
// Claude Code — the npm package's latest dist-tag.
|
// Claude Code — the npm package's latest dist-tag.
|
||||||
if let Some(v) = fetch_field(
|
if let Some(v) = fetch_field(
|
||||||
@@ -42,6 +43,16 @@ async fn check(pool: &PgPool, client: &reqwest::Client) {
|
|||||||
{
|
{
|
||||||
let _ = node_tools::set_latest(pool, "ollama", v.trim_start_matches('v')).await;
|
let _ = node_tools::set_latest(pool, "ollama", v.trim_start_matches('v')).await;
|
||||||
}
|
}
|
||||||
|
// Rust — latest stable, from the rust-lang/rust GitHub release tag.
|
||||||
|
if let Some(v) = fetch_field(
|
||||||
|
client,
|
||||||
|
"https://api.github.com/repos/rust-lang/rust/releases/latest",
|
||||||
|
&["tag_name"],
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
let _ = node_tools::set_latest(pool, "rust", v.trim_start_matches('v')).await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// GET `url` as JSON and read a (possibly nested) string field by `path`.
|
/// GET `url` as JSON and read a (possibly nested) string field by `path`.
|
||||||
|
|||||||
Reference in New Issue
Block a user