- #65: update policies + per-agent version pinning - add settings.update_policy (stable/latest/skip) - add AgentDef.pin_version - honor both in update_cmd - add update_policy tests - #69: REPL color theme CLI command - add am theme [name] (show/switch) - persist selected theme to config - #72: doctor checks local model runtimes - verify ollama and llama-server on PATH - for ollama, also check server responds (ollama ls) Version 0.4.4
This commit is contained in:
+3
-1
@@ -28,6 +28,7 @@ pub mod sessions_cmd;
|
||||
pub mod stats_cmd;
|
||||
pub mod self_update;
|
||||
pub mod status_cmd;
|
||||
pub mod theme_cmd;
|
||||
pub mod timeline_cmd;
|
||||
pub mod tip_cmd;
|
||||
pub mod uninstall_cmd;
|
||||
@@ -37,7 +38,7 @@ pub mod version_cmd;
|
||||
|
||||
use crate::app::App;
|
||||
use crate::cli::Command;
|
||||
use crate::config::{AgentDef, MethodSpec};
|
||||
use crate::config::{AgentDef, MethodSpec, UpdatePolicy};
|
||||
use crate::state::InstalledEntry;
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use std::collections::BTreeMap;
|
||||
@@ -164,6 +165,7 @@ pub fn execute_command(app: &App, cmd: &Command) -> Result<i32> {
|
||||
Command::Version => version_cmd::run(app),
|
||||
Command::Tip { random } => tip_cmd::run(app, *random),
|
||||
Command::Config(sub) => config_cmd::run(app, sub),
|
||||
Command::Theme { name } => theme_cmd::run(app, name.as_deref()),
|
||||
Command::Doctor { fix } => doctor_cmd::run(app, *fix),
|
||||
Command::Run { agent, args } => run_cmd::run(app, agent, args),
|
||||
Command::Completion { shell, installed } => completion_cmd::run(*shell, *installed),
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
//! theme: switch the active color theme and persist it for the next start.
|
||||
//!
|
||||
//! With no argument, prints the current theme and the available list.
|
||||
//! With a name, switches to that theme (also used by the REPL 'theme' command).
|
||||
|
||||
use super::*;
|
||||
use crate::theme;
|
||||
|
||||
pub fn run(app: &App, name: Option<&str>) -> Result<i32> {
|
||||
if let Some(name) = name {
|
||||
let theme = theme::find(name).ok_or_else(|| {
|
||||
anyhow::anyhow!(
|
||||
"unknown theme '{name}' — available: {}",
|
||||
theme::names().join(", ")
|
||||
)
|
||||
})?;
|
||||
app.set_theme(theme);
|
||||
crate::commands::config_cmd::persist_setting(app, "settings.theme", theme.name)?;
|
||||
app.log.success(&format!(
|
||||
"theme set to {} ({})",
|
||||
theme.name,
|
||||
theme.title
|
||||
));
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
// No argument: show current and list.
|
||||
let current = app.theme();
|
||||
if app.json() {
|
||||
crate::output::print_json(&serde_json::json!({
|
||||
"current": current.name,
|
||||
"title": current.title,
|
||||
"available": theme::names(),
|
||||
}));
|
||||
} else {
|
||||
println!("current theme: {} — {}", current.name, current.title);
|
||||
println!("available themes: {}", theme::names().join(", "));
|
||||
println!("use 'am theme <name>' to switch");
|
||||
}
|
||||
Ok(0)
|
||||
}
|
||||
@@ -11,7 +11,17 @@ use std::path::PathBuf;
|
||||
|
||||
pub fn run(app: &App, agent_name: Option<&str>, all: bool) -> Result<i32> {
|
||||
let runner = SystemRunner::new(app.dry_run(), app.cli.verbose, &app.log);
|
||||
|
||||
let policy = app.config.settings.update_policy.unwrap_or_default();
|
||||
if policy == UpdatePolicy::None && all {
|
||||
app.log.warn("update policy is 'none'; 'am update --all' is a no-op");
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
if let Some(name) = agent_name {
|
||||
if policy == UpdatePolicy::None && !app.yes() {
|
||||
app.log.warn("update policy is 'none'; use --yes to force a single-agent update");
|
||||
}
|
||||
return update_one(app, &runner, name);
|
||||
}
|
||||
if all {
|
||||
@@ -31,6 +41,30 @@ pub fn run(app: &App, agent_name: Option<&str>, all: bool) -> Result<i32> {
|
||||
|
||||
fn update_one(app: &App, runner: &dyn Runner, name: &str) -> Result<i32> {
|
||||
let agent = require_agent(app, name)?;
|
||||
|
||||
// Issue #65: honor per-agent pinned version.
|
||||
if let Some(pin) = agent.pin_version.as_deref() {
|
||||
let current = app
|
||||
.state
|
||||
.get(&agent.name)
|
||||
.ok()
|
||||
.flatten()
|
||||
.and_then(|e| e.version.clone());
|
||||
if current.as_deref() == Some(pin) {
|
||||
app.log.success(&format!(
|
||||
"{} is pinned to v{pin} and already at that version",
|
||||
agent.title()
|
||||
));
|
||||
} else {
|
||||
app.log.warn(&format!(
|
||||
"{} is pinned to v{pin} but currently at {}; update skipped",
|
||||
agent.title(),
|
||||
current.as_deref().unwrap_or("unknown")
|
||||
));
|
||||
}
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
let Some(entry) = app.state.get(&agent.name).ok().flatten() else {
|
||||
bail!(
|
||||
"agent '{}' is not installed by agent-manager — use 'am install {}'",
|
||||
|
||||
Reference in New Issue
Block a user