From 7b63c0a2ebcb5a655f652025566ed34755206dbf Mon Sep 17 00:00:00 2001 From: bellman Date: Fri, 15 May 2026 11:40:53 +0900 Subject: [PATCH] omx(team): auto-checkpoint worker-1 [1] --- README.md | 2 +- docs/g011-acp-json-rpc-status-contract.md | 68 ++++++++++++++ rust/README.md | 2 +- rust/crates/rusty-claude-cli/src/main.rs | 108 +++++++++++++++++----- 4 files changed, 157 insertions(+), 23 deletions(-) create mode 100644 docs/g011-acp-json-rpc-status-contract.md diff --git a/README.md b/README.md index 88751958..9b6fe5d0 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ The canonical implementation lives in [`rust/`](./rust), and the current source > [!IMPORTANT] > Start with [`USAGE.md`](./USAGE.md) for build, auth, CLI, session, and parity-harness workflows. For file submission/navigation questions, see [Navigation and file context](./docs/navigation-file-context.md). For local OpenAI-compatible models and offline skill installs, see [Local OpenAI-compatible providers and skills setup](./docs/local-openai-compatible-providers.md). Windows users can jump to the PowerShell-first [Windows install and release quickstart](./docs/windows-install-release.md). Make `claw doctor` your first health check after building, use [`rust/README.md`](./rust/README.md) for crate-level details, read [`PARITY.md`](./PARITY.md) for the current Rust-port checkpoint, and see [`docs/container.md`](./docs/container.md) for the container-first workflow. > -> **ACP / Zed status:** `claw-code` does not ship an ACP/Zed daemon entrypoint yet. Run `claw acp` (or `claw --acp`) for the current status instead of guessing from source layout; `claw acp serve` is currently a discoverability alias only, and real ACP support remains tracked separately in `ROADMAP.md`. +> **ACP / Zed status:** `claw-code` does not ship an ACP/Zed daemon or JSON-RPC entrypoint yet. Run `claw acp` (or `claw --acp`) for the current status instead of guessing from source layout; `claw acp serve` is currently a discoverability alias only, returns status with exit code 0, and real ACP support remains tracked separately in `ROADMAP.md`. For the public JSON contract, see [`docs/g011-acp-json-rpc-status-contract.md`](./docs/g011-acp-json-rpc-status-contract.md). ## Current repository shape diff --git a/docs/g011-acp-json-rpc-status-contract.md b/docs/g011-acp-json-rpc-status-contract.md new file mode 100644 index 00000000..c2cd2ed2 --- /dev/null +++ b/docs/g011-acp-json-rpc-status-contract.md @@ -0,0 +1,68 @@ +# G011 ACP/Zed and JSON-RPC status contract + +Claw Code 2.0 keeps ACP/Zed and JSON-RPC serving behind the stable task, +session-control, and event/report contracts from the roadmap. The current public +surface is therefore a **truthful unsupported status**, not a hidden daemon. + +## Supported status queries + +The following commands are status queries and exit with code `0`: + +```bash +claw acp +claw acp serve +claw --acp +claw -acp +claw acp --output-format json +claw acp serve --output-format json +``` + +`serve` is deliberately an alias for status today. It does not bind a socket, +start a daemon, or expose a JSON-RPC endpoint. + +## JSON envelope + +`claw acp --output-format json` returns a stable envelope for editor probes and +CI checks: + +```json +{ + "schema_version": "1.0", + "kind": "acp", + "status": "unsupported", + "phase": "discoverability_only", + "supported": false, + "exit_code": 0, + "serve_alias_only": true, + "protocol": { + "name": "ACP/Zed", + "json_rpc": false, + "daemon": false, + "endpoint": null, + "serve_starts_daemon": false + } +} +``` + +Consumers should check `kind == "acp"`, `supported == false`, and +`protocol.json_rpc == false` instead of inferring support from command presence. + +## Unsupported invocations + +Malformed ACP invocations, such as `claw acp start`, exit with code `1`. With +`--output-format json`, stderr uses the normal CLI error envelope and sets: + +```json +{ + "type": "error", + "kind": "unsupported_acp_invocation", + "exit_code": 1 +} +``` + +## Deferral gate + +Real ACP/Zed or JSON-RPC serve work remains deferred until the roadmap contracts +for task packets, session control, and event/report schemas are stable. This +keeps desktop, marketplace, and editor integrations from becoming alternate +sources of truth before the CLI/file/API contracts are ready. diff --git a/rust/README.md b/rust/README.md index 804e5bc4..b8f6bcb9 100644 --- a/rust/README.md +++ b/rust/README.md @@ -145,7 +145,7 @@ 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. +`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 or JSON-RPC entrypoint yet, and `claw acp serve` is only a status alias until the real protocol surface lands. Status queries exit 0 and expose the same machine-readable contract via `--output-format json`; malformed ACP invocations exit 1 with `kind: unsupported_acp_invocation`. The command surface is moving quickly. For the canonical live help text, run: diff --git a/rust/crates/rusty-claude-cli/src/main.rs b/rust/crates/rusty-claude-cli/src/main.rs index 1bce8c01..cee89845 100644 --- a/rust/crates/rusty-claude-cli/src/main.rs +++ b/rust/crates/rusty-claude-cli/src/main.rs @@ -219,6 +219,7 @@ fn main() { "error": short_reason, "kind": kind, "hint": hint, + "exit_code": 1, }) ); } else { @@ -262,6 +263,8 @@ fn classify_error_kind(message: &str) -> &'static str { "session_load_failed" } else if message.contains("no managed sessions found") { "no_managed_sessions" + } else if message.contains("unsupported ACP invocation") { + "unsupported_acp_invocation" } else if message.contains("unrecognized argument") || message.contains("unknown option") { "cli_parse" } else if message.contains("invalid model syntax") { @@ -6916,34 +6919,58 @@ fn print_help_topic( Ok(()) } +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." +} + +fn acp_status_json() -> serde_json::Value { + json!({ + "schema_version": "1.0", + "kind": "acp", + "status": "unsupported", + "phase": "discoverability_only", + "supported": false, + "exit_code": 0, + "serve_alias_only": true, + "message": acp_status_message(), + "launch_command": serde_json::Value::Null, + "protocol": { + "name": "ACP/Zed", + "json_rpc": false, + "daemon": false, + "endpoint": serde_json::Value::Null, + "serve_starts_daemon": false + }, + "contracts": { + "blocking_gates": [ + "task_packet_schema", + "session_control_schema", + "event_report_schema" + ], + "stable_status_surface": "claw acp [serve] --output-format json", + "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" + ], + }) +} + fn print_acp_status(output_format: CliOutputFormat) -> Result<(), Box> { - 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}" + "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_status_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" - ], - }))? - ); + println!("{}", serde_json::to_string_pretty(&acp_status_json())?); } } Ok(()) @@ -11394,6 +11421,41 @@ mod tests { output_format: CliOutputFormat::Text, } ); + assert_eq!( + parse_args(&[ + "acp".to_string(), + "serve".to_string(), + "--output-format".to_string(), + "json".to_string() + ]) + .expect("acp serve json should parse"), + CliAction::Acp { + output_format: CliOutputFormat::Json, + } + ); + let unsupported = parse_args(&["acp".to_string(), "start".to_string()]) + .expect_err("unknown ACP subcommand should fail with a typed contract"); + assert!(unsupported.contains("unsupported ACP invocation")); + } + + #[test] + fn acp_status_json_is_truthful_unsupported_contract() { + 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["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); + assert!(value["protocol"]["endpoint"].is_null()); + assert_eq!( + value["contracts"]["unsupported_invocation_kind"], + "unsupported_acp_invocation" + ); } #[test] @@ -11892,6 +11954,10 @@ mod tests { classify_error_kind("unrecognized argument `--foo` for subcommand `doctor`"), "cli_parse" ); + assert_eq!( + classify_error_kind("unsupported ACP invocation. Use `claw acp`."), + "unsupported_acp_invocation" + ); assert_eq!( classify_error_kind("invalid model syntax: 'gpt-4'. Expected ..."), "invalid_model_syntax"