Consolidate binary targets to galaxy-oss only

- Remove dev, integration, local, preview, and stable bin targets
- Update Cargo.toml to reflect single binary
- Fix related module references and tests
This commit is contained in:
Ryan Ward
2026-08-20 17:36:05 -05:00
parent cf1ae37369
commit 19b2c5f687
16 changed files with 309 additions and 413 deletions
-59
View File
@@ -22,32 +22,6 @@ name = "galaxy-oss"
path = "src/bin/oss.rs" path = "src/bin/oss.rs"
test = false test = false
[[bin]]
name = "galaxy-local"
path = "src/bin/local.rs"
test = false
[[bin]]
name = "integration"
path = "src/bin/integration.rs"
test = false
[[bin]]
name = "stable"
path = "src/bin/stable.rs"
test = false
[[bin]]
name = "galaxy-dev"
path = "src/bin/dev.rs"
test = false
[[bin]]
name = "galaxy-preview"
path = "src/bin/preview.rs"
required-features = ["preview_channel"]
test = false
[[bin]] [[bin]]
name = "generate_settings_schema" name = "generate_settings_schema"
path = "src/bin/generate_settings_schema.rs" path = "src/bin/generate_settings_schema.rs"
@@ -847,7 +821,6 @@ code_find_replace = []
command_palette_file_search = [] command_palette_file_search = []
conversation_filter = [] conversation_filter = []
ai_context_menu_commands = [] ai_context_menu_commands = []
preview_channel = []
ai_context_menu_code = [] ai_context_menu_code = []
expand_edit_to_pane = [] expand_edit_to_pane = []
fallback_model_load_output_messaging = [] fallback_model_load_output_messaging = []
@@ -984,37 +957,5 @@ resources = ["assets/onboarding"]
icon = ["channels/oss/icon/no-padding/512x512.png", "channels/oss/icon/no-padding/icon.ico"] icon = ["channels/oss/icon/no-padding/512x512.png", "channels/oss/icon/no-padding/icon.ico"]
short_description = "Galaxy - AI-powered terminal for development teams." short_description = "Galaxy - AI-powered terminal for development teams."
[package.metadata.bundle.bin.stable]
category = "public.app-category.developer-tools"
copyright = "© 2026, Samsung Electronics Co., Ltd."
identifier = "samsung.galaxy.GalaxyStable"
name = "Galaxy"
resources = ["assets/onboarding"]
short_description = "Galaxy - AI-powered terminal, stable build."
[package.metadata.bundle.bin.galaxy-preview]
category = "public.app-category.developer-tools"
copyright = "© 2026, Samsung Electronics Co., Ltd."
identifier = "samsung.galaxy.GalaxyPreview"
name = "Galaxy Preview"
resources = ["assets/onboarding"]
short_description = "Galaxy - AI-powered terminal, preview build."
[package.metadata.bundle.bin.galaxy-dev]
category = "public.app-category.developer-tools"
copyright = "© 2026, Samsung Electronics Co., Ltd."
identifier = "samsung.galaxy.GalaxyDev"
name = "Galaxy Dev"
resources = ["assets/onboarding"]
short_description = "Galaxy - AI-powered terminal, developer build."
[package.metadata.bundle.bin.galaxy-local]
category = "public.app-category.developer-tools"
copyright = "© 2026, Samsung Electronics Co., Ltd."
identifier = "samsung.galaxy.GalaxyLocal"
name = "Galaxy Local"
resources = ["assets/onboarding"]
short_description = "Galaxy - AI-powered terminal, local build."
[package.metadata.cargo-udeps.ignore] [package.metadata.cargo-udeps.ignore]
normal = ["embed_plist"] normal = ["embed_plist"]
+47 -48
View File
@@ -66,7 +66,7 @@ use crate::ai::blocklist::code_block::CodeSnippetButtonHandles;
use crate::ai::blocklist::inline_action::inline_action_icons::icon_size; use crate::ai::blocklist::inline_action::inline_action_icons::icon_size;
use crate::ai::blocklist::permissions::is_agent_mode_autonomy_allowed; use crate::ai::blocklist::permissions::is_agent_mode_autonomy_allowed;
use crate::ai::blocklist::{ use crate::ai::blocklist::{
BlocklistAIActionModel, BlocklistAIHistoryEvent, BlocklistAIPermissions, BlocklistAIActionModel, BlocklistAIController, BlocklistAIHistoryEvent, BlocklistAIPermissions,
}; };
use crate::ai::control_code_parser::{parse_control_codes_from_bytes, ParsedControlCodeOutput}; use crate::ai::control_code_parser::{parse_control_codes_from_bytes, ParsedControlCodeOutput};
use crate::ai::execution_profiles::profiles::{ use crate::ai::execution_profiles::profiles::{
@@ -489,27 +489,36 @@ impl CLISubagentView {
} }
fn task_inputs_to_render(&self, app: &AppContext) -> Vec<AIAgentInput> { fn task_inputs_to_render(&self, app: &AppContext) -> Vec<AIAgentInput> {
BlocklistAIHistoryModel::as_ref(app) let inputs = BlocklistAIHistoryModel::as_ref(app)
.conversation(&self.conversation_id) .conversation(&self.conversation_id)
.and_then(|conversation| conversation.get_task(&self.task_id)) .and_then(|conversation| conversation.get_task(&self.task_id))
.map(|task| { .map(|task| {
task.exchanges() task.exchanges()
.flat_map(|exchange| exchange.input.iter()) .flat_map(|exchange| exchange.input.iter())
.filter_map(|input| { .cloned()
matches!(input, AIAgentInput::UserQuery { .. }).then(|| input.clone()) .collect::<Vec<_>>()
})
.last()
.into_iter()
.collect()
}) })
.unwrap_or_else(|| self.model.inputs_to_render(app).to_vec()) .unwrap_or_else(|| self.model.inputs_to_render(app).to_vec());
inputs
.into_iter()
.rev()
.find_map(|input| match &input {
AIAgentInput::UserQuery { query, .. }
if query != BlocklistAIController::cli_monitor_nudge_message() =>
{
Some(input)
}
_ => None,
})
.into_iter()
.collect()
} }
/// Builds the compact visible transcript for the monitor task. /// Builds the compact visible transcript for the monitor task.
/// ///
/// The latest user query and the newest assistant text remain visible while historical tool /// The view shows at most one user query and one assistant progress message. Historical tool
/// activity is omitted to avoid a growing stack of repeated poll cards. Only the newest /// calls and monitor nudges are implementation details, not user-facing transcript content.
/// exchange's live action is retained.
fn task_output_to_render(&self, app: &AppContext) -> AIAgentOutput { fn task_output_to_render(&self, app: &AppContext) -> AIAgentOutput {
let Some(task) = BlocklistAIHistoryModel::as_ref(app) let Some(task) = BlocklistAIHistoryModel::as_ref(app)
.conversation(&self.conversation_id) .conversation(&self.conversation_id)
@@ -519,32 +528,17 @@ impl CLISubagentView {
.model .model
.status(app) .status(app)
.output_to_render() .output_to_render()
.map(|output| output.get().clone()) .map(|output| compact_monitor_output([output.get().clone()]))
.unwrap_or_default(); .unwrap_or_default();
}; };
let Some(last_exchange_id) = task.last_exchange().map(|exchange| exchange.id) else { let outputs = task.exchanges().filter_map(|exchange| {
return AIAgentOutput::default(); exchange
}; .output_status
.output()
let mut visible_output = AIAgentOutput::default(); .map(|output| output.get().clone())
for exchange in task.exchanges() { });
let Some(output) = exchange.output_status.output() else { compact_monitor_output(outputs)
continue;
};
let output = output.get();
for message in output.messages.iter().filter(|message| {
should_retain_task_output_message(&message.message, exchange.id == last_exchange_id)
}) {
if matches!(message.message, AIAgentOutputMessageType::Text(_)) {
visible_output.messages.retain(|existing| {
!matches!(existing.message, AIAgentOutputMessageType::Text(_))
});
}
visible_output.messages.push(message.clone());
}
}
visible_output
} }
fn execute_pending_action(&mut self, ctx: &mut ViewContext<Self>) { fn execute_pending_action(&mut self, ctx: &mut ViewContext<Self>) {
@@ -1635,18 +1629,23 @@ fn should_show_read_files_speedbump(app: &AppContext) -> bool {
&& *AISettings::as_ref(app).should_show_agent_mode_autoread_files_speedbump && *AISettings::as_ref(app).should_show_agent_mode_autoread_files_speedbump
} }
fn should_retain_task_output_message( fn compact_monitor_output(outputs: impl IntoIterator<Item = AIAgentOutput>) -> AIAgentOutput {
message: &AIAgentOutputMessageType, let latest_text = outputs
is_latest_exchange: bool, .into_iter()
) -> bool { .flat_map(|output| output.messages)
.filter(|message| should_retain_task_output_message(&message.message))
.last();
// Keep the monitor transcript to one user-visible assistant message. Tool calls are
// implementation details; the model's latest explanation is the useful progress update.
AIAgentOutput {
messages: latest_text.into_iter().collect(),
..Default::default()
}
}
fn should_retain_task_output_message(message: &AIAgentOutputMessageType) -> bool {
matches!(message, AIAgentOutputMessageType::Text(_)) matches!(message, AIAgentOutputMessageType::Text(_))
|| (is_latest_exchange
&& matches!(
message,
AIAgentOutputMessageType::Action(_)
| AIAgentOutputMessageType::RuntimeActivity(_)
| AIAgentOutputMessageType::WebSearch(_)
))
} }
fn get_action_loading_text(action: AIAgentActionType) -> Option<String> { fn get_action_loading_text(action: AIAgentActionType) -> Option<String> {
@@ -1663,10 +1662,10 @@ fn get_action_loading_text(action: AIAgentActionType) -> Option<String> {
AIAgentActionType::FileGlobV2 { .. } => Some(LOAD_OUTPUT_MESSAGE_FOR_FILE_GLOB.to_string()), AIAgentActionType::FileGlobV2 { .. } => Some(LOAD_OUTPUT_MESSAGE_FOR_FILE_GLOB.to_string()),
AIAgentActionType::ReadShellCommandOutput { delay, .. } => match delay { AIAgentActionType::ReadShellCommandOutput { delay, .. } => match delay {
Some(crate::ai::agent::ShellCommandDelay::OnCompletion) => { Some(crate::ai::agent::ShellCommandDelay::OnCompletion) => {
Some("Waiting for the running command to finish…".to_string()) Some("Waiting for the command to finish…".to_string())
} }
Some(crate::ai::agent::ShellCommandDelay::Duration(_)) | None => { Some(crate::ai::agent::ShellCommandDelay::Duration(_)) | None => {
Some("Checking the running command output…".to_string()) Some("Reading the latest command output…".to_string())
} }
}, },
AIAgentActionType::WriteToLongRunningShellCommand { .. } => { AIAgentActionType::WriteToLongRunningShellCommand { .. } => {
+34 -12
View File
@@ -3,11 +3,14 @@ use std::time::Duration;
use galaxy_agent_core::RuntimeActivity; use galaxy_agent_core::RuntimeActivity;
use galaxy_terminal::model::escape_sequences; use galaxy_terminal::model::escape_sequences;
use super::{get_action_icon, get_action_loading_text, should_retain_task_output_message}; use super::{
compact_monitor_output, get_action_icon, get_action_loading_text,
should_retain_task_output_message,
};
use crate::ai::agent::task::TaskId; use crate::ai::agent::task::TaskId;
use crate::ai::agent::{ use crate::ai::agent::{
AIAgentAction, AIAgentActionId, AIAgentActionType, AIAgentOutputMessageType, AIAgentAction, AIAgentActionId, AIAgentActionType, AIAgentOutput, AIAgentOutputMessage,
AIAgentPtyWriteMode, AIAgentText, ShellCommandDelay, AIAgentOutputMessageType, AIAgentPtyWriteMode, AIAgentText, MessageId, ShellCommandDelay,
}; };
use crate::terminal::model::block::BlockId; use crate::terminal::model::block::BlockId;
use crate::ui_components::icons::Icon; use crate::ui_components::icons::Icon;
@@ -21,7 +24,7 @@ fn command_output_poll_has_visible_monitor_status() {
assert_eq!( assert_eq!(
get_action_loading_text(action.clone()).as_deref(), get_action_loading_text(action.clone()).as_deref(),
Some("Checking the running command output…") Some("Reading the latest command output…")
); );
assert_eq!(get_action_icon(action), Some(Icon::ClockRefresh)); assert_eq!(get_action_icon(action), Some(Icon::ClockRefresh));
} }
@@ -43,11 +46,11 @@ fn typed_interrupt_has_distinct_visible_status() {
} }
#[test] #[test]
fn transcript_retains_prior_text_but_only_latest_tool_activity() { fn transcript_retains_only_one_user_visible_agent_message() {
let text = AIAgentOutputMessageType::Text(AIAgentText { sections: vec![] }); let text = AIAgentOutputMessageType::Text(AIAgentText { sections: vec![] });
assert!(should_retain_task_output_message(&text, false)); assert!(should_retain_task_output_message(&text));
let poll = AIAgentOutputMessageType::Action(AIAgentAction { let poll = AIAgentAction {
id: AIAgentActionId::from("poll".to_string()), id: AIAgentActionId::from("poll".to_string()),
task_id: TaskId::new("cli-task".to_string()), task_id: TaskId::new("cli-task".to_string()),
action: AIAgentActionType::ReadShellCommandOutput { action: AIAgentActionType::ReadShellCommandOutput {
@@ -56,9 +59,13 @@ fn transcript_retains_prior_text_but_only_latest_tool_activity() {
}, },
requires_result: true, requires_result: true,
tool_name: Some("read_shell_command_output".to_string()), tool_name: Some("read_shell_command_output".to_string()),
}); };
assert!(!should_retain_task_output_message(&poll, false)); assert!(!should_retain_task_output_message(
assert!(should_retain_task_output_message(&poll, true)); &AIAgentOutputMessageType::Action(poll.clone()),
));
assert!(!should_retain_task_output_message(
&AIAgentOutputMessageType::Action(poll),
));
let runtime_activity = AIAgentOutputMessageType::RuntimeActivity(RuntimeActivity { let runtime_activity = AIAgentOutputMessageType::RuntimeActivity(RuntimeActivity {
id: "acp-tool".to_owned(), id: "acp-tool".to_owned(),
@@ -66,6 +73,21 @@ fn transcript_retains_prior_text_but_only_latest_tool_activity() {
status: None, status: None,
output: None, output: None,
}); });
assert!(!should_retain_task_output_message(&runtime_activity, false)); assert!(!should_retain_task_output_message(&runtime_activity));
assert!(should_retain_task_output_message(&runtime_activity, true)); }
#[test]
fn compact_monitor_output_keeps_only_the_latest_text_message() {
let output = |id: &str| AIAgentOutput {
messages: vec![AIAgentOutputMessage::text(
MessageId::new(id.to_owned()),
AIAgentText { sections: vec![] },
)],
..Default::default()
};
let compacted = compact_monitor_output([output("old"), output("latest")]);
assert_eq!(compacted.messages.len(), 1);
assert_eq!(&*compacted.messages[0].id, "latest");
} }
+1 -1
View File
@@ -2954,7 +2954,7 @@ impl BlocklistAIController {
} }
pub(crate) fn cli_monitor_nudge_message() -> &'static str { pub(crate) fn cli_monitor_nudge_message() -> &'static str {
"The command is still running. Please check its latest output and keep monitoring it." "The command is still running. Before checking it again, provide one concise, user-facing sentence grounded in the latest output about what it appears to be doing, then continue monitoring it."
} }
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
+1 -1
View File
@@ -816,7 +816,7 @@ fn build_system_prompt(
"## Orchestration Mode\nDelegate only independent, bounded work where parallelism materially helps, then synthesize the results.\n\n", "## Orchestration Mode\nDelegate only independent, bounded work where parallelism materially helps, then synthesize the results.\n\n",
), ),
RigRequestMode::Cli => prompt.push_str( RigRequestMode::Cli => prompt.push_str(
"## Running Command Monitor\nKeep an eye on the existing command while continuing the user's request. Use the command ID from the tool result for every read/write operation. If the result says the command finished, report its outcome and stop polling. If it says the command is still running, the next assistant output MUST be a tool call. Use `read_shell_command_output` with a short delay for normal progress. If the snapshot clearly shows an interactive pager or editor, do not keep polling: an alternate screen containing `(END)` is `less`, so call `write_to_long_running_shell_command` with input `q` and mode `raw`; for a clearly identified Vim screen, send input `:q` with mode `line`. Poll briefly after sending quit input to verify the outcome. Use `interrupt_shell_command` immediately when the user's explicit stop condition is met. The next response must be a tool call, not a progress update. Never choose a poll interval that crosses a user-specified deadline or stop condition. After an interrupt, poll briefly to verify the outcome. Never start a duplicate command merely to check its state, and never report completion while a result says it is still running.\n\n", "## Running Command Monitor\nKeep an eye on the existing command while continuing the user's request. Use the command ID from the tool result for every read/write operation. If the result says the command finished, report its outcome and stop polling. If the result says the command is still running, write at most one concise, user-facing sentence grounded in the latest output explaining what the command appears to be doing or waiting for, then make the polling tool call in the same response. Do not send a text-only progress response, repeat a generic 'still running' message, or mention internal polling mechanics. If the snapshot clearly shows an interactive pager or editor, do not keep polling: an alternate screen containing `(END)` is `less`, so call `write_to_long_running_shell_command` with input `q` and mode `raw`; for a clearly identified Vim screen, send input `:q` with mode `line`. Poll briefly after sending quit input to verify the outcome. Use `interrupt_shell_command` immediately when the user's explicit stop condition is met. Never choose a poll interval that crosses a user-specified deadline or stop condition. After an interrupt, poll briefly to verify the outcome. Never start a duplicate command merely to check its state, and never report completion while a result says it is still running.\n\n",
), ),
RigRequestMode::CompletedCommandAssessment => prompt.push_str( RigRequestMode::CompletedCommandAssessment => prompt.push_str(
"## Completed Command Assessment\nThe monitored command has finished. Use its command, command ID, final terminal output, and the assessment instruction in the latest hidden input to provide the final user-facing outcome. Do not continue polling, request more terminal output, or call tools.\n\n", "## Completed Command Assessment\nThe monitored command has finished. Use its command, command ID, final terminal output, and the assessment instruction in the latest hidden input to provide the final user-facing outcome. Do not continue polling, request more terminal output, or call tools.\n\n",
+3 -2
View File
@@ -450,10 +450,11 @@ fn lrc_snapshot_follow_up_uses_the_cli_monitor_prompt_and_tools() {
assert!(prompt.contains("## Running Command Monitor")); assert!(prompt.contains("## Running Command Monitor"));
assert!(prompt.contains("`read_shell_command_output` with a short delay")); assert!(prompt.contains("`read_shell_command_output` with a short delay"));
assert!(prompt.contains("next assistant output MUST be a tool call")); assert!(prompt.contains("one concise, user-facing sentence"));
assert!(prompt.contains("Do not send a text-only progress response"));
assert!(prompt.contains("alternate screen containing `(END)` is `less`")); assert!(prompt.contains("alternate screen containing `(END)` is `less`"));
assert!(prompt.contains("`write_to_long_running_shell_command` with input `q` and mode `raw`")); assert!(prompt.contains("`write_to_long_running_shell_command` with input `q` and mode `raw`"));
assert!(prompt.contains("The next response must be a tool call, not a progress update")); assert!(prompt.contains("make the polling tool call in the same response"));
assert!(prepared assert!(prepared
.request .request
.tools .tools
-18
View File
@@ -1,18 +0,0 @@
// On Windows, we don't want to display a console window when the application is running in release
// builds. See https://doc.rust-lang.org/reference/runtime.html#the-windows_subsystem-attribute.
#![cfg_attr(feature = "release_bundle", windows_subsystem = "windows")]
use anyhow::Result;
use galaxy_core::channel::{Channel, ChannelState};
use galaxy_core::features;
fn main() -> Result<()> {
ChannelState::set(
ChannelState::new(Channel::Dev, warp_channel_config::load_config!("dev"))
.with_additional_features(features::DEBUG_FLAGS)
.with_additional_features(features::DOGFOOD_FLAGS)
.with_additional_features(features::PREVIEW_FLAGS),
);
galaxy::run()
}
-74
View File
@@ -1,74 +0,0 @@
use anyhow::Result;
use clap::Parser;
use galaxy_cli::WorkerCommand;
use galaxy_core::channel::{Channel, ChannelConfig, ChannelState, OzConfig, WarpServerConfig};
use galaxy_core::AppId;
#[derive(Debug, Default, Parser, Clone)]
#[command(name = "warp-integration")]
#[clap(args_conflicts_with_subcommands = true)]
pub struct Args {
#[command(subcommand)]
command: Option<WorkerCommand>,
}
pub fn main() -> Result<()> {
ChannelState::set(ChannelState::new(
Channel::Integration,
ChannelConfig {
app_id: AppId::new(
"dev",
"warp",
if cfg!(target_os = "macos") {
"Warp-Integration"
} else {
"WarpIntegration"
},
),
logfile_name: "warp_integration.log".into(),
server_config: WarpServerConfig {
firebase_auth_api_key: "".into(),
// Use an IP in the IANA testing range, with the TCP discard port, to
// black-hole server traffic.
server_root_url: "http://192.0.2.0:9".into(),
rtc_server_url: "ws://192.0.2.0:9/graphql/v2".into(),
session_sharing_server_url: None,
iap_config: None,
},
oz_config: OzConfig {
// Use an IP in the IANA testing range, with the TCP discard port, to
// black-hole server traffic.
oz_root_url: "http://192.0.2.0:9".into(),
workload_audience_url: None,
},
telemetry_config: None,
autoupdate_config: None,
mcp_static_config: None,
},
));
let args = Args::parse();
if let Some(command) = &args.command {
match command {
#[cfg(unix)]
WorkerCommand::TerminalServer(args) => {
// If we were asked to run as a terminal server (as opposed to the main
// GUI application), do so. This must occur before init_logging, as the
// terminal server sets up its own logger, and attempting to set a second
// logger leads to a panic.
galaxy::terminal::local_tty::server::run_terminal_server(args);
return Ok(());
}
#[cfg(not(target_family = "wasm"))]
WorkerCommand::RemoteServerProxy(_) | WorkerCommand::RemoteServerDaemon(_) => {
return galaxy::run();
}
// This is a catch-all to handle the plugin host, which the integration test crate doesn't have a feature flag for.
#[allow(unreachable_patterns)]
other => panic!("Worker not supported in integration tests: {other:?}"),
}
}
galaxy::run()
}
-59
View File
@@ -1,59 +0,0 @@
use anyhow::Result;
use galaxy_core::channel::{Channel, ChannelState};
use galaxy_core::features;
fn main() -> Result<()> {
let config = warp_channel_config::load_config!("local");
let mut state = ChannelState::new(Channel::Local, config)
.with_additional_features(features::DEBUG_FLAGS)
.with_additional_features(features::DOGFOOD_FLAGS)
.with_additional_features(features::PREVIEW_FLAGS)
.with_additional_features(features::LOCAL_FLAGS);
// Enable sandbox telemetry feature flag if the env var is set.
if std::env::var("WITH_SANDBOX_TELEMETRY").is_ok() {
state = state.with_additional_features(&[features::FeatureFlag::WithSandboxTelemetry]);
}
ChannelState::set(state);
galaxy::run()
}
// If we're not using an external plist, embed the following as the Info.plist.
#[cfg(all(not(feature = "extern_plist"), target_os = "macos"))]
embed_plist::embed_info_plist_bytes!(r#"
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleDisplayName</key>
<string>Galaxy</string>
<key>CFBundleExecutable</key>
<string>galaxy-local</string>
<key>CFBundleIdentifier</key>
<string>samsung.galaxy.GalaxyLocal</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Galaxy</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.1.0</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.developer-tools</string>
<key>NSHighResolutionCapable</key>
<true/>
<key>UIDesignRequiresCompatibility</key>
<true/>
<key>CFBundleURLTypes</key>
<array><dict><key>CFBundleURLName</key><string>Galaxy</string><key>CFBundleURLSchemes</key><array><string>galaxyai</string></array></dict></array>
<key>NSHumanReadableCopyright</key>
<string>© 2026, Samsung Electronics Co., Ltd.</string>
</dict>
</plist>
"#.as_bytes());
+1
View File
@@ -25,6 +25,7 @@ fn main() -> Result<()> {
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
state = state.with_additional_features(galaxy_core::features::DEBUG_FLAGS); state = state.with_additional_features(galaxy_core::features::DEBUG_FLAGS);
} }
state = state.with_additional_features(galaxy_core::features::PREVIEW_FLAGS);
state = state.with_additional_features(&[ state = state.with_additional_features(&[
FeatureFlag::AgentMode, FeatureFlag::AgentMode,
FeatureFlag::AgentView, FeatureFlag::AgentView,
-20
View File
@@ -1,20 +0,0 @@
// On Windows, we don't want to display a console window when the application is running in release
// builds. See https://doc.rust-lang.org/reference/runtime.html#the-windows_subsystem-attribute.
#![cfg_attr(feature = "release_bundle", windows_subsystem = "windows")]
use anyhow::Result;
use galaxy_core::channel::{Channel, ChannelState};
use galaxy_core::features;
fn main() -> Result<()> {
ChannelState::set(
ChannelState::new(
Channel::Preview,
warp_channel_config::load_config!("preview"),
)
.with_additional_features(features::PREVIEW_FLAGS)
.with_additional_features(&[features::FeatureFlag::ForceLogin]),
);
galaxy::run()
}
-15
View File
@@ -1,15 +0,0 @@
// On Windows, we don't want to display a console window when the application is running in release
// builds. See https://doc.rust-lang.org/reference/runtime.html#the-windows_subsystem-attribute.
#![cfg_attr(feature = "release_bundle", windows_subsystem = "windows")]
use anyhow::Result;
use galaxy_core::channel::{Channel, ChannelState};
fn main() -> Result<()> {
ChannelState::set(ChannelState::new(
Channel::Stable,
warp_channel_config::load_config!("stable"),
));
galaxy::run()
}
+4
View File
@@ -1239,6 +1239,10 @@ pub(crate) fn initialize_app(
} }
} }
// Migrate state and caches out of macOS Application Support before creating
// the new home-relative data directory.
galaxy_core::paths::migrate_legacy_macos_data_dir_if_needed();
// One-time migration: give Preview its own config directory by // One-time migration: give Preview its own config directory by
// symlinking contents from the shared ~/.warp location. Must run // symlinking contents from the shared ~/.warp location. Must run
// before ensure_galaxy_watch_roots_exist() creates the new directory. // before ensure_galaxy_watch_roots_exist() creates the new directory.
+4 -4
View File
@@ -27,20 +27,20 @@ This will create a new folder with an up.sql and down.sql.
## Step 3: Run the migration + generate the schema ## Step 3: Run the migration + generate the schema
``` ```
cd <repo root> cd <repo root>
diesel migration run --database-url="/Users/$USER/Library/Application Support/samsung.galaxy.GalaxyLocal/galaxy.sqlite" diesel migration run --database-url="/Users/$USER/.galaxy-local/galaxy.sqlite"
``` ```
This will run the migration on the same warp that runs when you run the app locally. This automatically generates or updates the `crates/persistence/src/schema.rs`. We do not make manual edits to `schema.rs`. This will run the migration on the same warp that runs when you run the app locally. This automatically generates or updates the `crates/persistence/src/schema.rs`. We do not make manual edits to `schema.rs`.
You can also print the schema from a database that already has the migration with: You can also print the schema from a database that already has the migration with:
``` ```
diesel print-schema --database-url="/Users/$USER/Library/Application Support/samsung.galaxy.GalaxyLocal/galaxy.sqlite" diesel print-schema --database-url="/Users/$USER/.galaxy-local/galaxy.sqlite"
``` ```
## Reverting/redo-ing migrations ## Reverting/redo-ing migrations
As you are writing features and changing branches, you'll want to undo migrations to fix your database and make it compatible with older code. Redo-ing can also be helpful as you are iterating on your schema. As you are writing features and changing branches, you'll want to undo migrations to fix your database and make it compatible with older code. Redo-ing can also be helpful as you are iterating on your schema.
``` ```
diesel migration revert --database-url="/Users/$USER/Library/Application Support/samsung.galaxy.GalaxyLocal/galaxy.sqlite" diesel migration revert --database-url="/Users/$USER/.galaxy-local/galaxy.sqlite"
diesel migration redo --database-url="/Users/$USER/Library/Application Support/samsung.galaxy.GalaxyLocal/galaxy.sqlite" diesel migration redo --database-url="/Users/$USER/.galaxy-local/galaxy.sqlite"
``` ```
# Schema style # Schema style
+128 -77
View File
@@ -204,36 +204,17 @@ pub fn galaxy_home_mcp_config_file_path() -> Option<PathBuf> {
galaxy_home_config_dir().map(|warp_config_dir| warp_config_dir.join(".mcp.json")) galaxy_home_config_dir().map(|warp_config_dir| warp_config_dir.join(".mcp.json"))
} }
/// Returns the macOS config directory name for the current channel.
///
/// Stable uses `.warp-core`, while other channels include a channel suffix
/// (e.g., `.warp-core-dev`, `.warp-core-local`).
///
/// These suffixes are persisted on disk as directory names and must not be
/// changed once established, or existing user data will be orphaned.
#[cfg(target_os = "macos")]
fn macos_config_dir_name() -> String {
match ChannelState::channel() {
Channel::Stable | Channel::Oss => WARP_CONFIG_DIR.to_owned(),
Channel::Preview => format!("{WARP_CONFIG_DIR}-preview"),
Channel::Dev => format!("{WARP_CONFIG_DIR}-dev"),
Channel::Integration => format!("{WARP_CONFIG_DIR}-integration"),
Channel::Local => format!("{WARP_CONFIG_DIR}-local"),
}
}
/// Returns the path to the directory where portable user data should be /// Returns the path to the directory where portable user data should be
/// stored. /// stored.
/// ///
/// This is the appropriate home for things like custom themes and workflows. /// This is the appropriate home for things like custom themes and workflows.
pub fn data_dir() -> PathBuf { pub fn data_dir() -> PathBuf {
cfg_if! { cfg_if! {
if #[cfg(target_os = "macos")] { if #[cfg(target_os = "windows")] {
// TODO(vorporeal): We should do something better than return a
// relative path.
dirs::home_dir().unwrap_or_default().join(macos_config_dir_name())
} else {
project_dirs().map(|dirs| dirs.data_dir().to_owned()).unwrap_or_default() project_dirs().map(|dirs| dirs.data_dir().to_owned()).unwrap_or_default()
} else {
// macOS and Linux both use ~/.galaxy
dirs::home_dir().unwrap_or_default().join(galaxy_home_config_dir_name())
} }
} }
} }
@@ -242,14 +223,13 @@ pub fn data_dir() -> PathBuf {
/// should be stored. /// should be stored.
pub fn config_local_dir() -> PathBuf { pub fn config_local_dir() -> PathBuf {
cfg_if! { cfg_if! {
if #[cfg(target_os = "macos")] { if #[cfg(target_os = "windows")] {
// TODO(vorporeal): We should do something better than return a
// relative path.
dirs::home_dir().unwrap_or_default().join(macos_config_dir_name())
} else {
project_dirs() project_dirs()
.map(|dirs| dirs.config_local_dir().to_owned()) .map(|dirs| dirs.config_local_dir().to_owned())
.unwrap_or_default() .unwrap_or_default()
} else {
// macOS and Linux both use ~/.galaxy
dirs::home_dir().unwrap_or_default().join(galaxy_home_config_dir_name())
} }
} }
} }
@@ -269,39 +249,34 @@ pub fn base_config_dir() -> PathBuf {
/// contains durable but non-critical and non-portable data like what windows /// contains durable but non-critical and non-portable data like what windows
/// the user had open and cached state of known Warp Drive objects. /// the user had open and cached state of known Warp Drive objects.
pub fn state_dir() -> PathBuf { pub fn state_dir() -> PathBuf {
let Some(project_dirs) = project_dirs() else { cfg_if! {
return PathBuf::new(); if #[cfg(target_os = "windows")] {
}; let Some(project_dirs) = project_dirs() else {
// For platforms that don't have a notion of a "state" directory (e.g.: return PathBuf::new();
// macOS and Windows), fall back to using the data directory. };
project_dirs project_dirs
.state_dir() .state_dir()
.unwrap_or_else(|| project_dirs.data_local_dir()) .unwrap_or_else(|| project_dirs.data_local_dir())
.to_owned() .to_owned()
} else {
// macOS and Linux both use ~/.galaxy (same as data_dir)
data_dir()
}
}
} }
/// Returns the path to the secure directory for non-portable application state data. /// Returns the path to the secure directory for non-portable application state data.
/// ///
/// Prefer this over [`state_dir`] where possible. /// macOS data is intentionally kept in [`data_dir`] rather than an App Group container so all
/// /// local Galaxy data is visible under the user's home directory.
/// On macOS, this will use the App Group container directory if available.
pub fn secure_state_dir() -> Option<PathBuf> { pub fn secure_state_dir() -> Option<PathBuf> {
// Do not use the secure state directory in integration tests, which have a temporary home directory instead. // Do not use a secure state directory in integration tests, which have a temporary home.
if ChannelState::channel() == Channel::Integration { if ChannelState::channel() == Channel::Integration {
return None; return None;
} }
#[cfg(target_os = "macos")] // No platform currently has a separate secure state directory. Callers fall back to
if let Some(app_group_root) = app_group_container_path() { // `state_dir()`, which is `~/.galaxy` on macOS.
// The macOS project_path is the bundle ID (i.e. `dev.warp.Warp-Stable`).
let project_dirs = project_dirs()?;
return Some(
app_group_root
.join("Library/Application Support")
.join(project_dirs.project_path()),
);
}
None None
} }
@@ -317,20 +292,110 @@ pub fn themes_dir() -> PathBuf {
/// we don't want to fetch on every launch of the app but can be safely /// we don't want to fetch on every launch of the app but can be safely
/// deleted by the OS. /// deleted by the OS.
pub fn cache_dir() -> PathBuf { pub fn cache_dir() -> PathBuf {
let Some(project_dirs) = project_dirs() else {
return PathBuf::new();
};
cfg_if! { cfg_if! {
if #[cfg(target_os = "macos")] { if #[cfg(target_os = "windows")] {
// TODO(vorporeal): Given that this is just cache data; do we want project_dirs()
// change the path we use on macOS? .map(|project_dirs| project_dirs.cache_dir().to_owned())
project_dirs.data_dir().to_owned() .unwrap_or_default()
} else { } else {
project_dirs.cache_dir().to_owned() // macOS and Linux both use ~/.galaxy (same as data_dir)
data_dir()
} }
} }
} }
/// Migrates data from the old macOS Application Support locations into the home-relative Galaxy
/// directory. Existing files are never overwritten; directory contents are merged recursively.
pub fn migrate_legacy_macos_data_dir_if_needed() {
#[cfg(target_os = "macos")]
{
if ChannelState::channel() == Channel::Integration {
return;
}
let target_dir = data_dir();
let mut legacy_dirs = Vec::new();
if let Some(project_dirs) = project_dirs() {
legacy_dirs.push(project_dirs.data_dir().to_owned());
}
// Older signed builds may have used the App Group container for SQLite state.
if let (Some(app_group_root), Some(project_dirs)) =
(app_group_container_path(), project_dirs())
{
legacy_dirs.push(
app_group_root
.join("Library/Application Support")
.join(project_dirs.project_path()),
);
}
legacy_dirs.sort();
legacy_dirs.dedup();
for legacy_dir in legacy_dirs {
if legacy_dir != target_dir && legacy_dir.exists() {
migrate_directory_contents(&legacy_dir, &target_dir);
}
}
}
}
#[cfg(target_os = "macos")]
fn migrate_directory_contents(source_dir: &Path, target_dir: &Path) {
if let Err(err) = std::fs::create_dir_all(target_dir) {
log::warn!(
"Failed to create Galaxy data directory {} while migrating {}: {err}",
target_dir.display(),
source_dir.display()
);
return;
}
let entries = match std::fs::read_dir(source_dir) {
Ok(entries) => entries,
Err(err) => {
log::warn!(
"Failed to read legacy Galaxy data directory {}: {err}",
source_dir.display()
);
return;
}
};
for entry in entries.flatten() {
let source_path = entry.path();
let target_path = target_dir.join(entry.file_name());
let source_is_dir = entry.file_type().is_ok_and(|file_type| file_type.is_dir());
if target_path.exists() {
if source_is_dir && target_path.is_dir() {
migrate_directory_contents(&source_path, &target_path);
} else {
log::warn!(
"Leaving legacy Galaxy data at {} because {} already exists",
source_path.display(),
target_path.display()
);
}
continue;
}
if let Err(err) = std::fs::rename(&source_path, &target_path) {
log::warn!(
"Failed to migrate Galaxy data {} to {}: {err}",
source_path.display(),
target_path.display()
);
}
}
if std::fs::read_dir(source_dir)
.is_ok_and(|mut entries| entries.next().is_none())
{
let _ = std::fs::remove_dir(source_dir);
}
}
/// Returns a display-ready version of the path that is formatted in a /// Returns a display-ready version of the path that is formatted in a
/// home-dir-relative manner, if appropriate. /// home-dir-relative manner, if appropriate.
pub fn home_relative_path(path: &Path) -> String { pub fn home_relative_path(path: &Path) -> String {
@@ -360,30 +425,16 @@ fn project_dirs() -> Option<directories::ProjectDirs> {
/// ///
/// This returns [`None`] if the user's home directory could not be determined. /// This returns [`None`] if the user's home directory could not be determined.
fn project_dirs_for_app_id( fn project_dirs_for_app_id(
app_id: AppId, _app_id: AppId,
data_profile: Option<&str>, data_profile: Option<&str>,
) -> Option<directories::ProjectDirs> { ) -> Option<directories::ProjectDirs> {
cfg_if::cfg_if! { let base_app_name = "Galaxy".to_owned();
if #[cfg(any(target_os = "linux", target_os = "freebsd"))] {
// Adjust the base application name so that we end up with
// directories like "warp-terminal" and "warp-terminal-dev", to
// match our Linux package name.
let base_app_name = match app_id.application_name() {
"Warp" => "Warp-Terminal".to_owned(),
"WarpOss" => "Warp-Oss".to_owned(),
other if other.starts_with("Warp") => other.replace("Warp", "Warp-Terminal-"),
_ => app_id.application_name().to_owned(),
};
} else {
let base_app_name = app_id.application_name().to_owned();
}
}
let app_name = if let Some(data_profile) = data_profile { let app_name = if let Some(data_profile) = data_profile {
format!("{base_app_name}-{data_profile}") format!("{base_app_name}-{data_profile}")
} else { } else {
base_app_name base_app_name
}; };
directories::ProjectDirs::from(app_id.qualifier(), app_id.organization(), &app_name) directories::ProjectDirs::from("com", "galaxy", &app_name)
} }
/// Returns the path to the app's secure group container on macOS. /// Returns the path to the app's secure group container on macOS.
+86 -23
View File
@@ -8,11 +8,11 @@ fn test_data_dir_path() {
// ChannelState, by default, is configured for Channel::Oss. // ChannelState, by default, is configured for Channel::Oss.
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(target_os = "macos")] { if #[cfg(target_os = "macos")] {
assert_eq!(data_dir(), home_dir.join(".warp-oss")); assert_eq!(data_dir(), home_dir.join(".galaxy"));
} else if #[cfg(any(target_os = "linux", target_os = "freebsd"))] { } else if #[cfg(any(target_os = "linux", target_os = "freebsd"))] {
assert_eq!(data_dir(), home_dir.join(".local/share/warp-oss")); assert_eq!(data_dir(), home_dir.join(".galaxy"));
} else if #[cfg(windows)] { } else if #[cfg(windows)] {
assert_eq!(data_dir(), home_dir.join("AppData\\Roaming\\warp\\WarpOss\\data")); assert_eq!(data_dir(), home_dir.join("AppData\\Roaming\\galaxy\\Galaxy\\data"));
} else { } else {
unimplemented!("Need to update tests for current platform!"); unimplemented!("Need to update tests for current platform!");
} }
@@ -25,11 +25,11 @@ fn test_config_local_dir_path() {
// ChannelState, by default, is configured for Channel::Oss. // ChannelState, by default, is configured for Channel::Oss.
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(target_os = "macos")] { if #[cfg(target_os = "macos")] {
assert_eq!(config_local_dir(), home_dir.join(".warp-oss")); assert_eq!(config_local_dir(), home_dir.join(".galaxy"));
} else if #[cfg(any(target_os = "linux", target_os = "freebsd"))] { } else if #[cfg(any(target_os = "linux", target_os = "freebsd"))] {
assert_eq!(config_local_dir(), home_dir.join(".config/warp-oss")); assert_eq!(config_local_dir(), home_dir.join(".galaxy"));
} else if #[cfg(windows)] { } else if #[cfg(windows)] {
assert_eq!(config_local_dir(), home_dir.join("AppData\\Local\\warp\\WarpOss\\config")); assert_eq!(config_local_dir(), home_dir.join("AppData\\Local\\galaxy\\Galaxy\\config"));
} else { } else {
unimplemented!("Need to update tests for current platform!"); unimplemented!("Need to update tests for current platform!");
} }
@@ -40,8 +40,8 @@ fn test_config_local_dir_path() {
fn test_galaxy_home_config_dir_path() { fn test_galaxy_home_config_dir_path() {
let home_dir = home_dir().expect("Should be able to compute home directory"); let home_dir = home_dir().expect("Should be able to compute home directory");
let expected_dir_name = match ChannelState::data_profile() { let expected_dir_name = match ChannelState::data_profile() {
Some(data_profile) => format!(".warp-core-oss-{data_profile}"), Some(data_profile) => format!(".galaxy-{data_profile}"),
None => ".warp-core-oss".to_string(), None => ".galaxy".to_string(),
}; };
assert_eq!( assert_eq!(
@@ -68,11 +68,11 @@ fn test_cache_dir_path() {
// ChannelState, by default, is configured for Channel::Oss. // ChannelState, by default, is configured for Channel::Oss.
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(target_os = "macos")] { if #[cfg(target_os = "macos")] {
assert_eq!(cache_dir(), home_dir.join("Library/Application Support/dev.warp.WarpOss")); assert_eq!(cache_dir(), home_dir.join(".galaxy"));
} else if #[cfg(any(target_os = "linux", target_os = "freebsd"))] { } else if #[cfg(any(target_os = "linux", target_os = "freebsd"))] {
assert_eq!(cache_dir(), home_dir.join(".cache/warp-oss")); assert_eq!(cache_dir(), home_dir.join(".galaxy"));
} else if #[cfg(windows)] { } else if #[cfg(windows)] {
assert_eq!(cache_dir(), home_dir.join("AppData\\Local\\warp\\WarpOss\\cache")); assert_eq!(cache_dir(), home_dir.join("AppData\\Local\\galaxy\\Galaxy\\cache"));
} else { } else {
unimplemented!("Need to update tests for current platform!"); unimplemented!("Need to update tests for current platform!");
} }
@@ -85,28 +85,91 @@ fn test_state_dir_path() {
cfg_if::cfg_if! { cfg_if::cfg_if! {
// ChannelState, by default, is configured for Channel::Oss. // ChannelState, by default, is configured for Channel::Oss.
if #[cfg(target_os = "macos")] { if #[cfg(target_os = "macos")] {
assert_eq!(state_dir(), home_dir.join("Library/Application Support/dev.warp.WarpOss")); assert_eq!(state_dir(), home_dir.join(".galaxy"));
} else if #[cfg(any(target_os = "linux", target_os = "freebsd"))] { } else if #[cfg(any(target_os = "linux", target_os = "freebsd"))] {
assert_eq!(state_dir(), home_dir.join(".local/state/warp-oss")); assert_eq!(state_dir(), home_dir.join(".galaxy"));
} else if #[cfg(windows)] { } else if #[cfg(windows)] {
assert_eq!(state_dir(), home_dir.join("AppData\\Local\\warp\\WarpOss\\data")); assert_eq!(state_dir(), home_dir.join("AppData\\Local\\galaxy\\Galaxy\\data"));
} else { } else {
unimplemented!("Need to update tests for current platform!"); unimplemented!("Need to update tests for current platform!");
} }
} }
} }
#[cfg(target_os = "macos")]
#[test]
fn test_migrate_legacy_macos_data_dir_merges_without_overwriting() {
let tempdir = tempfile::tempdir().expect("tempdir should be created");
let source_dir = tempdir.path().join("legacy");
let target_dir = tempdir.path().join(".galaxy");
std::fs::create_dir_all(source_dir.join("nested")).expect("source should be created");
std::fs::write(source_dir.join("galaxy.sqlite"), b"legacy database")
.expect("source file should be created");
std::fs::write(source_dir.join("nested/legacy.txt"), b"legacy content")
.expect("nested source file should be created");
std::fs::create_dir_all(target_dir.join("nested")).expect("target should be created");
std::fs::write(target_dir.join("galaxy.sqlite"), b"current database")
.expect("target file should be created");
std::fs::write(target_dir.join("nested/current.txt"), b"current content")
.expect("nested target file should be created");
migrate_directory_contents(&source_dir, &target_dir);
assert_eq!(
std::fs::read(target_dir.join("galaxy.sqlite")).unwrap(),
b"current database"
);
assert_eq!(
std::fs::read(target_dir.join("nested/legacy.txt")).unwrap(),
b"legacy content"
);
assert_eq!(
std::fs::read(target_dir.join("nested/current.txt")).unwrap(),
b"current content"
);
// The source dir should still exist because "galaxy.sqlite" conflicted
// and was left in place.
assert!(source_dir.join("galaxy.sqlite").exists());
// The nested directory was fully merged (legacy.txt moved) and removed.
assert!(!source_dir.join("nested").exists());
}
#[cfg(target_os = "macos")]
#[test]
fn test_migrate_legacy_macos_data_dir_keeps_conflicting_legacy_data() {
let tempdir = tempfile::tempdir().expect("tempdir should be created");
let source_dir = tempdir.path().join("legacy");
let target_dir = tempdir.path().join(".galaxy");
std::fs::create_dir_all(&source_dir).expect("source should be created");
std::fs::create_dir_all(&target_dir).expect("target should be created");
std::fs::write(source_dir.join("settings.json"), b"legacy")
.expect("source file should be created");
std::fs::write(target_dir.join("settings.json"), b"current")
.expect("target file should be created");
migrate_directory_contents(&source_dir, &target_dir);
assert_eq!(
std::fs::read(target_dir.join("settings.json")).unwrap(),
b"current"
);
assert_eq!(
std::fs::read(source_dir.join("settings.json")).unwrap(),
b"legacy"
);
}
#[test] #[test]
fn test_project_path_for_warp_app_id() { fn test_project_path_for_warp_app_id() {
let project_dirs = project_dirs_for_app_id(AppId::new("dev", "warp", "Warp"), None) let project_dirs = project_dirs_for_app_id(AppId::new("dev", "warp", "Warp"), None)
.expect("should be able to compute project dirs"); .expect("should be able to compute project dirs");
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(target_os = "macos")] { if #[cfg(target_os = "macos")] {
assert_eq!(project_dirs.project_path(), "dev.warp.Warp"); assert_eq!(project_dirs.project_path(), "com.galaxy.Galaxy");
} else if #[cfg(any(target_os = "linux", target_os = "freebsd"))] { } else if #[cfg(any(target_os = "linux", target_os = "freebsd"))] {
assert_eq!(project_dirs.project_path(), "warp-terminal"); assert_eq!(project_dirs.project_path(), "galaxy");
} else if #[cfg(windows)] { } else if #[cfg(windows)] {
assert_eq!(project_dirs.project_path(), "warp\\Warp"); assert_eq!(project_dirs.project_path(), "galaxy\\Galaxy");
} else { } else {
unimplemented!("Need to update tests for current platform!"); unimplemented!("Need to update tests for current platform!");
} }
@@ -119,11 +182,11 @@ fn test_project_path_for_warp_dev_app_id() {
.expect("should be able to compute project dirs"); .expect("should be able to compute project dirs");
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(target_os = "macos")] { if #[cfg(target_os = "macos")] {
assert_eq!(project_dirs.project_path(), "dev.warp.WarpDev"); assert_eq!(project_dirs.project_path(), "com.galaxy.Galaxy");
} else if #[cfg(any(target_os = "linux", target_os = "freebsd"))] { } else if #[cfg(any(target_os = "linux", target_os = "freebsd"))] {
assert_eq!(project_dirs.project_path(), "warp-terminal-dev"); assert_eq!(project_dirs.project_path(), "galaxy");
} else if #[cfg(windows)] { } else if #[cfg(windows)] {
assert_eq!(project_dirs.project_path(), "warp\\WarpDev"); assert_eq!(project_dirs.project_path(), "galaxy\\Galaxy");
} else { } else {
unimplemented!("Need to update tests for current platform!"); unimplemented!("Need to update tests for current platform!");
} }
@@ -136,11 +199,11 @@ fn test_project_path_for_oss_app_id() {
.expect("should be able to compute project dirs"); .expect("should be able to compute project dirs");
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(target_os = "macos")] { if #[cfg(target_os = "macos")] {
assert_eq!(project_dirs.project_path(), "dev.warp.WarpOss"); assert_eq!(project_dirs.project_path(), "com.galaxy.Galaxy");
} else if #[cfg(any(target_os = "linux", target_os = "freebsd"))] { } else if #[cfg(any(target_os = "linux", target_os = "freebsd"))] {
assert_eq!(project_dirs.project_path(), "warp-oss"); assert_eq!(project_dirs.project_path(), "galaxy");
} else if #[cfg(windows)] { } else if #[cfg(windows)] {
assert_eq!(project_dirs.project_path(), "warp\\WarpOss"); assert_eq!(project_dirs.project_path(), "galaxy\\Galaxy");
} else { } else {
unimplemented!("Need to update tests for current platform!"); unimplemented!("Need to update tests for current platform!");
} }