mirror of
https://github.com/instructkr/claw-code.git
synced 2026-04-17 05:24:50 +08:00
Make ACP/Zed status obvious before users go source-diving
ROADMAP #21, #22, and #23 were already closed on current main, so the next real repo-local backlog item was the ACP/Zed discoverability gap. This adds a local `claw acp` status surface plus aliases, updates help/docs, and separates the shipped discoverability fix from the still-open daemon/protocol follow-up so editor-first users get a crisp answer immediately. Constraint: No ACP/Zed daemon or protocol server exists in claw-code yet, so the new surface must be explicit status guidance rather than a fake implementation Rejected: Add a pretend `acp serve` daemon path | would imply supported protocol behavior that does not exist Rejected: Docs-only clarification | still leaves `claw --help` unable to answer the editor-launch question directly Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep ROADMAP discoverability fixes separate from future ACP daemon/protocol work so help text and backlog IDs stay unambiguous Tested: cargo fmt --check; cargo clippy --workspace --all-targets -- -D warnings; cargo test --workspace; cargo run -q -p rusty-claude-cli -- acp; cargo run -q -p rusty-claude-cli -- --output-format json acp; architect review APPROVED Not-tested: Real ACP/Zed daemon launch because no protocol-serving surface exists yet
This commit is contained in:
@@ -135,6 +135,7 @@ Top-level commands:
|
||||
version
|
||||
status
|
||||
sandbox
|
||||
acp [serve]
|
||||
dump-manifests
|
||||
bootstrap-plan
|
||||
agents
|
||||
@@ -144,6 +145,8 @@ Top-level commands:
|
||||
init
|
||||
```
|
||||
|
||||
`claw acp` is a local discoverability surface for editor-first users: it reports the current ACP/Zed status without starting the runtime. As of April 16, 2026, claw-code does **not** ship an ACP/Zed daemon entrypoint yet, and `claw acp serve` is only a status alias until the real protocol surface lands.
|
||||
|
||||
The command surface is moving quickly. For the canonical live help text, run:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -95,6 +95,8 @@ const CLI_OPTION_SUGGESTIONS: &[&str] = &[
|
||||
"--allowedTools",
|
||||
"--allowed-tools",
|
||||
"--resume",
|
||||
"--acp",
|
||||
"-acp",
|
||||
"--print",
|
||||
"--compact",
|
||||
"--base-commit",
|
||||
@@ -248,6 +250,7 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
|
||||
cli.run_turn_with_output(&effective_prompt, output_format, compact)?;
|
||||
}
|
||||
CliAction::Doctor { output_format } => run_doctor(output_format)?,
|
||||
CliAction::Acp { output_format } => print_acp_status(output_format)?,
|
||||
CliAction::State { output_format } => run_worker_state(output_format)?,
|
||||
CliAction::Init { output_format } => run_init(output_format)?,
|
||||
CliAction::Export {
|
||||
@@ -337,6 +340,9 @@ enum CliAction {
|
||||
Doctor {
|
||||
output_format: CliOutputFormat,
|
||||
},
|
||||
Acp {
|
||||
output_format: CliOutputFormat,
|
||||
},
|
||||
State {
|
||||
output_format: CliOutputFormat,
|
||||
},
|
||||
@@ -368,6 +374,7 @@ enum LocalHelpTopic {
|
||||
Status,
|
||||
Sandbox,
|
||||
Doctor,
|
||||
Acp,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@@ -547,6 +554,10 @@ fn parse_args(args: &[String]) -> Result<CliAction, String> {
|
||||
rest.push(flag[9..].to_string());
|
||||
index += 1;
|
||||
}
|
||||
"--acp" | "-acp" => {
|
||||
rest.push("acp".to_string());
|
||||
index += 1;
|
||||
}
|
||||
"--allowedTools" | "--allowed-tools" => {
|
||||
let value = args
|
||||
.get(index + 1)
|
||||
@@ -661,6 +672,7 @@ fn parse_args(args: &[String]) -> Result<CliAction, String> {
|
||||
}
|
||||
}
|
||||
"system-prompt" => parse_system_prompt_args(&rest[1..], output_format),
|
||||
"acp" => parse_acp_args(&rest[1..], output_format),
|
||||
"login" | "logout" => Err(removed_auth_surface_error(rest[0].as_str())),
|
||||
"init" => Ok(CliAction::Init { output_format }),
|
||||
"export" => parse_export_args(&rest[1..], output_format),
|
||||
@@ -715,6 +727,7 @@ fn parse_local_help_action(rest: &[String]) -> Option<Result<CliAction, String>>
|
||||
"status" => LocalHelpTopic::Status,
|
||||
"sandbox" => LocalHelpTopic::Sandbox,
|
||||
"doctor" => LocalHelpTopic::Doctor,
|
||||
"acp" => LocalHelpTopic::Acp,
|
||||
_ => return None,
|
||||
};
|
||||
Some(Ok(CliAction::HelpTopic(topic)))
|
||||
@@ -785,6 +798,16 @@ fn removed_auth_surface_error(command_name: &str) -> String {
|
||||
)
|
||||
}
|
||||
|
||||
fn parse_acp_args(args: &[String], output_format: CliOutputFormat) -> Result<CliAction, String> {
|
||||
match args {
|
||||
[] => 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`.",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_resolve_bare_skill_prompt(cwd: &Path, trimmed: &str) -> Option<String> {
|
||||
let bare_first_token = trimmed.split_whitespace().next().unwrap_or_default();
|
||||
let looks_like_skill_name = !bare_first_token.is_empty()
|
||||
@@ -5175,6 +5198,13 @@ fn render_help_topic(topic: LocalHelpTopic) -> String {
|
||||
Output local-only health report; no provider request or session resume required
|
||||
Related /doctor · claw --resume latest /doctor"
|
||||
.to_string(),
|
||||
LocalHelpTopic::Acp => "ACP / Zed
|
||||
Usage claw acp [serve]
|
||||
Aliases claw --acp · claw -acp
|
||||
Purpose explain the current editor-facing ACP/Zed launch contract without starting the runtime
|
||||
Status discoverability only; `serve` is a status alias and does not launch a daemon yet
|
||||
Related ROADMAP #64a (discoverability) · ROADMAP #76 (real ACP support) · claw --help"
|
||||
.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5182,6 +5212,39 @@ fn print_help_topic(topic: LocalHelpTopic) {
|
||||
println!("{}", render_help_topic(topic));
|
||||
}
|
||||
|
||||
fn print_acp_status(output_format: CliOutputFormat) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let message = "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 or Zed-specific protocol endpoint. Use the normal terminal surfaces for now and track ROADMAP #76 for real ACP support.";
|
||||
match output_format {
|
||||
CliOutputFormat::Text => {
|
||||
println!(
|
||||
"ACP / Zed\n Status discoverability only\n Launch `claw acp serve` / `claw --acp` / `claw -acp` report status only; no editor daemon is available yet\n Today use `claw prompt`, the REPL, or `claw doctor` for local verification\n Tracking ROADMAP #76\n Message {message}"
|
||||
);
|
||||
}
|
||||
CliOutputFormat::Json => {
|
||||
println!(
|
||||
"{}",
|
||||
serde_json::to_string_pretty(&json!({
|
||||
"kind": "acp",
|
||||
"status": "discoverability_only",
|
||||
"supported": false,
|
||||
"serve_alias_only": true,
|
||||
"message": message,
|
||||
"launch_command": serde_json::Value::Null,
|
||||
"aliases": ["acp", "--acp", "-acp"],
|
||||
"discoverability_tracking": "ROADMAP #64a",
|
||||
"tracking": "ROADMAP #76",
|
||||
"recommended_workflows": [
|
||||
"claw prompt TEXT",
|
||||
"claw",
|
||||
"claw doctor"
|
||||
],
|
||||
}))?
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn render_config_report(section: Option<&str>) -> Result<String, Box<dyn std::error::Error>> {
|
||||
let cwd = env::current_dir()?;
|
||||
let loader = ConfigLoader::default_for(&cwd);
|
||||
@@ -8148,6 +8211,11 @@ fn print_help_to(out: &mut impl Write) -> io::Result<()> {
|
||||
out,
|
||||
" Diagnose local auth, config, workspace, and sandbox health"
|
||||
)?;
|
||||
writeln!(out, " claw acp [serve]")?;
|
||||
writeln!(
|
||||
out,
|
||||
" Show ACP/Zed editor integration status (currently unsupported; aliases: --acp, -acp)"
|
||||
)?;
|
||||
writeln!(out, " Source of truth: {OFFICIAL_REPO_SLUG}")?;
|
||||
writeln!(
|
||||
out,
|
||||
@@ -9200,6 +9268,34 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parses_acp_command_surfaces() {
|
||||
assert_eq!(
|
||||
parse_args(&["acp".to_string()]).expect("acp should parse"),
|
||||
CliAction::Acp {
|
||||
output_format: CliOutputFormat::Text,
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
parse_args(&["acp".to_string(), "serve".to_string()]).expect("acp serve should parse"),
|
||||
CliAction::Acp {
|
||||
output_format: CliOutputFormat::Text,
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
parse_args(&["--acp".to_string()]).expect("--acp should parse"),
|
||||
CliAction::Acp {
|
||||
output_format: CliOutputFormat::Text,
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
parse_args(&["-acp".to_string()]).expect("-acp should parse"),
|
||||
CliAction::Acp {
|
||||
output_format: CliOutputFormat::Text,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn local_command_help_flags_stay_on_the_local_parser_path() {
|
||||
assert_eq!(
|
||||
@@ -9217,6 +9313,10 @@ mod tests {
|
||||
.expect("doctor help should parse"),
|
||||
CliAction::HelpTopic(LocalHelpTopic::Doctor)
|
||||
);
|
||||
assert_eq!(
|
||||
parse_args(&["acp".to_string(), "--help".to_string()]).expect("acp help should parse"),
|
||||
CliAction::HelpTopic(LocalHelpTopic::Acp)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -10125,6 +10225,7 @@ mod tests {
|
||||
assert!(help.contains("claw status"));
|
||||
assert!(help.contains("claw sandbox"));
|
||||
assert!(help.contains("claw init"));
|
||||
assert!(help.contains("claw acp [serve]"));
|
||||
assert!(help.contains("claw agents"));
|
||||
assert!(help.contains("claw mcp"));
|
||||
assert!(help.contains("claw skills"));
|
||||
|
||||
@@ -46,6 +46,24 @@ fn status_and_sandbox_emit_json_when_requested() {
|
||||
assert!(sandbox["filesystem_mode"].as_str().is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
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"]);
|
||||
assert_eq!(acp["kind"], "acp");
|
||||
assert_eq!(acp["status"], "discoverability_only");
|
||||
assert_eq!(acp["supported"], false);
|
||||
assert_eq!(acp["serve_alias_only"], true);
|
||||
assert_eq!(acp["discoverability_tracking"], "ROADMAP #64a");
|
||||
assert_eq!(acp["tracking"], "ROADMAP #76");
|
||||
assert!(acp["message"]
|
||||
.as_str()
|
||||
.expect("acp message")
|
||||
.contains("discoverability alias"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inventory_commands_emit_structured_json_when_requested() {
|
||||
let root = unique_temp_dir("inventory-json");
|
||||
|
||||
Reference in New Issue
Block a user