diff --git a/README.md b/README.md index 0ea2b86..afdab70 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,6 @@ Coming from [AIChat](https://github.com/sigoden/aichat)? Follow the [migration g homepage: https://github.com/example/oh-my-coyote # optional ``` * `coyote --install-builtins ` reinstalls Coyote's bundled assets for a category, overwriting any local changes (built-in assets are not bundles). - * The old `--install-from ` flag still works but is deprecated; use `--install` instead. * [REPL](https://github.com/Dark-Alex-17/coyote/wiki/REPL): Interactive Read-Eval-Print Loop for conversational interactions with LLMs and Coyote. * [Custom REPL Prompt](https://github.com/Dark-Alex-17/coyote/wiki/REPL-Prompt): Customize the REPL prompt to provide useful contextual information. * [Vault](https://github.com/Dark-Alex-17/coyote/wiki/Vault): Securely store and manage sensitive information such as API keys and credentials. diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 0c87db5..45c1b0c 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -50,7 +50,7 @@ pub enum McpScopeArg { "model", "prompt", "role", "session", "agent", "rag", "rebuild_rag", "macro_name", "execute", "code", "file", "no_stream", "no_memory", "init_memory", "dry_run", "info", "build_tools", "install", - "install_from", "install_builtins", "sync_models", "list_models", "list_roles", + "install_builtins", "sync_models", "list_models", "list_roles", "list_sessions", "list_agents", "list_rags", "list_macros", "list_skills", "list_bundles", "skill", "tail_logs", "completions", "update", "update_bundle", "uninstall", @@ -61,11 +61,6 @@ pub enum McpScopeArg { .args(["mcp_add", "mcp_remove", "mcp_list", "mcp_get"]) .multiple(false) ), - group( - ArgGroup::new("remote-install") - .args(["install", "install_from"]) - .multiple(false) - ), )] pub struct Cli { /// Input text @@ -197,33 +192,21 @@ pub struct Cli { long, value_name = "CATEGORY", value_enum, - conflicts_with_all = ["install", "install_from"], + conflicts_with_all = ["install"], help_heading = "Installation & Updates" )] pub install_builtins: Option, - /// Install assets from a remote git repository (URL may be suffixed with #) - #[arg( - long, - value_name = "GIT_URL", - hide = true, - help_heading = "Installation & Updates" - )] - pub install_from: Option, /// Restrict a remote install to a single asset category #[arg( long, value_name = "CATEGORY", value_enum, - requires = "remote-install", + requires = "install", help_heading = "Installation & Updates" )] pub filter: Option, /// Overwrite all conflicts without prompting (used with --install) - #[arg( - long, - requires = "remote-install", - help_heading = "Installation & Updates" - )] + #[arg(long, requires = "install", help_heading = "Installation & Updates")] pub install_force: bool, /// Update an installed bundle from its recorded source (NAME may be suffixed with # to move a pin) #[arg(long, value_name = "NAME", help_heading = "Installation & Updates")] @@ -581,65 +564,37 @@ mod tests { } #[test] - fn parse_install_from_flag_still_works() { - assert_eq!( - parse(&["--install-from", "https://github.com/x/y"]) - .install_from - .as_deref(), - Some("https://github.com/x/y") - ); + fn parse_install_from_is_no_longer_a_flag() { + let cli = parse(&["--install-from", "https://github.com/x/y"]); + assert!(cli.install.is_none()); + assert_eq!(cli.text, vec!["--install-from", "https://github.com/x/y"]); } #[test] - fn parse_install_conflicts_with_install_from() { - assert!(Cli::try_parse_from(["coyote", "--install", "x", "--install-from", "y"]).is_err()); - } - - #[test] - fn parse_install_builtins_conflicts_with_remote_install_flags() { + fn parse_install_builtins_conflicts_with_install() { assert!( Cli::try_parse_from(["coyote", "--install-builtins", "agents", "--install", "x"]) .is_err() ); - assert!( - Cli::try_parse_from([ - "coyote", - "--install-builtins", - "agents", - "--install-from", - "y" - ]) - .is_err() - ); } #[test] - fn parse_filter_requires_a_remote_install_flag() { + fn parse_filter_requires_install() { assert!(Cli::try_parse_from(["coyote", "--filter", "agents"]).is_err()); assert_eq!( parse(&["--install", "https://github.com/x/y", "--filter", "agents"]).filter, Some(InstallFilter::Agents) ); - assert_eq!( - parse(&[ - "--install-from", - "https://github.com/x/y", - "--filter", - "agents" - ]) - .filter, - Some(InstallFilter::Agents) - ); } #[test] - fn parse_install_force_requires_a_remote_install_flag() { + fn parse_install_force_requires_install() { assert!(Cli::try_parse_from(["coyote", "--install-force"]).is_err()); assert!(parse(&["--install", "https://github.com/x/y", "--install-force"]).install_force); } #[test] - fn help_hides_install_from_and_shows_install_builtins() { + fn help_omits_install_from_and_shows_install_builtins() { use clap::CommandFactory; let help = Cli::command().render_long_help().to_string(); assert!(!help.contains("--install-from"), "help: {help}"); diff --git a/src/config/install_remote.rs b/src/config/install_remote.rs index b747f3d..18df557 100644 --- a/src/config/install_remote.rs +++ b/src/config/install_remote.rs @@ -69,22 +69,6 @@ pub fn install_remote(git_url: &str, filter: Option, force: bool) Ok(()) } -pub fn install_remote_from_repl_args(args: &str) -> Result<()> { - let tokens = shell_words::split(args) - .with_context(|| format!("failed to parse '.install remote' args: {args}"))?; - - let mut iter = tokens.into_iter(); - let url = iter.next().with_context(|| { - format!( - "Usage: .install remote [--filter <{}>] [--force]", - InstallFilter::NAMES.join("|") - ) - })?; - - let (filter, force) = parse_repl_install_flags(".install remote", iter)?; - install_remote(&url, filter, force) -} - fn parse_repl_install_flags( command: &str, mut iter: impl Iterator, diff --git a/src/config/mod.rs b/src/config/mod.rs index a8ceb60..d3cf255 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -33,8 +33,7 @@ pub use self::app_state::AppState; pub use self::bundles::list_installed_bundles; pub use self::input::Input; pub use self::install_remote::{ - install_or_update, install_or_update_from_repl_args, install_remote, - install_remote_from_repl_args, uninstall_bundle, update_bundle, + install_or_update, install_or_update_from_repl_args, uninstall_bundle, update_bundle, }; pub use self::macro_policy::{ MacroAllowlistLevel, MacroPolicy, MacroSource, MacroState, RESERVED_MACRO_NAMES, ResolvedMacro, diff --git a/src/config/request_context.rs b/src/config/request_context.rs index 3b54b5d..c2e2489 100644 --- a/src/config/request_context.rs +++ b/src/config/request_context.rs @@ -3263,7 +3263,6 @@ impl RequestContext { ".install" => { let mut values: Vec = AssetCategory::NAMES.iter().map(|s| s.to_string()).collect(); - values.push("remote".to_string()); values.extend( BundleStore::load() .map(|store| { @@ -3495,7 +3494,7 @@ impl RequestContext { values = complete_skills_with_descriptions(paths::list_skills()); } else if cmd == ".skill" && args.first() == Some(&"unload") && args.len() == 2 { values = complete_skills_with_descriptions(self.skill_registry.loaded_names()); - } else if cmd == ".install" && args.first() == Some(&"remote") && args.len() >= 2 { + } else if cmd == ".install" && args.len() >= 2 { let prev = args.get(args.len() - 2).copied().unwrap_or(""); if prev == "--filter" { values = super::map_completion_values( @@ -4992,7 +4991,7 @@ mod tests { #[test] #[serial] - fn repl_complete_install_offers_categories_remote_and_bundles() { + fn repl_complete_install_offers_categories_and_bundles() { let _guard = TestConfigDirGuard::new(); let mut store = BundleStore::load().unwrap(); store @@ -5012,7 +5011,7 @@ mod tests { let values = ctx.repl_complete(".install", &[""], ""); - for expected in ["agents", "remote", "omc"] { + for expected in ["agents", "omc"] { assert!( values.iter().any(|(name, _)| name == expected), "missing '{expected}'; got: {values:?}" diff --git a/src/main.rs b/src/main.rs index eb36f2d..402e896 100644 --- a/src/main.rs +++ b/src/main.rs @@ -138,13 +138,6 @@ async fn main() -> Result<()> { return config::install_or_update(value, cli.filter, cli.install_force); } - if let Some(url) = cli.install_from.as_deref() { - eprintln!( - "warning: --install-from is deprecated and will be removed in a future release; use --install " - ); - return config::install_remote(url, cli.filter, cli.install_force); - } - if let Some(spec) = cli.update_bundle.as_deref() { return config::update_bundle(spec); } diff --git a/src/repl/mod.rs b/src/repl/mod.rs index f67bfde..ce25aa9 100644 --- a/src/repl/mod.rs +++ b/src/repl/mod.rs @@ -872,15 +872,12 @@ pub async fn run_repl_command( } ".install" => match parse_repl_install(args) { ReplInstallDispatch::Builtins(category) => config::install_assets(category)?, - ReplInstallDispatch::Remote(rest) => { - config::install_remote_from_repl_args(rest)?; - } ReplInstallDispatch::Unified(value) => { config::install_or_update_from_repl_args(value)?; } ReplInstallDispatch::Usage => println!( - "Usage: .install <{}> | .install | \ - .install remote [--filter ] [--force]", + "Usage: .install <{}> | .install \ + [--filter ] [--force]", AssetCategory::NAMES.join("|") ), }, @@ -1577,7 +1574,6 @@ fn unknown_command() -> Result<()> { #[derive(Debug, PartialEq)] enum ReplInstallDispatch<'a> { Builtins(AssetCategory), - Remote(&'a str), Unified(&'a str), Usage, } @@ -1586,7 +1582,6 @@ fn parse_repl_install(args: Option<&str>) -> ReplInstallDispatch<'_> { let trimmed = args.map(str::trim).unwrap_or(""); let mut parts = trimmed.splitn(2, char::is_whitespace); match parts.next() { - Some("remote") => ReplInstallDispatch::Remote(parts.next().unwrap_or("").trim()), Some(name) if !name.is_empty() => match AssetCategory::parse(name) { Some(category) => ReplInstallDispatch::Builtins(category), None => ReplInstallDispatch::Unified(trimmed), @@ -1821,15 +1816,11 @@ mod tests { } #[test] - fn parse_repl_install_keeps_category_and_remote_back_compat() { + fn parse_repl_install_routes_categories_to_builtins() { assert_eq!( parse_repl_install(Some("agents")), ReplInstallDispatch::Builtins(AssetCategory::Agents) ); - assert_eq!( - parse_repl_install(Some("remote https://x --force")), - ReplInstallDispatch::Remote("https://x --force") - ); } #[test]