diff --git a/app/Cargo.toml b/app/Cargo.toml index 5b1cb41f..bff560e4 100644 --- a/app/Cargo.toml +++ b/app/Cargo.toml @@ -934,8 +934,8 @@ cloud_mode_input_v2 = ["cloud_mode"] [package.metadata.bundle.bin.warp-oss] category = "public.app-category.developer-tools" copyright = "© 2025, Denver Technologies, Inc" -identifier = "dev.warp.WarpOss" -name = "WarpOss" +identifier = "dev.galaxy.GalaxyOss" +name = "Galaxy" resources = ["assets/onboarding"] icon = ["channels/oss/icon/no-padding/512x512.png", "channels/oss/icon/no-padding/icon.ico"] short_description = "The open-source, cloud-backed terminal for individuals and teams." @@ -943,8 +943,8 @@ short_description = "The open-source, cloud-backed terminal for individuals and [package.metadata.bundle.bin.stable] category = "public.app-category.developer-tools" copyright = "© 2025, Denver Technologies, Inc" -identifier = "dev.warp.Warp-Stable" -name = "Warp" +identifier = "dev.galaxy.Galaxy-Stable" +name = "Galaxy" osx_frameworks = [ "frameworks/default/Sentry-Dynamic-WithARM64e.xcframework/macos-arm64_arm64e_x86_64/Sentry.framework", ] @@ -954,8 +954,8 @@ short_description = "The cloud-backed terminal for individuals and teams, stable [package.metadata.bundle.bin.preview] category = "public.app-category.developer-tools" copyright = "© 2025, Denver Technologies, Inc" -identifier = "dev.warp.Warp-Preview" -name = "WarpPreview" +identifier = "dev.galaxy.Galaxy-Preview" +name = "GalaxyPreview" osx_frameworks = [ "frameworks/default/Sentry-Dynamic-WithARM64e.xcframework/macos-arm64_arm64e_x86_64/Sentry.framework", ] @@ -965,8 +965,8 @@ short_description = "The cloud-backed terminal for individuals and teams, featur [package.metadata.bundle.bin.dev] category = "public.app-category.developer-tools" copyright = "© 2025, Denver Technologies, Inc" -identifier = "dev.warp.Warp-Dev" -name = "WarpDev" +identifier = "dev.galaxy.Galaxy-Dev" +name = "GalaxyDev" osx_frameworks = [ "frameworks/dev/Sentry-Dynamic-WithARM64e.xcframework/macos-arm64_arm64e_x86_64/Sentry.framework", ] @@ -976,8 +976,8 @@ short_description = "The cloud-backed terminal for individuals and teams, develo [package.metadata.bundle.bin.warp] category = "public.app-category.developer-tools" copyright = "© 2025, Denver Technologies, Inc" -identifier = "dev.warp.Warp-Local" -name = "WarpLocal" +identifier = "dev.galaxy.Galaxy-Local" +name = "GalaxyLocal" resources = ["assets/onboarding"] short_description = "The cloud-backed terminal for individuals and teams, developer build." diff --git a/app/src/ai/bedrock/convert_request.rs b/app/src/ai/bedrock/convert_request.rs index 1f7d25c2..d4af8437 100644 --- a/app/src/ai/bedrock/convert_request.rs +++ b/app/src/ai/bedrock/convert_request.rs @@ -551,8 +551,80 @@ fn ensure_tool_results_paired(messages: &mut Vec) { } } -pub fn extract_system_prompt(_request: &api::Request) -> Option { - Some("You are a helpful AI coding assistant. You help users with software engineering tasks including writing code, debugging, and explaining concepts.".to_string()) +pub fn extract_system_prompt(request: &api::Request) -> Option { + let mut prompt = String::with_capacity(2048); + + prompt.push_str("You are Galaxy, an AI coding assistant embedded in a terminal application. You help users with software engineering tasks including writing code, debugging, explaining concepts, and navigating codebases.\n\n"); + + if let Some(input) = &request.input { + if let Some(context) = &input.context { + prompt.push_str("## Environment\n"); + if let Some(dir) = &context.directory { + if !dir.pwd.is_empty() { + prompt.push_str(&format!("- Working directory: {}\n", dir.pwd)); + } + if !dir.home.is_empty() { + prompt.push_str(&format!("- Home directory: {}\n", dir.home)); + } + } + if let Some(os) = &context.operating_system { + if !os.platform.is_empty() { + prompt.push_str(&format!("- OS: {}\n", os.platform)); + } + } + if let Some(shell) = &context.shell { + if !shell.name.is_empty() { + prompt.push_str(&format!("- Shell: {}", shell.name)); + if !shell.version.is_empty() { + prompt.push_str(&format!(" {}", shell.version)); + } + prompt.push('\n'); + } + } + if let Some(git) = &context.git { + if !git.branch.is_empty() { + prompt.push_str(&format!("- Git branch: {}\n", git.branch)); + } + } + if let Some(ts) = &context.current_time { + prompt.push_str(&format!("- Current time (UTC): {}\n", ts)); + } + prompt.push('\n'); + + if !context.project_rules.is_empty() { + prompt.push_str("## Project Rules\n"); + for rules in &context.project_rules { + if !rules.root_path.is_empty() { + prompt.push_str(&format!("### Rules from {}\n", rules.root_path)); + } + for file in &rules.active_rule_files { + if !file.content.is_empty() { + prompt.push_str(&file.content); + prompt.push('\n'); + } + } + } + prompt.push('\n'); + } + } + } + + prompt.push_str("## Tools\nYou have access to the following tools. Use them proactively to explore codebases and complete tasks:\n"); + prompt.push_str("- `run_shell_command`: Execute shell commands. Use absolute paths based on the working directory.\n"); + prompt.push_str("- `read_files`: Read file contents. Pass all files you need in a single call.\n"); + prompt.push_str("- `apply_file_diffs`: Apply search/replace edits to files.\n"); + prompt.push_str("- `grep`: Search for patterns in files. Pass all patterns in one call.\n"); + prompt.push_str("- `file_glob`: Find files matching glob patterns. Pass all patterns in one call.\n"); + prompt.push_str("- `get_tool_documentation`: Get detailed documentation for any tool or system capabilities.\n\n"); + + prompt.push_str("## Guidelines\n"); + prompt.push_str("- ALWAYS use tools to explore the codebase before answering questions about code.\n"); + prompt.push_str("- Use absolute paths based on the working directory shown above.\n"); + prompt.push_str("- When asked about a project, start by listing files with `file_glob` or `run_shell_command`.\n"); + prompt.push_str("- Read relevant files before making claims about code structure or behavior.\n"); + prompt.push_str("- Be concise and direct in responses.\n"); + + Some(prompt) } pub fn extract_tools(request: &api::Request) -> Vec { @@ -773,7 +845,11 @@ fn extract_tool_result_content(result: &api::request::input::ToolCallResult) -> api::request::input::tool_call_result::Result::RunShellCommand(cmd_result) => { match &cmd_result.result { Some(api::run_shell_command_result::Result::CommandFinished(finished)) => { - finished.output.clone() + if finished.output.is_empty() { + format!("Exit code: {}\n(no output)", finished.exit_code) + } else { + format!("Exit code: {}\n{}", finished.exit_code, finished.output) + } } Some(api::run_shell_command_result::Result::LongRunningCommandSnapshot( snapshot, @@ -803,6 +879,78 @@ fn extract_tool_result_content(result: &api::request::input::ToolCallResult) -> _ => "Failed to read files.".to_string(), } } + api::request::input::tool_call_result::Result::Grep(grep_result) => { + match &grep_result.result { + Some(api::grep_result::Result::Success(success)) => { + if success.matched_files.is_empty() { + "No matches found.".to_string() + } else { + success + .matched_files + .iter() + .map(|f| { + let lines: String = f + .matched_lines + .iter() + .map(|l| format!(" line {}", l.line_number)) + .collect::>() + .join(", "); + format!("{} (matches at: {})", f.file_path, lines) + }) + .collect::>() + .join("\n") + } + } + Some(api::grep_result::Result::Error(error)) => { + format!("Grep error: {}", error.message) + } + None => "Grep completed (no result).".to_string(), + } + } + api::request::input::tool_call_result::Result::FileGlobV2(glob_result) => { + match &glob_result.result { + Some(api::file_glob_v2_result::Result::Success(success)) => { + if success.matched_files.is_empty() { + "No files matched.".to_string() + } else { + success + .matched_files + .iter() + .map(|f| f.file_path.as_str()) + .collect::>() + .join("\n") + } + } + Some(api::file_glob_v2_result::Result::Error(error)) => { + format!("File glob error: {}", error.message) + } + None => "File glob completed (no result).".to_string(), + } + } + api::request::input::tool_call_result::Result::ApplyFileDiffs(diff_result) => { + match &diff_result.result { + Some(api::apply_file_diffs_result::Result::Success(success)) => { + let mut parts = Vec::new(); + for f in &success.updated_files_v2 { + if let Some(file) = &f.file { + parts.push(format!("Updated: {}", file.file_path)); + } + } + for f in &success.deleted_files { + parts.push(format!("Deleted: {}", f.file_path)); + } + if parts.is_empty() { + "Diffs applied successfully.".to_string() + } else { + parts.join("\n") + } + } + Some(api::apply_file_diffs_result::Result::Error(error)) => { + format!("Apply diffs error: {}", error.message) + } + None => "Apply diffs completed.".to_string(), + } + } _ => "Tool completed successfully.".to_string(), } } else { @@ -816,10 +964,14 @@ fn format_tool_call_result(result: &api::message::ToolCallResult) -> String { api::message::tool_call_result::Result::RunShellCommand(cmd_result) => { match &cmd_result.result { Some(api::run_shell_command_result::Result::CommandFinished(finished)) => { - format!( - "Exit code: {}\nOutput: {}", - finished.exit_code, finished.output - ) + if finished.output.is_empty() { + format!("Exit code: {}\n(no output)", finished.exit_code) + } else { + format!( + "Exit code: {}\n{}", + finished.exit_code, finished.output + ) + } } Some(api::run_shell_command_result::Result::LongRunningCommandSnapshot( snapshot, @@ -840,6 +992,78 @@ fn format_tool_call_result(result: &api::message::ToolCallResult) -> String { _ => "Read files completed.".to_string(), } } + api::message::tool_call_result::Result::Grep(grep_result) => { + match &grep_result.result { + Some(api::grep_result::Result::Success(success)) => { + if success.matched_files.is_empty() { + "No matches found.".to_string() + } else { + success + .matched_files + .iter() + .map(|f| { + let lines: String = f + .matched_lines + .iter() + .map(|l| format!(" line {}", l.line_number)) + .collect::>() + .join(", "); + format!("{} (matches at: {})", f.file_path, lines) + }) + .collect::>() + .join("\n") + } + } + Some(api::grep_result::Result::Error(error)) => { + format!("Grep error: {}", error.message) + } + None => "Grep completed (no result).".to_string(), + } + } + api::message::tool_call_result::Result::FileGlobV2(glob_result) => { + match &glob_result.result { + Some(api::file_glob_v2_result::Result::Success(success)) => { + if success.matched_files.is_empty() { + "No files matched.".to_string() + } else { + success + .matched_files + .iter() + .map(|f| f.file_path.as_str()) + .collect::>() + .join("\n") + } + } + Some(api::file_glob_v2_result::Result::Error(error)) => { + format!("File glob error: {}", error.message) + } + None => "File glob completed (no result).".to_string(), + } + } + api::message::tool_call_result::Result::ApplyFileDiffs(diff_result) => { + match &diff_result.result { + Some(api::apply_file_diffs_result::Result::Success(success)) => { + let mut parts = Vec::new(); + for f in &success.updated_files_v2 { + if let Some(file) = &f.file { + parts.push(format!("Updated: {}", file.file_path)); + } + } + for f in &success.deleted_files { + parts.push(format!("Deleted: {}", f.file_path)); + } + if parts.is_empty() { + "Diffs applied successfully.".to_string() + } else { + parts.join("\n") + } + } + Some(api::apply_file_diffs_result::Result::Error(error)) => { + format!("Apply diffs error: {}", error.message) + } + None => "Apply diffs completed.".to_string(), + } + } api::message::tool_call_result::Result::Server(server_result) => { server_result.serialized_result.clone() } diff --git a/app/src/ai/bedrock/tool_docs.rs b/app/src/ai/bedrock/tool_docs.rs index 34fbe60b..aaebbe96 100644 --- a/app/src/ai/bedrock/tool_docs.rs +++ b/app/src/ai/bedrock/tool_docs.rs @@ -1,4 +1,4 @@ -const CAPABILITIES_DOC: &str = r#"# Galaxy AI — System Capabilities +const CAPABILITIES_DOC: &str = r#"# Galaxy — System Capabilities You are Galaxy, an AI coding assistant embedded in a terminal application with direct filesystem and shell access. diff --git a/app/src/ai_assistant/mod.rs b/app/src/ai_assistant/mod.rs index e5725a96..4be9a32a 100644 --- a/app/src/ai_assistant/mod.rs +++ b/app/src/ai_assistant/mod.rs @@ -1,4 +1,4 @@ -//! AI Assistant has since been renamed to "Galaxy AI" in the product. +//! AI Assistant has since been renamed to "Galaxy" in the product. use std::{collections::HashSet, sync::Arc}; use crate::{ @@ -34,8 +34,8 @@ mod test_util; /// This is also roughly the limit at which the editor starts degrading. pub const PROMPT_CHARACTER_LIMIT: usize = 1000; -pub const AI_ASSISTANT_FEATURE_NAME: &str = "Galaxy AI"; -pub const ASK_AI_ASSISTANT_TEXT: &str = "Ask Galaxy AI"; +pub const AI_ASSISTANT_FEATURE_NAME: &str = "Galaxy"; +pub const ASK_AI_ASSISTANT_TEXT: &str = "Ask Galaxy"; pub const AI_ASSISTANT_SVG_PATH: &str = "bundled/svg/ai-assistant.svg"; diff --git a/app/src/ai_assistant/panel.rs b/app/src/ai_assistant/panel.rs index 967a0e78..2704e2dd 100644 --- a/app/src/ai_assistant/panel.rs +++ b/app/src/ai_assistant/panel.rs @@ -165,14 +165,14 @@ pub fn init(app: &mut AppContext) { .with_key_binding(cmd_or_ctrl_shift("l")), EditableBinding::new( "ai_assistant_panel:reset_context", - "Restart Galaxy AI", + "Restart Galaxy", AIAssistantAction::ResetContext, ) .with_context_predicate(id!("AIAssistantPanel")) .with_key_binding("ctrl-l"), EditableBinding::new( "ai_assistant_panel:reset_context", - "Restart Galaxy AI", + "Restart Galaxy", AIAssistantAction::ResetContext, ) .with_context_predicate(id!("AIAssistantPanel")) diff --git a/app/src/app_menus.rs b/app/src/app_menus.rs index 8d05e897..da13fdbb 100644 --- a/app/src/app_menus.rs +++ b/app/src/app_menus.rs @@ -243,7 +243,7 @@ fn make_new_app_menu(ctx: &AppContext) -> Menu { None, ))); menu_items.push(MenuItem::Standard(StandardAction::Quit)); - Menu::new("Galaxy AI", menu_items) + Menu::new("Galaxy", menu_items) } fn make_new_file_menu(ctx: &AppContext) -> Menu { diff --git a/app/src/bedrock_smoke_test.rs b/app/src/bedrock_smoke_test.rs index 987fd546..04065687 100644 --- a/app/src/bedrock_smoke_test.rs +++ b/app/src/bedrock_smoke_test.rs @@ -11,6 +11,20 @@ use crate::workspace::Workspace; use crate::BlocklistAIHistoryModel; const TARGET_DIR: &str = "~/GIT/stitcher/stitcher"; + +const FILE_VISIBILITY_QUERY: &str = r#"/agent Okay, let's try again. Can you see files now? List the files in the current directory using your tools. Then respond with EXACTLY this structured format: + +results: yes +file_count: + +If you cannot see any files or your tools fail, respond with: + +results: no +file_count: 0 + +You MUST use the file_glob or run_shell_command tool to check the directory contents first, then provide the structured response."#; + +#[allow(dead_code)] const AGENT_QUERY: &str = r#"/agent Analyze this project and respond with EXACTLY this structured format at the end of your response: Answer: @@ -49,11 +63,89 @@ fn run_cd(ctx: &mut galaxyui::ViewContext, window_id: WindowId) { ctx.spawn( async move { Timer::after(CD_SETTLE_DELAY).await }, move |_ws: &mut Workspace, _, ctx| { - submit_query(ctx, window_id); + submit_file_visibility_test(ctx, window_id); }, ); } +fn submit_file_visibility_test(ctx: &mut galaxyui::ViewContext, window_id: WindowId) { + log::info!("[smoke-test] === FILE VISIBILITY TEST ==="); + log::info!("[smoke-test] Submitting file visibility query..."); + + let terminal_view = get_terminal_view(ctx, window_id); + terminal_view.update(ctx, |view, ctx| { + let input = view.input().clone(); + input.update(ctx, |input, ctx| { + input.submit_queued_prompt(FILE_VISIBILITY_QUERY.to_string(), ctx); + }); + }); + + poll_file_visibility(ctx, window_id, std::time::Instant::now()); +} + +fn poll_file_visibility( + ctx: &mut galaxyui::ViewContext, + window_id: WindowId, + start: std::time::Instant, +) { + ctx.spawn( + async move { Timer::after(POLL_INTERVAL).await }, + move |_ws: &mut Workspace, _, ctx| { + let elapsed = start.elapsed(); + if elapsed > MAX_WAIT { + log::error!("[smoke-test] FILE VISIBILITY TEST TIMEOUT after {:?}", elapsed); + std::process::exit(1); + } + + let terminal_view = get_terminal_view(ctx, window_id); + if let Some(full_text) = get_finished_text(ctx, &terminal_view) { + log::info!("[smoke-test] === FILE VISIBILITY RESULT ({:.1}s) ===", elapsed.as_secs_f64()); + + let results = extract_field(&full_text, "results:"); + let file_count = extract_field(&full_text, "file_count:"); + + match (&results, &file_count) { + (Some(r), Some(c)) => { + log::info!("[smoke-test] results: {}", r); + log::info!("[smoke-test] file_count: {}", c); + + if *r == "yes" { + let count: u32 = c.parse().unwrap_or(0); + if count > 0 { + log::info!("[smoke-test] === FILE VISIBILITY TEST PASSED (found {} files) ===", count); + log::info!("[smoke-test] LLM can see files. Proceeding to main test..."); + std::process::exit(0); + } else { + log::error!("[smoke-test] === FILE VISIBILITY TEST FAILED (results=yes but file_count=0) ==="); + std::process::exit(1); + } + } else { + log::error!("[smoke-test] === FILE VISIBILITY TEST FAILED (results=no) ==="); + log::error!("[smoke-test] The LLM cannot see files in {}", TARGET_DIR); + log::error!("[smoke-test] Full response:"); + for line in full_text.lines() { + log::error!("[smoke-test] {}", line); + } + std::process::exit(1); + } + } + _ => { + log::error!("[smoke-test] === FILE VISIBILITY TEST FAILED (missing structured fields) ==="); + log::error!("[smoke-test] Full response:"); + for line in full_text.lines() { + log::error!("[smoke-test] {}", line); + } + std::process::exit(1); + } + } + } + + poll_file_visibility(ctx, window_id, start); + }, + ); +} + +#[allow(dead_code)] fn submit_query(ctx: &mut galaxyui::ViewContext, window_id: WindowId) { log::info!("[smoke-test] Submitting query..."); @@ -69,6 +161,7 @@ fn submit_query(ctx: &mut galaxyui::ViewContext, window_id: WindowId) poll(ctx, window_id, std::time::Instant::now()); } +#[allow(dead_code)] fn poll( ctx: &mut galaxyui::ViewContext, window_id: WindowId, diff --git a/app/src/bin/local.rs b/app/src/bin/local.rs index 08cc4009..809e013a 100644 --- a/app/src/bin/local.rs +++ b/app/src/bin/local.rs @@ -35,7 +35,7 @@ embed_plist::embed_info_plist_bytes!(r#" CFBundleDevelopmentRegion English CFBundleDisplayName - Galaxy AI + Galaxy CFBundleExecutable galaxy-ai CFBundleIdentifier @@ -43,7 +43,7 @@ embed_plist::embed_info_plist_bytes!(r#" CFBundleInfoDictionaryVersion 6.0 CFBundleName - Galaxy AI + Galaxy CFBundlePackageType APPL CFBundleShortVersionString @@ -55,7 +55,7 @@ embed_plist::embed_info_plist_bytes!(r#" UIDesignRequiresCompatibility CFBundleURLTypes - CFBundleURLNameGalaxy AICFBundleURLSchemesgalaxyai + CFBundleURLNameGalaxyCFBundleURLSchemesgalaxyai NSHumanReadableCopyright © 2026, Samsung Electronics Co., Ltd. diff --git a/app/src/bin/oss.rs b/app/src/bin/oss.rs index 887fd89d..5967dc69 100644 --- a/app/src/bin/oss.rs +++ b/app/src/bin/oss.rs @@ -39,7 +39,7 @@ embed_plist::embed_info_plist_bytes!(r#" CFBundleDevelopmentRegion English CFBundleDisplayName - Galaxy AI + Galaxy CFBundleExecutable galaxy-ai-oss CFBundleIdentifier @@ -47,7 +47,7 @@ embed_plist::embed_info_plist_bytes!(r#" CFBundleInfoDictionaryVersion 6.0 CFBundleName - Galaxy AI + Galaxy CFBundlePackageType APPL CFBundleShortVersionString @@ -59,7 +59,7 @@ embed_plist::embed_info_plist_bytes!(r#" UIDesignRequiresCompatibility CFBundleURLTypes - CFBundleURLNameGalaxy AICFBundleURLSchemesgalaxyai + CFBundleURLNameGalaxyCFBundleURLSchemesgalaxyai NSHumanReadableCopyright © 2026, Samsung Electronics Co., Ltd. diff --git a/app/src/pane_group/pane/get_started_view.rs b/app/src/pane_group/pane/get_started_view.rs index 9d54cd80..a99819d9 100644 --- a/app/src/pane_group/pane/get_started_view.rs +++ b/app/src/pane_group/pane/get_started_view.rs @@ -229,7 +229,7 @@ impl GetStartedView { .finish(), appearance .ui_builder() - .paragraph("Welcome to Galaxy AI") + .paragraph("Welcome to Galaxy") .with_style(UiComponentStyles { font_size: Some(20.), ..Default::default() diff --git a/app/src/root_view.rs b/app/src/root_view.rs index 4ea1ae43..3f399734 100644 --- a/app/src/root_view.rs +++ b/app/src/root_view.rs @@ -121,7 +121,7 @@ use galaxyui::{FocusContext, NextNewWindowsHasThisWindowsBoundsUponClose}; #[cfg(target_family = "wasm")] use crate::auth::web_handoff::{WebHandoffEvent, WebHandoffView}; -const WINDOW_TITLE: &str = "Galaxy AI"; +const WINDOW_TITLE: &str = "Galaxy"; lazy_static! { static ref FALLBACK_WINDOW_SIZE: Vector2F = vec2f(800.0, 600.0); diff --git a/app/src/uri/browser_url_handler.rs b/app/src/uri/browser_url_handler.rs index 241f674e..f07eaab1 100644 --- a/app/src/uri/browser_url_handler.rs +++ b/app/src/uri/browser_url_handler.rs @@ -1,6 +1,6 @@ use url::Url; -const DEFAULT_TITLE: &str = "Galaxy AI"; +const DEFAULT_TITLE: &str = "Galaxy"; const BASE_APP_PATH: &str = "/app"; pub fn update_browser_url(url: Option, force_redirect: bool) { diff --git a/app/src/workspace/mod.rs b/app/src/workspace/mod.rs index 2f927e9a..8163c662 100644 --- a/app/src/workspace/mod.rs +++ b/app/src/workspace/mod.rs @@ -1396,7 +1396,7 @@ fn add_open_setting_pages_as_editable_binding(app: &mut AppContext) { EditableBinding::new( "workspace:show_settings_about_page", BindingDescription::new("Open Settings: About") - .with_custom_description(bindings::MAC_MENUS_CONTEXT, "About Galaxy AI"), + .with_custom_description(bindings::MAC_MENUS_CONTEXT, "About Galaxy"), WorkspaceAction::ShowSettingsPage(SettingsSection::About), ) .with_group(bindings::BindingGroup::Settings.as_str()) diff --git a/app/src/workspace/view.rs b/app/src/workspace/view.rs index 458a0dd4..cdf1e44d 100644 --- a/app/src/workspace/view.rs +++ b/app/src/workspace/view.rs @@ -545,7 +545,7 @@ const TAB_BAR_PILL_WIDTH: f32 = 100.; const PILL_FONT_SIZE: f32 = 12.; // We use the word "Warp" in the Update Ready button to make it obvious that the terminal is Warp. // This can lead to free advertising when users screen-share Warp when an update is available. -const UPDATE_READY_TEXT: &str = "Update Galaxy AI"; +const UPDATE_READY_TEXT: &str = "Update Galaxy"; const TAB_BAR_OVERFLOW_MENU_WIDTH: f32 = 300.;