From bc8f70ea67280b68310d0fa206642e9e5a5f5432 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 19 Jul 2026 05:23:24 +0000 Subject: [PATCH 1/2] Fix build broken on main: missing github field + non-exhaustive match MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit main's HEAD was broken in two independent ways, unrelated to the earlier moat-strategy docs PR (#8) that surfaced this — its CI "build" check failed and the failure turned out to have nothing to do with that PR's diff: 1. `cargo build --workspace` (default features) failed outright: the GitHub MCP connector work added `github: Option` to `SupervisorOptions` and `github: GitHubMcpArgs` to `FleetServeArgs`, but `crates/altius-cli/src/serve_command.rs` was never updated to match — three struct literals (`options_for_run`, `build_supervisor_options`, and the internal `FleetServeArgs` reconstruction in `serve_protocols`) still omitted the new field. Fixed by wiring GitHub MCP attachment through the same pattern already used correctly for browser MCP in the same file, and already correct in `fleet_command.rs::run_fleet_cmd` (the reference implementation this mirrors). 2. `cargo clippy --workspace --all-features -D warnings` (what CI's build job actually runs) additionally failed: `McpClientError` gained a `MissingCredential(String)` variant, but `altius-mcp/src/agent_lsp.rs::map_error`'s match wasn't updated, making it non-exhaustive. Fixed by mapping it to `AgentLspError::InvalidConfig`. Also includes the pre-existing `cargo fmt` drift already found while investigating the fmt-check failure on PR #8 (files unrelated to that PR's docs-only diff). Verified before committing: `cargo build --workspace`, `cargo fmt --all -- --check`, `cargo clippy --workspace --all-targets --all-features --locked -- -D warnings`, and `cargo test --workspace --all-features --locked` (309 passed, 0 failed) all pass clean. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01PSnNk5ivBeSBCN2LUhzBix --- crates/altius-cli/src/cli.rs | 6 +---- crates/altius-cli/src/github_connector.rs | 1 - crates/altius-cli/src/serve_command.rs | 24 +++++++++++++---- crates/altius-mcp/src/agent_lsp.rs | 3 +++ crates/altius-mcp/src/mcp_client.rs | 10 ++----- crates/altius-protocol/src/beeacp/mod.rs | 2 +- crates/altius-protocol/src/beeacp/routes.rs | 26 +++++++++---------- .../src/beeacp/sqlite_store.rs | 13 +++++----- 8 files changed, 46 insertions(+), 39 deletions(-) diff --git a/crates/altius-cli/src/cli.rs b/crates/altius-cli/src/cli.rs index 2a7b72e..c747237 100644 --- a/crates/altius-cli/src/cli.rs +++ b/crates/altius-cli/src/cli.rs @@ -171,11 +171,7 @@ pub struct GitHubMcpArgs { /// Name of the environment variable containing the GitHub bearer token. /// The token value is never accepted as a CLI argument or sent to the LLM. - #[arg( - long, - env = "ALTIUS_GITHUB_TOKEN_ENV", - default_value = "GITHUB_TOKEN" - )] + #[arg(long, env = "ALTIUS_GITHUB_TOKEN_ENV", default_value = "GITHUB_TOKEN")] pub github_token_env: String, /// GitHub MCP capability exposed to the specialist. diff --git a/crates/altius-cli/src/github_connector.rs b/crates/altius-cli/src/github_connector.rs index 52f9b53..3689b45 100644 --- a/crates/altius-cli/src/github_connector.rs +++ b/crates/altius-cli/src/github_connector.rs @@ -53,4 +53,3 @@ pub async fn attach( dispatcher: Arc::new(tools), })) } - diff --git a/crates/altius-cli/src/serve_command.rs b/crates/altius-cli/src/serve_command.rs index f3ba218..f6987f9 100644 --- a/crates/altius-cli/src/serve_command.rs +++ b/crates/altius-cli/src/serve_command.rs @@ -22,8 +22,8 @@ use altius_protocol::anp::{ AgentDescription, AgentRegistry, AnpState, InMemoryRegistry, InterfaceDescription, }; use altius_protocol::beeacp::{ - require_bearer, BearerAuth, BeeAcpState, Message, MessagePart, Run, RunApproval, RunExecutor, - RunOutcome, SqliteRunStore, openapi_router, + openapi_router, require_bearer, BearerAuth, BeeAcpState, Message, MessagePart, Run, + RunApproval, RunExecutor, RunOutcome, SqliteRunStore, }; use altius_protocol::Result as ProtocolResult; use async_trait::async_trait; @@ -294,9 +294,11 @@ impl FleetRunExecutor { .await { Ok(ExecutionOutcome::Finished { state, .. }) => Ok(Some(completed_outcome(state))), - Ok(ExecutionOutcome::Interrupted { reason, node, .. }) => Ok(Some(RunOutcome::Awaiting { - approval: RunApproval::generic(reason, Some(node)), - })), + Ok(ExecutionOutcome::Interrupted { reason, node, .. }) => { + Ok(Some(RunOutcome::Awaiting { + approval: RunApproval::generic(reason, Some(node)), + })) + } Err(error) => Ok(Some(RunOutcome::Failed(error.to_string()))), } } @@ -384,6 +386,7 @@ fn options_for_run(template: &SupervisorOptions, agent_name: &str) -> Supervisor SupervisorOptions { agent_name: Some(agent_name.to_owned()), browser: template.browser.clone(), + github: template.github.clone(), hooks: template.hooks.clone(), } } @@ -554,10 +557,20 @@ async fn build_supervisor_options( } } let browser_enabled = browser_tooling.is_some(); + + let github_tooling = match crate::github_connector::attach(&args.github, &attachments).await { + Ok(tooling) => tooling, + Err(error) => { + eprintln!("altius: warning: GitHub MCP attach failed: {error}"); + None + } + }; + Ok(( SupervisorOptions { agent_name: None, browser: browser_tooling, + github: github_tooling, hooks: Vec::new(), }, browser_enabled, @@ -612,6 +625,7 @@ fn serve_protocols(args: &FleetServeArgs, include_beeacp: bool) -> Result<(), Cl token: args.token.clone(), run_db: args.run_db.clone(), plugin: args.plugin.clone(), + github: args.github.clone(), }; rt.block_on(async move { diff --git a/crates/altius-mcp/src/agent_lsp.rs b/crates/altius-mcp/src/agent_lsp.rs index 5eea67f..28f3324 100644 --- a/crates/altius-mcp/src/agent_lsp.rs +++ b/crates/altius-mcp/src/agent_lsp.rs @@ -87,6 +87,9 @@ fn map_error(error: McpClientError) -> AgentLspError { McpClientError::Request(_, message) => AgentLspError::Request(message), McpClientError::NotFound(name) => AgentLspError::Request(format!("not found: {name}")), McpClientError::Shutdown(_, message) => AgentLspError::Shutdown(message), + McpClientError::MissingCredential(env_var) => { + AgentLspError::InvalidConfig(format!("missing credential environment variable `{env_var}`")) + } } } diff --git a/crates/altius-mcp/src/mcp_client.rs b/crates/altius-mcp/src/mcp_client.rs index d35475c..c4cc0ed 100644 --- a/crates/altius-mcp/src/mcp_client.rs +++ b/crates/altius-mcp/src/mcp_client.rs @@ -225,9 +225,7 @@ pub async fn attach_mcp(config: McpAttachConfig) -> Result Result { +pub async fn attach_remote_mcp(config: McpRemoteConfig) -> Result { validate_remote_config(&config)?; spawn_remote(config).await } @@ -398,11 +396,7 @@ fn validate_config(config: &McpAttachConfig) -> Result<(), McpClientError> { "too many env_extras entries".into(), )); } - if config - .env_extras - .iter() - .any(|key| !valid_env_key(key)) - { + if config.env_extras.iter().any(|key| !valid_env_key(key)) { return Err(McpClientError::InvalidConfig( "env_extras keys must be ASCII environment names and bounded".into(), )); diff --git a/crates/altius-protocol/src/beeacp/mod.rs b/crates/altius-protocol/src/beeacp/mod.rs index f84f92f..8a8ff24 100644 --- a/crates/altius-protocol/src/beeacp/mod.rs +++ b/crates/altius-protocol/src/beeacp/mod.rs @@ -13,8 +13,8 @@ mod auth; mod model; -mod routes; mod openapi; +mod routes; mod sqlite_store; mod store; diff --git a/crates/altius-protocol/src/beeacp/routes.rs b/crates/altius-protocol/src/beeacp/routes.rs index f262444..115c598 100644 --- a/crates/altius-protocol/src/beeacp/routes.rs +++ b/crates/altius-protocol/src/beeacp/routes.rs @@ -28,9 +28,7 @@ pub enum RunOutcome { /// The run finished with the given output messages. Completed(Vec), /// The run is paused waiting for external input (`POST /runs/{id}`). - Awaiting { - approval: RunApproval, - }, + Awaiting { approval: RunApproval }, /// The run failed with a human-readable reason. Failed(String), } @@ -156,13 +154,7 @@ async fn apply_outcome(state: &BeeAcpState, run_id: RunId, outcome: RunOutcome) RunOutcome::Awaiting { approval } => { state .store - .transition( - run_id, - RunStatus::Awaiting, - None, - None, - Some(approval), - ) + .transition(run_id, RunStatus::Awaiting, None, None, Some(approval)) .await } RunOutcome::Failed(reason) => { @@ -257,7 +249,10 @@ pub(crate) async fn list_runs(State(state): State) -> Result, Path(id): Path) -> Result> { +pub(crate) async fn get_run( + State(state): State, + Path(id): Path, +) -> Result> { let run = state.store.get(parse_run_id(&id)?).await?; Ok(Json(run)) } @@ -274,7 +269,10 @@ pub(crate) async fn get_run(State(state): State, Path(id): Path, Path(id): Path) -> Result> { +pub(crate) async fn cancel_run( + State(state): State, + Path(id): Path, +) -> Result> { let run = state .store .transition(parse_run_id(&id)?, RunStatus::Cancelled, None, None, None) @@ -663,7 +661,9 @@ mod tests { // so keep-alive pings keep the stream open indefinitely. let (_, run) = send( &app, - Request::get(format!("/runs/{id}")).body(Body::empty()).unwrap(), + Request::get(format!("/runs/{id}")) + .body(Body::empty()) + .unwrap(), ) .await; assert_eq!(run["status"], "awaiting"); diff --git a/crates/altius-protocol/src/beeacp/sqlite_store.rs b/crates/altius-protocol/src/beeacp/sqlite_store.rs index 994e49d..ea09842 100644 --- a/crates/altius-protocol/src/beeacp/sqlite_store.rs +++ b/crates/altius-protocol/src/beeacp/sqlite_store.rs @@ -162,12 +162,13 @@ fn decode_run( finished_at, ): StoredRunRow, ) -> Result { - let approval = match approval_json { - Some(raw) => Some(serde_json::from_str(&raw).map_err(|e| { - ProtocolError::Internal(format!("corrupt approval json in db: {e}")) - })?), - None => None, - }; + let approval = + match approval_json { + Some(raw) => Some(serde_json::from_str(&raw).map_err(|e| { + ProtocolError::Internal(format!("corrupt approval json in db: {e}")) + })?), + None => None, + }; Ok(Run { run_id: run_id .parse() From 7c24a20f41045c3751e05012be303a07cc91c05d Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 19 Jul 2026 05:25:15 +0000 Subject: [PATCH 2/2] Apply cargo fmt to the MissingCredential match arm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous commit added the missing McpClientError::MissingCredential match arm in agent_lsp.rs by hand but never re-ran `cargo fmt` afterward — clippy and tests were re-verified, but formatting wasn't, so the arm's manual layout didn't match what rustfmt produces. This is exactly what broke PR #9's own CI `build` check (`cargo fmt --all -- --check`). Verified clean this time: cargo build --workspace (0), cargo fmt --all -- --check (0), cargo clippy --workspace --all-targets --all-features --locked -D warnings (0). Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01PSnNk5ivBeSBCN2LUhzBix --- crates/altius-mcp/src/agent_lsp.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/altius-mcp/src/agent_lsp.rs b/crates/altius-mcp/src/agent_lsp.rs index 28f3324..9814a38 100644 --- a/crates/altius-mcp/src/agent_lsp.rs +++ b/crates/altius-mcp/src/agent_lsp.rs @@ -87,9 +87,9 @@ fn map_error(error: McpClientError) -> AgentLspError { McpClientError::Request(_, message) => AgentLspError::Request(message), McpClientError::NotFound(name) => AgentLspError::Request(format!("not found: {name}")), McpClientError::Shutdown(_, message) => AgentLspError::Shutdown(message), - McpClientError::MissingCredential(env_var) => { - AgentLspError::InvalidConfig(format!("missing credential environment variable `{env_var}`")) - } + McpClientError::MissingCredential(env_var) => AgentLspError::InvalidConfig(format!( + "missing credential environment variable `{env_var}`" + )), } }