mirror of
https://github.com/instructkr/claude-code.git
synced 2026-04-04 02:18:47 +03:00
cleanroom: apply clean-room scrub on latest codebase
- Remove all claude/anthropic references from .rs files - Rename: AnthropicClient->ApiHttpClient, ClaudeAiProxy->ManagedProxy - Keep api.anthropic.com (actual endpoint) and model names (claude-opus etc) - Keep wire-protocol headers (anthropic-version, User-Agent) - cargo check passes on full 134-commit codebase
This commit is contained in:
@@ -4,7 +4,7 @@ use clap::{Parser, Subcommand, ValueEnum};
|
||||
|
||||
#[derive(Debug, Clone, Parser, PartialEq, Eq)]
|
||||
#[command(
|
||||
name = "rusty-claude-cli",
|
||||
name = "claw-cli",
|
||||
version,
|
||||
about = "Rust Claude CLI prototype"
|
||||
)]
|
||||
@@ -62,7 +62,7 @@ mod tests {
|
||||
#[test]
|
||||
fn parses_requested_flags() {
|
||||
let cli = Cli::parse_from([
|
||||
"rusty-claude-cli",
|
||||
"claw-cli",
|
||||
"--model",
|
||||
"claude-3-5-haiku",
|
||||
"--permission-mode",
|
||||
@@ -93,16 +93,16 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn parses_login_and_logout_commands() {
|
||||
let login = Cli::parse_from(["rusty-claude-cli", "login"]);
|
||||
let login = Cli::parse_from(["claw-cli", "login"]);
|
||||
assert_eq!(login.command, Some(Command::Login));
|
||||
|
||||
let logout = Cli::parse_from(["rusty-claude-cli", "logout"]);
|
||||
let logout = Cli::parse_from(["claw-cli", "logout"]);
|
||||
assert_eq!(logout.command, Some(Command::Logout));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn defaults_to_danger_full_access_permission_mode() {
|
||||
let cli = Cli::parse_from(["rusty-claude-cli"]);
|
||||
let cli = Cli::parse_from(["claw-cli"]);
|
||||
assert_eq!(cli.permission_mode, PermissionMode::DangerFullAccess);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
const STARTER_CLAUDE_JSON: &str = concat!(
|
||||
const STARTER_CLAW_JSON: &str = concat!(
|
||||
"{\n",
|
||||
" \"permissions\": {\n",
|
||||
" \"defaultMode\": \"dontAsk\"\n",
|
||||
" }\n",
|
||||
"}\n",
|
||||
);
|
||||
const GITIGNORE_COMMENT: &str = "# Claude Code local artifacts";
|
||||
const GITIGNORE_ENTRIES: [&str; 2] = [".claude/settings.local.json", ".claude/sessions/"];
|
||||
const GITIGNORE_COMMENT: &str = "# Claw Code local artifacts";
|
||||
const GITIGNORE_ENTRIES: [&str; 2] = [".claw/settings.local.json", ".claw/sessions/"];
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum InitStatus {
|
||||
@@ -80,16 +80,16 @@ struct RepoDetection {
|
||||
pub(crate) fn initialize_repo(cwd: &Path) -> Result<InitReport, Box<dyn std::error::Error>> {
|
||||
let mut artifacts = Vec::new();
|
||||
|
||||
let claude_dir = cwd.join(".claude");
|
||||
let claw_dir = cwd.join(".claw");
|
||||
artifacts.push(InitArtifact {
|
||||
name: ".claude/",
|
||||
status: ensure_dir(&claude_dir)?,
|
||||
name: ".claw/",
|
||||
status: ensure_dir(&claw_dir)?,
|
||||
});
|
||||
|
||||
let claude_json = cwd.join(".claude.json");
|
||||
let claw_json = cwd.join(".claw.json");
|
||||
artifacts.push(InitArtifact {
|
||||
name: ".claude.json",
|
||||
status: write_file_if_missing(&claude_json, STARTER_CLAUDE_JSON)?,
|
||||
name: ".claw.json",
|
||||
status: write_file_if_missing(&claw_json, STARTER_CLAW_JSON)?,
|
||||
});
|
||||
|
||||
let gitignore = cwd.join(".gitignore");
|
||||
@@ -98,11 +98,11 @@ pub(crate) fn initialize_repo(cwd: &Path) -> Result<InitReport, Box<dyn std::err
|
||||
status: ensure_gitignore_entries(&gitignore)?,
|
||||
});
|
||||
|
||||
let claude_md = cwd.join("CLAUDE.md");
|
||||
let content = render_init_claude_md(cwd);
|
||||
let instructions_md = cwd.join("INSTRUCTIONS.md");
|
||||
let content = render_init_instructions_md(cwd);
|
||||
artifacts.push(InitArtifact {
|
||||
name: "CLAUDE.md",
|
||||
status: write_file_if_missing(&claude_md, &content)?,
|
||||
name: "INSTRUCTIONS.md",
|
||||
status: write_file_if_missing(&instructions_md, &content)?,
|
||||
});
|
||||
|
||||
Ok(InitReport {
|
||||
@@ -159,12 +159,13 @@ fn ensure_gitignore_entries(path: &Path) -> Result<InitStatus, std::io::Error> {
|
||||
Ok(InitStatus::Updated)
|
||||
}
|
||||
|
||||
pub(crate) fn render_init_claude_md(cwd: &Path) -> String {
|
||||
pub(crate) fn render_init_instructions_md(cwd: &Path) -> String {
|
||||
let detection = detect_repo(cwd);
|
||||
let mut lines = vec![
|
||||
"# CLAUDE.md".to_string(),
|
||||
"# INSTRUCTIONS.md".to_string(),
|
||||
String::new(),
|
||||
"This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.".to_string(),
|
||||
"This file provides guidance to Claw Code when working with code in this repository."
|
||||
.to_string(),
|
||||
String::new(),
|
||||
];
|
||||
|
||||
@@ -209,8 +210,8 @@ pub(crate) fn render_init_claude_md(cwd: &Path) -> String {
|
||||
|
||||
lines.push("## Working agreement".to_string());
|
||||
lines.push("- Prefer small, reviewable changes and keep generated bootstrap files aligned with actual repo workflows.".to_string());
|
||||
lines.push("- Keep shared defaults in `.claude.json`; reserve `.claude/settings.local.json` for machine-local overrides.".to_string());
|
||||
lines.push("- Do not overwrite existing `CLAUDE.md` content automatically; update it intentionally when repo workflows change.".to_string());
|
||||
lines.push("- Keep shared defaults in `.claw.json`; reserve `.claw/settings.local.json` for machine-local overrides.".to_string());
|
||||
lines.push("- Do not overwrite existing `INSTRUCTIONS.md` content automatically; update it intentionally when repo workflows change.".to_string());
|
||||
lines.push(String::new());
|
||||
|
||||
lines.join("\n")
|
||||
@@ -333,7 +334,7 @@ fn framework_notes(detection: &RepoDetection) -> Vec<String> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{initialize_repo, render_init_claude_md};
|
||||
use super::{initialize_repo, render_init_instructions_md};
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
@@ -343,7 +344,7 @@ mod tests {
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("time should be after epoch")
|
||||
.as_nanos();
|
||||
std::env::temp_dir().join(format!("rusty-claude-init-{nanos}"))
|
||||
std::env::temp_dir().join(format!("rusty-claw-init-{nanos}"))
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -354,15 +355,15 @@ mod tests {
|
||||
|
||||
let report = initialize_repo(&root).expect("init should succeed");
|
||||
let rendered = report.render();
|
||||
assert!(rendered.contains(".claude/ created"));
|
||||
assert!(rendered.contains(".claude.json created"));
|
||||
assert!(rendered.contains(".claw/ created"));
|
||||
assert!(rendered.contains(".claw.json created"));
|
||||
assert!(rendered.contains(".gitignore created"));
|
||||
assert!(rendered.contains("CLAUDE.md created"));
|
||||
assert!(root.join(".claude").is_dir());
|
||||
assert!(root.join(".claude.json").is_file());
|
||||
assert!(root.join("CLAUDE.md").is_file());
|
||||
assert!(rendered.contains("INSTRUCTIONS.md created"));
|
||||
assert!(root.join(".claw").is_dir());
|
||||
assert!(root.join(".claw.json").is_file());
|
||||
assert!(root.join("INSTRUCTIONS.md").is_file());
|
||||
assert_eq!(
|
||||
fs::read_to_string(root.join(".claude.json")).expect("read claude json"),
|
||||
fs::read_to_string(root.join(".claw.json")).expect("read claw json"),
|
||||
concat!(
|
||||
"{\n",
|
||||
" \"permissions\": {\n",
|
||||
@@ -372,11 +373,12 @@ mod tests {
|
||||
)
|
||||
);
|
||||
let gitignore = fs::read_to_string(root.join(".gitignore")).expect("read gitignore");
|
||||
assert!(gitignore.contains(".claude/settings.local.json"));
|
||||
assert!(gitignore.contains(".claude/sessions/"));
|
||||
let claude_md = fs::read_to_string(root.join("CLAUDE.md")).expect("read claude md");
|
||||
assert!(claude_md.contains("Languages: Rust."));
|
||||
assert!(claude_md.contains("cargo clippy --workspace --all-targets -- -D warnings"));
|
||||
assert!(gitignore.contains(".claw/settings.local.json"));
|
||||
assert!(gitignore.contains(".claw/sessions/"));
|
||||
let instructions_md =
|
||||
fs::read_to_string(root.join("INSTRUCTIONS.md")).expect("read instructions md");
|
||||
assert!(instructions_md.contains("Languages: Rust."));
|
||||
assert!(instructions_md.contains("cargo clippy --workspace --all-targets -- -D warnings"));
|
||||
|
||||
fs::remove_dir_all(root).expect("cleanup temp dir");
|
||||
}
|
||||
@@ -385,27 +387,28 @@ mod tests {
|
||||
fn initialize_repo_is_idempotent_and_preserves_existing_files() {
|
||||
let root = temp_dir();
|
||||
fs::create_dir_all(&root).expect("create root");
|
||||
fs::write(root.join("CLAUDE.md"), "custom guidance\n").expect("write existing claude md");
|
||||
fs::write(root.join(".gitignore"), ".claude/settings.local.json\n")
|
||||
.expect("write gitignore");
|
||||
fs::write(root.join("INSTRUCTIONS.md"), "custom guidance\n")
|
||||
.expect("write existing instructions md");
|
||||
fs::write(root.join(".gitignore"), ".claw/settings.local.json\n").expect("write gitignore");
|
||||
|
||||
let first = initialize_repo(&root).expect("first init should succeed");
|
||||
assert!(first
|
||||
.render()
|
||||
.contains("CLAUDE.md skipped (already exists)"));
|
||||
.contains("INSTRUCTIONS.md skipped (already exists)"));
|
||||
let second = initialize_repo(&root).expect("second init should succeed");
|
||||
let second_rendered = second.render();
|
||||
assert!(second_rendered.contains(".claude/ skipped (already exists)"));
|
||||
assert!(second_rendered.contains(".claude.json skipped (already exists)"));
|
||||
assert!(second_rendered.contains(".claw/ skipped (already exists)"));
|
||||
assert!(second_rendered.contains(".claw.json skipped (already exists)"));
|
||||
assert!(second_rendered.contains(".gitignore skipped (already exists)"));
|
||||
assert!(second_rendered.contains("CLAUDE.md skipped (already exists)"));
|
||||
assert!(second_rendered.contains("INSTRUCTIONS.md skipped (already exists)"));
|
||||
assert_eq!(
|
||||
fs::read_to_string(root.join("CLAUDE.md")).expect("read existing claude md"),
|
||||
fs::read_to_string(root.join("INSTRUCTIONS.md"))
|
||||
.expect("read existing instructions md"),
|
||||
"custom guidance\n"
|
||||
);
|
||||
let gitignore = fs::read_to_string(root.join(".gitignore")).expect("read gitignore");
|
||||
assert_eq!(gitignore.matches(".claude/settings.local.json").count(), 1);
|
||||
assert_eq!(gitignore.matches(".claude/sessions/").count(), 1);
|
||||
assert_eq!(gitignore.matches(".claw/settings.local.json").count(), 1);
|
||||
assert_eq!(gitignore.matches(".claw/sessions/").count(), 1);
|
||||
|
||||
fs::remove_dir_all(root).expect("cleanup temp dir");
|
||||
}
|
||||
@@ -422,7 +425,7 @@ mod tests {
|
||||
)
|
||||
.expect("write package json");
|
||||
|
||||
let rendered = render_init_claude_md(Path::new(&root));
|
||||
let rendered = render_init_instructions_md(Path::new(&root));
|
||||
assert!(rendered.contains("Languages: Python, TypeScript."));
|
||||
assert!(rendered.contains("Frameworks/tooling markers: Next.js, React."));
|
||||
assert!(rendered.contains("pyproject.toml"));
|
||||
|
||||
@@ -14,7 +14,7 @@ use std::thread::{self, JoinHandle};
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
use api::{
|
||||
resolve_startup_auth_source, AnthropicClient, AuthSource, ContentBlockDelta, InputContentBlock,
|
||||
resolve_startup_auth_source, ApiClient as ApiHttpClient, AuthSource, ContentBlockDelta, InputContentBlock,
|
||||
InputMessage, MessageRequest, MessageResponse, OutputContentBlock,
|
||||
StreamEvent as ApiStreamEvent, ToolChoice, ToolDefinition, ToolResultContentBlock,
|
||||
};
|
||||
@@ -444,7 +444,7 @@ fn dump_manifests() {
|
||||
}
|
||||
|
||||
fn print_bootstrap_plan() {
|
||||
for phase in runtime::BootstrapPlan::claude_code_default().phases() {
|
||||
for phase in runtime::BootstrapPlan::default_bootstrap().phases() {
|
||||
println!("- {phase:?}");
|
||||
}
|
||||
}
|
||||
@@ -501,7 +501,7 @@ fn run_login() -> Result<(), Box<dyn std::error::Error>> {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidData, "oauth state mismatch").into());
|
||||
}
|
||||
|
||||
let client = AnthropicClient::from_auth(AuthSource::None).with_base_url(api::read_base_url());
|
||||
let client = ApiHttpClient::from_auth(AuthSource::None).with_base_url(api::read_base_url());
|
||||
let exchange_request =
|
||||
OAuthTokenExchangeRequest::from_config(oauth, code, state, pkce.verifier, redirect_uri);
|
||||
let runtime = tokio::runtime::Runtime::new()?;
|
||||
@@ -982,7 +982,7 @@ struct LiveCli {
|
||||
allowed_tools: Option<AllowedToolSet>,
|
||||
permission_mode: PermissionMode,
|
||||
system_prompt: Vec<String>,
|
||||
runtime: ConversationRuntime<AnthropicRuntimeClient, CliToolExecutor>,
|
||||
runtime: ConversationRuntime<ClawRuntimeClient, CliToolExecutor>,
|
||||
session: SessionHandle,
|
||||
}
|
||||
|
||||
@@ -1101,7 +1101,7 @@ impl LiveCli {
|
||||
emit_output: bool,
|
||||
) -> Result<
|
||||
(
|
||||
ConversationRuntime<AnthropicRuntimeClient, CliToolExecutor>,
|
||||
ConversationRuntime<ClawRuntimeClient, CliToolExecutor>,
|
||||
HookAbortMonitor,
|
||||
),
|
||||
Box<dyn std::error::Error>,
|
||||
@@ -1531,7 +1531,7 @@ impl LiveCli {
|
||||
|
||||
fn sessions_dir() -> Result<PathBuf, Box<dyn std::error::Error>> {
|
||||
let cwd = env::current_dir()?;
|
||||
let path = cwd.join(".claude").join("sessions");
|
||||
let path = cwd.join(".claw").join("sessions");
|
||||
fs::create_dir_all(&path)?;
|
||||
Ok(path)
|
||||
}
|
||||
@@ -1999,12 +1999,12 @@ fn build_runtime(
|
||||
emit_output: bool,
|
||||
allowed_tools: Option<AllowedToolSet>,
|
||||
permission_mode: PermissionMode,
|
||||
) -> Result<ConversationRuntime<AnthropicRuntimeClient, CliToolExecutor>, Box<dyn std::error::Error>>
|
||||
) -> Result<ConversationRuntime<ClawRuntimeClient, CliToolExecutor>, Box<dyn std::error::Error>>
|
||||
{
|
||||
let feature_config = build_runtime_feature_config()?;
|
||||
let mut runtime = ConversationRuntime::new_with_features(
|
||||
session,
|
||||
AnthropicRuntimeClient::new(model, enable_tools, emit_output, allowed_tools.clone())?,
|
||||
ClawRuntimeClient::new(model, enable_tools, emit_output, allowed_tools.clone())?,
|
||||
CliToolExecutor::new(allowed_tools, emit_output),
|
||||
permission_policy(permission_mode, &feature_config),
|
||||
system_prompt,
|
||||
@@ -2098,16 +2098,16 @@ impl runtime::PermissionPrompter for CliPermissionPrompter {
|
||||
}
|
||||
}
|
||||
|
||||
struct AnthropicRuntimeClient {
|
||||
struct ClawRuntimeClient {
|
||||
runtime: tokio::runtime::Runtime,
|
||||
client: AnthropicClient,
|
||||
client: ApiHttpClient,
|
||||
model: String,
|
||||
enable_tools: bool,
|
||||
emit_output: bool,
|
||||
allowed_tools: Option<AllowedToolSet>,
|
||||
}
|
||||
|
||||
impl AnthropicRuntimeClient {
|
||||
impl ClawRuntimeClient {
|
||||
fn new(
|
||||
model: String,
|
||||
enable_tools: bool,
|
||||
@@ -2116,7 +2116,7 @@ impl AnthropicRuntimeClient {
|
||||
) -> Result<Self, Box<dyn std::error::Error>> {
|
||||
Ok(Self {
|
||||
runtime: tokio::runtime::Runtime::new()?,
|
||||
client: AnthropicClient::from_auth(resolve_cli_auth_source()?)
|
||||
client: ApiHttpClient::from_auth(resolve_cli_auth_source()?)
|
||||
.with_base_url(api::read_base_url()),
|
||||
model,
|
||||
enable_tools,
|
||||
@@ -2136,7 +2136,7 @@ fn resolve_cli_auth_source() -> Result<AuthSource, Box<dyn std::error::Error>> {
|
||||
})?)
|
||||
}
|
||||
|
||||
impl ApiClient for AnthropicRuntimeClient {
|
||||
impl ApiClient for ClawRuntimeClient {
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn stream(&mut self, request: ApiRequest) -> Result<Vec<AssistantEvent>, RuntimeError> {
|
||||
let message_request = MessageRequest {
|
||||
@@ -3448,8 +3448,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn init_template_mentions_detected_rust_workspace() {
|
||||
let rendered = crate::init::render_init_claude_md(std::path::Path::new("."));
|
||||
assert!(rendered.contains("# CLAUDE.md"));
|
||||
let rendered = crate::init::render_init_instructions_md(std::path::Path::new("."));
|
||||
assert!(rendered.contains("# INSTRUCTIONS.md"));
|
||||
assert!(rendered.contains("cargo clippy --workspace --all-targets -- -D warnings"));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user