Files
tkmind_go/ui/goose2/acp-plus-migration-plan/09-delete-rust-acp-code.md
T
2026-04-16 07:34:19 +00:00

342 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Step 09: Delete the Rust ACP Middleware and Unused Dependencies
## Objective
Remove all Rust ACP protocol handling code that is no longer called by the frontend. This is the cleanup step — only do this after Steps 0108 are working and tested.
## Why
After Steps 0108, the frontend communicates directly with `goose serve` via WebSocket. The Rust ACP middleware (WebSocket bridge, session dispatcher, message writer, session registry, search) is dead code. Removing it:
- Eliminates ~3,500 lines of Rust
- Removes 56 heavy crate dependencies
- Reduces compile times
- Simplifies the codebase
## Changes
### 1. Delete the ACP manager subtree
**Delete these files entirely:**
```
src-tauri/src/services/acp/manager/
command_dispatch.rs
dispatcher.rs
dispatcher_tests.rs
session_ops.rs
session_ops/
prompt_ops.rs
tests.rs
thread.rs
```
**Delete these files:**
```
src-tauri/src/services/acp/manager.rs
src-tauri/src/services/acp/writer.rs
src-tauri/src/services/acp/payloads.rs
src-tauri/src/services/acp/registry.rs
src-tauri/src/services/acp/search.rs
```
### 2. Simplify `services/acp/mod.rs`
**File:** `src-tauri/src/services/acp/mod.rs`
Replace the entire file with:
```rust
pub(crate) mod goose_serve;
pub(crate) use goose_serve::GooseServeProcess;
```
All the old re-exports (`GooseAcpManager`, `AcpSessionRegistry`, `TauriMessageWriter`, `search_sessions_via_exports`, `make_composite_key`, `split_composite_key`, `AcpService`, `AcpRunningSession`, `AcpSessionInfo`, `SessionSearchResult`) are removed.
### 3. Simplify `commands/acp.rs`
**File:** `src-tauri/src/commands/acp.rs`
Replace the entire file with just the URL command:
```rust
use crate::services::acp::GooseServeProcess;
/// Return the WebSocket URL of the running goose serve process.
///
/// This command blocks until the server is confirmed ready. The frontend
/// uses this URL to establish a direct WebSocket ACP connection.
#[tauri::command]
pub async fn get_goose_serve_url() -> Result<String, String> {
GooseServeProcess::start().await?;
let process = GooseServeProcess::get()?;
Ok(process.ws_url())
}
```
All other ACP commands are deleted:
- `discover_acp_providers`
- `acp_prepare_session`
- `acp_set_model`
- `acp_send_message`
- `acp_cancel_session`
- `acp_list_sessions`
- `acp_search_sessions`
- `acp_load_session`
- `acp_list_running`
- `acp_cancel_all`
- `acp_export_session`
- `acp_import_session`
- `acp_duplicate_session`
Also delete the helper functions that were only used by those commands:
- `AcpProviderResponse` struct
- `should_include_provider`
- `default_artifacts_working_dir`
- `expand_home_dir`
- `resolve_working_dir`
- The `#[cfg(test)] mod tests` block
### 4. Update `lib.rs`
**File:** `src-tauri/src/lib.rs`
Remove the `AcpSessionRegistry` from managed state and remove all old ACP command registrations.
**Before:**
```rust
use std::sync::Arc;
use services::acp::AcpSessionRegistry;
// ...
let acp_registry = Arc::new(AcpSessionRegistry::new());
let acp_registry_for_exit = Arc::clone(&acp_registry);
let builder = tauri::Builder::default()
// ...
.manage(acp_registry);
// In invoke_handler:
commands::acp::discover_acp_providers,
commands::acp::acp_prepare_session,
commands::acp::acp_set_model,
commands::acp::acp_send_message,
commands::acp::acp_cancel_session,
commands::acp::acp_list_sessions,
commands::acp::acp_search_sessions,
commands::acp::acp_load_session,
commands::acp::acp_list_running,
commands::acp::acp_cancel_all,
commands::acp::acp_export_session,
commands::acp::acp_import_session,
commands::acp::acp_duplicate_session,
// In run closure:
.run(move |_app, event| {
if let tauri::RunEvent::Exit = event {
acp_registry_for_exit.cancel_all();
}
});
```
**After:**
```rust
// Remove: use std::sync::Arc;
// Remove: use services::acp::AcpSessionRegistry;
// Remove: let acp_registry = ...
// Remove: let acp_registry_for_exit = ...
let builder = tauri::Builder::default()
// ...
// Remove: .manage(acp_registry)
;
// In invoke_handler, replace all old ACP commands with just:
commands::acp::get_goose_serve_url,
// Simplify the run closure:
.run(|_app, _event| {});
```
The `Arc` import can be removed — `PersonaStore` and `GooseConfig` use `tauri::State` which handles the wrapping.
### 5. Clean up `goose_serve.rs`
**File:** `src-tauri/src/services/acp/goose_serve.rs`
1. Remove the `WS_BRIDGE_BUFFER_BYTES` constant (only used by the deleted `thread.rs`):
```rust
// DELETE:
pub(crate) const WS_BRIDGE_BUFFER_BYTES: usize = 64 * 1024;
```
2. Keep `resolve_goose_binary` exported as `pub(crate)` — it is still needed by `model_setup.rs` (which runs `goose configure`).
3. Replace the WebSocket readiness probe with a TCP connect check. This eliminates the `tokio-tungstenite` and `futures` dependencies:
```rust
async fn wait_for_server_ready(port: u16, child: &mut Child) -> Result<(), String> {
let deadline = Instant::now() + GOOSE_SERVE_CONNECT_TIMEOUT;
let addr = format!("{LOCALHOST}:{port}");
loop {
match tokio::net::TcpStream::connect(&addr).await {
Ok(_) => return Ok(()),
Err(_) => {
if let Some(status) = child
.try_wait()
.map_err(|e| format!("Failed to poll goose serve process: {e}"))?
{
return Err(format!(
"Goose serve exited before becoming ready: {status}"
));
}
if Instant::now() >= deadline {
return Err(format!(
"Timed out waiting for goose serve on port {port}"
));
}
tokio::time::sleep(GOOSE_SERVE_CONNECT_RETRY_DELAY).await;
}
}
}
}
```
Update the `spawn` method to call `wait_for_server_ready(port, &mut child)` instead of `wait_for_server_ready(&ws_url, &mut child)`.
### 6. Handle `acp-client` binary discovery
The `acp-client` crate is used by `goose_serve.rs` for `acp_client::find_acp_agent_by_id("goose")` in binary resolution. Two options:
- **Option A (simplest):** Keep `acp-client` solely for binary discovery. It only uses the `find_acp_agent_by_id` function.
- **Option B:** Inline the discovery logic — look for `goose` on PATH and check the `GOOSE_BIN` env var. The `GOOSE_BIN` path is already handled; the `find_acp_agent_by_id` fallback scans the login shell PATH, which can be replaced with a simple `which goose` equivalent.
Choose one approach and apply it consistently.
### 7. Remove unused Cargo dependencies
**File:** `src-tauri/Cargo.toml`
Remove these dependencies:
```toml
agent-client-protocol = { version = "0.10.4", features = ["unstable_session_fork"] }
tokio-tungstenite = "0.21.0"
async-trait = "0.1"
futures = "0.3"
tokio-util = { version = "0.7", features = ["compat", "rt"] }
```
If Option A from §6 is chosen, keep `acp-client`. If Option B is chosen, also remove:
```toml
acp-client = { git = "https://github.com/block/builderbot", rev = "db184d20cb48e0c90bbd3fea4a4a871fc9d8a6ad" }
```
After all removals, the remaining dependencies should be:
```toml
[dependencies]
tauri = { version = "2", features = ["protocol-asset"] }
tauri-plugin-app-test-driver = { path = "plugins/app-test-driver" }
tauri-plugin-opener = "2"
tauri-plugin-dialog = ">=2,<2.7"
tauri-plugin-window-state = "2"
tauri-plugin-log = "2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
dirs = "6.0.0"
log = "0.4.29"
tokio = { version = "1.50.0", features = ["full"] }
uuid = { version = "1", features = ["v4", "serde"] }
chrono = { version = "0.4", features = ["serde"] }
serde_yaml = "0.9"
etcetera = "0.8"
ignore = "0.4.25"
doctor = { git = "https://github.com/block/builderbot", rev = "8e1c3ec145edc0df5f04b4427cfd758378036862" }
keyring = { ... } # platform-specific
```
Run `cargo check` after editing `Cargo.toml` to verify nothing breaks.
### 8. Run full verification
```bash
cd ui/goose2/src-tauri
cargo fmt
cargo check
cargo clippy --all-targets -- -D warnings
cargo test
```
Then from the `ui/goose2` directory:
```bash
source ./bin/activate-hermit
just check
just test
just tauri-check
```
## Summary of Deletions
| Path | Lines | Purpose (was) |
|------|-------|---------------|
| `services/acp/manager/command_dispatch.rs` | ~258 | Command dispatch loop |
| `services/acp/manager/dispatcher.rs` | ~532 | Session event dispatcher + Client trait impl |
| `services/acp/manager/dispatcher_tests.rs` | ~28 | Dispatcher tests |
| `services/acp/manager/session_ops.rs` | ~611 | Session prepare/load/cancel/set-model |
| `services/acp/manager/session_ops/prompt_ops.rs` | ~(inline) | Send prompt logic |
| `services/acp/manager/session_ops/tests.rs` | ~(inline) | Session ops tests |
| `services/acp/manager/thread.rs` | ~169 | Manager thread + WebSocket bridge |
| `services/acp/manager.rs` | ~308 | GooseAcpManager struct + ManagerCommand enum |
| `services/acp/writer.rs` | ~156 | TauriMessageWriter |
| `services/acp/payloads.rs` | ~106 | Tauri event payload structs |
| `services/acp/registry.rs` | ~114 | AcpSessionRegistry |
| `services/acp/search.rs` | ~467 | Session content search |
| **Total** | **~2,749** | |
Plus significant simplification of `commands/acp.rs` (~330 → ~15 lines), `services/acp/mod.rs` (~147 → ~4 lines), and `lib.rs` (~114 → ~80 lines).
## Cargo Dependencies Removed
| Crate | Why it was needed |
|-------|-------------------|
| `agent-client-protocol` | Rust ACP client types (Agent, ClientSideConnection, etc.) |
| `acp-client` | Agent discovery, MessageWriter trait (kept if using Option A for binary discovery) |
| `tokio-tungstenite` | WebSocket connection to goose serve |
| `async-trait` | MessageWriter + Client trait impls |
| `futures` | WebSocket stream splitting (SinkExt, StreamExt) |
| `tokio-util` | Compat adapters for async read/write |
## Files Modified
| File | Change |
|------|--------|
| `src-tauri/src/services/acp/mod.rs` | Simplified to just goose_serve re-export |
| `src-tauri/src/services/acp/goose_serve.rs` | Remove `WS_BRIDGE_BUFFER_BYTES` constant, replace readiness probe with TCP connect |
| `src-tauri/src/commands/acp.rs` | Replaced with single `get_goose_serve_url` command |
| `src-tauri/src/lib.rs` | Remove AcpSessionRegistry, old ACP commands, simplify run closure |
| `src-tauri/Cargo.toml` | Remove 56 dependencies |
| `src-tauri/Cargo.lock` | Auto-updated |
## Files Deleted
All files listed in the "Summary of Deletions" table above.
## Dependencies
- Steps 0108 must be working and tested before this cleanup step.
## Notes
- Run `cargo check` after each deletion batch to catch remaining references.
- The `doctor` crate dependency stays — it's used by `commands/doctor.rs` which is not part of this migration.