diff --git a/CHANGELOG.md b/CHANGELOG.md index 23a80751..b7d238de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **Ephemeral generated project context (#3058).** Opening CodeWhale in a directory with no instruction files now keeps the bounded generated project overview in memory instead of creating `.codewhale/instructions.md`. +- **ACP registry auth metadata (#1447).** The ACP stdio adapter now advertises + terminal authentication setup in `initialize.authMethods`, matching the + registry's validation requirement. - **Cursor-style activity metadata rows (#3146).** Dense successful tool-run summaries now render as a single muted `Explored ...` / `Updated metadata` row, include short command-family labels for successful generic verifier diff --git a/crates/tui/CHANGELOG.md b/crates/tui/CHANGELOG.md index 1b47fea7..bf04d649 100644 --- a/crates/tui/CHANGELOG.md +++ b/crates/tui/CHANGELOG.md @@ -16,6 +16,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **Ephemeral generated project context (#3058).** Opening CodeWhale in a directory with no instruction files now keeps the bounded generated project overview in memory instead of creating `.codewhale/instructions.md`. +- **ACP registry auth metadata (#1447).** The ACP stdio adapter now advertises + terminal authentication setup in `initialize.authMethods`, matching the + registry's validation requirement. - **Cursor-style activity metadata rows (#3146).** Dense successful tool-run summaries now render as a single muted `Explored ...` / `Updated metadata` row, include short command-family labels for successful generic verifier diff --git a/crates/tui/src/acp_server.rs b/crates/tui/src/acp_server.rs index 72a110cf..6d28c66d 100644 --- a/crates/tui/src/acp_server.rs +++ b/crates/tui/src/acp_server.rs @@ -125,6 +125,7 @@ impl AcpServer { match method { "initialize" => Ok(AcpDispatch::Response(initialize_result( params.get("protocolVersion").and_then(Value::as_u64), + &self.config, ))), "session/new" => Ok(AcpDispatch::Response(self.new_session(params)?)), "session/prompt" => { @@ -265,7 +266,7 @@ impl AcpError { } } -fn initialize_result(client_protocol_version: Option) -> Value { +fn initialize_result(client_protocol_version: Option, config: &Config) -> Value { json!({ "protocolVersion": client_protocol_version .map(|version| version.min(ACP_PROTOCOL_VERSION)) @@ -288,10 +289,24 @@ fn initialize_result(client_protocol_version: Option) -> Value { "title": "codewhale", "version": env!("CARGO_PKG_VERSION") }, - "authMethods": [] + "authMethods": acp_auth_methods(config) }) } +fn acp_auth_methods(config: &Config) -> Value { + let provider = config.api_provider().as_str(); + json!([ + { + "id": "codewhale-terminal-auth", + "name": "Set CodeWhale API key", + "description": format!("Run CodeWhale's terminal credential setup for the {provider} provider."), + "type": "terminal", + "args": ["auth", "set", "--provider", provider], + "env": {} + } + ]) +} + fn extract_prompt_text(prompt: Option<&Value>) -> Option { match prompt? { Value::String(text) => Some(text.clone()), @@ -420,7 +435,7 @@ mod tests { #[test] fn initialize_advertises_baseline_acp_agent() { - let result = initialize_result(Some(1)); + let result = initialize_result(Some(1), &Config::default()); assert_eq!(result["protocolVersion"], 1); assert_eq!(result["agentInfo"]["name"], "codewhale"); @@ -429,7 +444,11 @@ mod tests { result["agentCapabilities"]["promptCapabilities"]["embeddedContext"], true ); - assert_eq!(result["authMethods"], json!([])); + assert_eq!(result["authMethods"][0]["type"], "terminal"); + assert_eq!( + result["authMethods"][0]["args"], + json!(["auth", "set", "--provider", "deepseek"]) + ); } #[test]