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:
2026-07-29 15:04:58 -05:00
parent 100f1eff1c
commit dbfa8bcd48
172 changed files with 6357 additions and 3825 deletions
+2 -2
View File
@@ -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 {
+2 -9
View File
@@ -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 {
+2 -2
View 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
+1 -1
View File
@@ -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,
+8 -8
View File
@@ -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.
+12 -12
View File
@@ -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(),
);
+3 -3
View File
@@ -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;
+4 -5
View File
@@ -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,
+14 -10
View File
@@ -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]
+5 -5
View File
@@ -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",
)),
}
}
+1 -1
View File
@@ -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,
+5 -5
View File
@@ -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 {