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 <dev@gajae-code.com>
This commit is contained in:
bellman
2026-06-05 00:11:31 +09:00
parent 58a30f6ab8
commit 0e54ec4c04
2 changed files with 36 additions and 30 deletions

View File

@ -1084,7 +1084,10 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
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<Cli
[] => 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<dyn std::e
match output_format {
CliOutputFormat::Text => {
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);

View File

@ -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:?}"
);
}