fix: remove goose tui command (#11484)

This commit is contained in:
Alex Hancock
2026-08-24 14:59:55 +00:00
committed by GitHub
parent 3a65236210
commit dd469e80b6
4 changed files with 1 additions and 169 deletions
+1 -3
View File
@@ -90,7 +90,6 @@ libc = { version = "0.2.182", default-features = false, features = ["std"] }
default = [
"code-mode",
"local-inference",
"tui",
"aws-providers",
"telemetry",
"nostr",
@@ -109,9 +108,8 @@ telemetry = ["goose/telemetry"]
nostr = ["goose/nostr"]
otel = ["goose/otel"]
system-keyring = ["goose/system-keyring"]
tui = []
update = ["dep:sigstore-verify", "dep:snap"]
portable-default = ["rustls-tls", "aws-providers", "telemetry", "otel", "tui"]
portable-default = ["rustls-tls", "aws-providers", "telemetry", "otel"]
# disables the update command
disable-update = []
rustls-tls = [
-37
View File
@@ -1045,27 +1045,6 @@ enum Command {
command: TermCommand,
},
/// Launch the goose terminal UI (TUI)
#[cfg(feature = "tui")]
#[command(
about = "Launch the goose terminal UI",
long_about = "Launch the goose terminal UI (the @aaif/goose npm package).\n\
\n\
Resolution order:\n \
1. GOOSE_TUI_SCRIPT, if set to an existing dist/tui.js\n \
2. A local checkout's ui/text/dist/tui.js (dev workflow)\n \
3. `npx --yes --package <spec> -- goose-tui` (deployed installs)\n\
\n\
Override the npm spec via GOOSE_TUI_NPM_SPEC (default: @aaif/goose@latest).\n\
Local script mode requires `node` on PATH; npx mode requires `npx` on PATH.\n\
Any extra arguments are passed through to the TUI."
)]
Tui {
/// Arguments forwarded to the TUI
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
args: Vec<String>,
},
/// Manage local inference models
#[cfg(feature = "local-inference")]
#[command(about = "Manage local inference models", visible_alias = "lm")]
@@ -1388,8 +1367,6 @@ fn get_command_name(command: &Option<Command>) -> &'static str {
Some(Command::Skills { .. }) => "skills",
Some(Command::Plugin { .. }) => "plugin",
Some(Command::Term { .. }) => "term",
#[cfg(feature = "tui")]
Some(Command::Tui { .. }) => "tui",
#[cfg(feature = "local-inference")]
Some(Command::LocalModels { .. }) => "local-models",
Some(Command::Completion { .. }) => "completion",
@@ -2761,8 +2738,6 @@ pub async fn cli() -> anyhow::Result<()> {
Some(Command::Skills { command }) => handle_skills_subcommand(command).await,
Some(Command::Plugin { command }) => handle_plugin_subcommand(command),
Some(Command::Term { command }) => handle_term_subcommand(command).await,
#[cfg(feature = "tui")]
Some(Command::Tui { args }) => crate::commands::tui::handle_tui(args),
#[cfg(feature = "local-inference")]
Some(Command::LocalModels { command }) => handle_local_models_command(command).await,
Some(Command::Review {
@@ -3055,18 +3030,6 @@ mod tests {
}
}
#[cfg(feature = "tui")]
#[test]
fn tui_command_accepts_trailing_args() {
let cli =
Cli::try_parse_from(["goose", "tui", "--", "--theme", "dark"]).expect("parse failed");
match cli.command {
Some(Command::Tui { args }) => assert_eq!(args, vec!["--theme", "dark"]),
_ => panic!("expected tui command"),
}
}
#[cfg(feature = "local-inference")]
mod local_search {
use super::super::{
-2
View File
@@ -9,7 +9,5 @@ pub mod schedule;
pub mod session;
pub mod skills;
pub mod term;
#[cfg(feature = "tui")]
pub mod tui;
#[cfg(feature = "update")]
pub mod update;
-127
View File
@@ -1,127 +0,0 @@
use anyhow::{anyhow, Context, Result};
use std::path::{Path, PathBuf};
use std::process::Command;
const TUI_NPM_SPEC_ENV: &str = "GOOSE_TUI_NPM_SPEC";
const TUI_REL_PATH: &str = "ui/text/dist/tui.js";
const DEFAULT_NPM_SPEC: &str = "@aaif/goose@latest";
const NPM_BIN_NAME: &str = "goose-tui";
enum TuiSource {
LocalScript(PathBuf),
Npx(String),
}
fn find_local_script() -> Option<PathBuf> {
let exe = std::env::current_exe().ok()?;
find_local_script_from(&exe)
}
fn find_local_script_from(exe: &Path) -> Option<PathBuf> {
let exe_dir = exe.parent().unwrap_or_else(|| Path::new("."));
let mut dir = Some(exe_dir.to_path_buf());
for _ in 0..6 {
if let Some(d) = dir.clone() {
let candidate = d.join(TUI_REL_PATH);
if candidate.is_file() {
return Some(candidate);
}
dir = d.parent().map(Path::to_path_buf);
}
}
None
}
fn resolve_source() -> TuiSource {
if let Some(script) = find_local_script() {
return TuiSource::LocalScript(script);
}
let spec = std::env::var(TUI_NPM_SPEC_ENV).unwrap_or_else(|_| DEFAULT_NPM_SPEC.to_string());
TuiSource::Npx(spec)
}
fn build_command(source: &TuiSource, args: &[String]) -> Result<Command> {
match source {
TuiSource::LocalScript(script) => {
let mut cmd = Command::new("node");
cmd.arg(script).args(args);
Ok(cmd)
}
TuiSource::Npx(spec) => {
let mut cmd = Command::new("npx");
cmd.arg("--yes")
.arg("--package")
.arg(spec)
.arg("--")
.arg(NPM_BIN_NAME)
.args(args);
Ok(cmd)
}
}
}
pub fn handle_tui(args: Vec<String>) -> Result<()> {
let source = resolve_source();
let goose_binary = std::env::current_exe()
.context("could not determine current goose executable to expose as GOOSE_BINARY")?;
let mut cmd = build_command(&source, &args)?;
cmd.env("GOOSE_BINARY", &goose_binary);
let descriptor = match &source {
TuiSource::LocalScript(p) => format!("node {}", p.display()),
TuiSource::Npx(spec) => format!("npx --package {} -- {}", spec, NPM_BIN_NAME),
};
#[cfg(unix)]
{
use std::os::unix::process::CommandExt;
let err = cmd.exec();
Err(anyhow!("failed to exec TUI ({descriptor}): {err}"))
}
#[cfg(not(unix))]
{
let status = cmd
.status()
.with_context(|| format!("failed to run `{descriptor}`"))?;
if !status.success() {
std::process::exit(status.code().unwrap_or(1));
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
#[test]
fn find_local_script_ignores_unrelated_directories() {
let temp_dir = tempfile::tempdir().expect("create temp dir");
let executable = temp_dir.path().join("install/bin/goose");
let planted_script = temp_dir.path().join("checkout").join(TUI_REL_PATH);
fs::create_dir_all(planted_script.parent().unwrap()).expect("create script directory");
fs::write(&planted_script, "process.exit(0)\n").expect("write planted script");
assert_eq!(find_local_script_from(&executable), None);
}
#[test]
fn find_local_script_accepts_executable_ancestor() {
let temp_dir = tempfile::tempdir().expect("create temp dir");
let executable = temp_dir.path().join("target/debug/goose");
let bundled_script = temp_dir.path().join(TUI_REL_PATH);
fs::create_dir_all(bundled_script.parent().unwrap()).expect("create script directory");
fs::write(&bundled_script, "process.exit(0)\n").expect("write bundled script");
assert_eq!(
find_local_script_from(&executable).as_deref(),
Some(bundled_script.as_path())
);
}
}