mirror of
https://github.com/aljazceru/goose.git
synced 2025-12-20 07:34:27 +01:00
feat: V1.0 (#734)
Co-authored-by: Michael Neale <michael.neale@gmail.com> Co-authored-by: Wendy Tang <wendytang@squareup.com> Co-authored-by: Jarrod Sibbison <72240382+jsibbison-square@users.noreply.github.com> Co-authored-by: Alex Hancock <alex.hancock@example.com> Co-authored-by: Alex Hancock <alexhancock@block.xyz> Co-authored-by: Lifei Zhou <lifei@squareup.com> Co-authored-by: Wes <141185334+wesrblock@users.noreply.github.com> Co-authored-by: Max Novich <maksymstepanenko1990@gmail.com> Co-authored-by: Zaki Ali <zaki@squareup.com> Co-authored-by: Salman Mohammed <smohammed@squareup.com> Co-authored-by: Kalvin C <kalvinnchau@users.noreply.github.com> Co-authored-by: Alec Thomas <alec@swapoff.org> Co-authored-by: lily-de <119957291+lily-de@users.noreply.github.com> Co-authored-by: kalvinnchau <kalvin@block.xyz> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Rizel Scarlett <rizel@squareup.com> Co-authored-by: bwrage <bwrage@squareup.com> Co-authored-by: Kalvin Chau <kalvin@squareup.com> Co-authored-by: Alice Hau <110418948+ahau-square@users.noreply.github.com> Co-authored-by: Alistair Gray <ajgray@stripe.com> Co-authored-by: Nahiyan Khan <nahiyan.khan@gmail.com> Co-authored-by: Alex Hancock <alexhancock@squareup.com> Co-authored-by: Nahiyan Khan <nahiyan@squareup.com> Co-authored-by: marcelle <1852848+laanak08@users.noreply.github.com> Co-authored-by: Yingjie He <yingjiehe@block.xyz> Co-authored-by: Yingjie He <yingjiehe@squareup.com> Co-authored-by: Lily Delalande <ldelalande@block.xyz> Co-authored-by: Adewale Abati <acekyd01@gmail.com> Co-authored-by: Ebony Louis <ebony774@gmail.com> Co-authored-by: Angie Jones <jones.angie@gmail.com> Co-authored-by: Ebony Louis <55366651+EbonyLouis@users.noreply.github.com>
This commit is contained in:
234
crates/goose-cli/src/main.rs
Normal file
234
crates/goose-cli/src/main.rs
Normal file
@@ -0,0 +1,234 @@
|
||||
use anyhow::Result;
|
||||
use clap::{CommandFactory, Parser, Subcommand};
|
||||
|
||||
mod commands;
|
||||
mod log_usage;
|
||||
mod logging;
|
||||
mod prompt;
|
||||
mod session;
|
||||
|
||||
use commands::agent_version::AgentCommand;
|
||||
use commands::configure::handle_configure;
|
||||
use commands::mcp::run_server;
|
||||
use commands::session::build_session;
|
||||
use commands::version::print_version;
|
||||
use console::style;
|
||||
use goose::config::Config;
|
||||
use logging::setup_logging;
|
||||
use std::io::{self, Read};
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_helpers;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, about, long_about = None)]
|
||||
struct Cli {
|
||||
#[arg(short = 'v', long = "version")]
|
||||
version: bool,
|
||||
|
||||
#[command(subcommand)]
|
||||
command: Option<Command>,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum Command {
|
||||
/// Configure Goose settings
|
||||
#[command(about = "Configure Goose settings")]
|
||||
Configure {},
|
||||
|
||||
/// Manage system prompts and behaviors
|
||||
#[command(about = "Run one of the mcp servers bundled with goose")]
|
||||
Mcp { name: String },
|
||||
|
||||
/// Start or resume interactive chat sessions
|
||||
#[command(about = "Start or resume interactive chat sessions", alias = "s")]
|
||||
Session {
|
||||
/// Name for the chat session
|
||||
#[arg(
|
||||
short,
|
||||
long,
|
||||
value_name = "NAME",
|
||||
help = "Name for the chat session (e.g., 'project-x')",
|
||||
long_help = "Specify a name for your chat session. When used with --resume, will resume this specific session if it exists."
|
||||
)]
|
||||
name: Option<String>,
|
||||
|
||||
/// Resume a previous session
|
||||
#[arg(
|
||||
short,
|
||||
long,
|
||||
help = "Resume a previous session (last used or specified by --session)",
|
||||
long_help = "Continue from a previous chat session. If --session is provided, resumes that specific session. Otherwise resumes the last used session."
|
||||
)]
|
||||
resume: bool,
|
||||
|
||||
/// Add a stdio extension with environment variables and command
|
||||
#[arg(
|
||||
long = "with-extension",
|
||||
value_name = "COMMAND",
|
||||
help = "Add a stdio extension (e.g., 'GITHUB_TOKEN=xyz npx -y @modelcontextprotocol/server-github')",
|
||||
long_help = "Add a stdio extension from a full command with environment variables. Format: 'ENV1=val1 ENV2=val2 command args...'"
|
||||
)]
|
||||
extension: Option<String>,
|
||||
|
||||
/// Add a builtin extension by name
|
||||
#[arg(
|
||||
long = "with-builtin",
|
||||
value_name = "NAME",
|
||||
help = "Add a builtin extension by name (e.g., 'developer')",
|
||||
long_help = "Add a builtin extension that is bundled with goose by specifying its name"
|
||||
)]
|
||||
builtin: Option<String>,
|
||||
},
|
||||
|
||||
/// Execute commands from an instruction file
|
||||
#[command(about = "Execute commands from an instruction file or stdin")]
|
||||
Run {
|
||||
/// Path to instruction file containing commands
|
||||
#[arg(
|
||||
short,
|
||||
long,
|
||||
value_name = "FILE",
|
||||
help = "Path to instruction file containing commands",
|
||||
conflicts_with = "input_text"
|
||||
)]
|
||||
instructions: Option<String>,
|
||||
|
||||
/// Input text containing commands
|
||||
#[arg(
|
||||
short = 't',
|
||||
long = "text",
|
||||
value_name = "TEXT",
|
||||
help = "Input text to provide to Goose directly",
|
||||
long_help = "Input text containing commands for Goose. Use this in lieu of the instructions argument.",
|
||||
conflicts_with = "instructions"
|
||||
)]
|
||||
input_text: Option<String>,
|
||||
|
||||
/// Name for this run session
|
||||
#[arg(
|
||||
short,
|
||||
long,
|
||||
value_name = "NAME",
|
||||
help = "Name for this run session (e.g., 'daily-tasks')",
|
||||
long_help = "Specify a name for this run session. This helps identify and resume specific runs later."
|
||||
)]
|
||||
name: Option<String>,
|
||||
|
||||
/// Resume a previous run
|
||||
#[arg(
|
||||
short,
|
||||
long,
|
||||
action = clap::ArgAction::SetTrue,
|
||||
help = "Resume from a previous run",
|
||||
long_help = "Continue from a previous run, maintaining the execution state and context."
|
||||
)]
|
||||
resume: bool,
|
||||
|
||||
/// Add a stdio extension with environment variables and command
|
||||
#[arg(
|
||||
long = "with-extension",
|
||||
value_name = "COMMAND",
|
||||
help = "Add a stdio extension with environment variables and command (e.g., 'GITHUB_TOKEN=xyz npx -y @modelcontextprotocol/server-github')",
|
||||
long_help = "Add a stdio extension with environment variables and command. Format: 'ENV1=val1 ENV2=val2 command args...'"
|
||||
)]
|
||||
extension: Option<String>,
|
||||
|
||||
/// Add a builtin extension by name
|
||||
#[arg(
|
||||
long = "with-builtin",
|
||||
value_name = "NAME",
|
||||
help = "Add a builtin extension by name (e.g., 'developer')",
|
||||
long_help = "Add a builtin extension that is compiled into goose by specifying its name"
|
||||
)]
|
||||
builtin: Option<String>,
|
||||
},
|
||||
|
||||
/// List available agent versions
|
||||
Agents(AgentCommand),
|
||||
}
|
||||
|
||||
#[derive(clap::ValueEnum, Clone, Debug)]
|
||||
enum CliProviderVariant {
|
||||
OpenAi,
|
||||
Databricks,
|
||||
Ollama,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
let cli = Cli::parse();
|
||||
|
||||
if cli.version {
|
||||
print_version();
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
match cli.command {
|
||||
Some(Command::Configure {}) => {
|
||||
let _ = handle_configure().await;
|
||||
return Ok(());
|
||||
}
|
||||
Some(Command::Mcp { name }) => {
|
||||
let _ = run_server(&name).await;
|
||||
}
|
||||
Some(Command::Session {
|
||||
name,
|
||||
resume,
|
||||
extension,
|
||||
builtin,
|
||||
}) => {
|
||||
let mut session = build_session(name, resume, extension, builtin).await;
|
||||
setup_logging(session.session_file().file_stem().and_then(|s| s.to_str()))?;
|
||||
|
||||
let _ = session.start().await;
|
||||
return Ok(());
|
||||
}
|
||||
Some(Command::Run {
|
||||
instructions,
|
||||
input_text,
|
||||
name,
|
||||
resume,
|
||||
extension,
|
||||
builtin,
|
||||
}) => {
|
||||
// Validate that we have some input source
|
||||
if instructions.is_none() && input_text.is_none() {
|
||||
eprintln!("Error: Must provide either --instructions or --text");
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
let contents = if let Some(file_name) = instructions {
|
||||
let file_path = std::path::Path::new(&file_name);
|
||||
std::fs::read_to_string(file_path).expect("Failed to read the instruction file")
|
||||
} else if let Some(input_text) = input_text {
|
||||
input_text
|
||||
} else {
|
||||
let mut stdin = String::new();
|
||||
io::stdin()
|
||||
.read_to_string(&mut stdin)
|
||||
.expect("Failed to read from stdin");
|
||||
stdin
|
||||
};
|
||||
let mut session = build_session(name, resume, extension, builtin).await;
|
||||
let _ = session.headless_start(contents.clone()).await;
|
||||
return Ok(());
|
||||
}
|
||||
Some(Command::Agents(cmd)) => {
|
||||
cmd.run()?;
|
||||
return Ok(());
|
||||
}
|
||||
None => {
|
||||
Cli::command().print_help()?;
|
||||
println!();
|
||||
if !Config::global().exists() {
|
||||
println!(
|
||||
"\n {}: Run '{}' to setup goose for the first time",
|
||||
style("Tip").green().italic(),
|
||||
style("goose configure").cyan()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user