diff --git a/README-old.md b/README-old.md
deleted file mode 100644
index 0b090077..00000000
--- a/README-old.md
+++ /dev/null
@@ -1,210 +0,0 @@
-# Claw Code
-
-
- ultraworkers/claw-code
- ·
- Usage
- ·
- Rust workspace
- ·
- Parity
- ·
- Roadmap
- ·
- UltraWorkers Discord
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Claw Code is the public Rust implementation of the `claw` CLI agent harness.
-The canonical implementation lives in [`rust/`](./rust), and the current source of truth for this repository is **ultraworkers/claw-code**.
-
-> [!IMPORTANT]
-> Start with [`USAGE.md`](./USAGE.md) for build, auth, CLI, session, and parity-harness workflows. 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`.
-
-## Current repository shape
-
-- **`rust/`** — canonical Rust workspace and the `claw` CLI binary
-- **`USAGE.md`** — task-oriented usage guide for the current product surface
-- **`PARITY.md`** — Rust-port parity status and migration notes
-- **`ROADMAP.md`** — active roadmap and cleanup backlog
-- **`PHILOSOPHY.md`** — project intent and system-design framing
-- **`src/` + `tests/`** — companion Python/reference workspace and audit helpers; not the primary runtime surface
-
-## Quick start
-
-> [!NOTE]
-> [!WARNING]
-> **`cargo install claw-code` installs the wrong thing.** The `claw-code` crate on crates.io is a deprecated stub that places `claw-code-deprecated.exe` — not `claw`. Running it only prints `"claw-code has been renamed to agent-code"`. **Do not use `cargo install claw-code`.** Either build from source (this repo) or install the upstream binary:
-> ```bash
-> cargo install agent-code # upstream binary — installs 'agent.exe' (Windows) / 'agent' (Unix), NOT 'agent-code'
-> ```
-> This repo (`ultraworkers/claw-code`) is **build-from-source only** — follow the steps below.
-
-```bash
-# 1. Clone and build
-git clone https://github.com/ultraworkers/claw-code
-cd claw-code/rust
-cargo build --workspace
-
-# 2. Set your API key (Anthropic API key — not a Claude subscription)
-export ANTHROPIC_API_KEY="sk-ant-..."
-
-# 3. Verify everything is wired correctly
-./target/debug/claw doctor
-
-# 4. Run a prompt
-./target/debug/claw prompt "say hello"
-```
-
-> [!NOTE]
-> **Windows (PowerShell):** the binary is `claw.exe`, not `claw`. Use `.\target\debug\claw.exe` or run `cargo run -- prompt "say hello"` to skip the path lookup.
-
-### Windows setup
-
-**PowerShell is a supported Windows path.** Use whichever shell works for you. The common onboarding issues on Windows are:
-
-1. **Install Rust first** — download from and run the installer. Close and reopen your terminal when it finishes.
-2. **Verify Rust is on PATH:**
- ```powershell
- cargo --version
- ```
- If this fails, reopen your terminal or run the PATH setup from the Rust installer output, then retry.
-3. **Clone and build** (works in PowerShell, Git Bash, or WSL):
- ```powershell
- git clone https://github.com/ultraworkers/claw-code
- cd claw-code/rust
- cargo build --workspace
- ```
-4. **Run** (PowerShell — note `.exe` and backslash):
- ```powershell
- $env:ANTHROPIC_API_KEY = "sk-ant-..."
- .\target\debug\claw.exe prompt "say hello"
- ```
-
-**Git Bash / WSL** are optional alternatives, not requirements. If you prefer bash-style paths (`/c/Users/you/...` instead of `C:\Users\you\...`), Git Bash (ships with Git for Windows) works well. In Git Bash, the `MINGW64` prompt is expected and normal — not a broken install.
-
-## Post-build: locate the binary and verify
-
-After running `cargo build --workspace`, the `claw` binary is built but **not** automatically installed to your system. Here's where to find it and how to verify the build succeeded.
-
-### Binary location
-
-After `cargo build --workspace` in `claw-code/rust/`:
-
-**Debug build (default, faster compile):**
-- **macOS/Linux:** `rust/target/debug/claw`
-- **Windows:** `rust/target/debug/claw.exe`
-
-**Release build (optimized, slower compile):**
-- **macOS/Linux:** `rust/target/release/claw`
-- **Windows:** `rust/target/release/claw.exe`
-
-If you ran `cargo build` without `--release`, the binary is in the `debug/` folder.
-
-### Verify the build succeeded
-
-Test the binary directly using its path:
-
-```bash
-# macOS/Linux (debug build)
-./rust/target/debug/claw --help
-./rust/target/debug/claw doctor
-
-# Windows PowerShell (debug build)
-.\rust\target\debug\claw.exe --help
-.\rust\target\debug\claw.exe doctor
-```
-
-If these commands succeed, the build is working. `claw doctor` is your first health check — it validates your API key, model access, and tool configuration.
-
-### Optional: Add to PATH
-
-If you want to run `claw` from any directory without the full path, choose one of these approaches:
-
-**Option 1: Symlink (macOS/Linux)**
-```bash
-ln -s $(pwd)/rust/target/debug/claw /usr/local/bin/claw
-```
-Then reload your shell and test:
-```bash
-claw --help
-```
-
-**Option 2: Use `cargo install` (all platforms)**
-
-Build and install to Cargo's default location (`~/.cargo/bin/`, which is usually on PATH):
-```bash
-# From the claw-code/rust/ directory
-cargo install --path . --force
-
-# Then from anywhere
-claw --help
-```
-
-**Option 3: Update shell profile (bash/zsh)**
-
-Add this line to `~/.bashrc` or `~/.zshrc`:
-```bash
-export PATH="$(pwd)/rust/target/debug:$PATH"
-```
-
-Reload your shell:
-```bash
-source ~/.bashrc # or source ~/.zshrc
-claw --help
-```
-
-### Troubleshooting
-
-- **"command not found: claw"** — The binary is in `rust/target/debug/claw`, but it's not on your PATH. Use the full path `./rust/target/debug/claw` or symlink/install as above.
-- **"permission denied"** — On macOS/Linux, you may need `chmod +x rust/target/debug/claw` if the executable bit isn't set (rare).
-- **Debug vs. release** — If the build is slow, you're in debug mode (default). Add `--release` to `cargo build` for faster runtime, but the build itself will take 5–10 minutes.
-
-> [!NOTE]
-> **Auth:** claw requires an **API key** (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, etc.) — Claude subscription login is not a supported auth path.
-
-Run the workspace test suite after verifying the binary works:
-
-```bash
-cd rust
-cargo test --workspace
-```
-
-## Documentation map
-
-- [`USAGE.md`](./USAGE.md) — quick commands, auth, sessions, config, parity harness
-- [`rust/README.md`](./rust/README.md) — crate map, CLI surface, features, workspace layout
-- [`PARITY.md`](./PARITY.md) — parity status for the Rust port
-- [`rust/MOCK_PARITY_HARNESS.md`](./rust/MOCK_PARITY_HARNESS.md) — deterministic mock-service harness details
-- [`ROADMAP.md`](./ROADMAP.md) — active roadmap and open cleanup work
-- [`PHILOSOPHY.md`](./PHILOSOPHY.md) — why the project exists and how it is operated
-
-## Ecosystem
-
-Claw Code is built in the open alongside the broader UltraWorkers toolchain:
-
-- [clawhip](https://github.com/Yeachan-Heo/clawhip)
-- [oh-my-openagent](https://github.com/code-yeongyu/oh-my-openagent)
-- [oh-my-claudecode](https://github.com/Yeachan-Heo/oh-my-claudecode)
-- [oh-my-codex](https://github.com/Yeachan-Heo/oh-my-codex)
-- [UltraWorkers Discord](https://discord.gg/5TUQKqFWd)
-
-## Ownership / affiliation disclaimer
-
-- This repository does **not** claim ownership of the original Claude Code source material.
-- This repository is **not affiliated with, endorsed by, or maintained by Anthropic**.
diff --git a/add_imports.py b/add_imports.py
deleted file mode 100644
index d6ad39f5..00000000
--- a/add_imports.py
+++ /dev/null
@@ -1,39 +0,0 @@
-import os
-
-files = [
- 'rust/crates/rusty-claude-cli/src/execution/client.rs',
- 'rust/crates/rusty-claude-cli/src/execution/stream.rs',
- 'rust/crates/rusty-claude-cli/src/execution/executor.rs'
-]
-
-imports = """
-use crate::*;
-use api::*;
-use runtime::*;
-use std::io::{self, Write};
-use std::sync::{Arc, Mutex};
-use std::path::Path;
-"""
-
-for file in files:
- with open(file, 'r') as f:
- content = f.read()
- with open(file, 'w') as f:
- f.write(imports + "\n" + content)
-
-main_file = "rust/crates/rusty-claude-cli/src/main.rs"
-with open(main_file, 'r') as f:
- main_content = f.read()
-
-main_imports = """
-use crate::execution::client::*;
-use crate::execution::stream::*;
-use crate::execution::executor::*;
-"""
-# inject right after mod declarations
-main_content = main_content.replace("pub(crate) mod ui;\n", "pub(crate) mod ui;\n" + main_imports)
-
-with open(main_file, 'w') as f:
- f.write(main_content)
-
-print("Imports added.")
diff --git a/anthropic_full.rs b/anthropic_full.rs
deleted file mode 100644
index c307a0d1..00000000
--- a/anthropic_full.rs
+++ /dev/null
@@ -1,255 +0,0 @@
-pub(crate) struct AnthropicRuntimeClient {
- runtime: tokio::runtime::Runtime,
- client: ApiProviderClient,
- session_id: String,
- model: String,
- enable_tools: bool,
- emit_output: bool,
- allowed_tools: Option,
- tool_registry: GlobalToolRegistry,
- progress_reporter: Option,
- reasoning_effort: Option,
-}
-impl AnthropicRuntimeClient {
- pub(crate) fn new(
- session_id: &str,
- model: String,
- enable_tools: bool,
- emit_output: bool,
- allowed_tools: Option,
- tool_registry: GlobalToolRegistry,
- progress_reporter: Option,
- ) -> Result> {
- // Dispatch to the correct provider at construction time.
- // `ApiProviderClient` (exposed by the api crate as
- // `ProviderClient`) is an enum over Anthropic / xAI / OpenAI
- // variants, where xAI and OpenAI both use the OpenAI-compat
- // wire format under the hood. We consult
- // `detect_provider_kind(&resolved_model)` so model-name prefix
- // routing (`openai/`, `gpt-`, `grok`, `qwen/`) wins over
- // env-var presence.
- //
- // For Anthropic we build the client directly instead of going
- // through `ApiProviderClient::from_model_with_anthropic_auth`
- // so we can explicitly apply `api::read_base_url()` — that
- // reads `ANTHROPIC_BASE_URL` and is required for the local
- // mock-server test harness
- // (`crates/rusty-claude-cli/tests/compact_output.rs`) to point
- // claw at its fake Anthropic endpoint. We also attach a
- // session-scoped prompt cache on the Anthropic path; the
- // prompt cache is Anthropic-only so non-Anthropic variants
- // skip it.
- let resolved_model = api::resolve_model_alias(&model);
- let client = match detect_provider_kind(&resolved_model) {
- ProviderKind::Anthropic => {
- let auth = resolve_cli_auth_source()?;
- let inner = AnthropicClient::from_auth(auth)
- .with_base_url(api::read_base_url())
- .with_prompt_cache(PromptCache::new(session_id));
- ApiProviderClient::Anthropic(inner)
- }
- ProviderKind::Xai | ProviderKind::OpenAi => {
- // The api crate's `ProviderClient::from_model_with_anthropic_auth`
- // with `None` for the anthropic auth routes via
- // `detect_provider_kind` and builds an
- // `OpenAiCompatClient::from_env` with the matching
- // `OpenAiCompatConfig` (openai / xai / dashscope).
- // That reads the correct API-key env var and BASE_URL
- // override internally, so this one call covers OpenAI,
- // OpenRouter, xAI, DashScope, Ollama, and any other
- // OpenAI-compat endpoint users configure via
- // `OPENAI_BASE_URL` / `XAI_BASE_URL` / `DASHSCOPE_BASE_URL`.
- ApiProviderClient::from_model_with_anthropic_auth(&resolved_model, None)?
- }
- };
- Ok(Self {
- runtime: tokio::runtime::Runtime::new()?,
- client,
- session_id: session_id.to_string(),
- model,
- enable_tools,
- emit_output,
- allowed_tools,
- tool_registry,
- progress_reporter,
- reasoning_effort: None,
- })
- }
-
- pub(crate) fn set_reasoning_effort(&mut self, effort: Option) {
- self.reasoning_effort = effort;
- }
-}
-impl AnthropicRuntimeClient {
- /// Consume a single streaming response, optionally applying a stall
- /// timeout on the first event for post-tool continuations.
- #[allow(clippy::too_many_lines)]
- pub(crate) async fn consume_stream(
- &self,
- message_request: &MessageRequest,
- apply_stall_timeout: bool,
- ) -> Result, RuntimeError> {
- let mut stream = self
- .client
- .stream_message(message_request)
- .await
- .map_err(|error| {
- RuntimeError::new(format_user_visible_api_error(&self.session_id, &error))
- })?;
- let mut stdout = io::stdout();
- let mut sink = io::sink();
- let out: &mut dyn Write = if self.emit_output {
- &mut stdout
- } else {
- &mut sink
- };
- let renderer = TerminalRenderer::new();
- let mut markdown_stream = MarkdownStreamState::default();
- let mut events = Vec::new();
- let mut pending_tool: Option<(String, String, String)> = None;
- let mut block_has_thinking_summary = false;
- let mut saw_stop = false;
- let mut received_any_event = false;
-
- loop {
- let next = if apply_stall_timeout && !received_any_event {
- match tokio::time::timeout(POST_TOOL_STALL_TIMEOUT, stream.next_event()).await {
- Ok(inner) => inner.map_err(|error| {
- RuntimeError::new(format_user_visible_api_error(&self.session_id, &error))
- })?,
- Err(_elapsed) => {
- return Err(RuntimeError::new(
- "post-tool stall: model did not respond within timeout",
- ));
- }
- }
- } else {
- stream.next_event().await.map_err(|error| {
- RuntimeError::new(format_user_visible_api_error(&self.session_id, &error))
- })?
- };
-
- let Some(event) = next else {
- break;
- };
- received_any_event = true;
-
- match event {
- ApiStreamEvent::MessageStart(start) => {
- for block in start.message.content {
- push_output_block(
- block,
- out,
- &mut events,
- &mut pending_tool,
- true,
- &mut block_has_thinking_summary,
- )?;
- }
- }
- ApiStreamEvent::ContentBlockStart(start) => {
- push_output_block(
- start.content_block,
- out,
- &mut events,
- &mut pending_tool,
- true,
- &mut block_has_thinking_summary,
- )?;
- }
- ApiStreamEvent::ContentBlockDelta(delta) => match delta.delta {
- ContentBlockDelta::TextDelta { text } => {
- if !text.is_empty() {
- if let Some(progress_reporter) = &self.progress_reporter {
- progress_reporter.mark_text_phase(&text);
- }
- if let Some(rendered) = markdown_stream.push(&renderer, &text) {
- write!(out, "{rendered}")
- .and_then(|()| out.flush())
- .map_err(|error| RuntimeError::new(error.to_string()))?;
- }
- events.push(AssistantEvent::TextDelta(text));
- }
- }
- ContentBlockDelta::InputJsonDelta { partial_json } => {
- if let Some((_, _, input)) = &mut pending_tool {
- input.push_str(&partial_json);
- }
- }
- ContentBlockDelta::ThinkingDelta { thinking } => {
- if !block_has_thinking_summary {
- render_thinking_block_summary(out, None, false)?;
- block_has_thinking_summary = true;
- }
- events.push(AssistantEvent::ThinkingDelta(thinking));
- }
- ContentBlockDelta::SignatureDelta { signature } => {
- events.push(AssistantEvent::SignatureDelta(signature));
- }
- },
- ApiStreamEvent::ContentBlockStop(_) => {
- block_has_thinking_summary = false;
- if let Some(rendered) = markdown_stream.flush(&renderer) {
- write!(out, "{rendered}")
- .and_then(|()| out.flush())
- .map_err(|error| RuntimeError::new(error.to_string()))?;
- }
- if let Some((id, name, input)) = pending_tool.take() {
- if let Some(progress_reporter) = &self.progress_reporter {
- progress_reporter.mark_tool_phase(&name, &input);
- }
- // Display tool call now that input is fully accumulated
- writeln!(out, "\n{}", format_tool_call_start(&name, &input))
- .and_then(|()| out.flush())
- .map_err(|error| RuntimeError::new(error.to_string()))?;
- events.push(AssistantEvent::ToolUse { id, name, input });
- }
- }
- ApiStreamEvent::MessageDelta(delta) => {
- events.push(AssistantEvent::Usage(delta.usage.token_usage()));
- }
- ApiStreamEvent::MessageStop(_) => {
- saw_stop = true;
- if let Some(rendered) = markdown_stream.flush(&renderer) {
- write!(out, "{rendered}")
- .and_then(|()| out.flush())
- .map_err(|error| RuntimeError::new(error.to_string()))?;
- }
- events.push(AssistantEvent::MessageStop);
- }
- }
- }
-
- push_prompt_cache_record(&self.client, &mut events);
-
- if !saw_stop
- && events.iter().any(|event| {
- matches!(event, AssistantEvent::TextDelta(text) if !text.is_empty())
- || matches!(event, AssistantEvent::ToolUse { .. })
- })
- {
- events.push(AssistantEvent::MessageStop);
- }
-
- if events
- .iter()
- .any(|event| matches!(event, AssistantEvent::MessageStop))
- {
- return Ok(events);
- }
-
- let response = self
- .client
- .send_message(&MessageRequest {
- stream: false,
- ..message_request.clone()
- })
- .await
- .map_err(|error| {
- RuntimeError::new(format_user_visible_api_error(&self.session_id, &error))
- })?;
- let mut events = response_to_events(response, out)?;
- push_prompt_cache_record(&self.client, &mut events);
- Ok(events)
- }
-}
diff --git a/anthropic_impl.rs b/anthropic_impl.rs
deleted file mode 100644
index ed5d01fb..00000000
--- a/anthropic_impl.rs
+++ /dev/null
@@ -1,243 +0,0 @@
-impl AnthropicRuntimeClient {
- fn new(
- session_id: &str,
- model: String,
- enable_tools: bool,
- emit_output: bool,
- allowed_tools: Option,
- tool_registry: GlobalToolRegistry,
- progress_reporter: Option,
- ) -> Result> {
- // Dispatch to the correct provider at construction time.
- // `ApiProviderClient` (exposed by the api crate as
- // `ProviderClient`) is an enum over Anthropic / xAI / OpenAI
- // variants, where xAI and OpenAI both use the OpenAI-compat
- // wire format under the hood. We consult
- // `detect_provider_kind(&resolved_model)` so model-name prefix
- // routing (`openai/`, `gpt-`, `grok`, `qwen/`) wins over
- // env-var presence.
- //
- // For Anthropic we build the client directly instead of going
- // through `ApiProviderClient::from_model_with_anthropic_auth`
- // so we can explicitly apply `api::read_base_url()` — that
- // reads `ANTHROPIC_BASE_URL` and is required for the local
- // mock-server test harness
- // (`crates/rusty-claude-cli/tests/compact_output.rs`) to point
- // claw at its fake Anthropic endpoint. We also attach a
- // session-scoped prompt cache on the Anthropic path; the
- // prompt cache is Anthropic-only so non-Anthropic variants
- // skip it.
- let resolved_model = api::resolve_model_alias(&model);
- let client = match detect_provider_kind(&resolved_model) {
- ProviderKind::Anthropic => {
- let auth = resolve_cli_auth_source()?;
- let inner = AnthropicClient::from_auth(auth)
- .with_base_url(api::read_base_url())
- .with_prompt_cache(PromptCache::new(session_id));
- ApiProviderClient::Anthropic(inner)
- }
- ProviderKind::Xai | ProviderKind::OpenAi => {
- // The api crate's `ProviderClient::from_model_with_anthropic_auth`
- // with `None` for the anthropic auth routes via
- // `detect_provider_kind` and builds an
- // `OpenAiCompatClient::from_env` with the matching
- // `OpenAiCompatConfig` (openai / xai / dashscope).
- // That reads the correct API-key env var and BASE_URL
- // override internally, so this one call covers OpenAI,
- // OpenRouter, xAI, DashScope, Ollama, and any other
- // OpenAI-compat endpoint users configure via
- // `OPENAI_BASE_URL` / `XAI_BASE_URL` / `DASHSCOPE_BASE_URL`.
- ApiProviderClient::from_model_with_anthropic_auth(&resolved_model, None)?
- }
- };
- Ok(Self {
- runtime: tokio::runtime::Runtime::new()?,
- client,
- session_id: session_id.to_string(),
- model,
- enable_tools,
- emit_output,
- allowed_tools,
- tool_registry,
- progress_reporter,
- reasoning_effort: None,
- })
- }
-
- fn set_reasoning_effort(&mut self, effort: Option) {
- self.reasoning_effort = effort;
- }
-}
-impl AnthropicRuntimeClient {
- /// Consume a single streaming response, optionally applying a stall
- /// timeout on the first event for post-tool continuations.
- #[allow(clippy::too_many_lines)]
- async fn consume_stream(
- &self,
- message_request: &MessageRequest,
- apply_stall_timeout: bool,
- ) -> Result, RuntimeError> {
- let mut stream = self
- .client
- .stream_message(message_request)
- .await
- .map_err(|error| {
- RuntimeError::new(format_user_visible_api_error(&self.session_id, &error))
- })?;
- let mut stdout = io::stdout();
- let mut sink = io::sink();
- let out: &mut dyn Write = if self.emit_output {
- &mut stdout
- } else {
- &mut sink
- };
- let renderer = TerminalRenderer::new();
- let mut markdown_stream = MarkdownStreamState::default();
- let mut events = Vec::new();
- let mut pending_tool: Option<(String, String, String)> = None;
- let mut block_has_thinking_summary = false;
- let mut saw_stop = false;
- let mut received_any_event = false;
-
- loop {
- let next = if apply_stall_timeout && !received_any_event {
- match tokio::time::timeout(POST_TOOL_STALL_TIMEOUT, stream.next_event()).await {
- Ok(inner) => inner.map_err(|error| {
- RuntimeError::new(format_user_visible_api_error(&self.session_id, &error))
- })?,
- Err(_elapsed) => {
- return Err(RuntimeError::new(
- "post-tool stall: model did not respond within timeout",
- ));
- }
- }
- } else {
- stream.next_event().await.map_err(|error| {
- RuntimeError::new(format_user_visible_api_error(&self.session_id, &error))
- })?
- };
-
- let Some(event) = next else {
- break;
- };
- received_any_event = true;
-
- match event {
- ApiStreamEvent::MessageStart(start) => {
- for block in start.message.content {
- push_output_block(
- block,
- out,
- &mut events,
- &mut pending_tool,
- true,
- &mut block_has_thinking_summary,
- )?;
- }
- }
- ApiStreamEvent::ContentBlockStart(start) => {
- push_output_block(
- start.content_block,
- out,
- &mut events,
- &mut pending_tool,
- true,
- &mut block_has_thinking_summary,
- )?;
- }
- ApiStreamEvent::ContentBlockDelta(delta) => match delta.delta {
- ContentBlockDelta::TextDelta { text } => {
- if !text.is_empty() {
- if let Some(progress_reporter) = &self.progress_reporter {
- progress_reporter.mark_text_phase(&text);
- }
- if let Some(rendered) = markdown_stream.push(&renderer, &text) {
- write!(out, "{rendered}")
- .and_then(|()| out.flush())
- .map_err(|error| RuntimeError::new(error.to_string()))?;
- }
- events.push(AssistantEvent::TextDelta(text));
- }
- }
- ContentBlockDelta::InputJsonDelta { partial_json } => {
- if let Some((_, _, input)) = &mut pending_tool {
- input.push_str(&partial_json);
- }
- }
- ContentBlockDelta::ThinkingDelta { thinking } => {
- if !block_has_thinking_summary {
- render_thinking_block_summary(out, None, false)?;
- block_has_thinking_summary = true;
- }
- events.push(AssistantEvent::ThinkingDelta(thinking));
- }
- ContentBlockDelta::SignatureDelta { signature } => {
- events.push(AssistantEvent::SignatureDelta(signature));
- }
- },
- ApiStreamEvent::ContentBlockStop(_) => {
- block_has_thinking_summary = false;
- if let Some(rendered) = markdown_stream.flush(&renderer) {
- write!(out, "{rendered}")
- .and_then(|()| out.flush())
- .map_err(|error| RuntimeError::new(error.to_string()))?;
- }
- if let Some((id, name, input)) = pending_tool.take() {
- if let Some(progress_reporter) = &self.progress_reporter {
- progress_reporter.mark_tool_phase(&name, &input);
- }
- // Display tool call now that input is fully accumulated
- writeln!(out, "\n{}", format_tool_call_start(&name, &input))
- .and_then(|()| out.flush())
- .map_err(|error| RuntimeError::new(error.to_string()))?;
- events.push(AssistantEvent::ToolUse { id, name, input });
- }
- }
- ApiStreamEvent::MessageDelta(delta) => {
- events.push(AssistantEvent::Usage(delta.usage.token_usage()));
- }
- ApiStreamEvent::MessageStop(_) => {
- saw_stop = true;
- if let Some(rendered) = markdown_stream.flush(&renderer) {
- write!(out, "{rendered}")
- .and_then(|()| out.flush())
- .map_err(|error| RuntimeError::new(error.to_string()))?;
- }
- events.push(AssistantEvent::MessageStop);
- }
- }
- }
-
- push_prompt_cache_record(&self.client, &mut events);
-
- if !saw_stop
- && events.iter().any(|event| {
- matches!(event, AssistantEvent::TextDelta(text) if !text.is_empty())
- || matches!(event, AssistantEvent::ToolUse { .. })
- })
- {
- events.push(AssistantEvent::MessageStop);
- }
-
- if events
- .iter()
- .any(|event| matches!(event, AssistantEvent::MessageStop))
- {
- return Ok(events);
- }
-
- let response = self
- .client
- .send_message(&MessageRequest {
- stream: false,
- ..message_request.clone()
- })
- .await
- .map_err(|error| {
- RuntimeError::new(format_user_visible_api_error(&self.session_id, &error))
- })?;
- let mut events = response_to_events(response, out)?;
- push_prompt_cache_record(&self.client, &mut events);
- Ok(events)
- }
-}
diff --git a/anthropic_struct.rs b/anthropic_struct.rs
deleted file mode 100644
index 6da0a6d8..00000000
--- a/anthropic_struct.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-struct AnthropicRuntimeClient {
- runtime: tokio::runtime::Runtime,
- client: ApiProviderClient,
- session_id: String,
- model: String,
- enable_tools: bool,
- emit_output: bool,
- allowed_tools: Option,
- tool_registry: GlobalToolRegistry,
- progress_reporter: Option,
- reasoning_effort: Option,
-}
diff --git a/anthropic_trait_impl.rs b/anthropic_trait_impl.rs
deleted file mode 100644
index a4476c5c..00000000
--- a/anthropic_trait_impl.rs
+++ /dev/null
@@ -1,49 +0,0 @@
-impl ApiClient for AnthropicRuntimeClient {
- #[allow(clippy::too_many_lines)]
- fn stream(&mut self, request: ApiRequest) -> Result, RuntimeError> {
- if let Some(progress_reporter) = &self.progress_reporter {
- progress_reporter.mark_model_phase();
- }
- let is_post_tool = request_ends_with_tool_result(&request);
- let message_request = MessageRequest {
- model: self.model.clone(),
- max_tokens: max_tokens_for_model(&self.model),
- messages: convert_messages(&request.messages),
- system: (!request.system_prompt.is_empty()).then(|| request.system_prompt.join("\n\n")),
- tools: self
- .enable_tools
- .then(|| filter_tool_specs(&self.tool_registry, self.allowed_tools.as_ref())),
- tool_choice: self.enable_tools.then_some(ToolChoice::Auto),
- stream: true,
- reasoning_effort: self.reasoning_effort.clone(),
- ..Default::default()
- };
-
- self.runtime.block_on(async {
- // When resuming after tool execution, apply a stall timeout on the
- // first stream event. If the model does not respond within the
- // deadline we drop the stalled connection and re-send the request as
- // a continuation nudge (one retry only).
- let max_attempts: usize = if is_post_tool { 2 } else { 1 };
-
- for attempt in 1..=max_attempts {
- let result = self
- .consume_stream(&message_request, is_post_tool && attempt == 1)
- .await;
- match result {
- Ok(events) => return Ok(events),
- Err(error)
- if error.to_string().contains("post-tool stall")
- && attempt < max_attempts =>
- {
- // Stalled after tool completion — nudge the model by
- // re-sending the same request.
- }
- Err(error) => return Err(error),
- }
- }
-
- Err(RuntimeError::new("post-tool continuation nudge exhausted"))
- })
- }
-}
diff --git a/debug.sh b/debug.sh
deleted file mode 100644
index 2fd83084..00000000
--- a/debug.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-cargo check
-cargo test
-cargo fmt --all
-
-
-
-### 跨平台编译
-rustup target add x86_64-unknown-linux-musl
-cargo build --target x86_64-unknown-linux-musl --release
-cp target/x86_64-unknown-linux-musl/release/claw /usr/local/bin/claw
-
-
-
-
-
-
-echo $DASHSCOPE_API_KEY
-echo $ANTHROPIC_MODEL
-claw "帮我看看这个项目的内容"
\ No newline at end of file
diff --git a/describe_tool_progress_summarizes_known_tools.rs_chunk b/describe_tool_progress_summarizes_known_tools.rs_chunk
deleted file mode 100644
index 270db5bf..00000000
--- a/describe_tool_progress_summarizes_known_tools.rs_chunk
+++ /dev/null
@@ -1,15 +0,0 @@
-#[test]
- fn describe_tool_progress_summarizes_known_tools() {
- assert_eq!(
- describe_tool_progress("read_file", r#"{"path":"src/main.rs"}"#),
- "reading src/main.rs"
- );
- assert!(
- describe_tool_progress("bash", r#"{"command":"cargo test -p rusty-claude-cli"}"#)
- .contains("cargo test -p rusty-claude-cli")
- );
- assert_eq!(
- describe_tool_progress("grep_search", r#"{"pattern":"ultraplan","path":"rust"}"#),
- "grep `ultraplan` in rust"
- );
- }
\ No newline at end of file
diff --git a/extract_client.py b/extract_client.py
deleted file mode 100644
index 9fd04321..00000000
--- a/extract_client.py
+++ /dev/null
@@ -1,67 +0,0 @@
-import re
-
-MAIN_FILE = "rust/crates/rusty-claude-cli/src/main.rs"
-
-with open(MAIN_FILE, 'r') as f:
- content = f.read()
-
-def extract_and_remove(pattern, content):
- match = re.search(pattern, content, re.MULTILINE | re.DOTALL)
- if match:
- extracted = match.group(0)
- content = content.replace(extracted, "")
- return extracted, content
- return None, content
-
-anthropic_client_pattern = r'struct AnthropicRuntimeClient \{.*?\n\}\n\nimpl AnthropicRuntimeClient \{.*?\n\}\n\nimpl runtime::Client for AnthropicRuntimeClient \{.*?\n\}'
-anthropic_client_code, content = extract_and_remove(anthropic_client_pattern, content)
-
-build_runtime_pattern = r'fn build_runtime\(\n session: Session,\n session_id: &str,\n model: String,\n system_prompts: Vec,\n enable_tools: bool,\n emit_output: bool,\n allowed_tools: Option,\n permission_mode: PermissionMode,\n reasoning_effort: Option,\n\) -> Result> \{.*?\n\}'
-build_runtime_code, content = extract_and_remove(build_runtime_pattern, content)
-
-build_runtime_with_plugin_state_pattern = r'fn build_runtime_with_plugin_state\(\n session: Session,\n session_id: &str,\n model: String,\n system_prompts: Vec,\n enable_tools: bool,\n emit_output: bool,\n allowed_tools: Option,\n permission_mode: PermissionMode,\n reasoning_effort: Option,\n plugin_state: RuntimePluginState,\n\) -> Result> \{.*?\n\}'
-build_runtime_with_plugin_state_code, content = extract_and_remove(build_runtime_with_plugin_state_pattern, content)
-
-build_runtime_plugin_state_pattern = r'fn build_runtime_plugin_state\(\) -> Result> \{.*?\n\}'
-build_runtime_plugin_state_code, content = extract_and_remove(build_runtime_plugin_state_pattern, content)
-
-build_runtime_plugin_state_with_loader_pattern = r'fn build_runtime_plugin_state_with_loader\(\n cwd: &Path,\n loader: &ConfigLoader,\n runtime_config: &runtime::RuntimeConfig,\n\) -> Result> \{.*?\n\}'
-build_runtime_plugin_state_with_loader_code, content = extract_and_remove(build_runtime_plugin_state_with_loader_pattern, content)
-
-runtime_plugin_state_pattern = r'struct RuntimePluginState \{.*?\n\}'
-runtime_plugin_state_code, content = extract_and_remove(runtime_plugin_state_pattern, content)
-
-build_runtime_mcp_state_pattern = r'fn build_runtime_mcp_state\(\n mcp_config: Option<&runtime::McpConfig>,\n cwd: &Path,\n\) -> Option>> \{.*?\n\}'
-build_runtime_mcp_state_code, content = extract_and_remove(build_runtime_mcp_state_pattern, content)
-
-mcp_wrapper_tools_pattern = r'fn mcp_wrapper_tool_definitions\(\) -> Vec \{.*?\n\}'
-mcp_wrapper_tools_code, content = extract_and_remove(mcp_wrapper_tools_pattern, content)
-
-mcp_runtime_tool_definition_pattern = r'fn mcp_runtime_tool_definition\(tool: &runtime::ManagedMcpTool\) -> RuntimeToolDefinition \{.*?\n\}'
-mcp_runtime_tool_definition_code, content = extract_and_remove(mcp_runtime_tool_definition_pattern, content)
-
-mcp_permission_mode_pattern = r'fn permission_mode_for_mcp_tool\(tool: &McpTool\) -> PermissionMode \{.*?\n\}'
-mcp_permission_mode_code, content = extract_and_remove(mcp_permission_mode_pattern, content)
-
-mcp_annotation_flag_pattern = r'fn mcp_annotation_flag\(tool: &McpTool, key: &str\) -> bool \{.*?\n\}'
-mcp_annotation_flag_code, content = extract_and_remove(mcp_annotation_flag_pattern, content)
-
-mcp_state_pattern = r'struct RuntimeMcpState \{.*?\n\}\n\nimpl RuntimeMcpState \{.*?\n\}'
-mcp_state_code, content = extract_and_remove(mcp_state_pattern, content)
-
-with open(MAIN_FILE, 'w') as f:
- f.write(content)
-
-with open('client_extracted.rs', 'w') as f:
- blocks = [
- anthropic_client_code, build_runtime_code, build_runtime_with_plugin_state_code,
- build_runtime_plugin_state_code, build_runtime_plugin_state_with_loader_code,
- runtime_plugin_state_code, build_runtime_mcp_state_code, mcp_wrapper_tools_code,
- mcp_runtime_tool_definition_code, mcp_permission_mode_code, mcp_annotation_flag_code,
- mcp_state_code
- ]
- for block in blocks:
- if block:
- f.write(block + "\n\n")
-
-print("Client extraction complete")
diff --git a/extract_executor.py b/extract_executor.py
deleted file mode 100644
index 3c486048..00000000
--- a/extract_executor.py
+++ /dev/null
@@ -1,26 +0,0 @@
-import re
-
-MAIN_FILE = "rust/crates/rusty-claude-cli/src/main.rs"
-
-with open(MAIN_FILE, 'r') as f:
- content = f.read()
-
-def extract_and_remove(pattern, content):
- match = re.search(pattern, content, re.MULTILINE | re.DOTALL)
- if match:
- extracted = match.group(0)
- content = content.replace(extracted, "")
- return extracted, content
- return None, content
-
-executor_pattern = r'struct CliToolExecutor \{.*?\n\}\n\nimpl CliToolExecutor \{.*?\n\}\n\nimpl ToolExecutor for CliToolExecutor \{.*?\n\}'
-executor_code, content = extract_and_remove(executor_pattern, content)
-
-with open(MAIN_FILE, 'w') as f:
- f.write(content)
-
-with open('executor_extracted.rs', 'w') as f:
- if executor_code:
- f.write(executor_code + "\n\n")
-
-print("Executor extraction complete")
diff --git a/extract_stream.py b/extract_stream.py
deleted file mode 100644
index afc4b656..00000000
--- a/extract_stream.py
+++ /dev/null
@@ -1,42 +0,0 @@
-import re
-import os
-
-MAIN_FILE = "rust/crates/rusty-claude-cli/src/main.rs"
-
-with open(MAIN_FILE, 'r') as f:
- content = f.read()
-
-def extract_and_remove(pattern, content):
- match = re.search(pattern, content, re.MULTILINE | re.DOTALL)
- if match:
- extracted = match.group(0)
- content = content.replace(extracted, "")
- return extracted, content
- return None, content
-
-consume_stream_pattern = r' /// Consume a single streaming response, optionally applying a stall\n /// timeout on the first event for post-tool continuations\.\n #\[allow\(clippy::too_many_lines\)\]\n async fn consume_stream\(\n &self,\n message_request: &MessageRequest,\n apply_stall_timeout: bool,\n \) -> Result, RuntimeError> \{.*?\n \}'
-consume_stream_code, content = extract_and_remove(consume_stream_pattern, content)
-
-response_to_events_pattern = r'fn response_to_events\(\n response: MessageResponse,\n out: &mut \(impl Write \+ \?Sized\),\n\) -> Result, RuntimeError> \{.*?\n\}'
-response_to_events_code, content = extract_and_remove(response_to_events_pattern, content)
-
-push_prompt_cache_record_pattern = r'fn push_prompt_cache_record\(client: &ApiProviderClient, events: &mut Vec\) \{.*?\n\}'
-push_prompt_cache_record_code, content = extract_and_remove(push_prompt_cache_record_pattern, content)
-
-prompt_cache_record_to_runtime_event_pattern = r'fn prompt_cache_record_to_runtime_event\(\n record: api::PromptCacheRecord,\n\) -> Option \{.*?\n\}'
-prompt_cache_record_to_runtime_event_code, content = extract_and_remove(prompt_cache_record_to_runtime_event_pattern, content)
-
-request_ends_with_tool_result_pattern = r'/// Returns `true` when the conversation ends with a tool-result message,\n/// meaning the model is expected to continue after tool execution\.\nfn request_ends_with_tool_result\(request: &ApiRequest\) -> bool \{.*?\n\}'
-request_ends_with_tool_result_code, content = extract_and_remove(request_ends_with_tool_result_pattern, content)
-
-with open(MAIN_FILE, 'w') as f:
- f.write(content)
-
-with open('stream_extracted.rs', 'w') as f:
- if consume_stream_code: f.write(consume_stream_code + "\n\n")
- if response_to_events_code: f.write(response_to_events_code + "\n\n")
- if push_prompt_cache_record_code: f.write(push_prompt_cache_record_code + "\n\n")
- if prompt_cache_record_to_runtime_event_code: f.write(prompt_cache_record_to_runtime_event_code + "\n\n")
- if request_ends_with_tool_result_code: f.write(request_ends_with_tool_result_code + "\n\n")
-
-print("Extraction complete")
diff --git a/extract_tests.py b/extract_tests.py
deleted file mode 100644
index 273af909..00000000
--- a/extract_tests.py
+++ /dev/null
@@ -1,30 +0,0 @@
-import re
-
-with open('rust/crates/rusty-claude-cli/src/main_tests.rs', 'r') as f:
- content = f.read()
-
-def extract_test(name):
- pattern = r'(#\[test\]\s+fn ' + name + r'\b.*?^ \})'
- match = re.search(pattern, content, re.MULTILINE | re.DOTALL)
- if match:
- return match.group(1)
- return None
-
-tests = [
- "resolves_known_model_aliases",
- "user_defined_aliases_resolve_before_provider_dispatch",
- "resolve_repl_model_returns_user_supplied_model_unchanged_when_explicit",
- "resolve_repl_model_falls_back_to_anthropic_model_env_when_default",
- "resolve_repl_model_returns_default_when_env_unset_and_no_config",
- "permission_policy_uses_plugin_tool_permissions",
- "describe_tool_progress_summarizes_known_tools"
-]
-
-for test in tests:
- extracted = extract_test(test)
- if extracted:
- with open(f"{test}.rs_chunk", "w") as out:
- out.write(extracted)
- else:
- print(f"Test not found: {test}")
-
diff --git a/fix_all.py b/fix_all.py
deleted file mode 100644
index e7095029..00000000
--- a/fix_all.py
+++ /dev/null
@@ -1,40 +0,0 @@
-import re
-
-STREAM_FILE = "rust/crates/rusty-claude-cli/src/execution/stream.rs"
-CLIENT_FILE = "rust/crates/rusty-claude-cli/src/execution/client.rs"
-EXECUTOR_FILE = "rust/crates/rusty-claude-cli/src/execution/executor.rs"
-
-with open(STREAM_FILE, 'r') as f:
- stream_content = f.read()
-
-# Extract consume_stream
-consume_stream_pattern = r' /// Consume a single streaming response.*?\}\n\n'
-match = re.search(consume_stream_pattern, stream_content, re.DOTALL | re.MULTILINE)
-if match:
- consume_stream_code = match.group(0)
- stream_content = stream_content.replace(consume_stream_code, "")
-
- with open(STREAM_FILE, 'w') as f:
- f.write(stream_content)
-
- with open(CLIENT_FILE, 'r') as f:
- client_content = f.read()
-
- # insert inside impl AnthropicRuntimeClient
- client_content = client_content.replace("impl AnthropicRuntimeClient {", "impl AnthropicRuntimeClient {\n" + consume_stream_code)
-
- # fix trait visibility issues
- client_content = client_content.replace("pub(crate) fn deref(", "fn deref(")
- client_content = client_content.replace("pub(crate) fn deref_mut(", "fn deref_mut(")
- client_content = client_content.replace("pub(crate) fn drop(", "fn drop(")
-
- with open(CLIENT_FILE, 'w') as f:
- f.write(client_content)
-
-with open(EXECUTOR_FILE, 'r') as f:
- executor_content = f.read()
-executor_content = executor_content.replace("pub(crate) fn execute(", "fn execute(")
-with open(EXECUTOR_FILE, 'w') as f:
- f.write(executor_content)
-
-print("Fixed.")
diff --git a/fix_anthropic.py b/fix_anthropic.py
deleted file mode 100644
index d6dd508a..00000000
--- a/fix_anthropic.py
+++ /dev/null
@@ -1,20 +0,0 @@
-import re
-
-with open('anthropic_full.rs', 'r') as f:
- content = f.read()
-
-content = re.sub(r'^struct ', r'pub(crate) struct ', content, flags=re.MULTILINE)
-content = re.sub(r'^(\s+)(async )?fn ', r'\1pub(crate) \2fn ', content, flags=re.MULTILINE)
-
-# except for trait methods
-content = re.sub(r'pub\(crate\) fn name\(', r'fn name(', content)
-content = re.sub(r'pub\(crate\) async fn process_stream\(', r'async fn process_stream(', content)
-content = re.sub(r'pub\(crate\) fn session_id\(', r'fn session_id(', content)
-content = re.sub(r'pub\(crate\) fn model\(', r'fn model(', content)
-content = re.sub(r'pub\(crate\) fn enable_tools\(', r'fn enable_tools(', content)
-
-with open('anthropic_full.rs', 'w') as f:
- f.write(content)
-
-with open('rust/crates/rusty-claude-cli/src/execution/client.rs', 'a') as f:
- f.write("\n" + content + "\n")
diff --git a/fix_diagnostics.sh b/fix_diagnostics.sh
deleted file mode 100644
index d3a6230c..00000000
--- a/fix_diagnostics.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-sed -i '' '1i\
-use crate::{CliOutputFormat, OFFICIAL_REPO_SLUG, DEPRECATED_INSTALL_COMMAND, OFFICIAL_REPO_URL, resolve_cli_auth_source_for_cwd};\
-use tools::{mvp_tool_specs, execute_tool};\
-use runtime::{McpTool, McpServerSpec, McpServer, load_oauth_credentials};\
-' rust/crates/rusty-claude-cli/src/diagnostics/mod.rs
-
-sed -i '' 's/fn run_doctor(/pub(crate) fn run_doctor(/g' rust/crates/rusty-claude-cli/src/diagnostics/mod.rs
-sed -i '' 's/fn run_worker_state(/pub(crate) fn run_worker_state(/g' rust/crates/rusty-claude-cli/src/diagnostics/mod.rs
-sed -i '' 's/fn run_mcp_serve(/pub(crate) fn run_mcp_serve(/g' rust/crates/rusty-claude-cli/src/diagnostics/mod.rs
diff --git a/fix_models_test.py b/fix_models_test.py
deleted file mode 100644
index 83aa46ca..00000000
--- a/fix_models_test.py
+++ /dev/null
@@ -1,52 +0,0 @@
-import re
-
-MODELS_FILE = "rust/crates/rusty-claude-cli/src/config/models.rs"
-
-with open(MODELS_FILE, 'r') as f:
- content = f.read()
-
-content = content.replace("use runtime::test_utils::{env_lock, temp_dir, with_current_dir};", """
- use std::sync::{Mutex, MutexGuard, OnceLock};
- use std::sync::atomic::{AtomicUsize, Ordering};
- use std::path::{Path, PathBuf};
- use std::fs;
-
- fn env_lock() -> MutexGuard<'static, ()> {
- static LOCK: OnceLock> = OnceLock::new();
- LOCK.get_or_init(|| Mutex::new(()))
- .lock()
- .unwrap_or_else(std::sync::PoisonError::into_inner)
- }
-
- fn cwd_lock() -> MutexGuard<'static, ()> {
- static LOCK: OnceLock> = OnceLock::new();
- LOCK.get_or_init(|| Mutex::new(()))
- .lock()
- .unwrap_or_else(std::sync::PoisonError::into_inner)
- }
-
- fn temp_dir() -> PathBuf {
- static COUNTER: AtomicUsize = AtomicUsize::new(0);
- let nanos = std::time::SystemTime::now()
- .duration_since(std::time::UNIX_EPOCH)
- .unwrap()
- .subsec_nanos();
- let unique = COUNTER.fetch_add(1, Ordering::Relaxed);
- std::env::temp_dir().join(format!("rusty-claude-cli-{nanos}-{unique}"))
- }
-
- fn with_current_dir(cwd: &Path, f: impl FnOnce() -> T) -> T {
- let _guard = cwd_lock();
- let previous = std::env::current_dir().expect("cwd should load");
- std::env::set_current_dir(cwd).expect("cwd should change");
- let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(f));
- std::env::set_current_dir(previous).expect("cwd should restore");
- match result {
- Ok(value) => value,
- Err(payload) => std::panic::resume_unwind(payload),
- }
- }
-""")
-
-with open(MODELS_FILE, 'w') as f:
- f.write(content)
diff --git a/fix_progress.sh b/fix_progress.sh
deleted file mode 100644
index c29881ea..00000000
--- a/fix_progress.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-sed -i '' 's/^struct InternalPromptProgressState/pub(crate) struct InternalPromptProgressState/g' rust/crates/rusty-claude-cli/src/ui/progress.rs
-sed -i '' 's/^enum InternalPromptProgressEvent/pub(crate) enum InternalPromptProgressEvent/g' rust/crates/rusty-claude-cli/src/ui/progress.rs
-sed -i '' 's/^struct InternalPromptProgressShared/pub(crate) struct InternalPromptProgressShared/g' rust/crates/rusty-claude-cli/src/ui/progress.rs
-sed -i '' 's/^struct InternalPromptProgressReporter/pub(crate) struct InternalPromptProgressReporter/g' rust/crates/rusty-claude-cli/src/ui/progress.rs
-sed -i '' 's/^struct InternalPromptProgressRun/pub(crate) struct InternalPromptProgressRun/g' rust/crates/rusty-claude-cli/src/ui/progress.rs
-sed -i '' 's/^struct CliHookProgressReporter/pub(crate) struct CliHookProgressReporter/g' rust/crates/rusty-claude-cli/src/ui/progress.rs
-sed -ised -i '' 's/^struct InternalPromptProgrplsed -i '' 's/^enum InternalPromptProgressEvent/pub(crate) enum InternalPromptProgressEvent/g' rust/crates/rusty-claude-cli/src/ui/progress.rs
-seresed -i '' 's/^struct InternalPromptProgressShared/pub(crate) struct InternalPromptProgressShared/g' rust/crates/rusty-claude-cli/src/ui/prog sed -i "''" "'s/^struct InternalPromptProgressReporter/pub(crate) struct InternalPromptProgressReporter/g'" rust/crates/rusty-claude-cli/src/ui/progrerased -i "''" "'s/^struct InternalPromptProgressRun/pub(crate) struct InternalPromptProgressRun/g'" rust/crates/rusty-claude-cli/src/ui/progress.rs
\ No newline at end of file
diff --git a/fix_prompter.py b/fix_prompter.py
deleted file mode 100644
index 2ad26cf2..00000000
--- a/fix_prompter.py
+++ /dev/null
@@ -1,20 +0,0 @@
-import re
-
-with open("rust/crates/rusty-claude-cli/src/permissions/prompter.rs", "r") as f:
- content = f.read()
-
-content = re.sub(r"^fn (parse_permission_mode_arg|permission_mode_from_label|permission_mode_from_resolved|default_permission_mode|config_permission_mode_for_current_dir|permission_policy)\(", r"pub(crate) fn \1(", content, flags=re.M)
-content = re.sub(r"^struct CliPermissionPrompter", r"pub(crate) struct CliPermissionPrompter", content, flags=re.M)
-content = re.sub(r"fn new\(", r"pub(crate) fn new(", content)
-
-prefix = """use std::env;
-use std::io::{self, Write};
-use runtime::{PermissionMode, ResolvedPermissionMode, ConfigLoader, PermissionPolicy};
-use tools::GlobalToolRegistry;
-
-"""
-
-with open("rust/crates/rusty-claude-cli/src/permissions/prompter.rs", "w") as f:
- f.write(prefix + content)
-
-print("done")
diff --git a/fix_stream_client.py b/fix_stream_client.py
deleted file mode 100644
index f29c0faa..00000000
--- a/fix_stream_client.py
+++ /dev/null
@@ -1,20 +0,0 @@
-import os
-
-with open('rust/crates/rusty-claude-cli/src/execution/stream.rs', 'r') as f:
- stream_content = f.read()
-
-import re
-
-# extract consume_stream from stream.rs
-match = re.search(r'impl AnthropicRuntimeClient \{.*?\n\}', stream_content, re.MULTILINE | re.DOTALL)
-if match:
- consume_stream_code = match.group(0)
- stream_content = stream_content.replace(consume_stream_code, "")
-
- with open('rust/crates/rusty-claude-cli/src/execution/stream.rs', 'w') as f:
- f.write(stream_content)
-
- with open('rust/crates/rusty-claude-cli/src/execution/client.rs', 'a') as f:
- f.write("\n" + consume_stream_code + "\n")
-
-print("Fixed stream and client")
diff --git a/make_pub_crate.py b/make_pub_crate.py
deleted file mode 100644
index 625e10b8..00000000
--- a/make_pub_crate.py
+++ /dev/null
@@ -1,37 +0,0 @@
-import os
-import re
-
-files = [
- 'rust/crates/rusty-claude-cli/src/execution/client.rs',
- 'rust/crates/rusty-claude-cli/src/execution/stream.rs',
- 'rust/crates/rusty-claude-cli/src/execution/executor.rs'
-]
-
-for file in files:
- with open(file, 'r') as f:
- content = f.read()
-
- # Change fn to pub(crate) fn
- content = re.sub(r'^(async )?fn ', r'pub(crate) \1fn ', content, flags=re.MULTILINE)
- content = re.sub(r'pub\(crate\) pub\(crate\) ', r'pub(crate) ', content)
-
- # Inside impl blocks, we also want pub(crate) fn
- content = re.sub(r'^(\s+)(async )?fn ', r'\1pub(crate) \2fn ', content, flags=re.MULTILINE)
-
- # Structs
- content = re.sub(r'^struct ', r'pub(crate) struct ', content, flags=re.MULTILINE)
-
- # Struct fields
- # Match structs block and add pub(crate) to fields
- def repl_struct(m):
- inner = m.group(2)
- # replace field definitions: "name: type,"
- inner = re.sub(r'^(\s+)([a-zA-Z0-9_]+)\s*:\s*', r'\1pub(crate) \2: ', inner, flags=re.MULTILINE)
- return m.group(1) + inner + m.group(3)
-
- content = re.sub(r'(pub\(crate\) struct [a-zA-Z0-9_]+ \{)(.*?)(\})', repl_struct, content, flags=re.DOTALL)
-
- with open(file, 'w') as f:
- f.write(content)
-
-print("Visibility updated.")
diff --git a/move_tests.py b/move_tests.py
deleted file mode 100644
index 7fd3af5f..00000000
--- a/move_tests.py
+++ /dev/null
@@ -1,114 +0,0 @@
-import re
-import os
-
-MAIN_TESTS_FILE = "rust/crates/rusty-claude-cli/src/main_tests.rs"
-CONFIG_MODELS_FILE = "rust/crates/rusty-claude-cli/src/config/models.rs"
-PERMISSIONS_PROMPTER_FILE = "rust/crates/rusty-claude-cli/src/permissions/prompter.rs"
-UI_PROGRESS_FILE = "rust/crates/rusty-claude-cli/src/ui/progress.rs"
-
-with open(MAIN_TESTS_FILE, 'r') as f:
- content = f.read()
-
-def remove_test(name, content):
- pattern = r'#\[test\]\s+fn ' + name + r'\b.*?^ \}'
- new_content, count = re.subn(pattern, '', content, flags=re.MULTILINE | re.DOTALL)
- if count == 0:
- print(f"Warning: Test {name} not found to remove.")
- return new_content
-
-tests_for_models = [
- "resolves_known_model_aliases",
- "user_defined_aliases_resolve_before_provider_dispatch",
- "resolve_repl_model_returns_user_supplied_model_unchanged_when_explicit",
- "resolve_repl_model_falls_back_to_anthropic_model_env_when_default",
- "resolve_repl_model_returns_default_when_env_unset_and_no_config",
-]
-
-for test in tests_for_models:
- content = remove_test(test, content)
-
-content = remove_test("permission_policy_uses_plugin_tool_permissions", content)
-content = remove_test("describe_tool_progress_summarizes_known_tools", content)
-
-# Remove imports from main_tests.rs
-imports_to_remove = [
- "resolve_model_alias,", "resolve_model_alias_with_config,", "resolve_repl_model,",
- "permission_policy,", "describe_tool_progress,"
-]
-for imp in imports_to_remove:
- content = content.replace(imp, "")
-
-with open(MAIN_TESTS_FILE, 'w') as f:
- f.write(content)
-
-# --- Append to src/config/models.rs ---
-models_tests = []
-for test in tests_for_models:
- with open(f"{test}.rs_chunk", "r") as f:
- models_tests.append(" " + f.read().replace("\n", "\n ").strip())
-
-models_test_mod = """
-#[cfg(test)]
-mod tests {
- use super::*;
- use runtime::test_utils::{env_lock, temp_dir, with_current_dir};
-
-""" + "\n\n".join(models_tests) + "\n}\n"
-
-with open(CONFIG_MODELS_FILE, 'a') as f:
- f.write(models_test_mod)
-
-# --- Append to src/permissions/prompter.rs ---
-with open("permission_policy_uses_plugin_tool_permissions.rs_chunk", "r") as f:
- prompter_test = " " + f.read().replace("\n", "\n ").strip()
-
-prompter_test_mod = """
-#[cfg(test)]
-mod tests {
- use super::*;
- use plugins::{PluginTool, PluginToolDefinition, PluginToolPermission};
- use serde_json::json;
- use tools::GlobalToolRegistry;
- use runtime::{PermissionMode, RuntimeFeatureConfig};
-
- fn registry_with_plugin_tool() -> GlobalToolRegistry {
- GlobalToolRegistry::with_plugin_tools(vec![PluginTool::new(
- "plugin-demo@external",
- "plugin-demo",
- PluginToolDefinition {
- name: "plugin_echo".to_string(),
- description: Some("Echo plugin payload".to_string()),
- input_schema: json!({
- "type": "object",
- "properties": {
- "message": { "type": "string" }
- },
- "required": ["message"],
- "additionalProperties": false
- }),
- },
- "echo".to_string(),
- PluginToolPermission::WorkspaceWrite,
- )])
- }
-
-""" + prompter_test + "\n}\n"
-
-with open(PERMISSIONS_PROMPTER_FILE, 'a') as f:
- f.write(prompter_test_mod)
-
-# --- Append to src/ui/progress.rs ---
-with open("describe_tool_progress_summarizes_known_tools.rs_chunk", "r") as f:
- progress_test = " " + f.read().replace("\n", "\n ").strip()
-
-progress_test_mod = """
-#[cfg(test)]
-mod tests {
- use super::*;
-
-""" + progress_test + "\n}\n"
-
-with open(UI_PROGRESS_FILE, 'a') as f:
- f.write(progress_test_mod)
-
-print("Done moving tests.")
diff --git a/permission_policy_uses_plugin_tool_permissions.rs_chunk b/permission_policy_uses_plugin_tool_permissions.rs_chunk
deleted file mode 100644
index a73cc994..00000000
--- a/permission_policy_uses_plugin_tool_permissions.rs_chunk
+++ /dev/null
@@ -1,12 +0,0 @@
-#[test]
- fn permission_policy_uses_plugin_tool_permissions() {
- let feature_config = runtime::RuntimeFeatureConfig::default();
- let policy = permission_policy(
- PermissionMode::ReadOnly,
- &feature_config,
- ®istry_with_plugin_tool(),
- )
- .expect("permission policy should build");
- let required = policy.required_mode_for("plugin_echo");
- assert_eq!(required, PermissionMode::WorkspaceWrite);
- }
\ No newline at end of file
diff --git a/prd.json b/prd.json
deleted file mode 100644
index 8faaa541..00000000
--- a/prd.json
+++ /dev/null
@@ -1,356 +0,0 @@
-{
- "version": "1.0",
- "description": "Clawable Coding Harness - Clear roadmap stories and commit each",
- "stories": [
- {
- "id": "US-001",
- "title": "Phase 1.6 - startup-no-evidence evidence bundle + classifier",
- "description": "When startup times out, emit typed worker.startup_no_evidence event with evidence bundle including last known worker lifecycle state, pane command, prompt-send timestamp, prompt-acceptance state, trust-prompt detection result, and transport/MCP health summary. Classifier should down-rank into specific failure classes.",
- "acceptanceCriteria": [
- "worker.startup_no_evidence event emitted on startup timeout with evidence bundle",
- "Evidence bundle includes: last lifecycle state, pane command, prompt-send timestamp, prompt-acceptance state, trust-prompt detection, transport/MCP health",
- "Classifier attempts to categorize into: trust_required, prompt_misdelivery, prompt_acceptance_timeout, transport_dead, worker_crashed, or unknown",
- "Tests verify evidence bundle structure and classifier behavior"
- ],
- "passes": true,
- "priority": "P0"
- },
- {
- "id": "US-002",
- "title": "Phase 2 - Canonical lane event schema (4.x series)",
- "description": "Define typed events for lane lifecycle: lane.started, lane.ready, lane.prompt_misdelivery, lane.blocked, lane.red, lane.green, lane.commit.created, lane.pr.opened, lane.merge.ready, lane.finished, lane.failed, branch.stale_against_main. Also implement event ordering, reconciliation, provenance, deduplication, and projection contracts.",
- "acceptanceCriteria": [
- "LaneEvent enum with all required variants defined",
- "Event ordering with monotonic sequence metadata attached",
- "Event provenance labels (live_lane, test, healthcheck, replay, transport)",
- "Session identity completeness at creation (title, workspace, purpose)",
- "Duplicate terminal-event suppression with fingerprinting",
- "Lane ownership/scope binding in events",
- "Nudge acknowledgment with dedupe contract",
- "clawhip consumes typed lane events instead of pane scraping"
- ],
- "passes": true,
- "priority": "P0"
- },
- {
- "id": "US-003",
- "title": "Phase 3 - Stale-branch detection before broad verification",
- "description": "Before broad test runs, compare current branch to main and detect if known fixes are missing. Emit branch.stale_against_main event and suggest/auto-run rebase/merge-forward.",
- "acceptanceCriteria": [
- "Branch freshness comparison against main implemented",
- "branch.stale_against_main event emitted when behind",
- "Auto-rebase/merge-forward policy integration",
- "Avoid misclassifying stale-branch failures as new regressions"
- ],
- "passes": true,
- "priority": "P1"
- },
- {
- "id": "US-004",
- "title": "Phase 3 - Recovery recipes with ledger",
- "description": "Encode automatic recoveries for common failures (trust prompt, prompt misdelivery, stale branch, compile red, MCP startup). Expose recovery attempt ledger with recipe id, attempt count, state, timestamps, failure summary.",
- "acceptanceCriteria": [
- "Recovery recipes defined for: trust_prompt_unresolved, prompt_delivered_to_shell, stale_branch, compile_red_after_refactor, MCP_handshake_failure, partial_plugin_startup",
- "Recovery attempt ledger with: recipe id, attempt count, state, timestamps, failure summary, escalation reason",
- "One automatic recovery attempt before escalation",
- "Ledger emitted as structured event data"
- ],
- "passes": true,
- "priority": "P1"
- },
- {
- "id": "US-005",
- "title": "Phase 4 - Typed task packet format",
- "description": "Define structured task packet with fields: objective, scope, repo/worktree, branch policy, acceptance tests, commit policy, reporting contract, escalation policy.",
- "acceptanceCriteria": [
- "TaskPacket struct with all required fields",
- "TaskScope resolution (workspace/module/single-file/custom)",
- "Validation and serialization support",
- "Integration into tools/src/lib.rs"
- ],
- "passes": true,
- "priority": "P1"
- },
- {
- "id": "US-006",
- "title": "Phase 4 - Policy engine for autonomous coding",
- "description": "Encode automation rules: if green + scoped diff + review passed -> merge to dev; if stale branch -> merge-forward before broad tests; if startup blocked -> recover once, then escalate; if lane completed -> emit closeout and cleanup session.",
- "acceptanceCriteria": [
- "Policy rules engine implemented",
- "Rules: green + scoped diff + review -> merge",
- "Rules: stale branch -> merge-forward before tests",
- "Rules: startup blocked -> recover once, then escalate",
- "Rules: lane completed -> closeout and cleanup"
- ],
- "passes": true,
- "priority": "P2"
- },
- {
- "id": "US-007",
- "title": "Phase 5 - Plugin/MCP lifecycle maturity",
- "description": "First-class plugin/MCP lifecycle contract: config validation, startup healthcheck, discovery result, degraded-mode behavior, shutdown/cleanup. Close gaps in end-to-end lifecycle.",
- "acceptanceCriteria": [
- "Plugin/MCP config validation contract",
- "Startup healthcheck with structured results",
- "Discovery result reporting",
- "Degraded-mode behavior documented and implemented",
- "Shutdown/cleanup contract",
- "Partial startup and per-server failures reported structurally"
- ],
- "passes": true,
- "priority": "P2"
- },
- {
- "id": "US-008",
- "title": "Fix kimi-k2.5 model API compatibility",
- "description": "The kimi-k2.5 model (and other kimi models) reject API requests containing the is_error field in tool result messages. The OpenAI-compatible provider currently always includes is_error for all models. Need to make this field conditional based on model support.",
- "acceptanceCriteria": [
- "translate_message function accepts model parameter",
- "is_error field excluded for kimi models (kimi-k2.5, kimi-k1.5, etc.)",
- "is_error field included for models that support it (openai, grok, xai, etc.)",
- "build_chat_completion_request passes model to translate_message",
- "Tests verify is_error presence/absence based on model",
- "cargo test passes",
- "cargo clippy passes",
- "cargo fmt passes"
- ],
- "passes": true,
- "priority": "P0"
- },
- {
- "id": "US-009",
- "title": "Add unit tests for kimi model compatibility fix",
- "description": "During dogfooding we discovered the existing test coverage for model-specific is_error handling is insufficient. Need to add dedicated tests for model_rejects_is_error_field function and translate_message behavior with different models.",
- "acceptanceCriteria": [
- "Test model_rejects_is_error_field identifies kimi-k2.5, kimi-k1.5, dashscope/kimi-k2.5",
- "Test translate_message includes is_error for gpt-4, grok-3, claude models",
- "Test translate_message excludes is_error for kimi models",
- "Test build_chat_completion_request produces correct payload for kimi vs non-kimi",
- "All new tests pass",
- "cargo test --package api passes"
- ],
- "passes": true,
- "priority": "P1"
- },
- {
- "id": "US-010",
- "title": "Add model compatibility documentation",
- "description": "Document which models require special handling (is_error exclusion, reasoning model tuning param stripping, etc.) in a MODEL_COMPATIBILITY.md file for operators and contributors.",
- "acceptanceCriteria": [
- "MODEL_COMPATIBILITY.md created in docs/ or repo root",
- "Document kimi models is_error exclusion",
- "Document reasoning models (o1, o3, grok-3-mini) tuning param stripping",
- "Document gpt-5 max_completion_tokens requirement",
- "Document qwen model routing through dashscope",
- "Cross-reference with existing code comments"
- ],
- "passes": true,
- "priority": "P2"
- },
- {
- "id": "US-011",
- "title": "Performance optimization: reduce API request serialization overhead",
- "description": "The translate_message function creates intermediate JSON Value objects that could be optimized. Profile and optimize the hot path for API request building, especially for conversations with many tool results.",
- "acceptanceCriteria": [
- "Profile current request building with criterion or similar",
- "Identify bottlenecks in translate_message and build_chat_completion_request",
- "Implement optimizations (Vec pre-allocation, reduced cloning, etc.)",
- "Benchmark before/after showing improvement",
- "No functional changes or API breakage"
- ],
- "passes": true,
- "priority": "P2"
- },
- {
- "id": "US-012",
- "title": "Trust prompt resolver with allowlist auto-trust",
- "description": "Add allowlisted auto-trust behavior for known repos/worktrees. Trust prompts currently block TUI startup and require manual intervention. Implement automatic trust resolution for pre-approved repositories.",
- "acceptanceCriteria": [
- "TrustAllowlist config structure with repo patterns",
- "Auto-trust behavior for allowlisted repos/worktrees",
- "trust_required event emitted when trust prompt detected",
- "trust_resolved event emitted when trust is granted",
- "Non-allowlisted repos remain gated (manual trust required)",
- "Integration with worker boot lifecycle",
- "Tests for allowlist matching and event emission"
- ],
- "passes": true,
- "priority": "P1"
- },
- {
- "id": "US-013",
- "title": "Phase 2 - Session event ordering + terminal-state reconciliation",
- "description": "When the same session emits contradictory lifecycle events (idle, error, completed, transport/server-down) in close succession, expose deterministic final truth. Attach monotonic sequence/causal ordering metadata, classify terminal vs advisory events, reconcile duplicate/out-of-order terminal events into one canonical lane outcome.",
- "acceptanceCriteria": [
- "Monotonic sequence / causal ordering metadata attached to session lifecycle events",
- "Terminal vs advisory event classification implemented",
- "Reconcile duplicate or out-of-order terminal events into one canonical outcome",
- "Distinguish 'session terminal state unknown because transport died' from real 'completed'",
- "Tests verify reconciliation behavior with out-of-order event bursts"
- ],
- "passes": true,
- "priority": "P1"
- },
- {
- "id": "US-014",
- "title": "Phase 2 - Event provenance / environment labeling",
- "description": "Every emitted event should declare its source (live_lane, test, healthcheck, replay, transport) so claws do not mistake test noise for production truth. Include environment/channel label, emitter identity, and confidence/trust level.",
- "acceptanceCriteria": [
- "EventProvenance enum with live_lane, test, healthcheck, replay, transport variants",
- "Environment/channel label attached to all events",
- "Emitter identity field on events",
- "Confidence/trust level field for downstream automation",
- "Tests verify provenance labeling and filtering"
- ],
- "passes": true,
- "priority": "P1"
- },
- {
- "id": "US-015",
- "title": "Phase 2 - Session identity completeness at creation time",
- "description": "A newly created session should emit stable title, workspace/worktree path, and lane/session purpose at creation time. If any field is not yet known, emit explicit typed placeholder reason rather than bare unknown string.",
- "acceptanceCriteria": [
- "Session creation emits stable title, workspace/worktree path, purpose immediately",
- "Explicit typed placeholder when fields unknown (not bare 'unknown' strings)",
- "Later-enriched metadata reconciles onto same session identity without ambiguity",
- "Tests verify session identity completeness and placeholder handling"
- ],
- "passes": true,
- "priority": "P1"
- },
- {
- "id": "US-016",
- "title": "Phase 2 - Duplicate terminal-event suppression",
- "description": "When the same session emits repeated completed/failed/terminal notifications, collapse duplicates before they trigger repeated downstream reactions. Attach canonical terminal-event fingerprint per lane/session outcome.",
- "acceptanceCriteria": [
- "Canonical terminal-event fingerprint attached per lane/session outcome",
- "Suppress/coalesce repeated terminal notifications within reconciliation window",
- "Preserve raw event history for audit while exposing one actionable outcome downstream",
- "Surface when later duplicate materially differs from original terminal payload",
- "Tests verify deduplication and material difference detection"
- ],
- "passes": true,
- "priority": "P2"
- },
- {
- "id": "US-017",
- "title": "Phase 2 - Lane ownership / scope binding",
- "description": "Each session and lane event should declare who owns it and what workflow scope it belongs to. Attach owner/assignee identity, workflow scope (claw-code-dogfood, external-git-maintenance, infra-health, manual-operator), and mark whether watcher is expected to act, observe only, or ignore.",
- "acceptanceCriteria": [
- "Owner/assignee identity attached to sessions and lane events",
- "Workflow scope field (claw-code-dogfood, external-git-maintenance, etc.)",
- "Watcher action expectation field (act, observe-only, ignore)",
- "Preserve scope through session restarts, resumes, and late terminal events",
- "Tests verify ownership and scope binding"
- ],
- "passes": true,
- "priority": "P2"
- },
- {
- "id": "US-018",
- "title": "Phase 2 - Nudge acknowledgment / dedupe contract",
- "description": "Periodic clawhip nudges should carry nudge id/cycle id and delivery timestamp. Expose whether claw has already acknowledged or responded for that cycle. Distinguish new nudge, retry nudge, and stale duplicate.",
- "acceptanceCriteria": [
- "Nudge id / cycle id and delivery timestamp attached",
- "Acknowledgment state exposed (already acknowledged or not)",
- "Distinguish new nudge vs retry nudge vs stale duplicate",
- "Allow downstream summaries to bind reported pinpoint back to triggering nudge id",
- "Tests verify nudge deduplication and acknowledgment tracking"
- ],
- "passes": true,
- "priority": "P2"
- },
- {
- "id": "US-019",
- "title": "Phase 2 - Stable roadmap-id assignment for newly filed pinpoints",
- "description": "When a claw records a new pinpoint/follow-up, assign or expose a stable tracking id immediately. Expose that id in structured event/report payload and preserve across edits, reorderings, and summary compression.",
- "acceptanceCriteria": [
- "Canonical roadmap id assigned at filing time",
- "Roadmap id exposed in structured event/report payload",
- "Same id preserved across edits, reorderings, summary compression",
- "Distinguish 'new roadmap filing' from 'update to existing roadmap item'",
- "Tests verify stable id assignment and update detection"
- ],
- "passes": true,
- "priority": "P2"
- },
- {
- "id": "US-020",
- "title": "Phase 2 - Roadmap item lifecycle state contract",
- "description": "Each roadmap pinpoint should carry machine-readable lifecycle state (filed, acknowledged, in_progress, blocked, done, superseded). Attach last state-change timestamp and preserve lineage when one pinpoint supersedes or merges into another.",
- "acceptanceCriteria": [
- "Lifecycle state enum with filed, acknowledged, in_progress, blocked, done, superseded",
- "Last state-change timestamp attached",
- "New report can declare first filing, status update, or closure",
- "Preserve lineage when one pinpoint supersedes or merges into another",
- "Tests verify lifecycle state transitions"
- ],
- "passes": true,
- "priority": "P2"
- },
- {
- "id": "US-021",
- "title": "Request body size pre-flight check for OpenAI-compatible provider",
- "description": "Implement pre-flight request body size estimation to prevent 400 Bad Request errors from API gateways with size limits. Based on dogfood findings with kimi-k2.5 testing, DashScope API has a 6MB request body limit that was exceeded by large system prompts.",
- "acceptanceCriteria": [
- "Pre-flight size estimation before sending requests to OpenAI-compatible providers",
- "Clear error message when request exceeds provider-specific size limit",
- "Configuration for different provider limits (6MB DashScope, 100MB OpenAI, etc.)",
- "Unit tests for size estimation and limit checking",
- "Integration with existing error handling for actionable user messages"
- ],
- "passes": true,
- "priority": "P1"
- },
- {
- "id": "US-022",
- "title": "Enhanced error context for API failures",
- "description": "Add structured error context to API failures including request ID tracking across retries, provider-specific error code mapping, and suggested user actions based on error type (e.g., 'Reduce prompt size' for 413, 'Check API key' for 401).",
- "acceptanceCriteria": [
- "Request ID tracking across retries with full context in error messages",
- "Provider-specific error code mapping with actionable suggestions",
- "Suggested user actions for common error types (401, 403, 413, 429, 500, 502-504)",
- "Unit tests for error context extraction",
- "All existing tests pass and clippy is clean"
- ],
- "passes": true,
- "priority": "P1"
- },
- {
- "id": "US-023",
- "title": "Add automatic routing for kimi models to DashScope",
- "description": "Based on dogfood findings with kimi-k2.5 testing, users must manually prefix with dashscope/kimi-k2.5 instead of just using kimi-k2.5. Add automatic routing for kimi/ and kimi- prefixed models to DashScope (similar to qwen models), and add a 'kimi' alias to the model registry.",
- "acceptanceCriteria": [
- "kimi/ and kimi- prefix routing to DashScope in metadata_for_model()",
- "'kimi' alias in MODEL_REGISTRY that resolves to 'kimi-k2.5'",
- "resolve_model_alias() handles the kimi alias correctly",
- "Unit tests for kimi routing (similar to qwen routing tests)",
- "All tests pass and clippy is clean"
- ],
- "passes": true,
- "priority": "P1"
- },
- {
- "id": "US-024",
- "title": "Add token limit metadata for kimi models",
- "description": "The model_token_limit() function has no entries for kimi-k2.5 or kimi-k1.5, causing preflight context window validation to skip these models. Add token limit metadata to enable preflight checks and accurate max token defaults. Per Moonshot AI documentation, kimi-k2.5 supports 256K context window and 16K max output tokens.",
- "acceptanceCriteria": [
- "model_token_limit('kimi-k2.5') returns Some(ModelTokenLimit { max_output_tokens: 16384, context_window_tokens: 256000 })",
- "model_token_limit('kimi-k1.5') returns appropriate limits",
- "model_token_limit('kimi') follows alias chain (kimi → kimi-k2.5) and returns k2.5 limits",
- "preflight_message_request() validates context window for kimi models (via generic preflight, no provider-specific code needed)",
- "Unit tests verify limits and preflight behavior for kimi models",
- "All tests pass and clippy is clean"
- ],
- "passes": true,
- "priority": "P1"
- }
- ],
- "metadata": {
- "lastUpdated": "2026-04-17",
- "completedStories": ["US-001", "US-002", "US-003", "US-004", "US-005", "US-006", "US-007", "US-008", "US-009", "US-010", "US-011", "US-012", "US-013", "US-014", "US-015", "US-016", "US-017", "US-018", "US-019", "US-020", "US-021", "US-022", "US-023", "US-024"],
- "inProgressStories": [],
- "totalStories": 24,
- "status": "completed"
- }
-}
diff --git a/progress.txt b/progress.txt
deleted file mode 100644
index d7953a17..00000000
--- a/progress.txt
+++ /dev/null
@@ -1,378 +0,0 @@
-Ralph Iteration Summary - claw-code Roadmap Implementation
-===========================================================
-
-Iteration 1: 2026-04-16
-------------------------
-
-US-001 COMPLETED (Phase 1.6 - startup-no-evidence evidence bundle + classifier)
-- Files: rust/crates/runtime/src/worker_boot.rs
-- Added StartupFailureClassification enum with 6 variants
-- Added StartupEvidenceBundle with 8 fields
-- Implemented classify_startup_failure() logic
-- Added observe_startup_timeout() method to Worker
-- Tests: 6 new tests verifying classification logic
-
-US-002 COMPLETED (Phase 2 - Canonical lane event schema)
-- Files: rust/crates/runtime/src/lane_events.rs
-- Added EventProvenance enum with 5 labels
-- Added SessionIdentity, LaneOwnership structs
-- Added LaneEventMetadata with sequence/ordering
-- Added LaneEventBuilder for construction
-- Implemented is_terminal_event(), dedupe_terminal_events()
-- Tests: 10 new tests for events and deduplication
-
-US-005 COMPLETED (Phase 4 - Typed task packet format)
-- Files:
- - rust/crates/runtime/src/task_packet.rs
- - rust/crates/runtime/src/task_registry.rs
- - rust/crates/tools/src/lib.rs
-- Added TaskScope enum (Workspace, Module, SingleFile, Custom)
-- Updated TaskPacket with scope_path and worktree fields
-- Added validate_scope_requirements() validation logic
-- Fixed all test compilation errors in dependent modules
-- Tests: Updated existing tests to use new types
-
-PRE-EXISTING IMPLEMENTATIONS (verified working):
-------------------------------------------------
-
-US-003 COMPLETE (Phase 3 - Stale-branch detection)
-- Files: rust/crates/runtime/src/stale_branch.rs
-- BranchFreshness enum (Fresh, Stale, Diverged)
-- StaleBranchPolicy (AutoRebase, AutoMergeForward, WarnOnly, Block)
-- StaleBranchEvent with structured events
-- check_freshness() with git integration
-- apply_policy() with policy resolution
-- Tests: 12 unit tests + 5 integration tests passing
-
-US-004 COMPLETE (Phase 3 - Recovery recipes with ledger)
-- Files: rust/crates/runtime/src/recovery_recipes.rs
-- FailureScenario enum with 7 scenarios
-- RecoveryStep enum with actionable steps
-- RecoveryRecipe with step sequences
-- RecoveryLedger for attempt tracking
-- RecoveryEvent for structured emission
-- attempt_recovery() with escalation logic
-- Tests: 15 unit tests + 1 integration test passing
-
-US-006 COMPLETE (Phase 4 - Policy engine for autonomous coding)
-- Files: rust/crates/runtime/src/policy_engine.rs
-- PolicyRule with condition/action/priority
-- PolicyCondition (And, Or, GreenAt, StaleBranch, etc.)
-- PolicyAction (MergeToDev, RecoverOnce, Escalate, etc.)
-- LaneContext for evaluation context
-- evaluate() for rule matching
-- Tests: 18 unit tests + 6 integration tests passing
-
-US-007 COMPLETE (Phase 5 - Plugin/MCP lifecycle maturity)
-- Files: rust/crates/runtime/src/plugin_lifecycle.rs
-- ServerStatus enum (Healthy, Degraded, Failed)
-- ServerHealth with capabilities tracking
-- PluginState with full lifecycle states
-- PluginLifecycle event tracking
-- PluginHealthcheck structured results
-- DiscoveryResult for capability discovery
-- DegradedMode behavior
-- Tests: 11 unit tests passing
-
-
-Iteration 2026-04-27 - ROADMAP #200 COMPLETED
-------------------------------------------------
-- Selected next actionable backlog item because no active task was in progress.
-- ROADMAP #200: Interactive MCP/tool permission prompts are invisible blockers.
-- Files: rust/crates/runtime/src/worker_boot.rs, rust/crates/runtime/src/recovery_recipes.rs, ROADMAP.md, progress.txt.
-- Added tool_permission_required worker status and event classification for interactive MCP/tool permission gates.
-- Added structured ToolPermissionPrompt payload with server/tool identity and prompt preview.
-- Startup evidence now records tool_permission_prompt_detected and classifies timeout evidence as tool_permission_required.
-- Readiness snapshots now mark tool-permission-gated workers as blocked, not ready/idle.
-- Tests: targeted tool_permission regressions, full runtime test/clippy/fmt pending in Ralph verification loop.
-
-VERIFICATION STATUS:
-------------------
-- cargo build --workspace: PASSED
-- cargo test --workspace: PASSED (476+ unit tests, 12 integration tests)
-- cargo clippy --workspace: PASSED
-
-All 7 stories from prd.json now have passes: true
-
-Iteration 2: 2026-04-16
-------------------------
-
-US-009 COMPLETED (Add unit tests for kimi model compatibility fix)
-- Files: rust/crates/api/src/providers/openai_compat.rs
-- Added 4 comprehensive unit tests:
- 1. model_rejects_is_error_field_detects_kimi_models - verifies detection of kimi-k2.5, kimi-k1.5, dashscope/kimi-k2.5, case insensitivity
- 2. translate_message_includes_is_error_for_non_kimi_models - verifies gpt-4o, grok-3, claude include is_error
- 3. translate_message_excludes_is_error_for_kimi_models - verifies kimi models exclude is_error (prevents 400 Bad Request)
- 4. build_chat_completion_request_kimi_vs_non_kimi_tool_results - full integration test for request building
-- Tests: 4 new tests, 119 unit tests total in api crate (+4), all passing
-- Integration tests: 29 passing (no regressions)
-
-US-010 COMPLETED (Add model compatibility documentation)
-- Files: docs/MODEL_COMPATIBILITY.md
-- Created comprehensive documentation covering:
- 1. Kimi Models (is_error Exclusion) - documents the 400 Bad Request issue and solution
- 2. Reasoning Models (Tuning Parameter Stripping) - covers o1, o3, o4, grok-3-mini, qwen-qwq, qwen3-thinking
- 3. GPT-5 (max_completion_tokens) - documents max_tokens vs max_completion_tokens requirement
- 4. Qwen Models (DashScope Routing) - explains routing and authentication
-- Added implementation details section with key functions
-- Added "Adding New Models" guide for future contributors
-- Added testing section with example commands
-- Cross-referenced with existing code comments in openai_compat.rs
-- cargo clippy passes
-
-Iteration 3: 2026-04-16
-------------------------
-
-US-012 COMPLETED (Trust prompt resolver with allowlist auto-trust)
-- Files: rust/crates/runtime/src/trust_resolver.rs
-- Enhanced TrustConfig with pattern matching and serde support:
- - TrustAllowlistEntry struct with pattern, worktree_pattern, description
- - TrustResolution enum (AutoAllowlisted, ManualApproval)
- - Enhanced TrustEvent variants with serde tags and metadata
- - Glob pattern matching with * and ? wildcards
- - Support for path prefix matching and worktree patterns
-- Updated TrustResolver with new resolve() signature:
- - Added worktree parameter for worktree pattern matching
- - Proper event emission with TrustResolution
- - Manual approval detection from screen text
-- Added helper functions:
- - extract_repo_name() - extracts repo name from path
- - detect_manual_approval() - detects manual trust from screen text
- - glob_matches() - recursive backtracking glob matcher
-- Tests: 25 new tests for pattern matching, serialization, and resolver behavior
-- All 483 runtime tests pass
-- cargo clippy passes with no warnings
-
-US-011 COMPLETED (Performance optimization: reduce API request serialization overhead)
-- Files:
- - rust/crates/api/Cargo.toml (added criterion dev-dependency and bench config)
- - rust/crates/api/benches/request_building.rs (new benchmark suite)
- - rust/crates/api/src/providers/openai_compat.rs (optimizations)
- - rust/crates/api/src/lib.rs (public exports for benchmarks)
-- Optimizations implemented:
- 1. flatten_tool_result_content: Pre-allocate String capacity and avoid intermediate Vec
- - Before: collected to Vec then joined
- - After: single String with pre-calculated capacity, push directly
- 2. Made key functions public for benchmarking: translate_message, build_chat_completion_request,
- flatten_tool_result_content, is_reasoning_model, model_rejects_is_error_field
-- Benchmark results:
- - flatten_tool_result_content/single_text: ~17ns
- - flatten_tool_result_content/multi_text (10 blocks): ~46ns
- - flatten_tool_result_content/large_content (50 blocks): ~11.7µs
- - translate_message/text_only: ~200ns
- - translate_message/tool_result: ~348ns
- - build_chat_completion_request/10 messages: ~16.4µs
- - build_chat_completion_request/100 messages: ~209µs
- - is_reasoning_model detection: ~26-42ns depending on model
-- All tests pass (119 unit tests + 29 integration tests)
-- cargo clippy passes
-
-VERIFICATION STATUS (Iteration 3):
-----------------------------------
-- cargo build --workspace: PASSED
-- cargo test --workspace: PASSED (891+ tests)
-- cargo clippy --workspace --all-targets -- -D warnings: PASSED
-- cargo fmt -- --check: PASSED
-
-All 12 stories from prd.json now have passes: true
-- US-001 through US-007: Pre-existing implementations
-- US-008: kimi-k2.5 model API compatibility fix
-- US-009: Unit tests for kimi model compatibility
-- US-010: Model compatibility documentation
-- US-011: Performance optimization with criterion benchmarks
-- US-012: Trust prompt resolver with allowlist auto-trust
-
-Iteration 4: 2026-04-16
-------------------------
-
-US-013 COMPLETED (Phase 2 - Session event ordering + terminal-state reconciliation)
-- Files: rust/crates/runtime/src/lane_events.rs
-- Added EventTerminality enum (Terminal, Advisory, Uncertainty)
-- Added classify_event_terminality() function for event classification
-- Added reconcile_terminal_events() function for deterministic event ordering:
- - Sorts events by monotonic sequence number
- - Deduplicates terminal events by fingerprint
- - Detects transport death uncertainty (terminal + transport death)
- - Handles out-of-order event bursts
-- Added events_materially_differ() for detecting meaningful differences
-- Added 8 comprehensive tests for reconciliation logic:
- - reconcile_terminal_events_sorts_by_monotonic_sequence
- - reconcile_terminal_events_deduplicates_same_fingerprint
- - reconcile_terminal_events_detects_transport_death_uncertainty
- - reconcile_terminal_events_handles_completed_idle_error_completed_noise
- - reconcile_terminal_events_returns_none_for_empty_input
- - reconcile_terminal_events_preserves_advisory_events
- - events_materially_differ_detects_real_differences
- - classify_event_terminality_correctly_classifies
-- Fixed test compilation issues with LaneEventBuilder API
-
-VERIFICATION STATUS (Iteration 4):
-----------------------------------
-- cargo build --workspace: PASSED
-- cargo test --workspace: PASSED (891+ tests)
-- cargo clippy --workspace --all-targets -- -D warnings: PASSED
-- cargo fmt -- --check: PASSED
-
-US-013 marked passes: true in prd.json
-
-US-014 COMPLETED (Phase 2 - Event provenance / environment labeling)
-- Files: rust/crates/runtime/src/lane_events.rs
-- Added ConfidenceLevel enum (High, Medium, Low, Unknown)
-- Added fields to LaneEventMetadata:
- - environment_label: Option - environment/channel (production, staging, dev)
- - emitter_identity: Option - emitter (clawd, plugin-name, operator-id)
- - confidence_level: Option - trust level for automation
-- Added builder methods: with_environment(), with_emitter(), with_confidence()
-- Added filtering functions:
- - filter_by_provenance() - select events by source
- - filter_by_environment() - select events by environment label
- - filter_by_confidence() - select events above confidence threshold
- - is_test_event() - check if synthetic source (test, healthcheck, replay)
- - is_live_lane_event() - check if production event
-- Added 7 comprehensive tests for US-014:
- - confidence_level_round_trips_through_serialization
- - filter_by_provenance_selects_only_matching_events
- - filter_by_environment_selects_only_matching_environment
- - filter_by_confidence_selects_events_above_threshold
- - is_test_event_detects_synthetic_sources
- - is_live_lane_event_detects_production_events
- - lane_event_metadata_includes_us014_fields
-
-US-016 COMPLETED (Phase 2 - Duplicate terminal-event suppression)
-- Files: rust/crates/runtime/src/lane_events.rs
-- Event fingerprinting already implemented via compute_event_fingerprint()
-- Fingerprint attached via LaneEventMetadata.event_fingerprint
-- Deduplication via dedupe_terminal_events() - returns first occurrence of each fingerprint
-- Raw event history preserved separately from deduplicated actionable events
-- Material difference detection via events_materially_differ():
- - Different event type (Finished vs Failed) is material
- - Different status is material
- - Different failure class is material
- - Different data payload is material
-- Reconcile function surfaces latest terminal event when materially different
-- Added 5 comprehensive tests for US-016:
- - canonical_terminal_event_fingerprint_attached_to_metadata
- - dedupe_terminal_events_suppresses_repeated_fingerprints
- - dedupe_preserves_raw_event_history_separately
- - events_materially_differ_detects_payload_differences
- - reconcile_terminal_events_surfaces_latest_when_different
-
-US-017 COMPLETED (Phase 2 - Lane ownership / scope binding)
-- Files: rust/crates/runtime/src/lane_events.rs
-- LaneOwnership struct already existed with:
- - owner: String - owner/assignee identity
- - workflow_scope: String - workflow scope (claw-code-dogfood, etc.)
- - watcher_action: WatcherAction - Act, Observe, Ignore
-- Ownership preserved through lifecycle via with_ownership() builder method
-- All lifecycle events (Started -> Ready -> Finished) preserve ownership
-- Added 3 comprehensive tests for US-017:
- - lane_ownership_attached_to_metadata
- - lane_ownership_preserved_through_lifecycle_events
- - lane_ownership_watcher_action_variants
-
-US-015 COMPLETED (Phase 2 - Session identity completeness at creation time)
-- Files: rust/crates/runtime/src/lane_events.rs
-- SessionIdentity struct already existed with:
- - title: String - stable title for the session
- - workspace: String - workspace/worktree path
- - purpose: String - lane/session purpose
- - placeholder_reason: Option - reason for placeholder values
-- Added reconcile_enriched() method for updating session identity:
- - Updates title/workspace/purpose with newly available data
- - Clears placeholder_reason when real values are provided
- - Preserves existing values for fields not being updated
- - Allows incremental enrichment without ambiguity
-- Added 2 comprehensive tests:
- - session_identity_reconcile_enriched_updates_fields
- - session_identity_reconcile_preserves_placeholder_if_no_new_data
-
-US-018 COMPLETED (Phase 2 - Nudge acknowledgment / dedupe contract)
-- Files: rust/crates/runtime/src/lane_events.rs
-- Added NudgeTracking struct:
- - nudge_id: String - unique nudge identifier
- - delivered_at: String - timestamp of delivery
- - acknowledged: bool - whether acknowledged
- - acknowledged_at: Option - when acknowledged
- - is_retry: bool - whether this is a retry
- - original_nudge_id: Option - original ID if retry
-- Added NudgeClassification enum (New, Retry, StaleDuplicate)
-- Added classify_nudge() function for deduplication logic
-- Added 6 comprehensive tests for US-018
-
-US-019 COMPLETED (Phase 2 - Stable roadmap-id assignment)
-- Files: rust/crates/runtime/src/lane_events.rs
-- Added RoadmapId struct:
- - id: String - canonical unique identifier
- - filed_at: String - timestamp when filed
- - is_new_filing: bool - new vs update
- - supersedes: Option - lineage for supersedes
-- Added builder methods: new_filing(), update(), supersedes()
-- Added 3 comprehensive tests for US-019
-
-US-020 COMPLETED (Phase 2 - Roadmap item lifecycle state contract)
-- Files: rust/crates/runtime/src/lane_events.rs
-- Added RoadmapLifecycleState enum (Filed, Acknowledged, InProgress, Blocked, Done, Superseded)
-- Added RoadmapLifecycle struct:
- - state: RoadmapLifecycleState - current state
- - state_changed_at: String - last transition timestamp
- - filed_at: String - original filing timestamp
- - lineage: Vec - supersession chain
-- Added methods: new_filed(), transition(), superseded_by(), is_terminal(), is_active()
-- Added 5 comprehensive tests for US-020
-
-VERIFICATION STATUS (Iteration 7):
-----------------------------------
-- cargo build --workspace: PASSED
-- cargo test --workspace: PASSED (891+ tests)
-- cargo clippy --workspace --all-targets -- -D warnings: PASSED
-- cargo fmt -- --check: PASSED
-
-US-013 through US-015 and US-018 through US-020 now marked passes: true
-
-FINAL VERIFICATION (All 20 Stories Complete):
-------------------------------------------------
-- cargo build --workspace: PASSED
-- cargo test --workspace: PASSED (119+ API tests, 39 runtime tests, 12 integration tests)
-- cargo clippy --workspace --all-targets -- -D warnings: PASSED
-- cargo fmt -- --check: PASSED
-
-ALL 20 STORIES FROM PRD COMPLETE:
-- US-001 through US-012: Pre-existing implementations (verified working)
-- US-013: Session event ordering + terminal-state reconciliation
-- US-014: Event provenance / environment labeling
-- US-015: Session identity completeness at creation time
-- US-016: Duplicate terminal-event suppression
-- US-017: Lane ownership / scope binding
-- US-018: Nudge acknowledgment / dedupe contract
-- US-019: Stable roadmap-id assignment
-- US-020: Roadmap item lifecycle state contract
-
-Iteration 8: 2026-04-16
-------------------------
-
-US-021 COMPLETED (Request body size pre-flight check - from dogfood findings)
-- Files:
- - rust/crates/api/src/error.rs (new error variant)
- - rust/crates/api/src/providers/openai_compat.rs
-- Added RequestBodySizeExceeded error variant with actionable message
-- Added max_request_body_bytes to OpenAiCompatConfig:
- - DashScope: 6MB (6_291_456 bytes) - from dogfood with kimi-k2.5
- - OpenAI: 100MB (104_857_600 bytes)
- - xAI: 50MB (52_428_800 bytes)
-- Added estimate_request_body_size() for pre-flight checks
-- Added check_request_body_size() for validation
-- Pre-flight check integrated in send_raw_request()
-- Tests: 5 new tests for size estimation and limit checking
-
-PROJECT STATUS: COMPLETE (21/21 stories)
-
-Iteration 2026-04-29 - ROADMAP #96 COMPLETED
-------------------------------------------------
-- Pulled origin/main: already up to date.
-- Selected ROADMAP #96 as a small repo-local Immediate Backlog item: the `claw --help` Resume-safe command summary leaked slash-command stubs despite the main Interactive command listing filtering them.
-- Files: rust/crates/rusty-claude-cli/src/main.rs, ROADMAP.md, progress.txt.
-- Changed help rendering to filter `resume_supported_slash_commands()` through `STUB_COMMANDS` before building the Resume-safe one-liner.
-- Added `stub_commands_absent_from_resume_safe_help` regression coverage so future stub additions cannot leak into the Resume-safe summary.
-- Targeted verification: `cargo test -p rusty-claude-cli stub_commands_absent_from_resume_safe_help -- --nocapture` passed; `cargo test -p rusty-claude-cli parses_direct_cli_actions -- --nocapture` passed.
-- Format/check verification: `cargo fmt --all --check`, `git diff --check`, and `cargo check -p rusty-claude-cli` passed.
-- Broader clippy note: `cargo clippy -p rusty-claude-cli --all-targets -- -D warnings` is blocked by pre-existing `clippy::unnecessary_wraps` failures in `rust/crates/commands/src/lib.rs` (`render_mcp_report_for`, `render_mcp_report_json_for`), outside this diff.
diff --git a/resolve_repl_model_falls_back_to_anthropic_model_env_when_default.rs_chunk b/resolve_repl_model_falls_back_to_anthropic_model_env_when_default.rs_chunk
deleted file mode 100644
index 60eee673..00000000
--- a/resolve_repl_model_falls_back_to_anthropic_model_env_when_default.rs_chunk
+++ /dev/null
@@ -1,19 +0,0 @@
-#[test]
- fn resolve_repl_model_falls_back_to_anthropic_model_env_when_default() {
- let _guard = env_lock();
- let root = temp_dir();
- fs::create_dir_all(&root).expect("root dir");
- let config_home = root.join("config");
- fs::create_dir_all(&config_home).expect("config home dir");
- std::env::set_var("CLAW_CONFIG_HOME", &config_home);
- std::env::remove_var("ANTHROPIC_MODEL");
- std::env::set_var("ANTHROPIC_MODEL", "sonnet");
-
- let resolved = with_current_dir(&root, || resolve_repl_model(DEFAULT_MODEL.to_string()));
-
- assert_eq!(resolved, "claude-sonnet-4-6");
-
- std::env::remove_var("ANTHROPIC_MODEL");
- std::env::remove_var("CLAW_CONFIG_HOME");
- fs::remove_dir_all(root).expect("cleanup temp dir");
- }
\ No newline at end of file
diff --git a/resolve_repl_model_returns_default_when_env_unset_and_no_config.rs_chunk b/resolve_repl_model_returns_default_when_env_unset_and_no_config.rs_chunk
deleted file mode 100644
index 7728cde5..00000000
--- a/resolve_repl_model_returns_default_when_env_unset_and_no_config.rs_chunk
+++ /dev/null
@@ -1,17 +0,0 @@
-#[test]
- fn resolve_repl_model_returns_default_when_env_unset_and_no_config() {
- let _guard = env_lock();
- let root = temp_dir();
- fs::create_dir_all(&root).expect("root dir");
- let config_home = root.join("config");
- fs::create_dir_all(&config_home).expect("config home dir");
- std::env::set_var("CLAW_CONFIG_HOME", &config_home);
- std::env::remove_var("ANTHROPIC_MODEL");
-
- let resolved = with_current_dir(&root, || resolve_repl_model(DEFAULT_MODEL.to_string()));
-
- assert_eq!(resolved, DEFAULT_MODEL);
-
- std::env::remove_var("CLAW_CONFIG_HOME");
- fs::remove_dir_all(root).expect("cleanup temp dir");
- }
\ No newline at end of file
diff --git a/resolve_repl_model_returns_user_supplied_model_unchanged_when_explicit.rs_chunk b/resolve_repl_model_returns_user_supplied_model_unchanged_when_explicit.rs_chunk
deleted file mode 100644
index bb12d14d..00000000
--- a/resolve_repl_model_returns_user_supplied_model_unchanged_when_explicit.rs_chunk
+++ /dev/null
@@ -1,8 +0,0 @@
-#[test]
- fn resolve_repl_model_returns_user_supplied_model_unchanged_when_explicit() {
- let user_model = "claude-sonnet-4-6".to_string();
-
- let resolved = resolve_repl_model(user_model);
-
- assert_eq!(resolved, "claude-sonnet-4-6");
- }
\ No newline at end of file
diff --git a/resolves_known_model_aliases.rs_chunk b/resolves_known_model_aliases.rs_chunk
deleted file mode 100644
index a532303c..00000000
--- a/resolves_known_model_aliases.rs_chunk
+++ /dev/null
@@ -1,7 +0,0 @@
-#[test]
- fn resolves_known_model_aliases() {
- assert_eq!(resolve_model_alias("opus"), "claude-opus-4-6");
- assert_eq!(resolve_model_alias("sonnet"), "claude-sonnet-4-6");
- assert_eq!(resolve_model_alias("haiku"), "claude-haiku-4-5-20251213");
- assert_eq!(resolve_model_alias("claude-opus"), "claude-opus");
- }
\ No newline at end of file
diff --git a/rm_from_main.py b/rm_from_main.py
deleted file mode 100644
index 1be8a216..00000000
--- a/rm_from_main.py
+++ /dev/null
@@ -1,14 +0,0 @@
-import re
-
-MAIN_FILE = "rust/crates/rusty-claude-cli/src/main.rs"
-
-with open(MAIN_FILE, 'r') as f:
- content = f.read()
-
-# remove AnthropicRuntimeClient from main.rs
-content = re.sub(r'struct AnthropicRuntimeClient \{.*?\n\}\n\nimpl AnthropicRuntimeClient \{.*?\n\}\n\nimpl runtime::Client for AnthropicRuntimeClient \{.*?\n\}', '', content, flags=re.DOTALL | re.MULTILINE)
-
-with open(MAIN_FILE, 'w') as f:
- f.write(content)
-
-print("Removed from main.rs")
diff --git a/user_defined_aliases_resolve_before_provider_dispatch.rs_chunk b/user_defined_aliases_resolve_before_provider_dispatch.rs_chunk
deleted file mode 100644
index 8bcd5f8d..00000000
--- a/user_defined_aliases_resolve_before_provider_dispatch.rs_chunk
+++ /dev/null
@@ -1,38 +0,0 @@
-#[test]
- fn user_defined_aliases_resolve_before_provider_dispatch() {
- // given
- let _guard = env_lock();
- let root = temp_dir();
- let cwd = root.join("project");
- let config_home = root.join("config-home");
- std::fs::create_dir_all(cwd.join(".claw")).expect("project config dir should exist");
- std::fs::create_dir_all(&config_home).expect("config home should exist");
- std::fs::write(
- cwd.join(".claw").join("settings.json"),
- r#"{"aliases":{"fast":"claude-haiku-4-5-20251213","smart":"opus","cheap":"grok-3-mini"}}"#,
- )
- .expect("project config should write");
-
- let original_config_home = std::env::var("CLAW_CONFIG_HOME").ok();
- std::env::set_var("CLAW_CONFIG_HOME", &config_home);
-
- // when
- let direct = with_current_dir(&cwd, || resolve_model_alias_with_config("fast"));
- let chained = with_current_dir(&cwd, || resolve_model_alias_with_config("smart"));
- let cross_provider = with_current_dir(&cwd, || resolve_model_alias_with_config("cheap"));
- let unknown = with_current_dir(&cwd, || resolve_model_alias_with_config("unknown-model"));
- let builtin = with_current_dir(&cwd, || resolve_model_alias_with_config("haiku"));
-
- match original_config_home {
- Some(value) => std::env::set_var("CLAW_CONFIG_HOME", value),
- None => std::env::remove_var("CLAW_CONFIG_HOME"),
- }
- std::fs::remove_dir_all(root).expect("temp config root should clean up");
-
- // then
- assert_eq!(direct, "claude-haiku-4-5-20251213");
- assert_eq!(chained, "claude-opus-4-6");
- assert_eq!(cross_provider, "grok-3-mini");
- assert_eq!(unknown, "unknown-model");
- assert_eq!(builtin, "claude-haiku-4-5-20251213");
- }
\ No newline at end of file