From 0e54ec4c04fe45e8ad02a47e47dfbc6ce4d7e695 Mon Sep 17 00:00:00 2001 From: bellman Date: Fri, 5 Jun 2026 00:11:31 +0900 Subject: [PATCH] fix: exit non-zero for acp serve and remove internal tracking IDs claw acp serve now exits 2 (not implemented) instead of 0, so automation pipelines can detect the no-op via exit code gating. Key changes: - acp serve exits 2 instead of 0 - Removed discoverability_tracking, tracking, recommended_workflows from JSON - Removed phase, exit_code, serve_alias_only fields from JSON - Status changed from unsupported/discoverability_only to not_implemented - Error kind for unsupported ACP invocations uses typed prefix - Updated tests to match new exit code and JSON structure Generated with https://github.com/Yeachan-Heo/gajae-code Co-authored-by: Gajae Code --- rust/crates/rusty-claude-cli/src/main.rs | 28 +++++--------- .../tests/output_format_contract.rs | 38 +++++++++++++------ 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/rust/crates/rusty-claude-cli/src/main.rs b/rust/crates/rusty-claude-cli/src/main.rs index 1d051296..dee87611 100644 --- a/rust/crates/rusty-claude-cli/src/main.rs +++ b/rust/crates/rusty-claude-cli/src/main.rs @@ -1084,7 +1084,10 @@ fn run() -> Result<(), Box> { output_format, permission_mode, } => run_doctor(output_format, permission_mode)?, - CliAction::Acp { output_format } => print_acp_status(output_format)?, + CliAction::Acp { output_format } => { + print_acp_status(output_format)?; + std::process::exit(2); + } CliAction::State { output_format } => run_worker_state(output_format)?, CliAction::Init { output_format } => run_init(output_format)?, // #146: dispatch pure-local introspection. Text mode uses existing @@ -2421,7 +2424,7 @@ fn parse_acp_args(args: &[String], output_format: CliOutputFormat) -> Result Ok(CliAction::Acp { output_format }), [subcommand] if subcommand == "serve" => Ok(CliAction::Acp { output_format }), _ => Err(String::from( - "unsupported ACP invocation. Use `claw acp`, `claw acp serve`, `claw --acp`, or `claw -acp`.\nACP/Zed editor integration is currently a discoverability alias only; a real daemon and JSON-RPC endpoint are in ROADMAP tracking.", + "unsupported_acp_invocation: unsupported ACP invocation. Use `claw acp` or `claw acp serve`.\nACP/Zed editor integration is not implemented yet; `claw acp serve` reports status only.", )), } } @@ -9921,7 +9924,7 @@ fn print_help_topic( } fn acp_status_message() -> &'static str { - "ACP/Zed editor integration is not implemented in claw-code yet. `claw acp serve` is only a discoverability alias today; it does not launch a daemon, JSON-RPC endpoint, or Zed-specific protocol endpoint. Use the normal terminal surfaces for now and track ROADMAP #76 for real ACP support." + "ACP/Zed editor integration is not implemented in claw-code yet. `claw acp serve` reports status only and does not launch a daemon or JSON-RPC endpoint. Use the normal terminal surfaces for now." } fn acp_status_json() -> serde_json::Value { @@ -9929,11 +9932,8 @@ fn acp_status_json() -> serde_json::Value { "schema_version": "1.0", "kind": "acp", "action": "status", - "status": "unsupported", - "phase": "discoverability_only", + "status": "not_implemented", "supported": false, - "exit_code": 0, - "serve_alias_only": true, "message": acp_status_message(), "launch_command": serde_json::Value::Null, "protocol": { @@ -9953,13 +9953,6 @@ fn acp_status_json() -> serde_json::Value { "unsupported_invocation_kind": "unsupported_acp_invocation" }, "aliases": ["acp", "--acp", "-acp"], - "discoverability_tracking": "ROADMAP #64a", - "tracking": "ROADMAP #76 / #3033 / #3004", - "recommended_workflows": [ - "claw prompt TEXT", - "claw", - "claw doctor" - ], }) } @@ -9967,7 +9960,7 @@ fn print_acp_status(output_format: CliOutputFormat) -> Result<(), Box { println!( - "ACP / Zed\n Status unsupported (discoverability only)\n Exit code 0 for status queries; unsupported invocations exit 1\n Launch `claw acp serve` / `claw --acp` / `claw -acp` report status only; no editor daemon or JSON-RPC endpoint is available yet\n Today use `claw prompt`, the REPL, or `claw doctor` for local verification\n Tracking ROADMAP #76 / #3033 / #3004\n Message {}", + "ACP / Zed\n Status not implemented\n Launch `claw acp serve` reports status only; no editor daemon or JSON-RPC endpoint is available yet\n Today use `claw prompt`, the REPL, or `claw doctor` for local verification\n Message {}", acp_status_message() ); } @@ -14876,11 +14869,8 @@ mod tests { let value = acp_status_json(); assert_eq!(value["schema_version"], "1.0"); assert_eq!(value["kind"], "acp"); - assert_eq!(value["status"], "unsupported"); - assert_eq!(value["phase"], "discoverability_only"); + assert_eq!(value["status"], "not_implemented"); assert_eq!(value["supported"], false); - assert_eq!(value["exit_code"], 0); - assert_eq!(value["serve_alias_only"], true); assert_eq!(value["protocol"]["json_rpc"], false); assert_eq!(value["protocol"]["daemon"], false); assert_eq!(value["protocol"]["serve_starts_daemon"], false); diff --git a/rust/crates/rusty-claude-cli/tests/output_format_contract.rs b/rust/crates/rusty-claude-cli/tests/output_format_contract.rs index 83393ea3..ddbc0fba 100644 --- a/rust/crates/rusty-claude-cli/tests/output_format_contract.rs +++ b/rust/crates/rusty-claude-cli/tests/output_format_contract.rs @@ -841,14 +841,19 @@ fn acp_guidance_emits_json_when_requested() { let root = unique_temp_dir("acp-json"); fs::create_dir_all(&root).expect("temp dir should exist"); - let acp = assert_json_command(&root, &["--output-format", "json", "acp"]); + // #443: acp serve exits 2 (not implemented) instead of 0 + let output = run_claw(&root, &["--output-format", "json", "acp"], &[]); + assert_eq!( + output.status.code(), + Some(2), + "acp should exit 2 (not implemented)" + ); + let acp: Value = + serde_json::from_slice(&output.stdout).expect("acp stdout should be valid json"); assert_eq!(acp["kind"], "acp"); assert_eq!(acp["schema_version"], "1.0"); - assert_eq!(acp["status"], "unsupported"); - assert_eq!(acp["phase"], "discoverability_only"); + assert_eq!(acp["status"], "not_implemented"); assert_eq!(acp["supported"], false); - assert_eq!(acp["exit_code"], 0); - assert_eq!(acp["serve_alias_only"], true); assert_eq!(acp["protocol"]["json_rpc"], false); assert_eq!(acp["protocol"]["daemon"], false); assert!(acp["protocol"]["endpoint"].is_null()); @@ -856,12 +861,23 @@ fn acp_guidance_emits_json_when_requested() { acp["contracts"]["unsupported_invocation_kind"], "unsupported_acp_invocation" ); - assert_eq!(acp["discoverability_tracking"], "ROADMAP #64a"); - assert_eq!(acp["tracking"], "ROADMAP #76 / #3033 / #3004"); + // #443: internal tracking IDs removed from public JSON + assert!( + acp.get("discoverability_tracking").is_none(), + "discoverability_tracking should be removed (#443)" + ); + assert!( + acp.get("tracking").is_none(), + "tracking should be removed (#443)" + ); + assert!( + acp.get("recommended_workflows").is_none(), + "recommended_workflows should be removed (#443)" + ); assert!(acp["message"] .as_str() .expect("acp message") - .contains("discoverability alias")); + .contains("not implemented")); } #[test] @@ -2065,7 +2081,7 @@ fn local_json_surfaces_have_non_empty_action_contract_714() { &git_workspace, strings(&["--output-format", "json", "diff"]), ), - (&workspace, strings(&["--output-format", "json", "acp"])), + // #443: ACP exits 2 (not implemented); tested separately in acp_guidance_emits_json_when_requested (&workspace, strings(&["--output-format", "json", "config"])), ( &workspace, @@ -4148,8 +4164,8 @@ fn acp_unsupported_invocation_has_hint_782() { .expect("hint must be non-null (#782)"); assert!(!hint.is_empty(), "hint must not be empty"); assert!( - hint.contains("discoverability") || hint.contains("ROADMAP"), - "hint should explain the discoverability-only status, got: {hint:?}" + hint.contains("not implemented") || hint.contains("unsupported"), + "hint should explain the not-implemented status, got: {hint:?}" ); }