Complete agent monitoring and Galaxy Control integration
- expose command-monitor conversations and preserve visible agent transcripts - add bounded polling and a dedicated shell interrupt tool - improve direct-provider images, skills, tool history, and usage handling - package and brand Galaxy Control across releases, installers, persistence, and docs
This commit is contained in:
@@ -314,6 +314,20 @@ impl AIAgentActionType {
|
||||
matches!(self, Self::WriteToLongRunningShellCommand { .. })
|
||||
}
|
||||
|
||||
/// Returns whether this action represents an exact terminal interrupt (Ctrl+C).
|
||||
///
|
||||
/// Direct AI providers expose a typed `interrupt_shell_command` tool, but encode it through
|
||||
/// the existing write-to-PTY protobuf for backwards compatibility. Keeping this predicate on
|
||||
/// the shared action type lets execution and UI code distinguish that typed operation from
|
||||
/// ordinary process input without relying on printable escape spellings from the model.
|
||||
pub fn is_shell_command_interrupt(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
Self::WriteToLongRunningShellCommand { input, mode, .. }
|
||||
if mode.is_shell_interrupt(input)
|
||||
)
|
||||
}
|
||||
|
||||
pub fn cancelled_result(&self) -> AIAgentActionResultType {
|
||||
match self {
|
||||
Self::RequestCommandOutput { .. } => AIAgentActionResultType::RequestCommandOutput(
|
||||
@@ -802,6 +816,12 @@ pub enum AIAgentPtyWriteMode {
|
||||
}
|
||||
|
||||
impl AIAgentPtyWriteMode {
|
||||
pub fn is_shell_interrupt(self, bytes: &[u8]) -> bool {
|
||||
use galaxy_terminal::model::escape_sequences;
|
||||
|
||||
self == Self::Raw && bytes == [escape_sequences::C0::ETX]
|
||||
}
|
||||
|
||||
/// Decorates input bytes according to the write mode.
|
||||
pub fn decorate_bytes(
|
||||
self,
|
||||
@@ -928,3 +948,7 @@ impl FileEdit {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "mod_tests.rs"]
|
||||
mod tests;
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
use galaxy_terminal::model::escape_sequences;
|
||||
|
||||
use super::AIAgentPtyWriteMode;
|
||||
|
||||
#[test]
|
||||
fn raw_etx_is_the_only_shell_interrupt_payload() {
|
||||
assert!(AIAgentPtyWriteMode::Raw.is_shell_interrupt(&[escape_sequences::C0::ETX]));
|
||||
assert!(!AIAgentPtyWriteMode::Raw.is_shell_interrupt(b"C-c"));
|
||||
assert!(!AIAgentPtyWriteMode::Raw.is_shell_interrupt(br"\u0003"));
|
||||
assert!(!AIAgentPtyWriteMode::Line.is_shell_interrupt(&[escape_sequences::C0::ETX]));
|
||||
assert!(!AIAgentPtyWriteMode::Block.is_shell_interrupt(&[escape_sequences::C0::ETX]));
|
||||
}
|
||||
@@ -120,8 +120,8 @@ pub fn parse_skill(path: &Path) -> Result<ParsedSkill> {
|
||||
/// Parse a bundled skill markdown file.
|
||||
///
|
||||
/// Unlike `parse_skill`, this function does not require the path to match a known
|
||||
/// skill provider directory. Bundled skills are always assigned `SkillProvider::Warp`
|
||||
/// and `SkillScope::Bundled`.
|
||||
/// skill provider directory. Bundled Galaxy skills retain the wire-compatible
|
||||
/// `SkillProvider::Warp` variant and use `SkillScope::Bundled`.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `path` - Path to the skill markdown file to parse
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Skill provider definitions and utilities.
|
||||
//!
|
||||
//! This module defines the supported skill providers (i.e. Agents, Claude, Codex, Warp) and their
|
||||
//! This module defines the supported skill providers (i.e. Agents, Claude, Codex, Galaxy) and their
|
||||
//! associated skills directory paths. It provides utilities for looking up providers
|
||||
//! from paths and vice versa.
|
||||
use std::path::{Path, PathBuf};
|
||||
@@ -14,7 +14,9 @@ use galaxy_util::local_or_remote_path::LocalOrRemotePath;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum_macros::{Display, EnumString, VariantNames};
|
||||
|
||||
/// Represents a skill provider/origin (Agents, Claude, Codex, or Warp).
|
||||
/// Represents a skill provider/origin.
|
||||
///
|
||||
/// `Warp` is retained as the wire-compatible variant for Galaxy-managed skills.
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
@@ -62,7 +64,7 @@ pub enum SkillScope {
|
||||
Home,
|
||||
/// Skills from a project directory (e.g., `./repo/.agents/skills`).
|
||||
Project,
|
||||
/// Bundled skills distributed with Warp.
|
||||
/// Bundled skills distributed with Galaxy.
|
||||
Bundled,
|
||||
}
|
||||
|
||||
@@ -82,11 +84,11 @@ impl SkillProvider {
|
||||
SkillProvider::Gemini => Icon::GeminiLogo,
|
||||
SkillProvider::Droid => Icon::DroidLogo,
|
||||
SkillProvider::OpenCode => Icon::OpenCodeLogo,
|
||||
SkillProvider::Warp
|
||||
| SkillProvider::Agents
|
||||
SkillProvider::Warp => Icon::GalaxyLogo,
|
||||
SkillProvider::Agents
|
||||
| SkillProvider::Cursor
|
||||
| SkillProvider::Copilot
|
||||
| SkillProvider::Github => Icon::WarpLogoLight,
|
||||
| SkillProvider::Github => Icon::GalaxyLogo,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use galaxy_core::ui::icons::Icon;
|
||||
use galaxy_util::host_id::HostId;
|
||||
use galaxy_util::local_or_remote_path::LocalOrRemotePath;
|
||||
use galaxy_util::remote_path::RemotePath;
|
||||
@@ -9,7 +10,7 @@ use super::{
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn warp_home_skills_path_uses_warp_home_path() {
|
||||
fn galaxy_managed_home_skills_path_uses_galaxy_home_path() {
|
||||
assert_eq!(
|
||||
home_skills_path(SkillProvider::Warp),
|
||||
galaxy_core::paths::galaxy_home_skills_dir()
|
||||
@@ -17,12 +18,12 @@ fn warp_home_skills_path_uses_warp_home_path() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn warp_home_skill_path_is_home_warp_skill() {
|
||||
let Some(warp_home_skills_dir) = galaxy_core::paths::galaxy_home_skills_dir() else {
|
||||
fn galaxy_managed_home_skill_path_is_home_skill() {
|
||||
let Some(galaxy_home_skills_dir) = galaxy_core::paths::galaxy_home_skills_dir() else {
|
||||
eprintln!("Skipping test: home directory not available");
|
||||
return;
|
||||
};
|
||||
let path = warp_home_skills_dir.join("my-skill").join("SKILL.md");
|
||||
let path = galaxy_home_skills_dir.join("my-skill").join("SKILL.md");
|
||||
|
||||
assert_eq!(
|
||||
get_provider_for_path(&LocalOrRemotePath::Local(path.clone())),
|
||||
@@ -31,6 +32,11 @@ fn warp_home_skill_path_is_home_warp_skill() {
|
||||
assert_eq!(get_scope_for_path(&path), SkillScope::Home);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn galaxy_managed_skills_use_the_galaxy_logo() {
|
||||
assert_eq!(SkillProvider::Warp.icon(), Icon::GalaxyLogo);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn remote_provider_path_is_classified_by_structure() {
|
||||
let path = LocalOrRemotePath::Remote(RemotePath::new(
|
||||
|
||||
@@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
|
||||
pub enum SkillReference {
|
||||
/// A skill identified by the path to its SKILL.md file.
|
||||
Path(LocalOrRemotePath),
|
||||
/// A bundled skill distributed with Warp.
|
||||
/// A bundled skill distributed with Galaxy.
|
||||
BundledSkillId(String),
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ impl fmt::Display for SkillReference {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
SkillReference::Path(path) => path.display_path().fmt(f),
|
||||
SkillReference::BundledSkillId(id) => write!(f, "@warp-skill:{id}"),
|
||||
SkillReference::BundledSkillId(id) => write!(f, "@galaxy-skill:{id}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "galaxy_cli"
|
||||
edition = "2024"
|
||||
description = "CLI argument parsing for Warp"
|
||||
description = "CLI argument parsing for Galaxy"
|
||||
authors.workspace = true
|
||||
publish.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
@@ -105,10 +105,10 @@ pub struct GlobalOptions {
|
||||
pub output_format: OutputFormat,
|
||||
}
|
||||
|
||||
/// Normal argument parser for the shared Warp executable across all channels.
|
||||
/// Normal argument parser for the shared Galaxy executable across all channels.
|
||||
///
|
||||
/// Oz commands are subcommands of this parser, so invoking an `oz` symlink does
|
||||
/// not require a mode flag. Warp Control uses its separate [`local_control::ControlArgs`]
|
||||
/// not require a mode flag. Galaxy Control uses its separate [`local_control::ControlArgs`]
|
||||
/// parser, selected before this parser sees the arguments.
|
||||
#[derive(Debug, Default, Parser, Clone)]
|
||||
#[command(
|
||||
@@ -505,8 +505,8 @@ pub enum WorkerCommand {
|
||||
},
|
||||
}
|
||||
|
||||
/// CLI-related subcommands. The command-line interface to Warp isn't a full SDK (e.g. with language bindings),
|
||||
/// but it allows scripting some Warp functionality.
|
||||
/// CLI-related subcommands. The Galaxy command-line interface isn't a full SDK (e.g. with language bindings),
|
||||
/// but it allows scripting some Galaxy functionality.
|
||||
#[derive(Debug, Clone, Subcommand)]
|
||||
pub enum CliCommand {
|
||||
/// Interact with Oz.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//! Implementations for user-facing `warpctrl` command groups.
|
||||
//! Implementations for user-facing `galaxyctrl` command groups.
|
||||
use galaxy_core::channel::ChannelState;
|
||||
use local_control::discovery::InstanceRecord;
|
||||
use local_control::protocol::{
|
||||
@@ -55,28 +55,6 @@ pub(super) fn run_surface_command(
|
||||
SurfaceCommand::Keybindings(command) => {
|
||||
run_surface_open_command(command, ActionKind::SurfaceKeybindingsOpen, output_format)
|
||||
}
|
||||
SurfaceCommand::WarpDrive(command) => match command {
|
||||
SurfaceOpenToggleCommand::Open(args) => run_action_with_params(
|
||||
args,
|
||||
ActionKind::SurfaceWarpDriveOpen,
|
||||
EmptyParams {},
|
||||
output_format,
|
||||
),
|
||||
SurfaceOpenToggleCommand::Toggle(args) => run_action_with_params(
|
||||
args,
|
||||
ActionKind::SurfaceWarpDriveToggle,
|
||||
EmptyParams {},
|
||||
output_format,
|
||||
),
|
||||
},
|
||||
SurfaceCommand::ResourceCenter(command) => run_surface_toggle_command(
|
||||
command,
|
||||
ActionKind::SurfaceResourceCenterToggle,
|
||||
output_format,
|
||||
),
|
||||
SurfaceCommand::AiAssistant(command) => {
|
||||
run_surface_toggle_command(command, ActionKind::SurfaceAiAssistantToggle, output_format)
|
||||
}
|
||||
SurfaceCommand::CodeReview(command) => match command {
|
||||
SurfaceOpenToggleCommand::Open(args) => run_action_with_params(
|
||||
args,
|
||||
@@ -99,14 +77,6 @@ pub(super) fn run_surface_command(
|
||||
SurfaceCommand::GlobalSearch(command) => {
|
||||
run_surface_open_command(command, ActionKind::SurfaceGlobalSearchOpen, output_format)
|
||||
}
|
||||
SurfaceCommand::ConversationList(command) => run_surface_open_command(
|
||||
command,
|
||||
ActionKind::SurfaceConversationListOpen,
|
||||
output_format,
|
||||
),
|
||||
SurfaceCommand::LeftPanel(command) => {
|
||||
run_surface_toggle_command(command, ActionKind::SurfaceLeftPanelToggle, output_format)
|
||||
}
|
||||
SurfaceCommand::RightPanel(command) => {
|
||||
run_surface_toggle_command(command, ActionKind::SurfaceRightPanelToggle, output_format)
|
||||
}
|
||||
@@ -124,23 +94,18 @@ pub(super) fn run_surface_command(
|
||||
output_format,
|
||||
),
|
||||
},
|
||||
SurfaceCommand::AgentManagement(command) => run_surface_open_command(
|
||||
command,
|
||||
ActionKind::SurfaceAgentManagementOpen,
|
||||
output_format,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn render_human_readable(action: ActionKind, data: &serde_json::Value) -> String {
|
||||
match action {
|
||||
ActionKind::AppPing => format!(
|
||||
"Warp instance {} is reachable (protocol version {})",
|
||||
"Galaxy instance {} is reachable (protocol version {})",
|
||||
value_or_unknown(data, "instance_id"),
|
||||
value_or_unknown(data, "protocol_version")
|
||||
),
|
||||
ActionKind::AppVersion => format!(
|
||||
"Warp instance {}\nchannel: {}\napp_id: {}\nprotocol_version: {}",
|
||||
"Galaxy instance {}\nchannel: {}\napp_id: {}\nprotocol_version: {}",
|
||||
value_or_unknown(data, "instance_id"),
|
||||
value_or_unknown(data, "channel"),
|
||||
value_or_unknown(data, "app_id"),
|
||||
@@ -191,7 +156,9 @@ pub(super) fn run_instance_command(
|
||||
) -> Result<(), ControlError> {
|
||||
match command {
|
||||
InstanceCommand::List => render_instance_list(
|
||||
local_control::discovery::list_instances(&ChannelState::channel().to_string()),
|
||||
local_control::discovery::list_instances(
|
||||
ChannelState::channel().local_control_channel_name(),
|
||||
),
|
||||
output_format,
|
||||
),
|
||||
InstanceCommand::Inspect(args) => run_action_with_params(
|
||||
@@ -203,7 +170,7 @@ pub(super) fn run_instance_command(
|
||||
}
|
||||
}
|
||||
|
||||
/// JSON payload for `warpctrl instance list`.
|
||||
/// JSON payload for `galaxyctrl instance list`.
|
||||
#[derive(Serialize)]
|
||||
pub(super) struct InstanceListOutput {
|
||||
instances: Vec<InstanceSummary>,
|
||||
@@ -249,7 +216,7 @@ fn render_instance_list(
|
||||
OutputFormat::Ndjson => write_json_line(&output),
|
||||
OutputFormat::Pretty | OutputFormat::Text => {
|
||||
if output.instances.is_empty() {
|
||||
println!("No running Warp instances with local control were found.");
|
||||
println!("No running Galaxy instances with local control were found.");
|
||||
return Ok(());
|
||||
}
|
||||
for instance in &output.instances {
|
||||
@@ -775,7 +742,9 @@ fn run_action_with_params<T: Serialize>(
|
||||
output_format: OutputFormat,
|
||||
) -> Result<(), ControlError> {
|
||||
let selector = instance_selector(&args);
|
||||
let records = local_control::discovery::list_instances(&ChannelState::channel().to_string());
|
||||
let records = local_control::discovery::list_instances(
|
||||
ChannelState::channel().local_control_channel_name(),
|
||||
);
|
||||
let target = target_selector(&args)?;
|
||||
let instance = select_instance(&records, &selector)?;
|
||||
let mut request = RequestEnvelope::new(Action::with_params(action, params)?);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//! Shell completion generation for `warpctrl`.
|
||||
//! Shell completion generation for `galaxyctrl`.
|
||||
use clap_complete::aot::{Shell, generate};
|
||||
use local_control::protocol::{ControlError, ErrorCode};
|
||||
|
||||
use crate::local_control::ControlArgs;
|
||||
use crate::local_control::{ControlArgs, normalized_control_command_name};
|
||||
|
||||
pub(super) fn generate_completions_to_stdout(shell: Option<Shell>) -> Result<(), ControlError> {
|
||||
let shell = shell.or_else(Shell::from_env).ok_or_else(|| {
|
||||
@@ -12,7 +12,8 @@ pub(super) fn generate_completions_to_stdout(shell: Option<Shell>) -> Result<(),
|
||||
)
|
||||
})?;
|
||||
let mut cmd = ControlArgs::clap_command();
|
||||
let bin_name = crate::binary_name().unwrap_or_else(|| "warpctrl".to_owned());
|
||||
let invocation_name = crate::binary_name();
|
||||
let bin_name = normalized_control_command_name(invocation_name.as_deref());
|
||||
generate(shell, &mut cmd, bin_name, &mut std::io::stdout());
|
||||
Ok(())
|
||||
}
|
||||
@@ -21,7 +22,7 @@ pub(super) fn generate_completions_to_stdout(shell: Option<Shell>) -> Result<(),
|
||||
pub(crate) fn generate_completion_string(shell: Shell) -> Result<String, ControlError> {
|
||||
let mut cmd = ControlArgs::clap_command();
|
||||
let mut output = Vec::new();
|
||||
generate(shell, &mut cmd, "warpctrl", &mut output);
|
||||
generate(shell, &mut cmd, "galaxyctrl", &mut output);
|
||||
String::from_utf8(output).map_err(|err| {
|
||||
ControlError::with_details(
|
||||
ErrorCode::Internal,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//! Command-line interface for controlling a running local Warp app.
|
||||
//! Command-line interface for controlling a running local Galaxy app.
|
||||
mod commands;
|
||||
mod completions;
|
||||
mod output;
|
||||
@@ -19,15 +19,22 @@ use output::write_control_error;
|
||||
|
||||
use crate::agent::OutputFormat;
|
||||
|
||||
/// Hidden flag used by the channel-specific Warp app binary to enter `warpctrl` mode.
|
||||
pub const CONTROL_MODE_FLAG: &str = "--warpctrl";
|
||||
/// Hidden flag used by the channel-specific Galaxy app binary to enter `galaxyctrl` mode.
|
||||
pub const CONTROL_MODE_FLAG: &str = "--galaxyctrl";
|
||||
|
||||
/// Parsed top-level arguments for `warpctrl`.
|
||||
fn normalized_control_command_name(invocation_name: Option<&str>) -> String {
|
||||
invocation_name
|
||||
.filter(|name| *name == "galaxyctrl" || name.starts_with("galaxyctrl-"))
|
||||
.unwrap_or("galaxyctrl")
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
/// Parsed top-level arguments for `galaxyctrl`.
|
||||
#[derive(Debug, Parser)]
|
||||
#[command(
|
||||
name = "warpctrl",
|
||||
display_name = "warpctrl",
|
||||
about = "Control a running local Warp app instance"
|
||||
name = "galaxyctrl",
|
||||
display_name = "galaxyctrl",
|
||||
about = "Control a running local Galaxy app instance"
|
||||
)]
|
||||
pub struct ControlArgs {
|
||||
/// Set the output format.
|
||||
@@ -36,7 +43,7 @@ pub struct ControlArgs {
|
||||
global = true,
|
||||
value_enum,
|
||||
default_value_t = OutputFormat::Pretty,
|
||||
env = "WARP_OUTPUT_FORMAT"
|
||||
env = "GALAXY_OUTPUT_FORMAT"
|
||||
)]
|
||||
pub output_format: OutputFormat,
|
||||
|
||||
@@ -59,15 +66,15 @@ pub enum ActionCatalogCommand {
|
||||
|
||||
impl ControlArgs {
|
||||
pub fn from_env() -> Self {
|
||||
let bin_name = crate::binary_name().unwrap_or_else(|| "warpctrl".to_owned());
|
||||
let bin_name = crate::binary_name().unwrap_or_else(|| "galaxyctrl".to_owned());
|
||||
Self::try_parse_from_args(std::env::args_os(), bin_name).unwrap_or_else(|err| err.exit())
|
||||
}
|
||||
|
||||
/// Parse Warp Control arguments only when the wrapper-injected mode flag is present.
|
||||
/// Parse Galaxy Control arguments only when the wrapper-injected mode flag is present.
|
||||
///
|
||||
/// Startup calls this before the normal Warp/Oz parser. Arguments through
|
||||
/// `--warpctrl` are removed, and the remaining arguments are parsed as if
|
||||
/// the standalone command name were `warpctrl`.
|
||||
/// Startup calls this before the normal Galaxy parser. Arguments through
|
||||
/// `--galaxyctrl` are removed, and the remaining arguments are parsed as if
|
||||
/// the standalone command name were `galaxyctrl`.
|
||||
pub fn from_control_mode_env() -> Option<Self> {
|
||||
Self::try_parse_control_mode_from(std::env::args_os())
|
||||
.map(|result| result.unwrap_or_else(|err| err.exit()))
|
||||
@@ -79,7 +86,7 @@ impl ControlArgs {
|
||||
I: IntoIterator<Item = T>,
|
||||
T: Into<OsString>,
|
||||
{
|
||||
let mut stripped_args = vec![OsString::from("warpctrl")];
|
||||
let mut stripped_args = vec![OsString::from("galaxyctrl")];
|
||||
let mut found_control_mode = false;
|
||||
|
||||
for arg in args {
|
||||
@@ -93,11 +100,12 @@ impl ControlArgs {
|
||||
stripped_args.push(arg);
|
||||
}
|
||||
|
||||
found_control_mode.then(|| Self::try_parse_from_args(stripped_args, "warpctrl"))
|
||||
found_control_mode.then(|| Self::try_parse_from_args(stripped_args, "galaxyctrl"))
|
||||
}
|
||||
|
||||
pub fn clap_command() -> clap::Command {
|
||||
let bin_name = crate::binary_name().unwrap_or_else(|| "warpctrl".to_owned());
|
||||
let invocation_name = crate::binary_name();
|
||||
let bin_name = normalized_control_command_name(invocation_name.as_deref());
|
||||
Self::clap_command_for_bin_name(bin_name)
|
||||
}
|
||||
|
||||
@@ -133,13 +141,13 @@ impl ControlArgs {
|
||||
}
|
||||
}
|
||||
|
||||
/// Top-level `warpctrl` command groups.
|
||||
/// Top-level `galaxyctrl` command groups.
|
||||
#[derive(Debug, Clone, Subcommand)]
|
||||
pub enum ControlCommand {
|
||||
/// Inspect local Warp app instances.
|
||||
/// Inspect local Galaxy app instances.
|
||||
#[command(subcommand)]
|
||||
Instance(InstanceCommand),
|
||||
/// Inspect a selected local Warp app.
|
||||
/// Inspect and control a selected local Galaxy app.
|
||||
#[command(subcommand)]
|
||||
App(AppCommand),
|
||||
/// Inspect local-control capabilities.
|
||||
@@ -149,34 +157,34 @@ pub enum ControlCommand {
|
||||
#[command(subcommand)]
|
||||
Action(ActionCatalogCommand),
|
||||
|
||||
/// Inspect local Warp windows.
|
||||
/// Control local Galaxy windows.
|
||||
#[command(subcommand)]
|
||||
Window(WindowCommand),
|
||||
|
||||
/// Control local Warp tabs.
|
||||
/// Control local Galaxy tabs.
|
||||
#[command(subcommand)]
|
||||
Tab(TabCommand),
|
||||
/// Inspect local Warp panes.
|
||||
/// Control local Galaxy panes.
|
||||
#[command(subcommand)]
|
||||
Pane(PaneCommand),
|
||||
|
||||
/// Inspect local Warp sessions.
|
||||
/// Control local Galaxy sessions.
|
||||
#[command(subcommand)]
|
||||
Session(SessionCommand),
|
||||
|
||||
/// Inspect terminal input state.
|
||||
/// Edit terminal input without submitting it.
|
||||
#[command(subcommand)]
|
||||
Input(InputCommand),
|
||||
|
||||
/// Inspect Warp themes.
|
||||
/// Inspect and change Galaxy themes.
|
||||
#[command(subcommand)]
|
||||
Theme(ThemeCommand),
|
||||
|
||||
/// Inspect appearance state.
|
||||
/// Inspect and change Galaxy appearance.
|
||||
#[command(subcommand)]
|
||||
Appearance(AppearanceCommand),
|
||||
|
||||
/// Inspect allowlisted settings.
|
||||
/// Inspect and change allowlisted settings.
|
||||
#[command(subcommand)]
|
||||
Setting(SettingCommand),
|
||||
|
||||
@@ -184,29 +192,29 @@ pub enum ControlCommand {
|
||||
#[command(subcommand)]
|
||||
Keybinding(KeybindingCommand),
|
||||
|
||||
/// Inspect open file app-state metadata.
|
||||
/// Open files in Galaxy.
|
||||
#[command(subcommand)]
|
||||
File(FileCommand),
|
||||
|
||||
/// Open or toggle local Warp surfaces.
|
||||
/// Open or toggle local Galaxy surfaces.
|
||||
#[command(subcommand)]
|
||||
Surface(SurfaceCommand),
|
||||
|
||||
/// Generate shell completions for your shell to stdout.
|
||||
///
|
||||
/// For bash, add the following to ~/.bashrc:
|
||||
/// source <(path/to/warpctrl completions bash)
|
||||
/// source <(path/to/galaxyctrl completions bash)
|
||||
///
|
||||
/// For zsh, add the following to ~/.zshrc:
|
||||
/// source <(path/to/warpctrl completions zsh)
|
||||
/// source <(path/to/galaxyctrl completions zsh)
|
||||
///
|
||||
/// For fish, add the following to ~/.config/fish/config.fish:
|
||||
/// path/to/warpctrl completions fish | source
|
||||
/// path/to/galaxyctrl completions fish | source
|
||||
///
|
||||
/// For Powershell, add the following to $PROFILE:
|
||||
/// path\to\warpctrl completions powershell | Out-String | Invoke-Expression
|
||||
/// path\to\galaxyctrl completions powershell | Out-String | Invoke-Expression
|
||||
///
|
||||
/// If no shell is provided, this defaults to the shell that Warp was run from.
|
||||
/// If no shell is provided, this defaults to the shell that Galaxy was run from.
|
||||
#[command(verbatim_doc_comment)]
|
||||
Completions {
|
||||
/// Shell to generate completions for.
|
||||
@@ -215,29 +223,29 @@ pub enum ControlCommand {
|
||||
},
|
||||
}
|
||||
|
||||
/// Commands that inspect locally discoverable Warp instances.
|
||||
/// Commands that inspect locally discoverable Galaxy instances.
|
||||
#[derive(Debug, Clone, Subcommand)]
|
||||
pub enum InstanceCommand {
|
||||
/// List locally discoverable Warp instances.
|
||||
/// List locally discoverable Galaxy instances.
|
||||
List,
|
||||
|
||||
/// Print app, protocol, active target, and action metadata for the selected instance.
|
||||
Inspect(TargetArgs),
|
||||
}
|
||||
|
||||
/// Commands that inspect the selected Warp app instance.
|
||||
/// Commands that inspect and control the selected Galaxy app instance.
|
||||
#[derive(Debug, Clone, Subcommand)]
|
||||
pub enum AppCommand {
|
||||
/// Check that the selected local Warp app responds.
|
||||
/// Check that the selected local Galaxy app responds.
|
||||
Ping(TargetArgs),
|
||||
|
||||
/// Print protocol and build identity metadata for the selected local Warp app.
|
||||
/// Print protocol and build identity metadata for the selected local Galaxy app.
|
||||
Version(TargetArgs),
|
||||
|
||||
/// Print the active window/tab/pane/session chain.
|
||||
Active(TargetArgs),
|
||||
|
||||
/// Focus the selected local Warp app.
|
||||
/// Focus the selected local Galaxy app.
|
||||
Focus(TargetArgs),
|
||||
}
|
||||
|
||||
@@ -256,10 +264,10 @@ pub enum CapabilityCommand {
|
||||
|
||||
#[derive(Debug, Clone, Subcommand)]
|
||||
pub enum WindowCommand {
|
||||
/// List windows in the selected local Warp app.
|
||||
/// List windows in the selected local Galaxy app.
|
||||
List(TargetArgs),
|
||||
|
||||
/// Inspect one window in the selected local Warp app.
|
||||
/// Inspect one window in the selected local Galaxy app.
|
||||
Inspect(TargetArgs),
|
||||
|
||||
/// Create a new window.
|
||||
@@ -272,13 +280,13 @@ pub enum WindowCommand {
|
||||
Close(TargetArgs),
|
||||
}
|
||||
|
||||
/// Commands that control tabs in the selected Warp app instance.
|
||||
/// Commands that control tabs in the selected Galaxy app instance.
|
||||
#[derive(Debug, Clone, Subcommand)]
|
||||
pub enum TabCommand {
|
||||
/// List tabs in the selected local Warp app.
|
||||
/// List tabs in the selected local Galaxy app.
|
||||
List(TargetArgs),
|
||||
|
||||
/// Inspect one tab in the selected local Warp app.
|
||||
/// Inspect one tab in the selected local Galaxy app.
|
||||
Inspect(TargetArgs),
|
||||
|
||||
/// Create a new terminal tab in the active window.
|
||||
@@ -314,13 +322,13 @@ pub enum TabColorCommand {
|
||||
Clear(TargetArgs),
|
||||
}
|
||||
|
||||
/// Commands that inspect local Warp panes.
|
||||
/// Commands that control local Galaxy panes.
|
||||
#[derive(Debug, Clone, Subcommand)]
|
||||
pub enum PaneCommand {
|
||||
/// List panes in the selected local Warp app.
|
||||
/// List panes in the selected local Galaxy app.
|
||||
List(TargetArgs),
|
||||
|
||||
/// Inspect one pane in the selected local Warp app.
|
||||
/// Inspect one pane in the selected local Galaxy app.
|
||||
Inspect(TargetArgs),
|
||||
|
||||
/// Split the active pane.
|
||||
@@ -351,13 +359,13 @@ pub enum PaneCommand {
|
||||
ResetName(TargetArgs),
|
||||
}
|
||||
|
||||
/// Commands that inspect local Warp sessions.
|
||||
/// Commands that control local Galaxy sessions.
|
||||
#[derive(Debug, Clone, Subcommand)]
|
||||
pub enum SessionCommand {
|
||||
/// List sessions in the selected local Warp app.
|
||||
/// List sessions in the selected local Galaxy app.
|
||||
List(TargetArgs),
|
||||
|
||||
/// Inspect one session in the selected local Warp app.
|
||||
/// Inspect one session in the selected local Galaxy app.
|
||||
Inspect(TargetArgs),
|
||||
|
||||
/// Activate a session.
|
||||
@@ -384,7 +392,7 @@ pub enum InputCommand {
|
||||
|
||||
#[derive(Debug, Clone, Subcommand)]
|
||||
pub enum SurfaceCommand {
|
||||
/// List available and unavailable tour surfaces.
|
||||
/// List available and unavailable Galaxy surfaces.
|
||||
List(TargetArgs),
|
||||
/// Open settings surfaces.
|
||||
#[command(subcommand)]
|
||||
@@ -405,18 +413,6 @@ pub enum SurfaceCommand {
|
||||
#[command(subcommand)]
|
||||
Keybindings(SurfaceOpenCommand),
|
||||
|
||||
/// Open or toggle Warp Drive.
|
||||
#[command(subcommand)]
|
||||
WarpDrive(SurfaceOpenToggleCommand),
|
||||
|
||||
/// Toggle the resource center.
|
||||
#[command(subcommand)]
|
||||
ResourceCenter(SurfaceToggleCommand),
|
||||
|
||||
/// Toggle the AI assistant.
|
||||
#[command(subcommand)]
|
||||
AiAssistant(SurfaceToggleCommand),
|
||||
|
||||
/// Open or toggle code review.
|
||||
#[command(subcommand)]
|
||||
CodeReview(SurfaceOpenToggleCommand),
|
||||
@@ -429,14 +425,6 @@ pub enum SurfaceCommand {
|
||||
#[command(subcommand)]
|
||||
GlobalSearch(SurfaceOpenCommand),
|
||||
|
||||
/// Open the conversation list.
|
||||
#[command(subcommand)]
|
||||
ConversationList(SurfaceOpenCommand),
|
||||
|
||||
/// Toggle the left panel.
|
||||
#[command(subcommand)]
|
||||
LeftPanel(SurfaceToggleCommand),
|
||||
|
||||
/// Toggle the right panel.
|
||||
#[command(subcommand)]
|
||||
RightPanel(SurfaceToggleCommand),
|
||||
@@ -444,10 +432,6 @@ pub enum SurfaceCommand {
|
||||
/// Open or toggle vertical tabs.
|
||||
#[command(subcommand)]
|
||||
VerticalTabs(SurfaceOpenToggleCommand),
|
||||
|
||||
/// Open agent management.
|
||||
#[command(subcommand)]
|
||||
AgentManagement(SurfaceOpenCommand),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Subcommand)]
|
||||
@@ -482,7 +466,7 @@ pub enum SurfaceToggleCommand {
|
||||
Toggle(TargetArgs),
|
||||
}
|
||||
|
||||
/// Commands that inspect Warp themes.
|
||||
/// Commands that inspect and change Galaxy themes.
|
||||
#[derive(Debug, Clone, Subcommand)]
|
||||
pub enum ThemeCommand {
|
||||
/// List available themes.
|
||||
@@ -494,7 +478,7 @@ pub enum ThemeCommand {
|
||||
/// Set the current theme.
|
||||
Set(ThemeSetArgs),
|
||||
|
||||
/// Set whether Warp follows the system theme.
|
||||
/// Set whether Galaxy follows the system theme.
|
||||
SystemSet(ThemeSystemSetArgs),
|
||||
|
||||
/// Set the light theme used when following the system theme.
|
||||
@@ -554,18 +538,18 @@ pub enum KeybindingCommand {
|
||||
|
||||
#[derive(Debug, Clone, Subcommand)]
|
||||
pub enum FileCommand {
|
||||
/// Open a file in Warp.
|
||||
/// Open a file in Galaxy.
|
||||
Open(FileOpenArgs),
|
||||
}
|
||||
|
||||
/// Exact selectors for a target within the selected Warp instance.
|
||||
/// Exact selectors for a target within the selected Galaxy instance.
|
||||
#[derive(Debug, Clone, Args, Default)]
|
||||
pub struct TargetArgs {
|
||||
/// Target a specific local Warp instance id from `warpctrl instance list`.
|
||||
/// Target a specific local Galaxy instance id from `galaxyctrl instance list`.
|
||||
#[arg(long = "instance", conflicts_with = "pid")]
|
||||
pub instance: Option<String>,
|
||||
|
||||
/// Target a specific local Warp process id.
|
||||
/// Target a specific local Galaxy process id.
|
||||
#[arg(long = "pid", conflicts_with = "instance")]
|
||||
pub pid: Option<u32>,
|
||||
|
||||
@@ -815,7 +799,6 @@ pub struct KeybindingGetArgs {
|
||||
pub enum CliTabType {
|
||||
Terminal,
|
||||
Agent,
|
||||
CloudAgent,
|
||||
Default,
|
||||
}
|
||||
|
||||
@@ -824,7 +807,6 @@ impl From<CliTabType> for local_control::protocol::TabType {
|
||||
match value {
|
||||
CliTabType::Terminal => Self::Terminal,
|
||||
CliTabType::Agent => Self::Agent,
|
||||
CliTabType::CloudAgent => Self::CloudAgent,
|
||||
CliTabType::Default => Self::Default,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//! Output rendering helpers for `warpctrl`.
|
||||
//! Output rendering helpers for `galaxyctrl`.
|
||||
use std::io::Write as _;
|
||||
|
||||
use local_control::protocol::{ControlError, ErrorCode};
|
||||
@@ -6,7 +6,7 @@ use serde::Serialize;
|
||||
|
||||
use crate::agent::OutputFormat;
|
||||
|
||||
/// JSON/NDJSON error payload emitted by `warpctrl`.
|
||||
/// JSON/NDJSON error payload emitted by `galaxyctrl`.
|
||||
#[derive(Serialize)]
|
||||
pub(crate) struct ErrorSummary<'a> {
|
||||
pub ok: bool,
|
||||
|
||||
@@ -9,7 +9,7 @@ use super::*;
|
||||
#[test]
|
||||
fn parses_typed_create_and_setting_list_params() {
|
||||
let args = ControlArgs::try_parse_from([
|
||||
"warpctrl",
|
||||
"galaxyctrl",
|
||||
"tab",
|
||||
"create",
|
||||
"--type",
|
||||
@@ -28,7 +28,7 @@ fn parses_typed_create_and_setting_list_params() {
|
||||
assert_eq!(args.target.session.as_deref(), Some("session_1"));
|
||||
|
||||
let args =
|
||||
ControlArgs::try_parse_from(["warpctrl", "setting", "list", "--namespace", "editor"])
|
||||
ControlArgs::try_parse_from(["galaxyctrl", "setting", "list", "--namespace", "editor"])
|
||||
.expect("setting list parses");
|
||||
let ControlCommand::Setting(SettingCommand::List(args)) = args.command else {
|
||||
panic!("expected setting list command");
|
||||
@@ -39,7 +39,7 @@ fn parses_typed_create_and_setting_list_params() {
|
||||
#[test]
|
||||
fn rejects_conflicting_instance_selectors() {
|
||||
let err = ControlArgs::try_parse_from([
|
||||
"warpctrl",
|
||||
"galaxyctrl",
|
||||
"tab",
|
||||
"create",
|
||||
"--instance",
|
||||
@@ -53,14 +53,15 @@ fn rejects_conflicting_instance_selectors() {
|
||||
|
||||
#[test]
|
||||
fn parses_instance_and_pid_selectors() {
|
||||
let args = ControlArgs::try_parse_from(["warpctrl", "tab", "create", "--instance", "inst_123"])
|
||||
.expect("instance selector parses");
|
||||
let args =
|
||||
ControlArgs::try_parse_from(["galaxyctrl", "tab", "create", "--instance", "inst_123"])
|
||||
.expect("instance selector parses");
|
||||
let ControlCommand::Tab(TabCommand::Create(create)) = args.command else {
|
||||
panic!("expected tab create command");
|
||||
};
|
||||
assert_eq!(create.target.instance.as_deref(), Some("inst_123"));
|
||||
|
||||
let args = ControlArgs::try_parse_from(["warpctrl", "app", "ping", "--pid", "123"])
|
||||
let args = ControlArgs::try_parse_from(["galaxyctrl", "app", "ping", "--pid", "123"])
|
||||
.expect("pid selector parses");
|
||||
let ControlCommand::App(AppCommand::Ping(target)) = args.command else {
|
||||
panic!("expected app ping command");
|
||||
@@ -71,7 +72,7 @@ fn parses_instance_and_pid_selectors() {
|
||||
#[test]
|
||||
fn surface_list_accepts_instance_selection() {
|
||||
let args =
|
||||
ControlArgs::try_parse_from(["warpctrl", "surface", "list", "--instance", "inst_123"])
|
||||
ControlArgs::try_parse_from(["galaxyctrl", "surface", "list", "--instance", "inst_123"])
|
||||
.expect("surface list instance selector parses");
|
||||
let ControlCommand::Surface(SurfaceCommand::List(target)) = args.command else {
|
||||
panic!("expected surface list command");
|
||||
@@ -82,17 +83,25 @@ fn surface_list_accepts_instance_selection() {
|
||||
#[test]
|
||||
fn rejects_excluded_command_routes() {
|
||||
for args in [
|
||||
vec!["warpctrl", "history", "list"],
|
||||
vec!["warpctrl", "block", "list"],
|
||||
vec!["warpctrl", "block", "inspect", "block_1"],
|
||||
vec!["warpctrl", "block", "output", "block_1"],
|
||||
vec!["warpctrl", "input", "get"],
|
||||
vec!["warpctrl", "input", "clear"],
|
||||
vec!["warpctrl", "input", "mode", "set", "agent"],
|
||||
vec!["warpctrl", "input", "run", "pwd"],
|
||||
vec!["warpctrl", "file", "list"],
|
||||
vec!["warpctrl", "drive", "list"],
|
||||
vec!["warpctrl", "auth", "status"],
|
||||
vec!["galaxyctrl", "history", "list"],
|
||||
vec!["galaxyctrl", "block", "list"],
|
||||
vec!["galaxyctrl", "block", "inspect", "block_1"],
|
||||
vec!["galaxyctrl", "block", "output", "block_1"],
|
||||
vec!["galaxyctrl", "input", "get"],
|
||||
vec!["galaxyctrl", "input", "clear"],
|
||||
vec!["galaxyctrl", "input", "mode", "set", "agent"],
|
||||
vec!["galaxyctrl", "input", "run", "pwd"],
|
||||
vec!["galaxyctrl", "file", "list"],
|
||||
vec!["galaxyctrl", "drive", "list"],
|
||||
vec!["galaxyctrl", "auth", "status"],
|
||||
vec!["galaxyctrl", "surface", "warp-drive", "open"],
|
||||
vec!["galaxyctrl", "surface", "warp-drive", "toggle"],
|
||||
vec!["galaxyctrl", "surface", "resource-center", "toggle"],
|
||||
vec!["galaxyctrl", "surface", "ai-assistant", "toggle"],
|
||||
vec!["galaxyctrl", "surface", "conversation-list", "open"],
|
||||
vec!["galaxyctrl", "surface", "agent-management", "open"],
|
||||
vec!["galaxyctrl", "surface", "left-panel", "toggle"],
|
||||
vec!["galaxyctrl", "tab", "create", "--type", "cloud-agent"],
|
||||
] {
|
||||
assert!(ControlArgs::try_parse_from(args).is_err());
|
||||
}
|
||||
@@ -100,7 +109,7 @@ fn rejects_excluded_command_routes() {
|
||||
|
||||
#[test]
|
||||
fn parses_first_slice_instance_list() {
|
||||
let args = ControlArgs::try_parse_from(["warpctrl", "instance", "list"])
|
||||
let args = ControlArgs::try_parse_from(["galaxyctrl", "instance", "list"])
|
||||
.expect("instance list parses");
|
||||
assert!(matches!(
|
||||
args.command,
|
||||
@@ -110,31 +119,31 @@ fn parses_first_slice_instance_list() {
|
||||
|
||||
#[test]
|
||||
fn parses_first_slice_app_smoke_metadata_commands() {
|
||||
assert!(ControlArgs::try_parse_from(["warpctrl", "app", "ping"]).is_ok());
|
||||
assert!(ControlArgs::try_parse_from(["warpctrl", "app", "version"]).is_ok());
|
||||
assert!(ControlArgs::try_parse_from(["warpctrl", "app", "active"]).is_ok());
|
||||
assert!(ControlArgs::try_parse_from(["warpctrl", "app", "focus"]).is_ok());
|
||||
assert!(ControlArgs::try_parse_from(["galaxyctrl", "app", "ping"]).is_ok());
|
||||
assert!(ControlArgs::try_parse_from(["galaxyctrl", "app", "version"]).is_ok());
|
||||
assert!(ControlArgs::try_parse_from(["galaxyctrl", "app", "active"]).is_ok());
|
||||
assert!(ControlArgs::try_parse_from(["galaxyctrl", "app", "focus"]).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parses_catalog_metadata_commands() {
|
||||
let args =
|
||||
ControlArgs::try_parse_from(["warpctrl", "action", "inspect", "surface.settings.open"])
|
||||
ControlArgs::try_parse_from(["galaxyctrl", "action", "inspect", "surface.settings.open"])
|
||||
.expect("action inspect parses");
|
||||
let ControlCommand::Action(ActionCatalogCommand::Inspect { action }) = args.command else {
|
||||
panic!("expected action inspect command");
|
||||
};
|
||||
assert_eq!(action, "surface.settings.open");
|
||||
assert!(ControlArgs::try_parse_from(["warpctrl", "action", "list"]).is_ok());
|
||||
assert!(ControlArgs::try_parse_from(["warpctrl", "capability", "list"]).is_ok());
|
||||
assert!(ControlArgs::try_parse_from(["galaxyctrl", "action", "list"]).is_ok());
|
||||
assert!(ControlArgs::try_parse_from(["galaxyctrl", "capability", "list"]).is_ok());
|
||||
assert!(
|
||||
ControlArgs::try_parse_from(["warpctrl", "capability", "inspect", "tab.create"]).is_ok()
|
||||
ControlArgs::try_parse_from(["galaxyctrl", "capability", "inspect", "tab.create"]).is_ok()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parses_control_mode_args_after_hidden_flag() {
|
||||
let args = ControlArgs::try_parse_control_mode_from(["warp", "--warpctrl", "tab", "create"])
|
||||
let args = ControlArgs::try_parse_control_mode_from(["warp", "--galaxyctrl", "tab", "create"])
|
||||
.expect("control mode flag is present")
|
||||
.expect("control mode args parse");
|
||||
assert!(matches!(
|
||||
@@ -150,7 +159,7 @@ fn ignores_args_without_control_mode_flag() {
|
||||
|
||||
#[test]
|
||||
fn parses_completion_generation_command() {
|
||||
let args = ControlArgs::try_parse_from(["warpctrl", "completions", "bash"])
|
||||
let args = ControlArgs::try_parse_from(["galaxyctrl", "completions", "bash"])
|
||||
.expect("completions parses");
|
||||
assert!(matches!(
|
||||
args.command,
|
||||
@@ -163,7 +172,7 @@ fn parses_completion_generation_command() {
|
||||
#[test]
|
||||
fn parses_exact_window_tab_pane_and_session_selectors() {
|
||||
let args = ControlArgs::try_parse_from([
|
||||
"warpctrl",
|
||||
"galaxyctrl",
|
||||
"session",
|
||||
"inspect",
|
||||
"--window-title",
|
||||
@@ -194,7 +203,7 @@ fn instance_list_output_serializes_empty_and_populated_lists() {
|
||||
let record = local_control::discovery::InstanceRecord::for_current_process(
|
||||
None,
|
||||
"dev",
|
||||
"dev.warp.Warp",
|
||||
"dev.galaxy.Galaxy",
|
||||
Some("v0.1.0".to_owned()),
|
||||
Vec::new(),
|
||||
);
|
||||
@@ -203,7 +212,10 @@ fn instance_list_output_serializes_empty_and_populated_lists() {
|
||||
.expect("populated list serializes");
|
||||
assert_eq!(populated["instances"][0]["instance_id"], json!(instance_id));
|
||||
assert_eq!(populated["instances"][0]["channel"], json!("dev"));
|
||||
assert_eq!(populated["instances"][0]["app_id"], json!("dev.warp.Warp"));
|
||||
assert_eq!(
|
||||
populated["instances"][0]["app_id"],
|
||||
json!("dev.galaxy.Galaxy")
|
||||
);
|
||||
assert_eq!(populated["instances"][0]["app_version"], json!("v0.1.0"));
|
||||
}
|
||||
|
||||
@@ -258,17 +270,39 @@ fn generated_bash_completions_include_mutating_command_groups() {
|
||||
generate_completion_string(Shell::Bash).expect("bash completions render to UTF-8");
|
||||
assert!(completions.contains("surface"));
|
||||
assert!(completions.contains("command-palette"));
|
||||
assert!(completions.contains("warp-drive"));
|
||||
assert!(completions.contains("resource-center"));
|
||||
assert!(!completions.contains("warp-drive"));
|
||||
assert!(!completions.contains("resource-center"));
|
||||
assert!(!completions.contains("ai-assistant"));
|
||||
assert!(!completions.contains("conversation-list"));
|
||||
assert!(!completions.contains("agent-management"));
|
||||
assert!(!completions.contains("left-panel"));
|
||||
assert!(!completions.contains("cloud-agent"));
|
||||
assert!(completions.contains("activate"));
|
||||
assert!(completions.contains("split"));
|
||||
assert!(!completions.contains("history"));
|
||||
assert!(!completions.contains("share-to-team"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completion_name_never_falls_back_to_the_forwarded_app_binary() {
|
||||
assert_eq!(
|
||||
normalized_control_command_name(Some("galaxyctrl-dev")),
|
||||
"galaxyctrl-dev"
|
||||
);
|
||||
assert_eq!(
|
||||
normalized_control_command_name(Some("galaxy-dev")),
|
||||
"galaxyctrl"
|
||||
);
|
||||
assert_eq!(
|
||||
normalized_control_command_name(Some("galaxy-oss")),
|
||||
"galaxyctrl"
|
||||
);
|
||||
assert_eq!(normalized_control_command_name(None), "galaxyctrl");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn structured_error_output_uses_stable_error_code() {
|
||||
let error = ControlError::new(ErrorCode::NoInstance, "no local Warp control instances");
|
||||
let error = ControlError::new(ErrorCode::NoInstance, "no local Galaxy control instances");
|
||||
let value = serde_json::to_value(ErrorSummary {
|
||||
ok: false,
|
||||
error: &error,
|
||||
@@ -278,7 +312,7 @@ fn structured_error_output_uses_stable_error_code() {
|
||||
assert_eq!(value["error"]["code"], json!("no_instance"));
|
||||
assert_eq!(
|
||||
value["error"]["message"],
|
||||
json!("no local Warp control instances")
|
||||
json!("no local Galaxy control instances")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -307,75 +341,87 @@ fn retained_action_examples() -> Vec<(ActionKind, Vec<&'static str>)> {
|
||||
vec![
|
||||
(
|
||||
ActionKind::InstanceList,
|
||||
vec!["warpctrl", "instance", "list"],
|
||||
vec!["galaxyctrl", "instance", "list"],
|
||||
),
|
||||
(
|
||||
ActionKind::InstanceInspect,
|
||||
vec!["warpctrl", "instance", "inspect"],
|
||||
vec!["galaxyctrl", "instance", "inspect"],
|
||||
),
|
||||
(ActionKind::AppPing, vec!["warpctrl", "app", "ping"]),
|
||||
(ActionKind::AppVersion, vec!["warpctrl", "app", "version"]),
|
||||
(ActionKind::AppActive, vec!["warpctrl", "app", "active"]),
|
||||
(ActionKind::AppFocus, vec!["warpctrl", "app", "focus"]),
|
||||
(ActionKind::AppPing, vec!["galaxyctrl", "app", "ping"]),
|
||||
(ActionKind::AppVersion, vec!["galaxyctrl", "app", "version"]),
|
||||
(ActionKind::AppActive, vec!["galaxyctrl", "app", "active"]),
|
||||
(ActionKind::AppFocus, vec!["galaxyctrl", "app", "focus"]),
|
||||
(
|
||||
ActionKind::CapabilityList,
|
||||
vec!["warpctrl", "capability", "list"],
|
||||
vec!["galaxyctrl", "capability", "list"],
|
||||
),
|
||||
(
|
||||
ActionKind::CapabilityInspect,
|
||||
vec!["warpctrl", "capability", "inspect", "tab.create"],
|
||||
vec!["galaxyctrl", "capability", "inspect", "tab.create"],
|
||||
),
|
||||
(ActionKind::WindowList, vec!["warpctrl", "window", "list"]),
|
||||
(ActionKind::WindowList, vec!["galaxyctrl", "window", "list"]),
|
||||
(
|
||||
ActionKind::WindowInspect,
|
||||
vec!["warpctrl", "window", "inspect"],
|
||||
vec!["galaxyctrl", "window", "inspect"],
|
||||
),
|
||||
(
|
||||
ActionKind::WindowCreate,
|
||||
vec!["warpctrl", "window", "create"],
|
||||
vec!["galaxyctrl", "window", "create"],
|
||||
),
|
||||
(
|
||||
ActionKind::WindowFocus,
|
||||
vec!["galaxyctrl", "window", "focus"],
|
||||
),
|
||||
(
|
||||
ActionKind::WindowClose,
|
||||
vec!["galaxyctrl", "window", "close"],
|
||||
),
|
||||
(ActionKind::TabList, vec!["galaxyctrl", "tab", "list"]),
|
||||
(ActionKind::TabInspect, vec!["galaxyctrl", "tab", "inspect"]),
|
||||
(ActionKind::TabCreate, vec!["galaxyctrl", "tab", "create"]),
|
||||
(
|
||||
ActionKind::TabActivate,
|
||||
vec!["galaxyctrl", "tab", "activate"],
|
||||
),
|
||||
(ActionKind::WindowFocus, vec!["warpctrl", "window", "focus"]),
|
||||
(ActionKind::WindowClose, vec!["warpctrl", "window", "close"]),
|
||||
(ActionKind::TabList, vec!["warpctrl", "tab", "list"]),
|
||||
(ActionKind::TabInspect, vec!["warpctrl", "tab", "inspect"]),
|
||||
(ActionKind::TabCreate, vec!["warpctrl", "tab", "create"]),
|
||||
(ActionKind::TabActivate, vec!["warpctrl", "tab", "activate"]),
|
||||
(
|
||||
ActionKind::TabMove,
|
||||
vec!["warpctrl", "tab", "move", "--direction", "next"],
|
||||
vec!["galaxyctrl", "tab", "move", "--direction", "next"],
|
||||
),
|
||||
(ActionKind::TabClose, vec!["warpctrl", "tab", "close"]),
|
||||
(ActionKind::TabClose, vec!["galaxyctrl", "tab", "close"]),
|
||||
(
|
||||
ActionKind::TabRename,
|
||||
vec!["warpctrl", "tab", "rename", "docs"],
|
||||
vec!["galaxyctrl", "tab", "rename", "docs"],
|
||||
),
|
||||
(
|
||||
ActionKind::TabResetName,
|
||||
vec!["warpctrl", "tab", "reset-name"],
|
||||
vec!["galaxyctrl", "tab", "reset-name"],
|
||||
),
|
||||
(
|
||||
ActionKind::TabColorSet,
|
||||
vec!["warpctrl", "tab", "color", "set", "red"],
|
||||
vec!["galaxyctrl", "tab", "color", "set", "red"],
|
||||
),
|
||||
(
|
||||
ActionKind::TabColorClear,
|
||||
vec!["warpctrl", "tab", "color", "clear"],
|
||||
vec!["galaxyctrl", "tab", "color", "clear"],
|
||||
),
|
||||
(ActionKind::PaneList, vec!["galaxyctrl", "pane", "list"]),
|
||||
(
|
||||
ActionKind::PaneInspect,
|
||||
vec!["galaxyctrl", "pane", "inspect"],
|
||||
),
|
||||
(ActionKind::PaneList, vec!["warpctrl", "pane", "list"]),
|
||||
(ActionKind::PaneInspect, vec!["warpctrl", "pane", "inspect"]),
|
||||
(
|
||||
ActionKind::PaneSplit,
|
||||
vec!["warpctrl", "pane", "split", "--direction", "right"],
|
||||
vec!["galaxyctrl", "pane", "split", "--direction", "right"],
|
||||
),
|
||||
(ActionKind::PaneFocus, vec!["warpctrl", "pane", "focus"]),
|
||||
(ActionKind::PaneFocus, vec!["galaxyctrl", "pane", "focus"]),
|
||||
(
|
||||
ActionKind::PaneNavigate,
|
||||
vec!["warpctrl", "pane", "navigate", "--direction", "next"],
|
||||
vec!["galaxyctrl", "pane", "navigate", "--direction", "next"],
|
||||
),
|
||||
(
|
||||
ActionKind::PaneResize,
|
||||
vec![
|
||||
"warpctrl",
|
||||
"galaxyctrl",
|
||||
"pane",
|
||||
"resize",
|
||||
"--direction",
|
||||
@@ -386,199 +432,183 @@ fn retained_action_examples() -> Vec<(ActionKind, Vec<&'static str>)> {
|
||||
),
|
||||
(
|
||||
ActionKind::PaneMaximize,
|
||||
vec!["warpctrl", "pane", "maximize"],
|
||||
vec!["galaxyctrl", "pane", "maximize"],
|
||||
),
|
||||
(
|
||||
ActionKind::PaneUnmaximize,
|
||||
vec!["warpctrl", "pane", "unmaximize"],
|
||||
vec!["galaxyctrl", "pane", "unmaximize"],
|
||||
),
|
||||
(ActionKind::PaneClose, vec!["warpctrl", "pane", "close"]),
|
||||
(ActionKind::PaneClose, vec!["galaxyctrl", "pane", "close"]),
|
||||
(
|
||||
ActionKind::PaneRename,
|
||||
vec!["warpctrl", "pane", "rename", "server"],
|
||||
vec!["galaxyctrl", "pane", "rename", "server"],
|
||||
),
|
||||
(
|
||||
ActionKind::PaneResetName,
|
||||
vec!["warpctrl", "pane", "reset-name"],
|
||||
vec!["galaxyctrl", "pane", "reset-name"],
|
||||
),
|
||||
(
|
||||
ActionKind::SessionList,
|
||||
vec!["galaxyctrl", "session", "list"],
|
||||
),
|
||||
(ActionKind::SessionList, vec!["warpctrl", "session", "list"]),
|
||||
(
|
||||
ActionKind::SessionInspect,
|
||||
vec!["warpctrl", "session", "inspect"],
|
||||
vec!["galaxyctrl", "session", "inspect"],
|
||||
),
|
||||
(
|
||||
ActionKind::SessionActivate,
|
||||
vec!["warpctrl", "session", "activate"],
|
||||
vec!["galaxyctrl", "session", "activate"],
|
||||
),
|
||||
(
|
||||
ActionKind::SessionPrevious,
|
||||
vec!["warpctrl", "session", "previous"],
|
||||
vec!["galaxyctrl", "session", "previous"],
|
||||
),
|
||||
(
|
||||
ActionKind::SessionNext,
|
||||
vec!["galaxyctrl", "session", "next"],
|
||||
),
|
||||
(ActionKind::SessionNext, vec!["warpctrl", "session", "next"]),
|
||||
(
|
||||
ActionKind::SessionReopenClosed,
|
||||
vec!["warpctrl", "session", "reopen-closed"],
|
||||
vec!["galaxyctrl", "session", "reopen-closed"],
|
||||
),
|
||||
(
|
||||
ActionKind::InputInsert,
|
||||
vec!["warpctrl", "input", "insert", "hello"],
|
||||
vec!["galaxyctrl", "input", "insert", "hello"],
|
||||
),
|
||||
(
|
||||
ActionKind::InputReplace,
|
||||
vec!["warpctrl", "input", "replace", "hello"],
|
||||
vec!["galaxyctrl", "input", "replace", "hello"],
|
||||
),
|
||||
(ActionKind::ThemeList, vec!["warpctrl", "theme", "list"]),
|
||||
(ActionKind::ThemeGet, vec!["warpctrl", "theme", "get"]),
|
||||
(ActionKind::ThemeList, vec!["galaxyctrl", "theme", "list"]),
|
||||
(ActionKind::ThemeGet, vec!["galaxyctrl", "theme", "get"]),
|
||||
(
|
||||
ActionKind::ThemeSet,
|
||||
vec!["warpctrl", "theme", "set", "Dracula"],
|
||||
vec!["galaxyctrl", "theme", "set", "Dracula"],
|
||||
),
|
||||
(
|
||||
ActionKind::ThemeSystemSet,
|
||||
vec!["warpctrl", "theme", "system-set", "true"],
|
||||
vec!["galaxyctrl", "theme", "system-set", "true"],
|
||||
),
|
||||
(
|
||||
ActionKind::ThemeLightSet,
|
||||
vec!["warpctrl", "theme", "light-set", "Light"],
|
||||
vec!["galaxyctrl", "theme", "light-set", "Light"],
|
||||
),
|
||||
(
|
||||
ActionKind::ThemeDarkSet,
|
||||
vec!["warpctrl", "theme", "dark-set", "Dark"],
|
||||
vec!["galaxyctrl", "theme", "dark-set", "Dark"],
|
||||
),
|
||||
(
|
||||
ActionKind::AppearanceGet,
|
||||
vec!["warpctrl", "appearance", "get"],
|
||||
vec!["galaxyctrl", "appearance", "get"],
|
||||
),
|
||||
(
|
||||
ActionKind::AppearanceFontSizeIncrease,
|
||||
vec!["warpctrl", "appearance", "font-size-increase"],
|
||||
vec!["galaxyctrl", "appearance", "font-size-increase"],
|
||||
),
|
||||
(
|
||||
ActionKind::AppearanceFontSizeDecrease,
|
||||
vec!["warpctrl", "appearance", "font-size-decrease"],
|
||||
vec!["galaxyctrl", "appearance", "font-size-decrease"],
|
||||
),
|
||||
(
|
||||
ActionKind::AppearanceFontSizeReset,
|
||||
vec!["warpctrl", "appearance", "font-size-reset"],
|
||||
vec!["galaxyctrl", "appearance", "font-size-reset"],
|
||||
),
|
||||
(
|
||||
ActionKind::AppearanceZoomIncrease,
|
||||
vec!["warpctrl", "appearance", "zoom-increase"],
|
||||
vec!["galaxyctrl", "appearance", "zoom-increase"],
|
||||
),
|
||||
(
|
||||
ActionKind::AppearanceZoomDecrease,
|
||||
vec!["warpctrl", "appearance", "zoom-decrease"],
|
||||
vec!["galaxyctrl", "appearance", "zoom-decrease"],
|
||||
),
|
||||
(
|
||||
ActionKind::AppearanceZoomReset,
|
||||
vec!["warpctrl", "appearance", "zoom-reset"],
|
||||
vec!["galaxyctrl", "appearance", "zoom-reset"],
|
||||
),
|
||||
(
|
||||
ActionKind::SettingList,
|
||||
vec!["galaxyctrl", "setting", "list"],
|
||||
),
|
||||
(ActionKind::SettingList, vec!["warpctrl", "setting", "list"]),
|
||||
(
|
||||
ActionKind::SettingGet,
|
||||
vec!["warpctrl", "setting", "get", "font_size"],
|
||||
vec!["galaxyctrl", "setting", "get", "font_size"],
|
||||
),
|
||||
(
|
||||
ActionKind::SettingSet,
|
||||
vec!["warpctrl", "setting", "set", "font_size", "14"],
|
||||
vec!["galaxyctrl", "setting", "set", "font_size", "14"],
|
||||
),
|
||||
(
|
||||
ActionKind::SettingToggle,
|
||||
vec!["warpctrl", "setting", "toggle", "autosuggestions"],
|
||||
vec!["galaxyctrl", "setting", "toggle", "autosuggestions"],
|
||||
),
|
||||
(
|
||||
ActionKind::KeybindingList,
|
||||
vec!["warpctrl", "keybinding", "list"],
|
||||
vec!["galaxyctrl", "keybinding", "list"],
|
||||
),
|
||||
(
|
||||
ActionKind::KeybindingGet,
|
||||
vec!["warpctrl", "keybinding", "get", "copy"],
|
||||
vec!["galaxyctrl", "keybinding", "get", "copy"],
|
||||
),
|
||||
(ActionKind::ActionList, vec!["warpctrl", "action", "list"]),
|
||||
(ActionKind::ActionList, vec!["galaxyctrl", "action", "list"]),
|
||||
(
|
||||
ActionKind::ActionInspect,
|
||||
vec!["warpctrl", "action", "inspect", "tab.create"],
|
||||
vec!["galaxyctrl", "action", "inspect", "tab.create"],
|
||||
),
|
||||
(
|
||||
ActionKind::SurfaceList,
|
||||
vec!["galaxyctrl", "surface", "list"],
|
||||
),
|
||||
(ActionKind::SurfaceList, vec!["warpctrl", "surface", "list"]),
|
||||
(
|
||||
ActionKind::SurfaceSettingsOpen,
|
||||
vec!["warpctrl", "surface", "settings", "open"],
|
||||
vec!["galaxyctrl", "surface", "settings", "open"],
|
||||
),
|
||||
(
|
||||
ActionKind::SurfaceCommandPaletteOpen,
|
||||
vec!["warpctrl", "surface", "command-palette", "open"],
|
||||
vec!["galaxyctrl", "surface", "command-palette", "open"],
|
||||
),
|
||||
(
|
||||
ActionKind::SurfaceCommandSearchOpen,
|
||||
vec!["warpctrl", "surface", "command-search", "open"],
|
||||
vec!["galaxyctrl", "surface", "command-search", "open"],
|
||||
),
|
||||
(
|
||||
ActionKind::SurfaceThemePickerOpen,
|
||||
vec!["warpctrl", "surface", "theme-picker", "open"],
|
||||
vec!["galaxyctrl", "surface", "theme-picker", "open"],
|
||||
),
|
||||
(
|
||||
ActionKind::SurfaceKeybindingsOpen,
|
||||
vec!["warpctrl", "surface", "keybindings", "open"],
|
||||
),
|
||||
(
|
||||
ActionKind::SurfaceWarpDriveOpen,
|
||||
vec!["warpctrl", "surface", "warp-drive", "open"],
|
||||
),
|
||||
(
|
||||
ActionKind::SurfaceWarpDriveToggle,
|
||||
vec!["warpctrl", "surface", "warp-drive", "toggle"],
|
||||
),
|
||||
(
|
||||
ActionKind::SurfaceResourceCenterToggle,
|
||||
vec!["warpctrl", "surface", "resource-center", "toggle"],
|
||||
),
|
||||
(
|
||||
ActionKind::SurfaceAiAssistantToggle,
|
||||
vec!["warpctrl", "surface", "ai-assistant", "toggle"],
|
||||
vec!["galaxyctrl", "surface", "keybindings", "open"],
|
||||
),
|
||||
(
|
||||
ActionKind::SurfaceCodeReviewOpen,
|
||||
vec!["warpctrl", "surface", "code-review", "open"],
|
||||
vec!["galaxyctrl", "surface", "code-review", "open"],
|
||||
),
|
||||
(
|
||||
ActionKind::SurfaceCodeReviewToggle,
|
||||
vec!["warpctrl", "surface", "code-review", "toggle"],
|
||||
vec!["galaxyctrl", "surface", "code-review", "toggle"],
|
||||
),
|
||||
(
|
||||
ActionKind::SurfaceProjectExplorerOpen,
|
||||
vec!["warpctrl", "surface", "project-explorer", "open"],
|
||||
vec!["galaxyctrl", "surface", "project-explorer", "open"],
|
||||
),
|
||||
(
|
||||
ActionKind::SurfaceGlobalSearchOpen,
|
||||
vec!["warpctrl", "surface", "global-search", "open"],
|
||||
),
|
||||
(
|
||||
ActionKind::SurfaceConversationListOpen,
|
||||
vec!["warpctrl", "surface", "conversation-list", "open"],
|
||||
),
|
||||
(
|
||||
ActionKind::SurfaceLeftPanelToggle,
|
||||
vec!["warpctrl", "surface", "left-panel", "toggle"],
|
||||
vec!["galaxyctrl", "surface", "global-search", "open"],
|
||||
),
|
||||
(
|
||||
ActionKind::SurfaceRightPanelToggle,
|
||||
vec!["warpctrl", "surface", "right-panel", "toggle"],
|
||||
vec!["galaxyctrl", "surface", "right-panel", "toggle"],
|
||||
),
|
||||
(
|
||||
ActionKind::SurfaceVerticalTabsOpen,
|
||||
vec!["warpctrl", "surface", "vertical-tabs", "open"],
|
||||
vec!["galaxyctrl", "surface", "vertical-tabs", "open"],
|
||||
),
|
||||
(
|
||||
ActionKind::SurfaceVerticalTabsToggle,
|
||||
vec!["warpctrl", "surface", "vertical-tabs", "toggle"],
|
||||
),
|
||||
(
|
||||
ActionKind::SurfaceAgentManagementOpen,
|
||||
vec!["warpctrl", "surface", "agent-management", "open"],
|
||||
vec!["galaxyctrl", "surface", "vertical-tabs", "toggle"],
|
||||
),
|
||||
(
|
||||
ActionKind::FileOpen,
|
||||
vec!["warpctrl", "file", "open", "/tmp/example.txt"],
|
||||
vec!["galaxyctrl", "file", "open", "/tmp/example.txt"],
|
||||
),
|
||||
]
|
||||
}
|
||||
@@ -696,16 +726,6 @@ fn parsed_action_kind(command: &ControlCommand) -> Option<ActionKind> {
|
||||
SurfaceCommand::Keybindings(command) => match command {
|
||||
SurfaceOpenCommand::Open(_) => Some(ActionKind::SurfaceKeybindingsOpen),
|
||||
},
|
||||
SurfaceCommand::WarpDrive(command) => match command {
|
||||
SurfaceOpenToggleCommand::Open(_) => Some(ActionKind::SurfaceWarpDriveOpen),
|
||||
SurfaceOpenToggleCommand::Toggle(_) => Some(ActionKind::SurfaceWarpDriveToggle),
|
||||
},
|
||||
SurfaceCommand::ResourceCenter(command) => match command {
|
||||
SurfaceToggleCommand::Toggle(_) => Some(ActionKind::SurfaceResourceCenterToggle),
|
||||
},
|
||||
SurfaceCommand::AiAssistant(command) => match command {
|
||||
SurfaceToggleCommand::Toggle(_) => Some(ActionKind::SurfaceAiAssistantToggle),
|
||||
},
|
||||
SurfaceCommand::CodeReview(command) => match command {
|
||||
SurfaceOpenToggleCommand::Open(_) => Some(ActionKind::SurfaceCodeReviewOpen),
|
||||
SurfaceOpenToggleCommand::Toggle(_) => Some(ActionKind::SurfaceCodeReviewToggle),
|
||||
@@ -716,12 +736,6 @@ fn parsed_action_kind(command: &ControlCommand) -> Option<ActionKind> {
|
||||
SurfaceCommand::GlobalSearch(command) => match command {
|
||||
SurfaceOpenCommand::Open(_) => Some(ActionKind::SurfaceGlobalSearchOpen),
|
||||
},
|
||||
SurfaceCommand::ConversationList(command) => match command {
|
||||
SurfaceOpenCommand::Open(_) => Some(ActionKind::SurfaceConversationListOpen),
|
||||
},
|
||||
SurfaceCommand::LeftPanel(command) => match command {
|
||||
SurfaceToggleCommand::Toggle(_) => Some(ActionKind::SurfaceLeftPanelToggle),
|
||||
},
|
||||
SurfaceCommand::RightPanel(command) => match command {
|
||||
SurfaceToggleCommand::Toggle(_) => Some(ActionKind::SurfaceRightPanelToggle),
|
||||
},
|
||||
@@ -729,9 +743,6 @@ fn parsed_action_kind(command: &ControlCommand) -> Option<ActionKind> {
|
||||
SurfaceOpenToggleCommand::Open(_) => Some(ActionKind::SurfaceVerticalTabsOpen),
|
||||
SurfaceOpenToggleCommand::Toggle(_) => Some(ActionKind::SurfaceVerticalTabsToggle),
|
||||
},
|
||||
SurfaceCommand::AgentManagement(command) => match command {
|
||||
SurfaceOpenCommand::Open(_) => Some(ActionKind::SurfaceAgentManagementOpen),
|
||||
},
|
||||
},
|
||||
ControlCommand::Completions { .. } => None,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
use super::Channel;
|
||||
|
||||
#[test]
|
||||
fn local_control_channel_names_do_not_expose_legacy_branding() {
|
||||
assert_eq!(Channel::Stable.local_control_channel_name(), "stable");
|
||||
assert_eq!(Channel::Preview.local_control_channel_name(), "preview");
|
||||
assert_eq!(Channel::Dev.local_control_channel_name(), "dev");
|
||||
assert_eq!(Channel::Local.local_control_channel_name(), "local");
|
||||
assert_eq!(
|
||||
Channel::Integration.local_control_channel_name(),
|
||||
"integration"
|
||||
);
|
||||
assert_eq!(Channel::Oss.local_control_channel_name(), "oss");
|
||||
}
|
||||
@@ -18,7 +18,7 @@ pub enum Channel {
|
||||
/// The internal-only HEAD build.
|
||||
Local,
|
||||
|
||||
/// The open-source build of Warp.
|
||||
/// The open-source build of Galaxy.
|
||||
Oss,
|
||||
|
||||
/// The integration test build.
|
||||
@@ -59,15 +59,30 @@ impl Channel {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the Warp Control CLI command name corresponding to this channel.
|
||||
pub fn warpctrl_command_name(&self) -> &'static str {
|
||||
/// Returns the Galaxy Control CLI command name corresponding to this channel.
|
||||
pub fn galaxyctrl_command_name(&self) -> &'static str {
|
||||
match self {
|
||||
Channel::Stable => "warpctrl",
|
||||
Channel::Dev => "warpctrl-dev",
|
||||
Channel::Preview => "warpctrl-preview",
|
||||
Channel::Local => "warpctrl-local",
|
||||
Channel::Integration => "warpctrl-integration",
|
||||
Channel::Oss => "warpctrl-oss",
|
||||
Channel::Stable => "galaxyctrl",
|
||||
Channel::Dev => "galaxyctrl-dev",
|
||||
Channel::Preview => "galaxyctrl-preview",
|
||||
Channel::Local => "galaxyctrl-local",
|
||||
Channel::Integration => "galaxyctrl-integration",
|
||||
Channel::Oss => "galaxyctrl-oss",
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the stable channel identifier exposed through Galaxy Control.
|
||||
///
|
||||
/// This intentionally avoids the legacy `warp-oss` display value retained
|
||||
/// for compatibility with existing on-disk paths and update infrastructure.
|
||||
pub fn local_control_channel_name(&self) -> &'static str {
|
||||
match self {
|
||||
Channel::Stable => "stable",
|
||||
Channel::Preview => "preview",
|
||||
Channel::Dev => "dev",
|
||||
Channel::Local => "local",
|
||||
Channel::Integration => "integration",
|
||||
Channel::Oss => "oss",
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,3 +99,7 @@ impl fmt::Display for Channel {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "channel_tests.rs"]
|
||||
mod tests;
|
||||
|
||||
@@ -66,6 +66,7 @@ pub enum Icon {
|
||||
WarpDrive,
|
||||
Warp,
|
||||
WarpLogoLight,
|
||||
GalaxyLogo,
|
||||
ArrowLeft,
|
||||
ArrowBlockLeft,
|
||||
ArrowBlockUp,
|
||||
@@ -404,6 +405,7 @@ impl From<Icon> for &'static str {
|
||||
Icon::WarpDrive => "bundled/svg/warp.svg",
|
||||
Icon::Warp => "bundled/svg/warp-drive.svg",
|
||||
Icon::WarpLogoLight => "bundled/svg/warp-logo-light.svg",
|
||||
Icon::GalaxyLogo => "bundled/svg/galaxy-logo.svg",
|
||||
Icon::ArrowLeft => "bundled/svg/arrow-left.svg",
|
||||
Icon::ArrowBlockLeft => "bundled/svg/arrow-block-left.svg",
|
||||
Icon::ArrowBlockUp => "bundled/svg/arrow-block-up.svg",
|
||||
|
||||
@@ -18,3 +18,21 @@ fn local_child_harnesses_are_local_only_by_default() {
|
||||
assert!(!DEBUG_FLAGS.contains(&FeatureFlag::LocalClaudeCodexChildHarnesses));
|
||||
assert!(!DOGFOOD_FLAGS.contains(&FeatureFlag::LocalClaudeCodexChildHarnesses));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dogfood_flags_do_not_enable_upstream_hosted_services() {
|
||||
for flag in [
|
||||
FeatureFlag::CreatingSharedSessions,
|
||||
FeatureFlag::AgentModeAnalytics,
|
||||
FeatureFlag::ProviderCommand,
|
||||
FeatureFlag::SummarizationViaMessageReplacement,
|
||||
FeatureFlag::GeminiNotifications,
|
||||
FeatureFlag::OzLaunchModal,
|
||||
FeatureFlag::WaitForEventsParentRegistration,
|
||||
] {
|
||||
assert!(
|
||||
!DOGFOOD_FLAGS.contains(&flag),
|
||||
"{flag:?} depends on upstream-hosted or upstream-branded infrastructure"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -797,8 +797,8 @@ pub enum FeatureFlag {
|
||||
/// Enables tab configs — user-definable TOML templates for launching custom tab layouts.
|
||||
TabConfigs,
|
||||
|
||||
/// Enables Warp local control through the standalone warpctrl CLI.
|
||||
WarpControlCli,
|
||||
/// Enables Galaxy local control through the standalone galaxyctrl CLI.
|
||||
GalaxyControlCli,
|
||||
|
||||
/// Enables the ask_user_question tool allowing the agent to ask clarifying questions.
|
||||
AskUserQuestion,
|
||||
@@ -931,18 +931,16 @@ static FEATURES_INITIALIZED: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
/// Features used in debugging.
|
||||
pub const DEBUG_FLAGS: &[FeatureFlag] = &[FeatureFlag::DebugMode, FeatureFlag::RuntimeFeatureFlags];
|
||||
/// Features enabled only for the WarpLocal developer build.
|
||||
/// Features enabled only for the Galaxy Local developer build.
|
||||
pub const LOCAL_FLAGS: &[FeatureFlag] = &[FeatureFlag::LocalClaudeCodexChildHarnesses];
|
||||
|
||||
/// Features enabled for the development team. The expectation is that, over
|
||||
/// time, these will move on to PREVIEW_FLAGS before being launched.
|
||||
pub const DOGFOOD_FLAGS: &[FeatureFlag] = &[
|
||||
FeatureFlag::ToggleBootstrapBlock,
|
||||
FeatureFlag::CreatingSharedSessions,
|
||||
FeatureFlag::RemoveAutosuggestionDuringTabCompletions,
|
||||
FeatureFlag::ResizeFix,
|
||||
FeatureFlag::AgentModeWorkflows,
|
||||
FeatureFlag::AgentModeAnalytics,
|
||||
FeatureFlag::LazySceneBuilding,
|
||||
FeatureFlag::SshDragAndDrop,
|
||||
FeatureFlag::MultiWorkspace,
|
||||
@@ -952,15 +950,11 @@ pub const DOGFOOD_FLAGS: &[FeatureFlag] = &[
|
||||
FeatureFlag::ContextLineReviewComments,
|
||||
FeatureFlag::RunGeneratorsWithCmdExe,
|
||||
FeatureFlag::Projects,
|
||||
FeatureFlag::ProviderCommand,
|
||||
FeatureFlag::MarkdownImages,
|
||||
FeatureFlag::FileAndDiffSetComments,
|
||||
FeatureFlag::FileGlobV2Warnings,
|
||||
FeatureFlag::SummarizationViaMessageReplacement,
|
||||
FeatureFlag::LocalComputerUse,
|
||||
FeatureFlag::OzLaunchModal,
|
||||
// These are enabled via 100% experiment on prod warp-server,
|
||||
// but we need to enable here for dogfood builds.
|
||||
// Keep local code-context experiments enabled in Galaxy dogfood builds.
|
||||
FeatureFlag::CrossRepoContext,
|
||||
FeatureFlag::CodebaseIndexPersistence,
|
||||
FeatureFlag::FullSourceCodeEmbedding,
|
||||
@@ -969,31 +963,28 @@ pub const DOGFOOD_FLAGS: &[FeatureFlag] = &[
|
||||
FeatureFlag::EditableMarkdownMermaid,
|
||||
FeatureFlag::CodeReviewScrollPreservation,
|
||||
FeatureFlag::RememberFastForwardState,
|
||||
FeatureFlag::GeminiNotifications,
|
||||
FeatureFlag::LocalDockerSandbox,
|
||||
#[cfg(not(windows))]
|
||||
FeatureFlag::SshRemoteServer,
|
||||
FeatureFlag::RemoteCodebaseIndexing,
|
||||
FeatureFlag::GPTConfigurableContextWindow,
|
||||
FeatureFlag::RestorePromptOnInlineModelSelectorSearch,
|
||||
FeatureFlag::WarpControlCli,
|
||||
FeatureFlag::PromptCacheExpiryWarning,
|
||||
FeatureFlag::PinnedTabs,
|
||||
FeatureFlag::BackgroundComputerUse,
|
||||
FeatureFlag::ContextWindowUsageBreakdown,
|
||||
FeatureFlag::WaitForEventsParentRegistration,
|
||||
FeatureFlag::CrosscheckWork,
|
||||
];
|
||||
|
||||
/// Features enabled for feature preview build users (e.g.: Friends of Warp).
|
||||
/// All PREVIEW_FLAGS are also automatically added to dogfood builds (WarpDev).
|
||||
/// Features enabled for Galaxy Preview builds.
|
||||
/// All PREVIEW_FLAGS are also automatically added to Galaxy dogfood builds.
|
||||
pub const PREVIEW_FLAGS: &[FeatureFlag] = &[
|
||||
FeatureFlag::AsyncFind,
|
||||
#[cfg(any(target_os = "macos", target_os = "windows"))]
|
||||
FeatureFlag::DragTabsToWindows,
|
||||
];
|
||||
|
||||
/// Features enabled for all release builds (i.e.: everything but WarpLocal).
|
||||
/// Features enabled for all Galaxy release builds (i.e. everything but Galaxy Local).
|
||||
/// NOTE: if you are promoting a feature from Preview to launch, you'll likely
|
||||
/// want to enable the feature by default in app/Cargo.toml, rather than add it to RELEASE_FLAGS.
|
||||
pub const RELEASE_FLAGS: &[FeatureFlag] = &[
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "local_control"
|
||||
edition = "2024"
|
||||
description = "Shared protocol and discovery primitives for Warp local control"
|
||||
description = "Shared protocol and discovery primitives for Galaxy local control"
|
||||
authors.workspace = true
|
||||
publish.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
@@ -94,7 +94,7 @@ impl ScopedCredential {
|
||||
}
|
||||
}
|
||||
|
||||
/// Authorization grant issued by the localhost server running inside Warp for a
|
||||
/// Authorization grant issued by the localhost server running inside Galaxy for a
|
||||
/// single action.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CredentialGrant {
|
||||
@@ -135,7 +135,7 @@ impl CredentialGrant {
|
||||
if &self.instance_id != instance_id {
|
||||
return Err(ControlError::new(
|
||||
ErrorCode::UnauthorizedLocalClient,
|
||||
"local-control credential belongs to a different Warp instance",
|
||||
"local-control credential belongs to a different Galaxy instance",
|
||||
));
|
||||
}
|
||||
if self.action != action {
|
||||
|
||||
@@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
pub const PROTOCOL_VERSION: u32 = 1;
|
||||
|
||||
/// Level of Warp hierarchy or orthogonal product noun an action targets.
|
||||
/// Level of Galaxy hierarchy or orthogonal product noun an action targets.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum TargetScope {
|
||||
@@ -111,7 +111,7 @@ macro_rules! define_action_catalog {
|
||||
),+ $(,)?
|
||||
}
|
||||
)+ $(,)?) => {
|
||||
/// Stable protocol name for every approved `warpctrl` action.
|
||||
/// Stable protocol name for every approved `galaxyctrl` action.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum ActionKind {
|
||||
$($(#[serde(rename = $name)] $variant,)+)+
|
||||
@@ -274,20 +274,13 @@ define_action_catalog! {
|
||||
SurfaceCommandSearchOpen => { name: "surface.command_search.open", status: Implemented, target: Surface, params: Query, result: Acknowledgement },
|
||||
SurfaceThemePickerOpen => { name: "surface.theme_picker.open", status: Implemented, target: Surface, params: None, result: Acknowledgement },
|
||||
SurfaceKeybindingsOpen => { name: "surface.keybindings.open", status: Implemented, target: Surface, params: None, result: Acknowledgement },
|
||||
SurfaceWarpDriveOpen => { name: "surface.warp_drive.open", status: Implemented, target: Surface, params: None, result: Acknowledgement },
|
||||
SurfaceWarpDriveToggle => { name: "surface.warp_drive.toggle", status: Implemented, target: Surface, params: None, result: Acknowledgement },
|
||||
SurfaceResourceCenterToggle => { name: "surface.resource_center.toggle", status: Implemented, target: Surface, params: None, result: Acknowledgement },
|
||||
SurfaceAiAssistantToggle => { name: "surface.ai_assistant.toggle", status: Implemented, target: Surface, params: None, result: Acknowledgement },
|
||||
SurfaceCodeReviewOpen => { name: "surface.code_review.open", status: Implemented, target: Surface, params: None, result: Acknowledgement },
|
||||
SurfaceCodeReviewToggle => { name: "surface.code_review.toggle", status: Implemented, target: Surface, params: None, result: Acknowledgement },
|
||||
SurfaceProjectExplorerOpen => { name: "surface.project_explorer.open", status: Implemented, target: Surface, params: None, result: Acknowledgement },
|
||||
SurfaceGlobalSearchOpen => { name: "surface.global_search.open", status: Implemented, target: Surface, params: None, result: Acknowledgement },
|
||||
SurfaceConversationListOpen => { name: "surface.conversation_list.open", status: Implemented, target: Surface, params: None, result: Acknowledgement },
|
||||
SurfaceLeftPanelToggle => { name: "surface.left_panel.toggle", status: Implemented, target: Surface, params: None, result: Acknowledgement },
|
||||
SurfaceRightPanelToggle => { name: "surface.right_panel.toggle", status: Implemented, target: Surface, params: None, result: Acknowledgement },
|
||||
SurfaceVerticalTabsOpen => { name: "surface.vertical_tabs.open", status: Implemented, target: Surface, params: None, result: Acknowledgement },
|
||||
SurfaceVerticalTabsToggle => { name: "surface.vertical_tabs.toggle", status: Implemented, target: Surface, params: None, result: Acknowledgement },
|
||||
SurfaceAgentManagementOpen => { name: "surface.agent_management.open", status: Implemented, target: Surface, params: None, result: Acknowledgement },
|
||||
}
|
||||
|
||||
file {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//! Blocking client helpers used by the standalone `warpctrl` CLI.
|
||||
//! Blocking client helpers used by the standalone `galaxyctrl` CLI.
|
||||
//!
|
||||
//! Authentication is a two-transport flow:
|
||||
//!
|
||||
@@ -14,7 +14,7 @@
|
||||
//! issuing a short-lived, action-scoped credential.
|
||||
//! 4. The client keeps that credential in memory and presents it as a bearer
|
||||
//! token only to the selected instance's loopback HTTP endpoint. The running
|
||||
//! Warp app revalidates the credential, current settings, action scope, and
|
||||
//! Galaxy app revalidates the credential, current settings, action scope, and
|
||||
//! request before dispatch.
|
||||
//!
|
||||
//! Client-side validation prevents accidental use of inconsistent discovery
|
||||
|
||||
@@ -56,7 +56,7 @@ fn probe_rejects_mismatched_instance_identity() {
|
||||
instance_id: InstanceId("inst_expected".to_owned()),
|
||||
pid: std::process::id(),
|
||||
channel: "local".to_owned(),
|
||||
app_id: "dev.warp.WarpLocal".to_owned(),
|
||||
app_id: "dev.galaxy.GalaxyLocal".to_owned(),
|
||||
app_version: None,
|
||||
started_at: Utc::now(),
|
||||
executable_path: None,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//! Private filesystem registry for discovering running local Warp instances.
|
||||
//! Private filesystem registry for discovering running local Galaxy instances.
|
||||
//!
|
||||
//! This module answers “which compatible instances are available, and where
|
||||
//! can a client begin authentication?” It does not listen for control requests
|
||||
@@ -17,13 +17,13 @@
|
||||
//! Before following a record, clients require the endpoint host to be exactly
|
||||
//! `127.0.0.1` and the broker filename to be derived from the instance ID. A
|
||||
//! discovery scan also rejects incompatible records, prunes dead PIDs, and
|
||||
//! performs an authenticated `app.ping` probe. When Scripting is disabled,
|
||||
//! performs an authenticated `app.ping` probe. When Galaxy Control is disabled,
|
||||
//! records contain neither an endpoint nor a broker reference.
|
||||
//!
|
||||
//! The owner-only directory, records, and broker sockets protect against other
|
||||
//! OS users. The broker's kernel-reported peer-UID check is the authoritative
|
||||
//! same-user check before credential issuance. Neither mechanism distinguishes
|
||||
//! trusted Warp code from arbitrary software already running as that user.
|
||||
//! trusted Galaxy code from arbitrary software already running as that user.
|
||||
use std::collections::HashSet;
|
||||
use std::fs;
|
||||
#[cfg(unix)]
|
||||
@@ -38,12 +38,12 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::protocol::{ActionMetadata, ControlError, ErrorCode, PROTOCOL_VERSION};
|
||||
|
||||
const DISCOVERY_DIR_ENV: &str = "WARP_LOCAL_CONTROL_DISCOVERY_DIR";
|
||||
const DISCOVERY_DIR_ENV: &str = "GALAXY_LOCAL_CONTROL_DISCOVERY_DIR";
|
||||
const BROKER_SOCKET_SUFFIX: &str = ".broker.sock";
|
||||
const TEMP_RECORD_SUFFIX: &str = ".json.tmp";
|
||||
const ORPHAN_SOCKET_GRACE_PERIOD: Duration = Duration::from_secs(60);
|
||||
|
||||
/// Stable identifier for one running Warp instance.
|
||||
/// Stable identifier for one running Galaxy instance.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct InstanceId(pub String);
|
||||
@@ -93,7 +93,7 @@ pub struct CredentialBrokerReference {
|
||||
pub socket_path: PathBuf,
|
||||
}
|
||||
|
||||
/// Filesystem-published routing metadata for a running Warp app process.
|
||||
/// Filesystem-published routing metadata for a running Galaxy app process.
|
||||
///
|
||||
/// An enabled record connects the three stages of the protocol: filesystem
|
||||
/// discovery, Unix-socket credential issuance, and authenticated loopback HTTP
|
||||
@@ -282,10 +282,10 @@ pub fn discovery_dir() -> PathBuf {
|
||||
return PathBuf::from(path);
|
||||
}
|
||||
if let Some(path) = std::env::var_os("XDG_RUNTIME_DIR") {
|
||||
return PathBuf::from(path).join("warp").join("local-control");
|
||||
return PathBuf::from(path).join("galaxy").join("local-control");
|
||||
}
|
||||
let home = std::env::var_os("HOME").unwrap_or_else(|| ".".into());
|
||||
PathBuf::from(home).join(".warp").join("local-control")
|
||||
PathBuf::from(home).join(".galaxy").join("local-control")
|
||||
}
|
||||
|
||||
/// Returns compatible live instances from `channel` that pass an authenticated app ping.
|
||||
|
||||
@@ -18,7 +18,7 @@ fn broker_socket_reference_is_bound_to_instance_identity() {
|
||||
let record = InstanceRecord::for_current_process(
|
||||
Some(ControlEndpoint::localhost(4000)),
|
||||
"local",
|
||||
"dev.warp.WarpLocal",
|
||||
"dev.galaxy.GalaxyLocal",
|
||||
Some("test".to_owned()),
|
||||
crate::protocol::ActionKind::implemented_metadata(),
|
||||
);
|
||||
@@ -38,7 +38,7 @@ fn registered_instance_round_trips_discovery_record() {
|
||||
let record = InstanceRecord::for_current_process(
|
||||
Some(ControlEndpoint::localhost(4000)),
|
||||
"local",
|
||||
"dev.warp.WarpLocal",
|
||||
"dev.galaxy.GalaxyLocal",
|
||||
Some("test".to_owned()),
|
||||
crate::protocol::ActionKind::implemented_metadata(),
|
||||
);
|
||||
@@ -54,7 +54,7 @@ fn incompatible_protocol_record_is_ignored() {
|
||||
let mut record = InstanceRecord::for_current_process(
|
||||
Some(ControlEndpoint::localhost(4000)),
|
||||
"local",
|
||||
"dev.warp.WarpLocal",
|
||||
"dev.galaxy.GalaxyLocal",
|
||||
Some("test".to_owned()),
|
||||
crate::protocol::ActionKind::implemented_metadata(),
|
||||
);
|
||||
@@ -119,7 +119,7 @@ fn stale_process_record_is_pruned() {
|
||||
let mut record = InstanceRecord::for_current_process(
|
||||
Some(ControlEndpoint::localhost(4000)),
|
||||
"local",
|
||||
"dev.warp.WarpLocal",
|
||||
"dev.galaxy.GalaxyLocal",
|
||||
Some("test".to_owned()),
|
||||
crate::protocol::ActionKind::implemented_metadata(),
|
||||
);
|
||||
@@ -148,7 +148,7 @@ fn multiple_live_process_records_are_discovered() {
|
||||
let mut first_record = InstanceRecord::for_current_process(
|
||||
Some(ControlEndpoint::localhost(4000)),
|
||||
"local",
|
||||
"dev.warp.WarpLocal",
|
||||
"dev.galaxy.GalaxyLocal",
|
||||
Some("test".to_owned()),
|
||||
crate::protocol::ActionKind::implemented_metadata(),
|
||||
);
|
||||
@@ -156,7 +156,7 @@ fn multiple_live_process_records_are_discovered() {
|
||||
let mut second_record = InstanceRecord::for_current_process(
|
||||
Some(ControlEndpoint::localhost(4001)),
|
||||
"local",
|
||||
"dev.warp.WarpLocal",
|
||||
"dev.galaxy.GalaxyLocal",
|
||||
Some("test".to_owned()),
|
||||
crate::protocol::ActionKind::implemented_metadata(),
|
||||
);
|
||||
@@ -188,7 +188,7 @@ fn records_from_other_channels_are_ignored() {
|
||||
let record = InstanceRecord::for_current_process(
|
||||
Some(ControlEndpoint::localhost(4000)),
|
||||
"dev",
|
||||
"dev.warp.Warp-Dev",
|
||||
"dev.galaxy.Galaxy-Dev",
|
||||
Some("test".to_owned()),
|
||||
crate::protocol::ActionKind::implemented_metadata(),
|
||||
);
|
||||
@@ -206,7 +206,7 @@ fn serialized_discovery_record_does_not_contain_raw_credential_material() {
|
||||
let record = InstanceRecord::for_current_process(
|
||||
Some(ControlEndpoint::localhost(4000)),
|
||||
"local",
|
||||
"dev.warp.WarpLocal",
|
||||
"dev.galaxy.GalaxyLocal",
|
||||
Some("test".to_owned()),
|
||||
crate::protocol::ActionKind::implemented_metadata(),
|
||||
);
|
||||
@@ -221,7 +221,7 @@ fn disabled_record_does_not_expose_actionable_authority() {
|
||||
let record = InstanceRecord::for_current_process(
|
||||
None,
|
||||
"local",
|
||||
"dev.warp.WarpLocal",
|
||||
"dev.galaxy.GalaxyLocal",
|
||||
Some("test".to_owned()),
|
||||
crate::protocol::ActionKind::implemented_metadata(),
|
||||
);
|
||||
@@ -234,7 +234,7 @@ fn rejects_unsafe_or_divergent_discovery_authority() {
|
||||
let mut record = InstanceRecord::for_current_process(
|
||||
Some(ControlEndpoint::localhost(4000)),
|
||||
"local",
|
||||
"dev.warp.WarpLocal",
|
||||
"dev.galaxy.GalaxyLocal",
|
||||
Some("test".to_owned()),
|
||||
crate::protocol::ActionKind::implemented_metadata(),
|
||||
);
|
||||
@@ -269,7 +269,7 @@ fn discovery_directory_is_owner_only_on_unix() {
|
||||
let record = InstanceRecord::for_current_process(
|
||||
Some(ControlEndpoint::localhost(4000)),
|
||||
"local",
|
||||
"dev.warp.WarpLocal",
|
||||
"dev.galaxy.GalaxyLocal",
|
||||
Some("test".to_owned()),
|
||||
crate::protocol::ActionKind::implemented_metadata(),
|
||||
);
|
||||
@@ -290,7 +290,7 @@ fn discovery_record_is_owner_only_on_unix() {
|
||||
let record = InstanceRecord::for_current_process(
|
||||
Some(ControlEndpoint::localhost(4000)),
|
||||
"local",
|
||||
"dev.warp.WarpLocal",
|
||||
"dev.galaxy.GalaxyLocal",
|
||||
Some("test".to_owned()),
|
||||
crate::protocol::ActionKind::implemented_metadata(),
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Shared protocol, discovery, authentication, and client types for local Warp control.
|
||||
//! Shared protocol, discovery, authentication, and client types for local Galaxy control.
|
||||
//!
|
||||
//! The `local_control` crate is intentionally UI-agnostic so the Warp app and
|
||||
//! `warpctrl` CLI can share the same wire envelopes, action catalog, discovery
|
||||
//! The `local_control` crate is intentionally UI-agnostic so the Galaxy app and
|
||||
//! `galaxyctrl` CLI can share the same wire envelopes, action catalog, discovery
|
||||
//! records, selectors, and credential validation rules.
|
||||
pub mod auth;
|
||||
pub mod catalog;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//! Wire protocol envelopes and error types for Warp local control.
|
||||
//! Wire protocol envelopes and error types for Galaxy local control.
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
@@ -30,7 +30,6 @@ pub enum Direction {
|
||||
pub enum TabType {
|
||||
Terminal,
|
||||
Agent,
|
||||
CloudAgent,
|
||||
Default,
|
||||
}
|
||||
|
||||
@@ -89,7 +88,7 @@ pub struct DirectionParams {
|
||||
pub direction: Direction,
|
||||
}
|
||||
|
||||
/// Parameters for opening a file in Warp's app/editor state.
|
||||
/// Parameters for opening a file in Galaxy's app/editor state.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct FileOpenParams {
|
||||
@@ -311,7 +310,7 @@ pub enum ControlResult {
|
||||
Content { data: serde_json::Value },
|
||||
}
|
||||
|
||||
/// Top-level request sent by a local-control client to a Warp instance.
|
||||
/// Top-level request sent by a local-control client to a Galaxy instance.
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct RequestEnvelope {
|
||||
pub protocol_version: u32,
|
||||
@@ -372,7 +371,7 @@ impl Action {
|
||||
}
|
||||
}
|
||||
|
||||
/// Top-level response returned by a Warp instance for a control request.
|
||||
/// Top-level response returned by a Galaxy instance for a control request.
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ResponseEnvelope {
|
||||
pub protocol_version: u32,
|
||||
|
||||
@@ -151,14 +151,26 @@ fn malformed_and_removed_action_names_are_not_deserialized() {
|
||||
"drive.object.insert",
|
||||
"drive.object.share_to_team",
|
||||
"drive.workflow.run",
|
||||
"surface.warp_drive.open",
|
||||
"surface.warp_drive.toggle",
|
||||
"surface.resource_center.toggle",
|
||||
"surface.ai_assistant.toggle",
|
||||
"surface.conversation_list.open",
|
||||
"surface.agent_management.open",
|
||||
"surface.left_panel.toggle",
|
||||
] {
|
||||
assert!(serde_json::from_value::<ActionKind>(serde_json::json!(action)).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn catalog_has_exactly_84_retained_actions() {
|
||||
assert_eq!(ActionKind::ALL.len(), 84);
|
||||
fn removed_cloud_agent_tab_type_is_not_deserialized() {
|
||||
assert!(serde_json::from_value::<TabType>(serde_json::json!("cloud_agent")).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn catalog_has_exactly_77_retained_actions() {
|
||||
assert_eq!(ActionKind::ALL.len(), 77);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -184,18 +196,10 @@ fn direct_surface_actions_have_stable_names() {
|
||||
ActionKind::SurfaceGlobalSearchOpen.as_str(),
|
||||
"surface.global_search.open"
|
||||
);
|
||||
assert_eq!(
|
||||
ActionKind::SurfaceConversationListOpen.as_str(),
|
||||
"surface.conversation_list.open"
|
||||
);
|
||||
assert_eq!(
|
||||
ActionKind::SurfaceVerticalTabsOpen.as_str(),
|
||||
"surface.vertical_tabs.open"
|
||||
);
|
||||
assert_eq!(
|
||||
ActionKind::SurfaceAgentManagementOpen.as_str(),
|
||||
"surface.agent_management.open"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
use crate::discovery::{InstanceId, InstanceRecord};
|
||||
use crate::protocol::{ControlError, ErrorCode};
|
||||
|
||||
/// CLI-level selector for choosing one discovered Warp instance.
|
||||
/// CLI-level selector for choosing one discovered Galaxy instance.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum InstanceSelector {
|
||||
Active,
|
||||
@@ -23,7 +23,7 @@ pub fn select_instance(
|
||||
.ok_or_else(|| {
|
||||
ControlError::new(
|
||||
ErrorCode::NoInstance,
|
||||
format!("no Warp instance with id {}", instance_id.0),
|
||||
format!("no Galaxy instance with id {}", instance_id.0),
|
||||
)
|
||||
}),
|
||||
InstanceSelector::Pid(pid) => records
|
||||
@@ -33,7 +33,7 @@ pub fn select_instance(
|
||||
.ok_or_else(|| {
|
||||
ControlError::new(
|
||||
ErrorCode::NoInstance,
|
||||
format!("no Warp instance with pid {pid}"),
|
||||
format!("no Galaxy instance with pid {pid}"),
|
||||
)
|
||||
}),
|
||||
}
|
||||
@@ -43,12 +43,12 @@ fn select_active(records: &[InstanceRecord]) -> Result<InstanceRecord, ControlEr
|
||||
match records {
|
||||
[] => Err(ControlError::new(
|
||||
ErrorCode::NoInstance,
|
||||
"no local Warp control instances were discovered",
|
||||
"no local Galaxy instances with Galaxy Control enabled were discovered",
|
||||
)),
|
||||
[record] => Ok(record.clone()),
|
||||
_ => Err(ControlError::new(
|
||||
ErrorCode::AmbiguousInstance,
|
||||
"multiple local Warp control instances were discovered; pass --instance",
|
||||
"multiple local Galaxy instances with Galaxy Control enabled were discovered; pass --instance",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ fn record(id: &str, pid: u32) -> InstanceRecord {
|
||||
instance_id: InstanceId(id.to_owned()),
|
||||
pid,
|
||||
channel: "local".to_owned(),
|
||||
app_id: "dev.warp.WarpLocal".to_owned(),
|
||||
app_id: "dev.galaxy.GalaxyLocal".to_owned(),
|
||||
app_version: None,
|
||||
started_at: Utc::now(),
|
||||
executable_path: None,
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
//! Serializable selectors for targeting windows, tabs, and panes.
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Opaque window identifier supplied by Warp metadata.
|
||||
/// Opaque window identifier supplied by Galaxy metadata.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct WindowSelector(pub String);
|
||||
|
||||
/// Opaque tab identifier supplied by Warp metadata.
|
||||
/// Opaque tab identifier supplied by Galaxy metadata.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct TabSelector(pub String);
|
||||
|
||||
/// Opaque pane identifier supplied by Warp metadata.
|
||||
/// Opaque pane identifier supplied by Galaxy metadata.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct PaneSelector(pub String);
|
||||
|
||||
/// Opaque session identifier supplied by Warp metadata.
|
||||
/// Opaque session identifier supplied by Galaxy metadata.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct SessionSelector(pub String);
|
||||
|
||||
/// Hierarchical target for actions that operate on a specific Warp surface.
|
||||
/// Hierarchical target for actions that operate on a specific Galaxy surface.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct TargetSelector {
|
||||
|
||||
Reference in New Issue
Block a user